1. 程式人生 > >Banner豎向輪播實現

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實現更加簡單易用。