傳統的ViewPager做循環滾動有兩種思路。
- 一種是設置count爲Integer.MAX,然後根據index對實際數量取模
- 一種是在開頭在開頭添加end,在末尾添加start。簡單的說就是多兩個,滑動到這兩個的時候直接setCurrentItem到真正的位置。
在觀察pdd的拼單的循環滾動的時候,想到幾種實現方式。
- 通過Recyclerview,同樣跟ViewPager做循環滾動的思路類似,多一點要攔截掉所有的觸摸事件。但是這種方式的話無法像pdd的效果那樣設置進入和出去的動畫。
- 通過改造VerticalViewpager的形式,應該也是可以的,但是感覺比較麻煩。
- 通過自定義的方式實現。(原本以爲挺簡單的,實現了下,代碼不多但是有些小細節需要注意下。)
我選擇了自定義的這裏只是一個demo,提供一種思路。
最核心的就是上面的item滑出屏幕的時候將它remove掉然後再加到自定義的ViewGroup的末尾。
public class LoopView extends ViewGroup {
private static final String TAG = "LoopView";
private float dis;
private ObjectAnimator animator;
private int currentIndex = 0;
private Handler handler = new Handler(Looper.getMainLooper());
public LoopView(Context context) {
super(context);
init();
}
public LoopView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public LoopView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
void init() {
View view1 = new View(getContext());
view1.setTag("gray");
view1.setBackgroundColor(Color.GRAY);
LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, 200);
addView(view1, layoutParams);
View view2 = new View(getContext());
view2.setTag("red");
view2.setBackgroundColor(Color.RED);
LayoutParams layoutParams1 = new LayoutParams(LayoutParams.MATCH_PARENT, 200);
addView(view2, layoutParams1);
View view3 = new View(getContext());
view3.setTag("green");
view3.setBackgroundColor(Color.GREEN);
LayoutParams layoutParams2 = new LayoutParams(LayoutParams.MATCH_PARENT, 200);
addView(view3, layoutParams2);
animator = ObjectAnimator.ofFloat(this, "dis", 0, 1);
animator.setDuration(2000);
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
currentIndex++;
View first = getChildAt(0);
removeView(first);
addView(first);
handler.postDelayed(new Runnable() {
@Override
public void run() {
animator.clone().start();
}
}, 3000);
}
});
}
public void start() {
animator.start();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
measureChildren(widthMeasureSpec, heightMeasureSpec);
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(200, MeasureSpec.EXACTLY));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount = getChildCount();
int top = currentIndex * getMeasuredHeight();
for (int i = 0; i < childCount; i++) {
View childAt = getChildAt(i);
childAt.layout(l, top, r, top + childAt.getMeasuredHeight());
top += childAt.getMeasuredHeight();
}
}
public float getDis() {
return dis;
}
public void setDis(float dis) {
this.dis = dis;
float disY = dis * getHeight();
scrollTo(0, (int) (currentIndex * getHeight() + disY));
}
}
需要注意的就是onLayout的時候對於top的取值。