您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關使用VerticalBannerView怎么實現垂直輪播廣告,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
一、項目使用
(1).添加項目依賴。
dependencies { compile 'com.github.Rowandjj:VerticalBannerView:1.0' }
(2).添加布局。
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="5dp" android:text="淘寶頭條" android:textStyle="bold"/> <View android:layout_width="1dp" android:layout_height="40dp" android:layout_marginLeft="5dp" android:layout_marginRight="5dp" android:background="#cccccc"/> <com.taobao.library.VerticalBannerView xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/banner" android:layout_width="wrap_content" android:layout_height="36dp" app:animDuration="900" app:gap="2000"/> </LinearLayout>
(3).實現Adapter。
public class SampleAdapter extends BaseBannerAdapter<Model> { private List<Model> mDatas; public SampleAdapter01(List<Model> datas) { super(datas); } @Override public View getView(VerticalBannerView parent) { return LayoutInflater.from(parent.getContext()).inflate(R.layout.your_item,null); } @Override public void setItem(final View view, final Model data) { TextView textView = (TextView) view.findViewById(R.id.text); textView.setText(data.title); // 你可以增加點擊事件 view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO handle click event } }); } }
(4).為VerticalBannerView設置Adapter,并啟動動畫。
List<Model> datas = new ArrayList<>(); datas.add(new Model01("Note7發布了")); datas.add(new Model01("Note7被召回了")); SampleAdapter adapter = new SampleAdapter(datas); VerticalBannerView banner = (VerticalBannerView) findViewById(R.id.banner); banner.setAdapter(adapter); banner.start();
二、源碼分析
實現原理:
VerticalBannerView本質上是一個垂直的LinearLayout。定義一個Adapter類,向LinearLayout提供子View。初始狀態下往LinearLayout中添加兩個子View,子View的高度同LinearLayout的高度一致,這樣一來只有第1個子View顯示出來,第2個子View在底部不顯示。然后使用屬性動畫ObjectAnimator同時修改兩個子View的translationY屬性,動畫執行過程中translationY從默認值0漸變到負的LinearLayout的高度,顯示出來的效果就是第1個子View逐漸向上退出,第2個子View從底部向上逐漸顯示。動畫執行完畢后,移除第1個子View,這樣第2個子View的索引變成0,并完全顯示出來占據LinearLayout的高度。再將已經移除的第1個子View,添加到索引為1的位置,此時該子View超出父視圖之外完全不顯示。一輪動畫執行完畢,再調用postDelay()方法重復上述動畫,一直循環下去。
下面進入代碼部分,主要是兩個類BaseBannerAdapter和VerticalBannerView。
(1).BaseBannerAdapter類
BaseBannerAdapter類負責為廣告欄提供數據。我們在使用時,需要寫一個Adapter類繼承BaseBannerAdapter,實現getView()和setItem()方法。在getView()方法中,我們需要把要添加到廣告欄中的item view創建出來并返回,setItem()方法則負責為創建的item view綁定數據。
public abstract class BaseBannerAdapter<T> { private List<T> mDatas; private OnDataChangedListener mOnDataChangedListener; public BaseBannerAdapter(List<T> datas) { mDatas = datas; if (datas == null || datas.isEmpty()) { throw new RuntimeException("nothing to show"); } } public BaseBannerAdapter(T[] datas) { mDatas = new ArrayList<>(Arrays.asList(datas)); } // 設置banner填充的數據 public void setData(List<T> datas) { this.mDatas = datas; notifyDataChanged(); } void setOnDataChangedListener(OnDataChangedListener listener) { mOnDataChangedListener = listener; } // 獲取banner總數 public int getCount() { return mDatas == null ? 0 : mDatas.size(); } // 通知數據改變 void notifyDataChanged() { mOnDataChangedListener.onChanged(); } // 獲取數據 public T getItem(int position) { return mDatas.get(position); } // 設置banner的ItemView public abstract View getView(VerticalBannerView parent); // 設置banner的數據 public abstract void setItem(View view, T data); // 數據變化的監聽 interface OnDataChangedListener { void onChanged(); } }
(2).VerticalBannerView類
VerticalBannerView類繼承自LinearLayout,并在構造方法中設定方向為垂直。同時VerticalBannerView類實現了OnDataChangedListener接口,實現onChanged()方法,這樣當改變數據后調用BaseBannerAdapter的notifyDataChanged()時,VerticalBannerView的onChanged()方法被回調,執行setupAdapter()重新初始化數據。
public class VerticalBannerView extends LinearLayout implements BaseBannerAdapter.OnDataChangedListener { public VerticalBannerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs, defStyleAttr); } private void init(Context context, AttributeSet attrs, int defStyleAttr) { setOrientation(VERTICAL); ...... } ...... @Override public void onChanged() { setupAdapter(); } ...... }
為VerticalBannerView添加item數據,需要調用setAdapter()方法,關鍵在于其中執行的setupAdapter()方法。
public void setAdapter(BaseBannerAdapter adapter) { if (adapter == null) { throw new RuntimeException("adapter must not be null"); } if (mAdapter != null) { throw new RuntimeException("you have already set an Adapter"); } this.mAdapter = adapter; mAdapter.setOnDataChangedListener(this); setupAdapter(); }
在setupAdapter()方法中,先移除所有的子View,然后調用Adapter的getView()方法創建兩個子View,分別賦值給成員變量mFirstView和mSecondView,并為這兩個子View綁定數據,最后再調用addView()添加進來。
// 初始化Child View private void setupAdapter() { // 先移除所有的子View removeAllViews(); if (mAdapter.getCount() == 1) { mFirstView = mAdapter.getView(this); mAdapter.setItem(mFirstView, mAdapter.getItem(0)); addView(mFirstView); } else { // 調用Adapter的getView()方法,創建兩個子View,分別賦值給mFirstView和mSecondView mFirstView = mAdapter.getView(this); mSecondView = mAdapter.getView(this); // 使用索引0和1的數據,為mFirstView和mSecondView設置數據 mAdapter.setItem(mFirstView, mAdapter.getItem(0)); mAdapter.setItem(mSecondView, mAdapter.getItem(1)); // 將mFirstView和mSecondView添加到當前View addView(mFirstView); addView(mSecondView); mPosition = 1; isStarted = false; } setBackgroundDrawable(mFirstView.getBackground()); }
為了實現子View之間的切換,需要把上面添加進來的子View的高度修改為與VerticalBannerView高度一致。這個操作在onMeasure()方法中完成。
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 成員變量mBannerHeight有一個默認值 if (LayoutParams.WRAP_CONTENT == getLayoutParams().height) { // 如果當前View的高度設置為wrap_content,使用默認值 getLayoutParams().height = (int) mBannerHeight; } else { // 如果當前View設定了固定高度,則使用設定的高度 mBannerHeight = getHeight(); } // 修改mFirstView和mSecondView的高度為其父視圖的高度 if (mFirstView != null) { mFirstView.getLayoutParams().height = (int) mBannerHeight; } if (mSecondView != null) { mSecondView.getLayoutParams().height = (int) mBannerHeight; } }
上面的準備工作完成后,就可以進入動畫的執行了。VerticalBannerView通過調用start()方法啟動切換動畫。在start()方法中,調用postDelayed()執行AnimRunnable任務,在AnimRunnable的run()方法中,先調用performSwitch(),然后再次調用postDelayed()使AnimRunnable任務一直循環執行下去。兩個子View之間的切換工作由performSwitch()負責執行。
public void start() { if (mAdapter == null) { throw new RuntimeException("you must call setAdapter() before start"); } if (!isStarted && mAdapter.getCount() > 1) { isStarted = true; postDelayed(mRunnable, mGap); } } private AnimRunnable mRunnable = new AnimRunnable(); private class AnimRunnable implements Runnable { @Override public void run() { performSwitch(); // 調用postDelayed()延時再執行,一直循環下去 postDelayed(this, mGap); } }
下面再進入performSwitch()方法,該方法是Item View之間產生切換效果的核心。
// 執行切換 private void performSwitch() { // 動畫在執行過程中,View的translationY屬性從0一直減小到-mBannerHeight // 因為translationY屬性一直是負值,所以View向上移動 ObjectAnimator animator1 = ObjectAnimator.ofFloat(mFirstView, "translationY", -mBannerHeight); ObjectAnimator animator2 = ObjectAnimator.ofFloat(mSecondView, "translationY", -mBannerHeight); AnimatorSet set = new AnimatorSet(); set.playTogether(animator1, animator2); set.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { // 動畫執行完成,把mFirstView和mSecondView的translationY恢復到默認狀態 mFirstView.setTranslationY(0); mSecondView.setTranslationY(0); // 使用下一條數據,設置到第一個子View View removedView = getChildAt(0); mPosition++; mAdapter.setItem(removedView, mAdapter.getItem(mPosition % mAdapter.getCount())); // 移除第一個子View,此時當前LinearLayout的childCount==1 removeView(removedView); // 移除的View,再添加到第2個位置 addView(removedView, 1); } }); set.setDuration(mAnimDuration); set.start(); }
關于使用VerticalBannerView怎么實現垂直輪播廣告就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。