在逛Dribbble時(shí)無意間看到這樣的效果,看著挺cool的何荚,就自己來實(shí)現(xiàn)一番须教。
Dribble.gif
實(shí)現(xiàn)的效果:
效果 | 效果 |
---|---|
SkidRightLayoutManager1.gif
|
SkidRightLayoutManager2.gif
|
實(shí)現(xiàn)思路是自定義LayoutManager來實(shí)現(xiàn)Item中的布局,通過RecyclerView來展示。
1.必須實(shí)現(xiàn)的方法
@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(RecyclerView.LayoutParams.WRAP_CONTENT,
RecyclerView.LayoutParams.WRAP_CONTENT);
}
2.通過重寫onLayoutChildren方法來實(shí)現(xiàn)初始化的布局以及初始化一些需要的數(shù)據(jù)
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
if (state.getItemCount() == 0 || state.isPreLayout()) return;
//首先將所有的Item回收到緩存中
removeAndRecycleAllViews(recycler);
//第一進(jìn)來典勇,聲明Item的寬高劫哼,并標(biāo)識Item的數(shù)目不為0.
if (!mHasChild) {
mItemViewHeight = getVerticalSpace();
mItemViewWidth = (int) (mItemViewHeight / mItemHeightWidthRatio);
mHasChild = true;
}
mItemCount = getItemCount();
mScrollOffset = makeScrollOffsetWithinRange(mScrollOffset);
//對Item進(jìn)行布局
fill(recycler);
}
3.Item的布局以及縮放的關(guān)鍵就是在fill(recycler)函數(shù)和fillChild()函數(shù)中,同時(shí)對Item進(jìn)行回收處理
public void fill(RecyclerView.Recycler recycler) {
//獲取最右邊Item的位置
int bottomItemPosition = (int) Math.floor(mScrollOffset / mItemViewWidth);
//獲取最右邊的Item的可見寬度
int bottomItemVisibleSize = mScrollOffset % mItemViewWidth;
//獲取最右邊Item可見寬度相對于Item寬度的比例
final float offsetPercent = bottomItemVisibleSize * 1.0f / mItemViewWidth;
final int space = getHorizontalSpace();
//用于存儲要顯示的Item的信息割笙,從最右邊的Item開始添加
ArrayList<ItemViewInfo> layoutInfos = new ArrayList<>();
for (int i = bottomItemPosition - 1, j = 1, remainSpace = space - mItemViewWidth;
i >= 0; i--, j++) {
//左右兩個(gè)Item間最大偏移量
double maxOffset = (getHorizontalSpace() - mItemViewWidth) / 2 * Math.pow(mScale, j);
//Item左邊的位置
int start = (int) (remainSpace - offsetPercent * maxOffset);
ItemViewInfo info = new ItemViewInfo(start,
(float) (Math.pow(mScale, j - 1) * (1 - offsetPercent * (1 - mScale))),
offsetPercent,
start * 1.0f / space
);
layoutInfos.add(0, info);
remainSpace -= maxOffset;
if (remainSpace <= 0) {
info.setTop((int) (remainSpace + maxOffset));
info.setPositionOffset(0);
info.setLayoutPercent(info.getTop() / space);
info.setScaleXY( (float) Math.pow(mScale, j - 1));
break;
}
}
if (bottomItemPosition < mItemCount) {
final int start = space - bottomItemVisibleSize;
layoutInfos.add(new ItemViewInfo(start, 1.0f,
bottomItemVisibleSize * 1.0f / mItemViewWidth, start * 1.0f / space).
setIsBottom());
} else {
bottomItemPosition -= 1;
}
//Item回收處理的邏輯
int layoutCount = layoutInfos.size();
final int startPos = bottomItemPosition - (layoutCount - 1);
final int endPos = bottomItemPosition;
final int childCount = getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
View childView = getChildAt(i);
int pos = convert2LayoutPosition(getPosition(childView));
if (pos > endPos || pos < startPos) {
removeAndRecycleView(childView, recycler);
}
}
detachAndScrapAttachedViews(recycler);
for (int i = 0; i < layoutCount; i++) {
//將Item進(jìn)行排列
fillChild(recycler.getViewForPosition(convert2AdapterPosition(startPos + i)), layoutInfos.get(i));
}
}
private void fillChild(View view, ItemViewInfo layoutInfo) {
addView(view);
measureChildWithExactlySize(view);
//計(jì)算縮放比例
final int scaleFix = (int) (mItemViewWidth * (1 - layoutInfo.getScaleXY()) / 2);
int top = (int) getPaddingTop();
//排列Item
layoutDecoratedWithMargins(view, layoutInfo.getTop() - scaleFix, top
, layoutInfo.getTop() + mItemViewWidth - scaleFix, top + mItemViewHeight);
//對Item進(jìn)行縮放
ViewCompat.setScaleX(view, layoutInfo.getScaleXY());
ViewCompat.setScaleY(view, layoutInfo.getScaleXY());
}
4.設(shè)置列表的滑動方向
@Override
public boolean canScrollHorizontally() {
return true;
}
5.滑動處理邏輯权烧,滑動的同時(shí)也要對Item進(jìn)行位置排列
@Override
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
int pendingScrollOffset = mScrollOffset + dx;
mScrollOffset = makeScrollOffsetWithinRange(pendingScrollOffset);
fill(recycler);
return mScrollOffset - pendingScrollOffset + dx;
}
主要邏輯已將完成眯亦,一句代碼實(shí)現(xiàn)cool~~~列表
mSkidRightLayoutManager = new SkidRightLayoutManager(1.5f, 0.85f);
mRecyclerView.setLayoutManager(mSkidRightLayoutManager);
詳細(xì)代碼請看github源碼哦