Banner豎向輪播實現
前言
除了常用橫向輪播廣告條,現在也有不少應用比如支付寶、美團外賣等首頁會有豎向的輪播Banner。其實橫向輪播Banner在一個頁面上如果有兩個或以上,會讓使用者覺得很怪,這主要是因為只有橫向切換展現方式過於單調。增加了豎向輪播控制元件,介面上又多了一種吸引使用者的表現方式,這對提升使用者體驗很有幫助。接下來使用兩種不同的方式實現豎向輪播。
實現效果
實現介面
在同一個位置有兩個檢視,這兩個檢視一個在可見位置向上到使用者看不到的位置,另外一個從底部看不到的位置向上運動到使用者完全看到的位置。可以用下圖來描述整個運動過程:
這樣就很容易想到一個屬性translationY,可以看到隱藏和展示的兩個View都在不停的變換自己的translationY屬性值。現在就可以通過屬性動畫結合postDelay來實現不斷的豎向切換效果。
還有另外一種實現就是使用ViewFlipper切換,檢視ViewFlipper的原始碼會發現實現其實是在FrameLayout中把所有的View都加入,然後展示哪個View就先設定可見再執行translate動畫,隱藏哪個View就先執行translate動畫再隱藏View。
實現過程
TranslationY屬性動畫
觀察上面的動畫示意圖會發現第一個要隱藏View的translationY是從(0, -view.getHeight()),而第二個要展示的View的translationY是從(view.getHeight(), 0)變化,找到這個規律之後很容易實現豎向的切換效果。
public class VerticalScrollView extends FrameLayout {
// 處於隱藏狀態的View
private View recycleView;
// 處於可見狀態的View
private View currentView;
// 正常的資料Adapter
private BaseAdapter adapter;
private int current = -1;
private Runnable playRunnable = new Runnable() {
@Override
public void run() {
// 每過一段時間切換資料
current = (current + 1) % adapter.getCount();
// 為隱藏的View更新資料,複用以前用過的View
View newView = adapter.getView(current, recycleView, VerticalScrollView.this);
// 定義隱藏屬性動畫
ObjectAnimator hide = ObjectAnimator.ofFloat(currentView, "translationY", 0, -recycleView.getHeight());
// 定義展示屬性動畫
ObjectAnimator show = ObjectAnimator.ofFloat(newView, "translationY", newView.getHeight(), 0);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(hide).with(show);
animatorSet.setDuration(1000);
animatorSet.start();
// 交換隱藏View和當前View的引用
recycleView = currentView;
currentView = newView;
// 3秒之後再進行一次
postDelayed(this, 3000);
}
};
public VerticalScrollView(@NonNull Context context) {
this(context, null);
}
public VerticalScrollView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public VerticalScrollView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
}
public void setAdapter(BaseAdapter adapter) {
this.adapter = adapter;
if (adapter == null || adapter.getCount() < 1) {
setVisibility(View.GONE);
return;
}
// 初始化第一次展示的View
currentView = adapter.getView(0, null, this);
// 初始化隱藏的View
recycleView = adapter.getView(1, null, this);
current = 0;
addView(recycleView);
addView(currentView);
}
public void pausePlay() {
removeCallbacks(playRunnable);
}
public void resumePlay() {
removeCallbacks(playRunnable);
postDelayed(playRunnable, 3000);
}
public void destroy() {
pausePlay();
playRunnable = null;
}
}
通過簡單的對postDelay和ObjectAnimator做封裝,使用者只要呼叫setAdapter就可以實現豎向輪播的效果。
ViewFlipper實現
ViewFlipper的實現就更簡單了,只需要提供展示和隱藏時候的動畫效果就可以了。
// slide_in.xml
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromXDelta="0"
android:fromYDelta="100%p"
android:toXDelta="0"
android:toYDelta="0">
</translate>
// slide_out.xml
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="0"
android:toYDelta="-100%p">
</translate>
public class VerticalScrollView2 extends ViewFlipper {
private BaseAdapter adapter;
public VerticalScrollView2(@NonNull Context context) {
this(context, null);
}
public VerticalScrollView2(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// 初始化ViewFlipper,設定展示進入和隱藏退出的動畫效果
setAutoStart(false);
setFlipInterval(3000);
setInAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.slide_in));
setOutAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.slide_out));
}
public void setAdapter(BaseAdapter adapter) {
this.adapter = adapter;
if (adapter == null || adapter.getCount() < 1) {
setVisibility(View.GONE);
return;
}
// 把Adapter中所有的ItemView都生成新增到ViewFlipper中
for (int i = 0, count = adapter.getCount(); i < count; i++) {
addView(adapter.getView(i, null, this));
}
}
public void pausePlay() {
stopFlipping();
}
public void resumePlay() {
startFlipping();
}
public void destroy() {
pausePlay();
}
}
檢視全部實現程式碼請點選檢視原始碼
總結
豎向輪播相對比較簡單,但是屬性動畫的實現方式只會生成兩個檢視佈局,一個是展示用,另外一個是隱藏時用,這裡借鑑了ListView的複用思想。但是ViewFlipper要求一次把所有的檢視都生成,如果資料量很大明顯就不合適。所以如果很在乎不要大量產生檢視物件,採用屬性動畫方式更好,如果資料量不大ViewFlipper實現更加簡單易用。