RecycleView新增分割線(ItemDecoration)以及互動動畫效果
阿新 • • 發佈:2019-01-07
1、分割線:
實現分割線的程式碼寫在一個Activity類中,其中兩個內部類重寫了ItemDecoration實現分割線效果;
GridDividerItemDecoration:
這個類實現了表格分割線效果;
LinearDividerItemDecoration:
這個類實現類似ListView的分割線效果,支援水平和垂直方向;
package com.longshun.recycleviewdemo;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* 自定義RecycleView的ItemDecoration
*/
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private RecyclerView.ItemDecoration itemDecoration;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.rv);
itemDecoration = new LinearDividerItemDecoration(this, LinearLayoutManager.VERTICAL);
recyclerView.addItemDecoration(itemDecoration);
recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
final List<String> listStr = new ArrayList<>();
for (int i = 0; i < 29; i++) {
listStr.add("item" + i);
}
final MyAdapter adapter = new MyAdapter(this, listStr);
recyclerView.setAdapter(adapter);
//互動動畫
MyItemTouchHelperCallback callback = new MyItemTouchHelperCallback(new MyItemTouchHelperCallback.ItemSwipeListener() {
@Override
public void onItemSwipe(RecyclerView.ViewHolder viewHolder, int direction) {
//刪除資料 更新列表
int position = viewHolder.getAdapterPosition();
listStr.remove(position);
adapter.notifyItemRemoved(position);
}
@Override
public void onItemDrag(RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
//交換資料 更新列表
int fromPosition = viewHolder.getAdapterPosition();
int toPosition = target.getAdapterPosition();
Collections.swap(listStr, fromPosition, toPosition);
adapter.notifyItemMoved(fromPosition, toPosition);
}
});
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
itemTouchHelper.attachToRecyclerView(recyclerView);
}
public void showLinear(View view) {
recyclerView.removeItemDecoration(itemDecoration);
itemDecoration = new LinearDividerItemDecoration(this, LinearLayoutManager.VERTICAL);
recyclerView.addItemDecoration(itemDecoration);
recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
}
public void showGrid(View view) {
recyclerView.removeItemDecoration(itemDecoration);
itemDecoration = new GridDividerItemDecoration(this);
recyclerView.addItemDecoration(itemDecoration);
recyclerView.setLayoutManager(new GridLayoutManager(this, 3, GridLayoutManager.VERTICAL, false));
}
/*適用於 RecycleView的GridLayoutManager和StaggerGridLayoutManager*/
class GridDividerItemDecoration extends RecyclerView.ItemDecoration {
private int[] attrs = {android.R.attr.listDivider};
private Drawable mDividerDrawable;
public GridDividerItemDecoration(Context context) {
TypedArray typedArray = context.obtainStyledAttributes(attrs);
this.mDividerDrawable = typedArray.getDrawable(0);
typedArray.recycle();
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
drawVertical(c, parent);
drawHorizontal(c, parent);
}
private void drawHorizontal(Canvas c, RecyclerView parent) {
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int left = child.getLeft() - params.leftMargin;
int top = child.getBottom() + params.bottomMargin;
int right = child.getRight() + params.rightMargin;
int bottom = top + mDividerDrawable.getIntrinsicHeight();
//畫下面的線
mDividerDrawable.setBounds(left, top, right, bottom);
mDividerDrawable.draw(c);
//如果是第一行 那麼畫上面的線
if (isFirstRow(parent, i)) {
top = child.getTop() - params.topMargin;
bottom = top + mDividerDrawable.getIntrinsicHeight();
mDividerDrawable.setBounds(left, top, right, bottom);
mDividerDrawable.draw(c);
}
}
}
private void drawVertical(Canvas c, RecyclerView parent) {
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int left = child.getRight() + params.rightMargin;
int top = child.getTop() - params.topMargin;
int right = left + mDividerDrawable.getIntrinsicWidth();
int bottom = child.getBottom() + params.bottomMargin;
//畫右邊的線
mDividerDrawable.setBounds(left, top, right, bottom);
mDividerDrawable.draw(c);
//如果是第一列 畫左邊的線
if (isFirstColumn(parent, i)) {
left = child.getLeft() - params.leftMargin;
right = left + mDividerDrawable.getIntrinsicWidth();
mDividerDrawable.setBounds(left, top, right, bottom);
mDividerDrawable.draw(c);
}
}
}
private boolean isFirstColumn(RecyclerView parent, int position) {
int spanCount = getSpanCount(parent);
return position % spanCount == 0;
}
/*是否是第一行*/
private boolean isFirstRow(RecyclerView parent, int i) {
int spanCount = getSpanCount(parent);
return i <= spanCount - 1;
}
private int getSpanCount(RecyclerView parent) {
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof StaggeredGridLayoutManager) {
return ((StaggeredGridLayoutManager) layoutManager).getSpanCount();
} else if (layoutManager instanceof GridLayoutManager) {
return ((GridLayoutManager) layoutManager).getSpanCount();
}
return 0;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.set(mDividerDrawable.getIntrinsicWidth(), mDividerDrawable.getIntrinsicHeight(), mDividerDrawable.getIntrinsicWidth(), mDividerDrawable.getIntrinsicHeight());
}
}
/*適用於 RecycleView的LineaLayoutManager*/
class LinearDividerItemDecoration extends RecyclerView.ItemDecoration {
private int[] attrs = {android.R.attr.listDivider};
private Drawable mDividerDrawable;
private int mOri;
public LinearDividerItemDecoration(Context context, int ori) {
TypedArray typedArray = context.obtainStyledAttributes(attrs);
mDividerDrawable = typedArray.getDrawable(0);
this.mOri = ori;
typedArray.recycle();
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
if (mOri == LinearLayoutManager.VERTICAL) {
//畫水平線 上下左右的每條分割線都看成一個小矩形,繪製每個item的矩形分割線
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int left = child.getLeft() - params.leftMargin;
int top = child.getBottom() + params.bottomMargin;
int right = child.getRight() + params.rightMargin;
int bottom = top + mDividerDrawable.getIntrinsicHeight();
mDividerDrawable.setBounds(left, top, right, bottom);
mDividerDrawable.draw(c);
}
} else if (mOri == LinearLayoutManager.HORIZONTAL) {
//畫垂直線
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int left = child.getRight() + params.rightMargin;
int right = left + mDividerDrawable.getIntrinsicWidth();
int top = child.getTop() - params.topMargin;
int bottom = child.getBottom() + params.bottomMargin;
mDividerDrawable.setBounds(left, top, right, bottom);
mDividerDrawable.draw(c);
}
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
//獲取每個item上下左右四邊向外的偏移量 上下左右的每條分割線都看成一個小矩形
if (mOri == LinearLayoutManager.HORIZONTAL) {
outRect.set(0, 0, mDividerDrawable.getIntrinsicWidth(), 0);
} else if (mOri == LinearLayoutManager.VERTICAL) {
outRect.set(0, 0, 0, mDividerDrawable.getIntrinsicHeight());
}
}
}
class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private Context context;
private List<String> listStr;
public MyAdapter(Context context, List<String> listStr) {
this.context = context;
this.listStr = listStr;
}
@Override
public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, parent, false);
return new MyViewHolder(view);
}
@Override
public void onBindViewHolder(MyAdapter.MyViewHolder holder, int position) {
holder.tvStr.setText(listStr.get(position));
}
@Override
public int getItemCount() {
return listStr == null ? 0 : listStr.size();
}
class MyViewHolder extends RecyclerView.ViewHolder {
TextView tvStr;
public MyViewHolder(View itemView) {
super(itemView);
tvStr = (TextView) itemView.findViewById(android.R.id.text1);
}
}
}
}
2、互動動畫效果
關鍵類:ItemTouchHelper,ItemTouchHelper.Callback
//互動動畫
MyItemTouchHelperCallback callback = new MyItemTouchHelperCallback(new MyItemTouchHelperCallback.ItemSwipeListener() {
@Override
public void onItemSwipe(RecyclerView.ViewHolder viewHolder, int direction) {
//刪除資料 更新列表
int position = viewHolder.getAdapterPosition();
listStr.remove(position);
adapter.notifyItemRemoved(position);
}
@Override
public void onItemDrag(RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
//交換資料 更新列表
int fromPosition = viewHolder.getAdapterPosition();
int toPosition = target.getAdapterPosition();
Collections.swap(listStr, fromPosition, toPosition);
adapter.notifyItemMoved(fromPosition, toPosition);
}
});
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
itemTouchHelper.attachToRecyclerView(recyclerView);
package com.longshun.recycleviewdemo;
import android.graphics.Canvas;
import android.graphics.Color;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
/**
* Created by longShun on 2017/4/22.
*/
public class MyItemTouchHelperCallback extends ItemTouchHelper.Callback {
private ItemSwipeListener itemSwipeListener;
public MyItemTouchHelperCallback(ItemSwipeListener itemSwipeListener) {
this.itemSwipeListener = itemSwipeListener;
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
//設定拖動方向和滑動方向
//上下拖動
int dragFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
//左右滑動
int swipeFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
return makeMovementFlags(dragFlag, swipeFlag);
}
/*拖拽移動*/
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
if (itemSwipeListener != null) {
itemSwipeListener.onItemDrag(viewHolder, target);
}
return false;
}
/*開啟長按拖拽*/
@Override
public boolean isLongPressDragEnabled() {
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
//滑動事件交給外部處理
if (itemSwipeListener != null) {
itemSwipeListener.onItemSwipe(viewHolder, direction);
}
}
/*在這裡做一些動畫效果*/
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
//dX 0-> +(-)viewHolder.itemView.getWidth
float alpha= 1 - Math.abs(dX) / viewHolder.itemView.getWidth();
viewHolder.itemView.setAlpha(alpha);
//產生的佈局複用問題 可以在這裡處理
//item滑出刪除,那麼透明度變化的item的佈局可能會被複用
if(alpha== 0){
//還原佈局之前的狀態
viewHolder.itemView.setAlpha(1);
}
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
//判斷選中狀態,拖動和滑動的時候 設定item的背景
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
viewHolder.itemView.setBackgroundColor(Color.GRAY);
}
super.onSelectedChanged(viewHolder, actionState);
}
//*這個方法中恢復 item的狀態*/
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
viewHolder.itemView.setBackgroundColor(Color.WHITE);
super.clearView(recyclerView, viewHolder);
}
public interface ItemSwipeListener {
void onItemSwipe(RecyclerView.ViewHolder viewHolder, int direction);
void onItemDrag(RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target);
}
}