效果图:
值得一提的是,这是旧版本的特效,新版本的喵街已经去掉了这种效果。
看完了效果,接下来就是动手的时间了。
我们先来分析一下思路:我们先给RecyclerView添加一个OnScrollListener,然后分别去获得firstVisiblePosition和firstCompletelyVisiblePosition。这里要注意一下,firstVisiblePosition是第一个在屏幕中可见的itemView对应的position,而firstCompletelyVisiblePosition是是第一个在屏幕中完全可见的itemView对应的position。之后在滚动中去动态地设置itemView的高度。整体的思路就这样了,下面我们直接来看代码。
创建几个自定义的属性,以便后面备用:
1 2 3 4 5 6 7 8 9
| <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="ExpandRecyclerView"> <attr name="max_item_height" format="dimension"></attr> <attr name="normal_item_height" format="dimension"></attr> </declare-styleable> </resources>
|
之后我们新建一个类继承自RecyclerView,类名就叫ExpandRecyclerView。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| private float maxItemHeight;
private float normalItemHeight;
private float defaultMaxItemHeight;
private float defaultNormalItemHeight;
public ExpandRecyclerView(Context context) { this(context, null); }
public ExpandRecyclerView(Context context, AttributeSet attrs) { this(context, attrs, 0); }
public ExpandRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ExpandRecyclerView); defaultMaxItemHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 256, context.getResources().getDisplayMetrics()); defaultNormalItemHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 120, context.getResources().getDisplayMetrics()); maxItemHeight = a.getDimension(R.styleable.ExpandRecyclerView_max_item_height, defaultMaxItemHeight); normalItemHeight = a.getDimension(R.styleable.ExpandRecyclerView_normal_item_height, defaultNormalItemHeight); a.recycle();
setHasFixedSize(true); setLayoutManager(new LinearLayoutManager(context)); setItemAnimator(new DefaultItemAnimator()); this.addOnScrollListener(listener); }
|
在构造器中我们得到了maxItemHeight
和normalItemHeight
,之后设置了OnScrollListener。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| OnScrollListener listener = new RecyclerView.OnScrollListener() {
@Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); Log.i(TAG,"dy : " + dy); LinearLayoutManager mLinearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); int firstVisiblePosition = mLinearLayoutManager.findFirstVisibleItemPosition(); RecyclerView.ViewHolder firstVisibleViewHolder = recyclerView.findViewHolderForLayoutPosition(firstVisiblePosition); int firstCompletelyVisiblePosition = mLinearLayoutManager.findFirstCompletelyVisibleItemPosition(); RecyclerView.ViewHolder firstCompletelyVisibleViewHolder = recyclerView.findViewHolderForLayoutPosition(firstCompletelyVisiblePosition);
Log.i(TAG, "firstVisiblePosition : " + firstVisiblePosition + " , firstCompletelyVisiblePosition : " + firstCompletelyVisiblePosition); if (firstVisibleViewHolder.itemView.getLayoutParams().height - dy < maxItemHeight && firstVisibleViewHolder.itemView.getLayoutParams().height - dy >= normalItemHeight) { firstVisibleViewHolder.itemView.getLayoutParams().height -= dy; firstVisibleViewHolder.itemView.setLayoutParams(firstVisibleViewHolder.itemView.getLayoutParams()); } if (firstCompletelyVisibleViewHolder.itemView.getLayoutParams().height + dy <= maxItemHeight && firstCompletelyVisibleViewHolder.itemView.getLayoutParams().height + dy >= normalItemHeight) { firstCompletelyVisibleViewHolder.itemView.getLayoutParams().height += dy; firstCompletelyVisibleViewHolder.itemView.setLayoutParams(firstCompletelyVisibleViewHolder.itemView.getLayoutParams()); }
}
};
|
在onScrolled(RecyclerView recyclerView, int dx, int dy)
里大部分的代码都加上注释了,就是根据dy
去动态地改变了firstVisibleViewHolder
和firstCompletelyVisibleViewHolder
的高度。
上面的搞定了之后,别忘了要在Adapter里去初始化设置Item的高度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
@Override public void setAdapter(Adapter adapter) { super.setAdapter(adapter); if (adapter instanceof ExpandRecyclerViewAdapter) { ExpandRecyclerViewAdapter mAdapter = (ExpandRecyclerViewAdapter) adapter; mAdapter.setMaxItemHeight(maxItemHeight); mAdapter.setNormalItemHeight(normalItemHeight); } }
|
ExpandRecyclerViewAdapter的代码,重写onBindViewHolder(RecyclerView.ViewHolder holder, int position)
:
1 2 3 4 5 6 7 8 9 10 11
| @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if(position == 0){ holder.itemView.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) maxItemHeight)); }else{ holder.itemView.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) normalItemHeight)); } bindCustomViewHolder(holder, position); }
public abstract void bindCustomViewHolder(RecyclerView.ViewHolder holder, int position);
|
好了,整体的代码就这些了,下面贴出运行效果: