那些年我们用过的第三方库
SnapKit(Masonry) 的使用 - 杨志平
这两个库的用法都是差不多的,只是由两个不同的人来主导开源
**SnapKit**是Swift版
**Masonry**是OC版自动布局及交互式编程是iOS开发的趋势,同时Swift也会在不久将来替换OC语言。所以现在的iOS开发者可以开始学习Swift2.0 以及应用 Autolayout 来编程
代码对比(概况了解)
开始前OC原生布局代码
UIView *superview = self;
UIView *view1 = [[UIView alloc] init];
view1.translatesAutoresizingMaskIntoConstraints = NO;
view1.backgroundColor = [UIColor greenColor];
[superview addSubview:view1];
UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);
[superview addConstraints:@[
//view1 constraints
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:padding.top],
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:padding.left],
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:-padding.bottom],
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeRight
multiplier:1
constant:-padding.right],
]];
使用Masonry
精简
UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(superview.mas_top).with.offset(padding.top); //with is an optional semantic filler
make.left.equalTo(superview.mas_left).with.offset(padding.left);
make.bottom.equalTo(superview.mas_bottom).with.offset(- padding.bottom);
make.right.equalTo(superview.mas_right).with.offset(-padding.right);
}];
更加精简
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(superview).with.insets(padding);
}];
同理使用SnapKit
精简
let box = UIView()
superview.addSubview(box)
box.snp_makeConstraints { (make) -> Void in
make.top.equalTo(superview).offset(20)
make.left.equalTo(superview).offset(20)
make.bottom.equalTo(superview).offset(-20)
make.right.equalTo(superview).offset(-20)
}
更加精简
box.snp_makeConstraints { (make) -> Void in
make.edges.equalTo(superview).inset(UIEdgeInsetsMake(20, 20, 20, 20))
}
如何使用 && 原理
常见的约束类型对比
ViewAttribute | NSLayoutAttribute |
---|---|
view.snp_left | NSLayoutAttribute.Left |
view.snp_right | NSLayoutAttribute.Right |
view.snp_top | NSLayoutAttribute.Top |
view.snp_bottom | NSLayoutAttribute.Bottom |
view.snp_leading | NSLayoutAttribute.Leading |
view.snp_trailing | NSLayoutAttribute.Trailing |
view.snp_width | NSLayoutAttribute.Width |
view.snp_height | NSLayoutAttribute.Height |
view.snp_centerX | NSLayoutAttribute.CenterX |
view.snp_centerY | NSLayoutAttribute.CenterY |
view.snp_baseline | NSLayoutAttribute.Baseline |
常见的用法
make.top.equalTo(42)
make.lessThanOrEqualTo.equalTo(SuperView)
make.top.equalTo(SuperView)
make.size.equalTo(CGSizeMake(50, 100))
make.edges.equalTo(UIEdgeInsetsMake(10, 0, 10, 0))
make.left.equalTo(view).offset(UIEdgeInsetsMake(10, 0, 10, 0))
make.height.equalTo(OtherView).offset(10)
make.trailing.equalTo(OtherView.snp_trailing).offset(10)
make.bottom.equalTo(-20).priority(250)
对比交互式编程的约束布局
JSONModel for swift 的探索 - 曾铭
// 可在 Playground 中尝试
import Foundation
import UIKit
// 基本的类型转换
let a:String = ""
let b = ""
var c:String? = nil
c = "test"
let d:String = c as String!
var e = Int(c!)
e = Int("123")
var f = Int("123")!
print("a type:\(a.dynamicType)")
print("b type:\(b.dynamicType)")
print("c type:\(c.dynamicType)")
print("d type:\(d.dynamicType)")
print("e type:\(e.dynamicType)")
print("f type:\(f.dynamicType)\n")
// KVC for NSObject
class FooKVC : NSObject {
var p1 : String = "s"
}
let fk1 = FooKVC()
fk1.p1
fk1.setValue("y", forKey: "p1")
fk1.p1
// reflect for swift2.0
class A
{
var name = "namevalue"
var age = 123
var some:(String, Int) = ("ming", 2)
}
let a1 = A()
a1.age = 456
a1.age
let r = Mirror(reflecting: a1)
for c in r.children {
print(c.label.dynamicType)
print(c.label)
print(c.value.dynamicType)
print(c.value)
print("===")
}
- KVO for NSObject 略, 注意监听者与被监听者都要是 NSObject 子类
JSONModel for swift?
NB: Swift works in a different way under the hood than Objective-C. Therefore I can’t find a way to re-create JSONModel in Swift. JSONModel in Objective-C works in Swift apps through CocoaPods or as an imported Objective-C library.
JSONModel 做的事情
- String(NSData) -> Dictionary(Array)
- Dictionary(Array) -> Model-Object
对应实现
- 容易:
- swift 容器取值的坑 https://github.com/SwiftyJSON/SwiftyJSON
- swift 反射不支持赋值,没办法
- 通过 NSObject KVC 解决 https://github.com/PonyCui/PPJSONSerialization
- 临时方案?
参考链接
RATreeView的简单使用 - 张超耀
RATreeView:实现树形结构的TableView;点击每个cell,都可以展开出现新的cell;可以自定义树的层数
主要方法介绍
cell的高度
-(CGFloat)treeView:(RATreeView *)treeView heightForRowForItem:(id)item treeNodeInfo:(RATreeNodeInfo *)treeNodeInfo
这个函数决定是否可以展开,通过设定我们可以设置哪些单元格可以展开到下一层,哪些不可以展开
- (BOOL)treeView:(RATreeView *)treeView shouldExpandItem:(id)item treeNodeInfo:(RATreeNodeInfo *)treeNodeInfo
这个看字面意识就理解了,在单元格显示之前(或者说将要显示时)我们可以做些设置,这里是设置相应深度的颜色背景
- (void)treeView:(RATreeView *)treeView willDisplayCell:(UITableViewCell *)cell forItem:(id)item treeNodeInfo:(RATreeNodeInfo *)treeNodeInfo
这里就是我们最熟悉的点击cell处理函数,看代码慢慢体会treeNodeInfo的使用,不想多说了
-(void)treeView:(RATreeView *)treeView didSelectRowForItem:(id)item treeNodeInfo:(RATreeNodeInfo *)treeNodeInfo
数据源处理,相当于UITableViewCell处理,关键还是理解treeNodeInfo概念
- (UITableViewCell *)treeView:(RATreeView *)treeView cellForItem:(id)item treeNodeInfo:(RATreeNodeInfo *)treeNodeInfo
返回每一层包含成员的个数,来制表
- (NSInteger)treeView:(RATreeView *)treeView numberOfChildrenOfItem:(id)item
返回cell对象
- (id)treeView:(RATreeView *)treeView child:(NSInteger)index ofItem:(id)item
RATreeView - github
Facebook 开源的图片加载库Fresco - 王胜
Fresco诞生背景
为提高Android中图片的加载速度,一般的图片库都采用了三级缓存:Memory Cache、Disk Cache和Network。但是,Android的系统层是将物理内存平均分配给每一个App。这样每个App所分配的空间都是有限的,早起的android设备,每个App只被分配16MB空间,这样,如果App中使用大量的图片,那么很容易因OOM而Crashes掉。Facebook App正是大量使用图片的App,面临这个问题刻不容缓,所以他们历尽艰难,开发了Fresco图片加载库。
Fresco诞生过程
内存区域分析:
Java heap
每个厂商会为App分配一个固定尺寸的运行空间。所有的申请通过Java的new操作申请,操作相对安全,通过GC内存自动回收保证内存不被泄露。但不幸的时,GC不够精确化,回收得不够及时。因此还是会存在OOM。
Native heap
通过C或者C++可绕过Java虚拟机直接操作物理内存,但Java程序员习惯了GC的自动回收,很难操作C++的手动操作内存。
Ashmen
Android还有一块内存区域,叫Ashmen。这里的操作很像Nativew heap,但是这里是系统调用的。Java 应用程序是不能直接访问Ashmen的,但是一些例外的情况可以操作,图片就是一种例外。
BitmapFactory.Options = new BitmapFactory.Options(); options.inPurgeable = true; Bitmap bitmap = BitmapFactory.decodeByteArray(jpeg, 0, jpeg.length, options);
难点突破:
尽管发现了Purgeable bitmaps,但是这个解码的过程是在UI线程操作的,因此他们又采用了异步实现,并保证了UI线程不引用时,unpin的区域不会被释放。
上层构建
提供给上层调用时,采用了MVC的架构:
- Model:DraweeHierarchy
- Control:DraweeControllers
- View:DraweeViews
使用示例
gradle配置中添加库引用
```
compile ‘com.facebook.fresco:fresco:0.6.1+’
2. xml中添加组件
```XML
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/sdv"
android:layout_width="match_parent"
android:layout_height="match_parent"
fresco:roundAsCircle="true"
fresco:roundingBorderWidth="1dp"
fresco:roundingBorderColor="#00ff00"
代码中指定图片地址
```Java
SimpleDraweeView sdv = (SimpleDraweeView) findViewById(R.id.sdv);
sdv.setImageURI(Uri.parse(“http://g.hiphotos.baidu.com/image/pic/item/2e2eb9389b504fc2b351980be7dde71190ef6db5.jpg"));
### 参考资料:
- [Fresco的由来](https://code.facebook.com/posts/366199913563917/introducing-fresco-a-new-image-library-for-android/)
- [Fresco的源码托管](http://github.com/facebook/fresco)
- [中文使用手册](http://fresco-cn.org/docs/index.html)
----
#SIAlertView 阅读 - 潘君
- 创建自定义alert view的流程
自定义window->添加自定义view controller->定制view->view引用window
- @class
@class SIAlertView;
能不使用import的就不使用
用@class代替
- 通知 和 Block
- 层级
const UIWindowLevel UIWindowLevelSIAlert = 1996.0; // don’t overlap system’s alert
const UIWindowLevel UIWindowLevelSIAlertBackground = 1985.0; // below the alert window
- UIViewTintAdjustmentMode
通过获取keyWindow的`UIViewTintAdjustmentMode`来设置alertWindow的
该属性能够设置tint的调整模式
typedef enum {
// 和父视图的一样
UIViewTintAdjustmentModeAutomatic,
// 不对tintColor做任何修改
UIViewTintAdjustmentModeNormal,
// 在原有tintColor基础上变暗
UIViewTintAdjustmentModeDimmed,}UIViewTintAdjustmentMode;
- iOS特有版本代码
#ifdef __IPHONE_7_0
//some code
#endif
此处填写iOS7才能运行的代码
- initialize
- (void)initialize
{
if (self != [SIAlertView class])
return;
// 默认值赋值
}
一些值放在+(void)initialize;中赋值为默认值,这样不管通过何种方式初始化
- UIAppearance
SIAlertView *appearance = [self appearance];
UIView符合UIAppearence协议,能够全局修改所有实例的UI
- 调用Bundle中资源
[UIImage imageNamed:@"SIAlertView.bundle/button-default"]
bundle中资源的调用方法
- _cmd
oc特有的方法,无法通过c语言获取
- [self invalidateLayout]
- 合理利用循环引用
if (!self.alertWindow) {
UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
window.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
window.opaque = NO;
window.windowLevel = UIWindowLevelSIAlert;
window.rootViewController = viewController;
self.alertWindow = window;
}
- oldKeyWindow
通知alert后面的视图转变方向
取用一些oldKeyWindow的值
----
## android饼图库 -吴明
- 饼图选择
- [AChartEngine](https://github.com/jondwillis/AChartEngine/tree/master/achartengine):(太丑了)
- [xcl-charts](https://github.com/xcltapestry/XCL-Charts):(接口文档没有)
- [HelloCharts](https://github.com/lecho/hellocharts-android):(接口文档没有)
- [MPAndroidChart](https://github.com/PhilJay/MPAndroidChart):(接口文档多)
- [MPAndroidChart](https://github.com/PhilJay/MPAndroidChart)
- ![Alt Image Text](https://camo.githubusercontent.com/7e8a4a3c938c21d032d44d999edd781b6e146f2a/68747470733a2f2f7261772e6769746875622e636f6d2f5068696c4a61792f4d50416e64726f696443686172742f6d61737465722f73637265656e73686f74732f73696d706c6564657369676e5f7069656368617274312e706e67)
- 饼图对象:PieChat
- [详见接口文档](https://github.com/PhilJay/MPAndroidChart/wiki)
----
## HeaderFooterRecyclerViewAdapter——李仙鹏
[HeaderFooterRecyclerViewAdapter](https://gist.github.com/mheras/0908873267def75dc746),用于RecyclerView。可方便的添加header或者footer。使用非常简单,只需要按照实际需求,在对应的header、content、footer相关方法进行重写即可。
附上源码
public abstract class HeaderFooterRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int VIEW_TYPE_MAX_COUNT = 1000;
private static final int HEADER_VIEW_TYPE_OFFSET = 0;
private static final int FOOTER_VIEW_TYPE_OFFSET = HEADER_VIEW_TYPE_OFFSET + VIEW_TYPE_MAX_COUNT;
private static final int CONTENT_VIEW_TYPE_OFFSET = FOOTER_VIEW_TYPE_OFFSET + VIEW_TYPE_MAX_COUNT;
private int headerItemCount;
private int contentItemCount;
private int footerItemCount;
/**
* {@inheritDoc}
*/
@Override
public final RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// Delegate to proper methods based on the viewType ranges.
if (viewType >= HEADER_VIEW_TYPE_OFFSET && viewType < HEADER_VIEW_TYPE_OFFSET + VIEW_TYPE_MAX_COUNT) {
return onCreateHeaderItemViewHolder(parent, viewType - HEADER_VIEW_TYPE_OFFSET);
} else if (viewType >= FOOTER_VIEW_TYPE_OFFSET && viewType < FOOTER_VIEW_TYPE_OFFSET + VIEW_TYPE_MAX_COUNT) {
return onCreateFooterItemViewHolder(parent, viewType - FOOTER_VIEW_TYPE_OFFSET);
} else if (viewType >= CONTENT_VIEW_TYPE_OFFSET && viewType < CONTENT_VIEW_TYPE_OFFSET + VIEW_TYPE_MAX_COUNT) {
return onCreateContentItemViewHolder(parent, viewType - CONTENT_VIEW_TYPE_OFFSET);
} else {
// This shouldn't happen as we check that the viewType provided by the client is valid.
throw new IllegalStateException();
}
}
/**
* {@inheritDoc}
*/
@Override
public final void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
// Delegate to proper methods based on the viewType ranges.
if (headerItemCount > 0 && position < headerItemCount) {
onBindHeaderItemViewHolder(viewHolder, position);
} else if (contentItemCount > 0 && position - headerItemCount < contentItemCount) {
onBindContentItemViewHolder(viewHolder, position - headerItemCount);
} else {
onBindFooterItemViewHolder(viewHolder, position - headerItemCount - contentItemCount);
}
}
/**
* {@inheritDoc}
*/
@Override
public final int getItemCount() {
// Cache the counts and return the sum of them.
headerItemCount = getHeaderItemCount();
contentItemCount = getContentItemCount();
footerItemCount = getFooterItemCount();
return headerItemCount + contentItemCount + footerItemCount;
}
/**
* {@inheritDoc}
*/
@Override
public final int getItemViewType(int position) {
// Delegate to proper methods based on the position, but validate first.
if (headerItemCount > 0 && position < headerItemCount) {
return validateViewType(getHeaderItemViewType(position)) + HEADER_VIEW_TYPE_OFFSET;
} else if (contentItemCount > 0 && position - headerItemCount < contentItemCount) {
return validateViewType(getContentItemViewType(position - headerItemCount)) + CONTENT_VIEW_TYPE_OFFSET;
} else {
return validateViewType(getFooterItemViewType(position - headerItemCount - contentItemCount)) + FOOTER_VIEW_TYPE_OFFSET;
}
}
/**
* Validates that the view type is within the valid range.
*
* @param viewType the view type.
* @return the given view type.
*/
private int validateViewType(int viewType) {
if (viewType < 0 || viewType >= VIEW_TYPE_MAX_COUNT) {
throw new IllegalStateException("viewType must be between 0 and " + VIEW_TYPE_MAX_COUNT);
}
return viewType;
}
/**
* Notifies that a header item is inserted.
*
* @param position the position of the header item.
*/
public final void notifyHeaderItemInserted(int position) {
int newHeaderItemCount = getHeaderItemCount();
if (position < 0 || position >= newHeaderItemCount) {
throw new IndexOutOfBoundsException("The given position " + position + " is not within the position bounds for header items [0 - " + (newHeaderItemCount - 1) + "].");
}
notifyItemInserted(position);
}
/**
* Notifies that multiple header items are inserted.
*
* @param positionStart the position.
* @param itemCount the item count.
*/
public final void notifyHeaderItemRangeInserted(int positionStart, int itemCount) {
int newHeaderItemCount = getHeaderItemCount();
if (positionStart < 0 || itemCount < 0 || positionStart + itemCount > newHeaderItemCount) {
throw new IndexOutOfBoundsException("The given range [" + positionStart + " - " + (positionStart + itemCount - 1) + "] is not within the position bounds for header items [0 - " + (newHeaderItemCount - 1) + "].");
}
notifyItemRangeInserted(positionStart, itemCount);
}
/**
* Notifies that a header item is changed.
*
* @param position the position.
*/
public final void notifyHeaderItemChanged(int position) {
if (position < 0 || position >= headerItemCount) {
throw new IndexOutOfBoundsException("The given position " + position + " is not within the position bounds for header items [0 - " + (headerItemCount - 1) + "].");
}
notifyItemChanged(position);
}
/**
* Notifies that multiple header items are changed.
*
* @param positionStart the position.
* @param itemCount the item count.
*/
public final void notifyHeaderItemRangeChanged(int positionStart, int itemCount) {
if (positionStart < 0 || itemCount < 0 || positionStart + itemCount >= headerItemCount) {
throw new IndexOutOfBoundsException("The given range [" + positionStart + " - " + (positionStart + itemCount - 1) + "] is not within the position bounds for header items [0 - " + (headerItemCount - 1) + "].");
}
notifyItemRangeChanged(positionStart, itemCount);
}
/**
* Notifies that an existing header item is moved to another position.
*
* @param fromPosition the original position.
* @param toPosition the new position.
*/
public void notifyHeaderItemMoved(int fromPosition, int toPosition) {
if (fromPosition < 0 || toPosition < 0 || fromPosition >= headerItemCount || toPosition >= headerItemCount) {
throw new IndexOutOfBoundsException("The given fromPosition " + fromPosition + " or toPosition " + toPosition + " is not within the position bounds for header items [0 - " + (headerItemCount - 1) + "].");
}
notifyItemMoved(fromPosition, toPosition);
}
/**
* Notifies that a header item is removed.
*
* @param position the position.
*/
public void notifyHeaderItemRemoved(int position) {
if (position < 0 || position >= headerItemCount) {
throw new IndexOutOfBoundsException("The given position " + position + " is not within the position bounds for header items [0 - " + (headerItemCount - 1) + "].");
}
notifyItemRemoved(position);
}
/**
* Notifies that multiple header items are removed.
*
* @param positionStart the position.
* @param itemCount the item count.
*/
public void notifyHeaderItemRangeRemoved(int positionStart, int itemCount) {
if (positionStart < 0 || itemCount < 0 || positionStart + itemCount > headerItemCount) {
throw new IndexOutOfBoundsException("The given range [" + positionStart + " - " + (positionStart + itemCount - 1) + "] is not within the position bounds for header items [0 - " + (headerItemCount - 1) + "].");
}
notifyItemRangeRemoved(positionStart, itemCount);
}
/**
* Notifies that a content item is inserted.
*
* @param position the position of the content item.
*/
public final void notifyContentItemInserted(int position) {
int newHeaderItemCount = getHeaderItemCount();
int newContentItemCount = getContentItemCount();
if (position < 0 || position >= newContentItemCount) {
throw new IndexOutOfBoundsException("The given position " + position + " is not within the position bounds for content items [0 - " + (newContentItemCount - 1) + "].");
}
notifyItemInserted(position + newHeaderItemCount);
}
/**
* Notifies that multiple content items are inserted.
*
* @param positionStart the position.
* @param itemCount the item count.
*/
public final void notifyContentItemRangeInserted(int positionStart, int itemCount) {
int newHeaderItemCount = getHeaderItemCount();
int newContentItemCount = getContentItemCount();
if (positionStart < 0 || itemCount < 0 || positionStart + itemCount > newContentItemCount) {
throw new IndexOutOfBoundsException("The given range [" + positionStart + " - " + (positionStart + itemCount - 1) + "] is not within the position bounds for content items [0 - " + (newContentItemCount - 1) + "].");
}
notifyItemRangeInserted(positionStart + newHeaderItemCount, itemCount);
}
/**
* Notifies that a content item is changed.
*
* @param position the position.
*/
public final void notifyContentItemChanged(int position) {
if (position < 0 || position >= contentItemCount) {
throw new IndexOutOfBoundsException("The given position " + position + " is not within the position bounds for content items [0 - " + (contentItemCount - 1) + "].");
}
notifyItemChanged(position + headerItemCount);
}
/**
* Notifies that multiple content items are changed.
*
* @param positionStart the position.
* @param itemCount the item count.
*/
public final void notifyContentItemRangeChanged(int positionStart, int itemCount) {
if (positionStart < 0 || itemCount < 0 || positionStart + itemCount > contentItemCount) {
throw new IndexOutOfBoundsException("The given range [" + positionStart + " - " + (positionStart + itemCount - 1) + "] is not within the position bounds for content items [0 - " + (contentItemCount - 1) + "].");
}
notifyItemRangeChanged(positionStart + headerItemCount, itemCount);
}
/**
* Notifies that an existing content item is moved to another position.
*
* @param fromPosition the original position.
* @param toPosition the new position.
*/
public final void notifyContentItemMoved(int fromPosition, int toPosition) {
if (fromPosition < 0 || toPosition < 0 || fromPosition >= contentItemCount || toPosition >= contentItemCount) {
throw new IndexOutOfBoundsException("The given fromPosition " + fromPosition + " or toPosition " + toPosition + " is not within the position bounds for content items [0 - " + (contentItemCount - 1) + "].");
}
notifyItemMoved(fromPosition + headerItemCount, toPosition + headerItemCount);
}
/**
* Notifies that a content item is removed.
*
* @param position the position.
*/
public final void notifyContentItemRemoved(int position) {
if (position < 0 || position >= contentItemCount) {
throw new IndexOutOfBoundsException("The given position " + position + " is not within the position bounds for content items [0 - " + (contentItemCount - 1) + "].");
}
notifyItemRemoved(position + headerItemCount);
}
/**
* Notifies that multiple content items are removed.
*
* @param positionStart the position.
* @param itemCount the item count.
*/
public final void notifyContentItemRangeRemoved(int positionStart, int itemCount) {
if (positionStart < 0 || itemCount < 0 || positionStart + itemCount > contentItemCount) {
throw new IndexOutOfBoundsException("The given range [" + positionStart + " - " + (positionStart + itemCount - 1) + "] is not within the position bounds for content items [0 - " + (contentItemCount - 1) + "].");
}
notifyItemRangeRemoved(positionStart + headerItemCount, itemCount);
}
/**
* Notifies that a footer item is inserted.
*
* @param position the position of the content item.
*/
public final void notifyFooterItemInserted(int position) {
int newHeaderItemCount = getHeaderItemCount();
int newContentItemCount = getContentItemCount();
int newFooterItemCount = getFooterItemCount();
if (position < 0 || position >= newFooterItemCount) {
throw new IndexOutOfBoundsException("The given position " + position + " is not within the position bounds for footer items [0 - " + (newFooterItemCount - 1) + "].");
}
notifyItemInserted(position + newHeaderItemCount + newContentItemCount);
}
/**
* Notifies that multiple footer items are inserted.
*
* @param positionStart the position.
* @param itemCount the item count.
*/
public final void notifyFooterItemRangeInserted(int positionStart, int itemCount) {
int newHeaderItemCount = getHeaderItemCount();
int newContentItemCount = getContentItemCount();
int newFooterItemCount = getFooterItemCount();
if (positionStart < 0 || itemCount < 0 || positionStart + itemCount > newFooterItemCount) {
throw new IndexOutOfBoundsException("The given range [" + positionStart + " - " + (positionStart + itemCount - 1) + "] is not within the position bounds for footer items [0 - " + (newFooterItemCount - 1) + "].");
}
notifyItemRangeInserted(positionStart + newHeaderItemCount + newContentItemCount, itemCount);
}
/**
* Notifies that a footer item is changed.
*
* @param position the position.
*/
public final void notifyFooterItemChanged(int position) {
if (position < 0 || position >= footerItemCount) {
throw new IndexOutOfBoundsException("The given position " + position + " is not within the position bounds for footer items [0 - " + (footerItemCount - 1) + "].");
}
notifyItemChanged(position + headerItemCount + contentItemCount);
}
/**
* Notifies that multiple footer items are changed.
*
* @param positionStart the position.
* @param itemCount the item count.
*/
public final void notifyFooterItemRangeChanged(int positionStart, int itemCount) {
if (positionStart < 0 || itemCount < 0 || positionStart + itemCount > footerItemCount) {
throw new IndexOutOfBoundsException("The given range [" + positionStart + " - " + (positionStart + itemCount - 1) + "] is not within the position bounds for footer items [0 - " + (footerItemCount - 1) + "].");
}
notifyItemRangeChanged(positionStart + headerItemCount + contentItemCount, itemCount);
}
/**
* Notifies that an existing footer item is moved to another position.
*
* @param fromPosition the original position.
* @param toPosition the new position.
*/
public final void notifyFooterItemMoved(int fromPosition, int toPosition) {
if (fromPosition < 0 || toPosition < 0 || fromPosition >= footerItemCount || toPosition >= footerItemCount) {
throw new IndexOutOfBoundsException("The given fromPosition " + fromPosition + " or toPosition " + toPosition + " is not within the position bounds for footer items [0 - " + (footerItemCount - 1) + "].");
}
notifyItemMoved(fromPosition + headerItemCount + contentItemCount, toPosition + headerItemCount + contentItemCount);
}
/**
* Notifies that a footer item is removed.
*
* @param position the position.
*/
public final void notifyFooterItemRemoved(int position) {
if (position < 0 || position >= footerItemCount) {
throw new IndexOutOfBoundsException("The given position " + position + " is not within the position bounds for footer items [0 - " + (footerItemCount - 1) + "].");
}
notifyItemRemoved(position + headerItemCount + contentItemCount);
}
/**
* Notifies that multiple footer items are removed.
*
* @param positionStart the position.
* @param itemCount the item count.
*/
public final void notifyFooterItemRangeRemoved(int positionStart, int itemCount) {
if (positionStart < 0 || itemCount < 0 || positionStart + itemCount > footerItemCount) {
throw new IndexOutOfBoundsException("The given range [" + positionStart + " - " + (positionStart + itemCount - 1) + "] is not within the position bounds for footer items [0 - " + (footerItemCount - 1) + "].");
}
notifyItemRangeRemoved(positionStart + headerItemCount + contentItemCount, itemCount);
}
/**
* Gets the header item view type. By default, this method returns 0.
*
* @param position the position.
* @return the header item view type (within the range [0 - VIEW_TYPE_MAX_COUNT-1]).
*/
protected int getHeaderItemViewType(int position) {
return 0;
}
/**
* Gets the footer item view type. By default, this method returns 0.
*
* @param position the position.
* @return the footer item view type (within the range [0 - VIEW_TYPE_MAX_COUNT-1]).
*/
protected int getFooterItemViewType(int position) {
return 0;
}
/**
* Gets the content item view type. By default, this method returns 0.
*
* @param position the position.
* @return the content item view type (within the range [0 - VIEW_TYPE_MAX_COUNT-1]).
*/
protected int getContentItemViewType(int position) {
return 0;
}
/**
* Gets the header item count. This method can be called several times, so it should not calculate the count every time.
*
* @return the header item count.
*/
protected abstract int getHeaderItemCount();
/**
* Gets the footer item count. This method can be called several times, so it should not calculate the count every time.
*
* @return the footer item count.
*/
protected abstract int getFooterItemCount();
/**
* Gets the content item count. This method can be called several times, so it should not calculate the count every time.
*
* @return the content item count.
*/
protected abstract int getContentItemCount();
/**
* This method works exactly the same as {@link #onCreateViewHolder(android.view.ViewGroup, int)}, but for header items.
*
* @param parent the parent view.
* @param headerViewType the view type for the header.
* @return the view holder.
*/
protected abstract RecyclerView.ViewHolder onCreateHeaderItemViewHolder(ViewGroup parent, int headerViewType);
/**
* This method works exactly the same as {@link #onCreateViewHolder(android.view.ViewGroup, int)}, but for footer items.
*
* @param parent the parent view.
* @param footerViewType the view type for the footer.
* @return the view holder.
*/
protected abstract RecyclerView.ViewHolder onCreateFooterItemViewHolder(ViewGroup parent, int footerViewType);
/**
* This method works exactly the same as {@link #onCreateViewHolder(android.view.ViewGroup, int)}, but for content items.
*
* @param parent the parent view.
* @param contentViewType the view type for the content.
* @return the view holder.
*/
protected abstract RecyclerView.ViewHolder onCreateContentItemViewHolder(ViewGroup parent, int contentViewType);
/**
* This method works exactly the same as {@link #onBindViewHolder(android.support.v7.widget.RecyclerView.ViewHolder, int)}, but for header items.
*
* @param headerViewHolder the view holder for the header item.
* @param position the position.
*/
protected abstract void onBindHeaderItemViewHolder(RecyclerView.ViewHolder headerViewHolder, int position);
/**
* This method works exactly the same as {@link #onBindViewHolder(android.support.v7.widget.RecyclerView.ViewHolder, int)}, but for footer items.
*
* @param footerViewHolder the view holder for the footer item.
* @param position the position.
*/
protected abstract void onBindFooterItemViewHolder(RecyclerView.ViewHolder footerViewHolder, int position);
/**
* This method works exactly the same as {@link #onBindViewHolder(android.support.v7.widget.RecyclerView.ViewHolder, int)}, but for content items.
*
* @param contentViewHolder the view holder for the content item.
* @param position the position.
*/
protected abstract void onBindContentItemViewHolder(RecyclerView.ViewHolder contentViewHolder, int position);
}
Comments