效果如下:
cardRecyclerView.gif
首先自定义LayouManager,实现自己摆放控件
public class CardLayoutManager extends RecyclerView.LayoutManager {
@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(RecyclerView.LayoutParams.WRAP_CONTENT, RecyclerView.LayoutParams.WRAP_CONTENT);
}
/**
* 自定义LayoutManager核心是摆放控件,所以onLayoutChildren方法是我们要改写的核心
*
* @param recycler
* @param state
*/
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
//缓存
detachAndScrapAttachedViews(recycler);
//获取所有item(包括不可见的)个数
int count = getItemCount();
//由于我们是倒序摆放,所以初始索引从后面开始
int initIndex = count - CardConfig.SHOW_MAX_COUNT;
if (initIndex < 0) {
initIndex = 0;
}
for (int i = initIndex; i < count; i++) {
//从缓存中获取view
View view = recycler.getViewForPosition(i);
//添加到recyclerView
addView(view);
//测量一下view
measureChild(view, 0, 0);
//居中摆放,getDecoratedMeasuredWidth方法是获取带分割线的宽度,比直接使用view.getWidth()精确
int realWidth = getDecoratedMeasuredWidth(view);
int realHeight = getDecoratedMeasuredHeight(view);
int widthPadding = (int) ((getWidth() - realWidth) / 2f);
int heightPadding = (int) ((getHeight() - realHeight) / 2f);
//摆放child
layoutDecorated(view, widthPadding, heightPadding,
widthPadding + realWidth, heightPadding + realHeight);
//根据索引,来位移和缩放child
int level = count - i - 1;
//level范围(CardConfig.SHOW_MAX_COUNT-1)- 0
// 最下层的不动和最后第二层重叠
if (level == CardConfig.SHOW_MAX_COUNT - 1) {
level--;
}
view.setTranslationY(level * CardConfig.TRANSLATION_Y);
view.setScaleX(1 - level * CardConfig.SCALE);
view.setScaleY(1 - level * CardConfig.SCALE);
}
}
}
然后利用ItemTouchHelper,对item的移动进行计算,并对每个item进行属性设置
public class ItemTouchHelperCallback extends ItemTouchHelper.Callback {
private List<String> mDatas;
private RecyclerView.Adapter mAdapter;
public ItemTouchHelperCallback(List<String> mDatas, RecyclerView.Adapter mAdapter) {
this.mDatas = mDatas;
this.mAdapter = mAdapter;
}
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
return makeMovementFlags(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT | ItemTouchHelper.UP | ItemTouchHelper.DOWN);
}
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder viewHolder1) {
return false;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
String s = mDatas.remove(viewHolder.getLayoutPosition());
mDatas.add(0, s);
mAdapter.notifyDataSetChanged();
}
@Override
public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
//计算移动距离
float distance = (float) Math.hypot(dX, dY);
float maxDistance = recyclerView.getWidth() / 2f;
//比例
float fraction = distance / maxDistance;
if (fraction > 1) {
fraction = 1;
}
//为每个child执行动画
int count = recyclerView.getChildCount();
for (int i = 0; i < count; i++) {
//获取的view从下层到上层
View view = recyclerView.getChildAt(i);
int level = CardConfig.SHOW_MAX_COUNT - i - 1;
//level范围(CardConfig.SHOW_MAX_COUNT-1)-0,每个child最大只移动一个CardConfig.TRANSLATION_Y和放大CardConfig.SCALE
if (level == CardConfig.SHOW_MAX_COUNT - 1) { // 最下层的不动和最后第二层重叠
view.setTranslationY(CardConfig.TRANSLATION_Y * (level - 1));
view.setScaleX(1 - CardConfig.SCALE * (level - 1));
view.setScaleY(1 - CardConfig.SCALE * (level - 1));
} else if (level > 0) {
view.setTranslationY(level * CardConfig.TRANSLATION_Y - fraction * CardConfig.TRANSLATION_Y);
view.setScaleX(1 - level * CardConfig.SCALE + fraction * CardConfig.SCALE);
view.setScaleY(1 - level * CardConfig.SCALE + fraction * CardConfig.SCALE);
}
}
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
@Override
public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
return 0.3f;
}
}
再设置给RecyclerView
public class MainActivity extends AppCompatActivity {
RecyclerView rv;
List<String> mStrings = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rv = (RecyclerView) findViewById(R.id.rv);
rv.setLayoutManager(new CardLayoutManager());
for (int i = 1; i < 21; i++) {
mStrings.add(String.valueOf(i));
}
MyAdapter myAdapter = new MyAdapter(this, mStrings);
rv.setAdapter(myAdapter);
ItemTouchHelperCallback itemTouchHelperCallback = new ItemTouchHelperCallback(mStrings, myAdapter);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(itemTouchHelperCallback);
itemTouchHelper.attachToRecyclerView(rv);
}
class MyAdapter extends RecyclerView.Adapter {
private Context mContext;
private List<String> mStrings;
public MyAdapter(Context mContext, List<String> mStrings) {
this.mContext = mContext;
this.mStrings = mStrings;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
return new MyViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_recyclerview, viewGroup, false));
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
MyViewHolder myViewHolder = (MyViewHolder) viewHolder;
myViewHolder.textView.setText(mStrings.get(i) + "/" + getItemCount());
}
@Override
public int getItemCount() {
return mStrings.size();
}
class MyViewHolder extends RecyclerView.ViewHolder {
public TextView textView;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.tv);
}
}
}
}
网友评论