您的位置:首页 > 移动开发 > Android开发

Android RecyclerView ItemTouchHelper、自定义LayoutManager

2018-02-23 22:36 489 查看
学习自https://mp.weixin.qq.com/s/jn5JUfKhJGfoLJv88_a5qg
绝对的recycler view进阶使用,又精炼简单,get了新技能。感谢原文作者。

效果



静态界面,自定义layout manager,因为recycler view的layout由layout manager托管
public class MyLayoutManager extends RecyclerView.LayoutManager{

public static final int MAX_SHOWN_COUNT = 4;
public static final float SCALE = 0.05f;
public static final int TRANS_Y = 30;//需要dp2px

//其实非常简单 就是layout (RecyclerView的layout是交给lm托管的)
//第一步只是一次性layout 所以动不起来(因为layout应该还负责移动)

@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}

@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
detachAndScrapAttachedViews(recycler);//报废所有view到recycler里
int itemCount = getItemCount();
if (itemCount >= MAX_SHOWN_COUNT) {
//为什么是最后4个?因为第一个item放在最下面,一张张放上去的
for (int position = itemCount - MAX_SHOWN_COUNT; position < itemCount; position ++) {
View view = recycler.getViewForPosition(position);
addView(view);
measureChildWithMargins(view, 0, 0);
int widthSpace = getWidth() - getDecoratedMeasuredWidth(view);
int heightSpace = getHeight() - getDecoratedMeasuredHeight(view);
//居中
layoutDecoratedWithMargins(view, widthSpace / 2, heightSpace / 2,
widthSpace / 2 + getDecoratedMeasuredWidth(view),
heightSpace / 2 + getDecoratedMeasuredHeight(view));
//顶层scale=1 translationY=0
//每一级scale相差0.05f translationY=7dp
//拖动时,顶层scale不变,-1层scale慢慢变为1,transY慢慢变为0(这句话先不考虑)
//-2层变成-1层
//-3层scale变化,tranY不变
int level = itemCount - position - 1;
//顶层不需要变化
if (level > 0) {
//每一层都要scale变化
view.setScaleX(1 - SCALE * level);
if (level < MAX_SHOWN_COUNT - 1) {
view.setTranslationY(TRANS_Y * level);
view.setScaleY(1 - SCALE * level);
} else {
view.setTranslationY(TRANS_Y * (level - 1));
view.setScaleY(1 - SCALE * (level - 1));
}
}
}
}
}
}
动态界面,重写item touch helper callbackclass CallBack extends ItemTouchHelper.SimpleCallback {
public CallBack(int dragDirs, int swipeDirs) {
super(dragDirs, swipeDirs);
}

@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}

@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
String s = list.remove(viewHolder.getLayoutPosition());
list.add(0,s);
adapter.notifyDataSetChanged();
}

@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
double swipeValue = Math.sqrt(dX * dX + dY * dY);
double fraction = swipeValue / (getSwipeThreshold(viewHolder) * recyclerView.getWidth());//阈值
if (fraction > 1) {
fraction = 1;
}
int childCount = recyclerView.getChildCount();
for (int i = 0; i < childCount; i ++) {
View child = recyclerView.getChildAt(i);
int level = childCount - i - 1;
if (level > 0) {
child.setScaleX((float) (1-SCALE * level + fraction * SCALE));

if (level < MAX_SHOWN_COUNT - 1) {
child.setScaleY((float) (1 - SCALE * level + fraction * SCALE));
child.setTranslationY((float) (TRANS_Y * level - fraction * TRANS_Y));
}
}
}
}
}使用
CallBack callBack = new CallBack(0,
ItemTouchHelper.DOWN |
ItemTouchHelper.UP |
ItemTouchHelper.LEFT |
ItemTouchHelper.RIGHT);
ItemTouchHelper helper = new ItemTouchHelper(callBack);
helper.attachToRecyclerView(rv);

动画。item touch helper帮你做的工作就是
1.让当前item可拖拽,在item一半的区域被拖到外面时(作者自定义了阈值),移除
2.移除后,下面的view进行补充动画
这里我们需要增加一个补充动画的过度,原生动画太生硬了
就是重写的call back中的onChildDraw@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
double swipeValue = Math.sqrt(dX * dX + dY * dY);
double fraction = swipeValue / (getSwipeThreshold(viewHolder) * recyclerView.getWidth());//阈值
if (fraction > 1) {
fraction = 1;
}
int childCount = recyclerView.getChildCount();
for (int i = 0; i < childCount; i ++) {
View child = recyclerView.getChildAt(i);
int level = childCount - i - 1;
if (level > 0) {
child.setScaleX((float) (1-SCALE * level + fraction * SCALE));

if (level < MAX_SHOWN_COUNT - 1) {
child.setScaleY((float) (1 - SCALE * level + fraction * SCALE));
child.setTranslationY((float) (TRANS_Y * level - fraction * TRANS_Y));
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: