SimpleRecyclerView
介绍:
一个让列表创建更简单的RecyclerView。
运行效果:
使用说明:
安装
在项目的build.gradle中:
allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}
在app级的build.gradle 中:
dependencies {
compile 'com.github.jaychang0917:SimpleRecyclerView:1.0.4'
}
1. 配置SimpleRecyclerView
<com.jaychang.srv.SimpleRecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:srv_layoutMode="linearVertical|linearHorizontal|grid"
app:srv_gridSpanCount="integer"
app:srv_gridSpanSequence="integer string (e.g. 2233)"
... />
2. 通过继承SimpleCell<T,VH>定义cell
/**
* Accept two type arguments,
* 1st is the data model this cell represents, 2nd is the view holder.
* */
public class BookCell extends SimpleCell<Book, BookCell.ViewHolder> {
/**
* Mandatory constructor, pass your data model as argument
* */
public BookCell(Book item) {
super(item);
}
/**
* Define the layout resource of this cell
* */
@Override
protected int getLayoutRes() {
return R.layout.cell_book;
}
@NonNull
@Override
protected ViewHolder onCreateViewHolder(ViewGroup parent, View cellView) {
return new ViewHolder(cellView);
}
@Override
protected void onBindViewHolder(ViewHolder holder, int position, Context context, List<Object> payloads) {
holder.textView.setText(getItem().getTitle());
}
/**
* Optional
* */
@Override
protected void onUnbindViewHolder(ViewHolder holder) {
// do your cleaning jobs here when the item view is recycled.
}
/**
* The unique identifier of your data model.
* If you use updateCell() or addOrUpdateCell(), you must return a valid
* unique id. If you're not going to use those operations, you can simply
* return 0.
* */
@Override
protected long getItemId() {
return getItem().getId();
}
/**
* Define your view holder, which must extend SimpleViewHolder.
* */
static class ViewHolder extends SimpleViewHolder {
@BindView(R.id.textView)
TextView textView;
ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}
3. 创建cell并把它们添加到SimpleRecyclerView
List<Book> books = DataUtils.getBooks();
List<BookCell> cells = new ArrayList<>();
for (Book book : books) {
BookCell cell = new BookCell(book);
// There are two default cell listeners: OnCellClickListener<T> and OnCellLongClickListener<T>
cell.setOnCellClickListener(new SimpleCell.OnCellClickListener<Book>() {
@Override
public void onCellClicked(Book item) {
...
}
});
cell.setOnCellLongClickListener(new SimpleCell.OnCellLongClickListener<Book>() {
@Override
public void onCellLongClicked(Book item) {
...
}
});
cells.add(cell);
}
simpleRecyclerView.addCells(cells);
Multiple Types
SimpleRecyclerView支持多个cell类型。你可以添加不同类型的cell,只需添加不同类型的对象就可以了,其余的事情交给SimpleRecyclerView。
List<Book> books = DataUtils.getBooks();
List<Ad> ads = DataUtils.getAds();
List<SimpleCell> cells = new ArrayList<>();
for (Book book : books) {
BookCell cell = new BookCell(book);
cells.add(cell);
}
for (Ad ad : ads) {
BookAdCell cell = new BookAdCell(ad);
int position = (ads.indexOf(ad) + 1) * 3;
// take up full row
cell.setSpanSize(simpleRecyclerView.getGridSpanCount());
cells.add(position, cell);
}
simpleRecyclerView.addCells(cells);
Cell Operations
SimpleRecyclerView提供了基本的CRUD cell操作。
通常我们会先从缓存读取数据然后再用网络数据更新。该库提供了 addOrUpdateCell() 和 addOrUpdateCells()操作来完成这个功能(使用 DiffUtils )。如果绑定的数据模型是相同的,cell将不会更新(比如收到 onBindViewHolder() callback) ,否则它们将被追加到列表的最后。要启用这个功能,cell必须实现Updatable接口。
public interface Updatable<T> {
boolean areContentsTheSame(T newItem);
Object getChangePayload(T newItem);
}
public class BookCell extends SimpleCell<Book, BookCell.ViewHolder>
implements Updatable<Book> {
...
@Override
protected void onBindViewHolder(ViewHolder holder, int position, Context context, Object payload) {
if (payload != null) {
// partial update
if (payload instanceof Bundle) {
Bundle bundle = ((Bundle) payload);
for (String key : bundle.keySet()) {
if (KEY_TITLE.equals(key)) {
holder.textView.setText(bundle.getString(key));
}
}
}
return;
}
...
}
/**
* If the titles of books are same, no need to update the cell, onBindViewHolder() will not be called.
*/
@Override
public boolean areContentsTheSame(Book newItem) {
return getItem().getTitle().equals(newItem.getTitle());
}
/**
* If getItem() is the same as newItem (i.e. their return value of getItemId() are the same)
* and areContentsTheSame() return false, then the cell need to be updated,
* onBindViewHolder() will be called with this payload object.
* */
@Override
public Object getChangePayload(Book newItem) {
Bundle bundle = new Bundle();
bundle.putString(KEY_TITLE, newItem.getTitle());
return bundle;
}
...
}
Divider
<com.jaychang.srv.SimpleRecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:srv_layoutMode="linearVertical"
app:srv_showDivider="true|false"
app:srv_showLastDivider="true|false"
app:srv_dividerOrientation="vertical|horizontal|both"
app:srv_dividerColor="@color/your_color"
app:srv_dividerPaddingLeft="dp"
app:srv_dividerPaddingRight="dp"
app:srv_dividerPaddingTop="dp"
app:srv_dividerPaddingBottom="dp" />
Spacing
<com.jaychang.srv.SimpleRecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:srv_layoutMode="linearVertical"
app:srv_spacing="dp"
app:srv_verticalSpacing="dp"
app:srv_horizontalSpacing="dp"
app:srv_isSpacingIncludeEdge="true|false" />
空白视图
如果没有数据将自动显示空白视图。
<com.jaychang.srv.SimpleRecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:srv_layoutMode="linearVertical"
app:srv_emptyStateView="@layout/view_empty_state" />
Section Header
你可以使用 SectionHeaderProvider把几个cell组合在一起,然后调用setSectionHeader(provider)。除此之外还提供了更简便的方法: SectionHeaderProviderAdapter 。
SectionHeaderProvider<Book> sectionHeaderProvider = new SectionHeaderProviderAdapter<Book>() {
// Your section header view here
@NonNull
@Override
public View getSectionHeaderView(Book item, int position) {
View view = LayoutInflater.from(SectionHeaderActivity.this).inflate(R.layout.view_section_header, null, false);
TextView textView = (TextView) view.findViewById(R.id.textView);
textView.setText(String.format(getString(R.string.category), item.getCategoryName()));
return view;
}
// Your grouping logic here
@Override
public boolean isSameSection(Book item, Book nextItem) {
return item.getCategoryId() == nextItem.getCategoryId();
}
// Optional, whether the header is sticky, default false
@Override
public boolean isSticky() {
return stickyCheckbox.isChecked();
}
// Optional, top margin of each section header
@Override
public int getSectionHeaderMarginTop(Book item, int position) {
return position == 0 ? 0 : Utils.dp2px(SectionHeaderActivity.this, 16);
}
};
simpleRecyclerView.setSectionHeader(sectionHeaderProvider);
自动加载更多
// if the total beneath hidden cells count <= 4, onLoadMore() will be called. Default threshold is 0.
simpleRecyclerView.setAutoLoadMoreThreshold(4);
simpleRecyclerView.setOnLoadMoreListener(new OnLoadMoreListener() {
@Override
public void onLoadMore(SimpleRecyclerView simpleRecyclerView) {
loadBooks();
}
});
如果你要创建一个类似聊天窗口的界面,cell是从顶部开始添加的,你应该调用setLoadMoreToTop(true)。它强制SimpleRecyclerView从上面检查隐藏的cell。
simpleRecyclerView.setLoadMoreToTop(true);
Drag & Drop
你可以为enableDragAndDrop(callback) 或者 enableDragAndDrop(dragHandleResId, callback)提供一个DragAndDropCallback来启用拖拽功能,后面的那个方法需要接收一个滑块视图的资源id,只有按下这个视图才会开始拖拽,默认是长按启用拖拽行为。 DragAndDropCallback的回调方法是可选的。
DragAndDropCallback<Book> dragAndDropCallback = new DragAndDropCallback<Book>() {
// Optional, return false if you manipulate custom drag effect in the rest of callbacks.
@Override
public boolean enableDefaultRaiseEffect() {
// default return true
return super.enableDefaultRaiseEffect();
}
// Optional
@Override
public void onCellDragStarted(SimpleRecyclerView simpleRecyclerView, View itemView, Book item, int position) {
resultView.setText("Started dragging " + item);
}
// Optional
@Override
public void onCellMoved(SimpleRecyclerView simpleRecyclerView, View itemView, Book item, int fromPosition, int toPosition){
resultView.setText("Moved " + item + " from " + fromPosition + " to " + toPosition);
}
// Optional
@Override
public void onCellDropped(SimpleRecyclerView simpleRecyclerView, View itemView, Book item, int fromPosition, int toPosition) {
resultView.setText("Dragged " + item + " from " + fromPosition + " to " + toPosition);
}
// Optional
@Override
public void onCellDragCancelled(SimpleRecyclerView simpleRecyclerView, View itemView, Book item, int currentPosition) {
resultView.setText("Cancelled dragging " + item);
}
};
simpleRecyclerView.enableDragAndDrop(R.id.dragHandle, dragAndDropCallback);
// or
simpleRecyclerView.enableDragAndDrop(dragAndDropCallback);
Swipe To Dismiss
你可以通过提供 SwipeToDismissCallback 来启用SwipeToDismiss功能。SwipeToDismissCallback的回调方法是可选的。
SwipeToDismissCallback<Book> swipeToDismissCallback = new SwipeToDismissCallback<Book>() {
// Optional, return false if you manipulate custom swipe effect in the rest of callbacks.
@Override
public boolean enableDefaultFadeOutEffect() {
// default return true
return super.enableDefaultFadeOutEffect();
}
// Optional
@Override
public void onCellSwiping(SimpleRecyclerView simpleRecyclerView, View itemView, Book item, int position, Canvas canvas, float dX, float dY, boolean isControlledByUser) {
resultView.setText("Item " + item + " is swiping.");
}
// Optional
@Override
public void onCellSettled(SimpleRecyclerView simpleRecyclerView, View itemView, Book item, int position) {
resultView.setText("Item " + item + " is settled.");
}
// Optional
@Override
public void onCellDismissed(SimpleRecyclerView simpleRecyclerView, Book item, int position) {
resultView.setText("Item: " + item + " is dismissed.");
}
};
// enable swipe left or right to dismiss
simpleRecyclerView.enableSwipeToDismiss(swipeToDismissCallback, LEFT, RIGHT);
Snappy
<com.jaychang.srv.SimpleRecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:srv_layoutMode="linearHorizontal"
app:srv_snappy="true|false"
app:srv_snap_alignment="center|start" />
Reference
Attributes
All attrs have coressponding java method.
attr | Description |
---|---|
srv_layoutMode | Set which layout mode to be used. Support linearVertical , linearHorizontal and grid . Default linearVertical |
srv_gridSpanCount | Set span count for grid layout mode |
srv_gridSpanSequence | Set span sequence for grid layout mode |
srv_spacing | Cell spacing, if srv_verticalSpacing or srv_horizontalSpacing are also set, this takes precedence over them |
srv_verticalSpacing | Vertical cell spacing for grid layout mode |
srv_horizontalSpacing | Horizontal cell spacing for grid layout mode |
srv_isSpacingIncludeEdge | If set to true, spacing will be included in the edges of recyclerview. i.e. top & bottom for linear, all edges for grid. Default false |
srv_showDivider | If set to true, add dividers between cells. Default false |
srv_showLastDivider | If set to true, show last divider. Default false |
srv_dividerOrientation | Divider orientation, works with grid layout mode. Support vertical , horizontal and both . Default both |
srv_dividerColor | Divider color. Default #e0e0e0 |
srv_dividerPaddingLeft | Divider padding left |
srv_dividerPaddingRight | Divider padding right |
srv_dividerPaddingTop | Divider padding top |
srv_dividerPaddingBottom | Divider padding bottom |
srv_emptyView | Layout resource of empty state view to be shown when there is no data. |
srv_snappy | If set to true, snappy mode is enabled. Default false |
srv_snap_alignment | Snap alignment. Support center and start |
Cell Operations
Operation | Remark |
---|---|
addCell(SimpleCell cell) | Add the cell to the end of list |
addCell(int atPosition, SimpleCell cell) | Add the cell to a specific position of list |
addCells(List<? extends SimpleCell> cells) | Add the cells to the end of list |
addCells(SimpleCell... cells) | Same as above |
addCells(int fromPosition, List<? extends SimpleCell> cells) | Add the cells to list from a specific position |
addCells(int fromPosition, SimpleCell... cells) | Same as above |
addOrUpdateCell(T cell) | Add or udpate the cell. The cell should be implemented Updatable interface |
addOrUpdateCells(List cells) | Add or update the cells. The cells should be implemented Updatable interface |
addOrUpdateCells(T... cells) | Same as above |
removeCell(SimpleCell cell) | Remove the cell from list |
removeCell(int atPosition) | Remove the cell at specific position |
removeCells(int fromPosition, int toPosition) | Remove range of cells [fromPosition..toPosition] from list |
removeCells(int fromPosition) | Remove range of cells [fromPosition..end] from list |
removeAllCells() | Remove all cells from list |
removeAllCells(boolean showEmptyStateView) | Remove all cells from list and tell the SimpleRecyclerView if need to show empty state view. Default true |
updateCell(int atPosition, Object payload) | Update the specific cell with payload. |
updateCells(int fromPosition, int toPosition, List payloads) | Update the range of cells [fromPosition..toPosition] with payloads.| |
getCell(int atPosition) | Get the cell at specific postion |
getCells(int fromPosition, int toPosition) | Get a range of cells [fromPosition..toPosition] |
getAllCells() | Get all cells |