先贴图
要实现上面的画廊效果,传统通过ViewPager clipChildren置为false实现。网上很多教程这个不多说,现在说说用RecyclerView实现上面的效果。这个效果分两步:
- ViewPager滑动最终居中停止
- 滑动过程中缩放
ViewPager滑动最终居中停止
Support RecyclerView中增加一个非常重要的类SnapHelper
,他的作用是让RecyclerView滑动视图后使停止位置正好停在某页的正中间。使用方式很简单
重点在于new LinearSnapHelper().attachToRecyclerView(recyclerView);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false);
recyclerView.setLayoutManager(linearLayoutManager);
new LinearSnapHelper().attachToRecyclerView(recyclerView);
一行代码搞定居中,LinearSnapHelper的源码解析查看这里。
滑动过程中缩放
毫无疑问,RecyclerView的滑动缩放必须要监听RecyclerView的滑动
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// dx>0则表示右滑, dx<0表示左滑, dy<0表示上滑, dy>0表示下滑
mCurrentItemOffset += dx;
computeCurrentItemPos();
onScrolledChangedCallback();
}
});
mCurrentItemOffset为滑动总距离,Card每页滑动的距离是固定的,根据这个可以计算出当前显示的位置。缩放看onScrolledChangedCallback
这个函数,有了滑动位置就能实时计算滑动某页的百分比float percent = (float) Math.max(Math.abs(offset) * 1.0 / mOnePageWidth, 0.0001);
得到百分比, 再获取当前位置相邻的视图调用setScaleY
函数实现缩放
/**
* RecyclerView位移事件监听, view大小随位移事件变化
*/
private void onScrolledChangedCallback() {
int offset = mCurrentItemOffset - mCurrentItemPos * mOnePageWidth;
float percent = (float) Math.max(Math.abs(offset) * 1.0 / mOnePageWidth, 0.0001);
View leftView = null;
View currentView;
View rightView = null;
if (mCurrentItemPos > 0) {
leftView = mRecyclerView.getLayoutManager().findViewByPosition(mCurrentItemPos - 1);
}
currentView = mRecyclerView.getLayoutManager().findViewByPosition(mCurrentItemPos);
if (mCurrentItemPos < mRecyclerView.getAdapter().getItemCount() - 1) {
rightView = mRecyclerView.getLayoutManager().findViewByPosition(mCurrentItemPos + 1);
}
if (leftView != null) {
// y = (1 - mScale)x + mScale
leftView.setScaleY((1 - mScale) * percent + mScale);
}
if (currentView != null) {
// y = (mScale - 1)x + 1
currentView.setScaleY((mScale - 1) * percent + 1);
}
if (rightView != null) {
// y = (1 - mScale)x + mScale
rightView.setScaleY((1 - mScale) * percent + mScale);
}
}