微信讀書 本周推送的類似傳送帶View的具體實(shí)現(xiàn)
實(shí)現(xiàn)效果
image
使用
<com.icool.carousel_lib.CarouselLayout
android:id="@+id/carousel"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:carousel_angle="-30"
app:carousel_spacing="20dp"
app:carousel_speed="1" />
只需要通過設(shè)置Adapter就OK了
public void setAdapter(RecyclerView.Adapter adapter1, RecyclerView.Adapter adapter2, RecyclerView.Adapter adapter3) {
mRv1.setAdapter(adapter1);
mRv2.setAdapter(adapter2);
mRv3.setAdapter(adapter3);
}
屬性說明
屬性值 | 說明 | 值 |
---|---|---|
carousel_angle | 傾斜角度 | 默認(rèn)-30° |
carousel_spacing | 列表之間的間隙影斑,通常設(shè)置為recyclerView的item間距大小一致 | dp |
carousel_speed | 速度矫户,值越大傳送越快残邀,不小于0 | 默認(rèn)1 |
- 可在代碼中設(shè)置間隙
setGapSpacing
- 代碼中設(shè)置角度
setAngle
- 代碼中設(shè)置速度
setSpeed
需求分析
- 直觀有 三條傳送帶式列表
- 一個(gè)正向移動(dòng) 兩個(gè)反向移動(dòng)
- 有一個(gè)傾斜角度
- 可以循環(huán)展示
具體分析
- 根據(jù)樣式 可以確定的是需要自定義ViewGroup來實(shí)現(xiàn)
- 結(jié)合列表的正向反向移動(dòng) 可以確定:
RecyclerView
+LinearLayoutManager
可以做到 - 不停滾動(dòng)借助
Scroller
來實(shí)現(xiàn) - 傾斜角度 可以通過
setRatation()
方法來旋轉(zhuǎn)一個(gè)角度 - 循環(huán)展示 通過設(shè)置
RecyclerView.Adapter
的itemCount
為Inter.MAX_VALUE
具體實(shí)現(xiàn)
自定義CarouselLayout
繼承自ViewGroup
添加一個(gè)子View LinearLayout
, setOrientation(LinearLayout.VERTICAL);
依次添加三個(gè) RecyclerView
,設(shè)置其 marginTop
為 gapSpacing
的值
mContainer = new LinearLayout(getContext());
mContainer.setOrientation(LinearLayout.VERTICAL);
addView(mContainer, generateDefaultLayoutParams());
mRv1 = new CarouselRecyclerView(getContext());
mRv2 = new CarouselRecyclerView(getContext());
mRv3 = new CarouselRecyclerView(getContext());
mContainer.addView(mRv1);
mContainer.addView(mRv2);
mContainer.addView(mRv3);
setSpacing();//此方法設(shè)置margin,詳見代碼
mRv1.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false));
mRv2.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, true));
mRv3.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false));
旋轉(zhuǎn)一個(gè)角度
設(shè)置 LinearLayout
的rotation
mContainer.setRotation(mAngle);//旋轉(zhuǎn)角度
設(shè)置LinearLayout
的大小來保證切斜后仍可以占滿全屏
由于在ViewGroup中最大的距離就是對(duì)角線驱闷,所以 設(shè)置 子View的寬高都為對(duì)角線的長(zhǎng)度
//對(duì)角線長(zhǎng)度
mDiagonalLine = (int) Math.sqrt(getMeasuredWidth() * getMeasuredWidth() + getMeasuredHeight() * getMeasuredHeight());
ViewGroup.LayoutParams params = mContainer.getLayoutParams();
params.width = mDiagonalLine;
params.height = mDiagonalLine;
mContainer.setLayoutParams(params);
移動(dòng)起來
借助Scroller類來不斷 調(diào)用 computeScroll
方法實(shí)現(xiàn)滾動(dòng)
@Override
public void computeScroll() {
super.computeScroll();
mRv1.scrollBy(mSpeed, 0);//speed 對(duì)應(yīng)移動(dòng)像素值
mRv2.scrollBy(-mSpeed, 0);
mRv3.scrollBy(mSpeed, 0);
if (mScroller.isFinished()) {
start();
}
}
其他
- 因?yàn)榱斜硎褂?code>RecyclerView實(shí)現(xiàn)空另,所以我們手動(dòng)還可以滑動(dòng)它鼓蜒。
如果不想手動(dòng)滑動(dòng)的話征字,重寫RecyclerView
的onTouchEvent
方法,return false;
- 無限循環(huán)
設(shè)置Adapter的時(shí)候
@Override
public int getItemCount() {
return Integer.MAX_VALUE;
}
然后在 onBindViewHolder
方法取item的時(shí)候 進(jìn)行取余操作
String url = mSources[position % mSources.length];
后記
這個(gè)效果在微信閱讀上是WebView實(shí)現(xiàn)的匙姜,我們的UI直接抄了過來氮昧。所以只能用Android代碼實(shí)現(xiàn)一下。
如果有更好的實(shí)現(xiàn)方式袖肥,或者需要改進(jìn)的地方振劳,希望可以一起探討。