先貼圖
要實現上面的畫廊效果,傳統通過ViewPager clipChildren置為false實現。網上很多教程這個不多說,現在說說用RecyclerView實現上面的效果。這個效果分兩步:
- ViewPager滑動最終居中停止
- 滑動過程中縮放
ViewPager滑動最終居中停止
Support RecyclerView 24.2.0中增加一個非常重要的類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);
}
}