1. 程式人生 > >RecycleView新增分割線(ItemDecoration)以及互動動畫效果

RecycleView新增分割線(ItemDecoration)以及互動動畫效果

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);
    }
}