1. 程式人生 > >自動無限輪播廣告欄

自動無限輪播廣告欄

自動滑動廣告欄是比較常用的功能之一,方法一是使用的是一個第三方工具AutoScrollViewPager,方法二使用的是自定義控制元件實現需要的要求.

1.AutoScrollViewPager

第三方庫,github地址:
https://github.com/Trinea/android-auto-scroll-view-pager

直接使用線上導包:

  compile('cn.trinea.android.view.autoscrollviewpager:android-auto-scroll-view-pager:1.1.2') {
        exclude module
: 'support-v4'
}

開始使用:

①在佈局中使用控制元件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height
="match_parent" tools:context="com.simon.autobanner.MainActivity">
<cn.trinea.android.view.autoscrollviewpager.AutoScrollViewPager android:id="@+id/main_autoscrollviewpager" android:layout_width="match_parent" android:layout_height="175dp"/> </RelativeLayout
>

②建立Adapter,繼承PagerAdapter

因為這個控制元件是ViewPager,要用到Adapter(介面卡)來展現資料
Activity程式碼

public class MainActivity extends AppCompatActivity {

    private AutoScrollViewPager mAutoscrollViewPager;
    private MyViewPagerAdapter mMyViewPagerAdapter;
    private ArrayList<ImageView> mImageViews;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        initView();

    }

    private void initData() {
        //模擬廣告圖片,一般是從網路後臺獲取
        mImageViews = new ArrayList<>();

        ImageView img1 = new ImageView(this);
        img1.setScaleType(ImageView.ScaleType.FIT_XY);
        img1.setImageResource(R.mipmap.mao1);
        mImageViews.add(img1);

        ImageView img2= new ImageView(this);
        img2.setScaleType(ImageView.ScaleType.FIT_XY);
        img2.setImageResource(R.mipmap.mao2);
        mImageViews.add(img2);

        ImageView img3 = new ImageView(this);
        img3.setScaleType(ImageView.ScaleType.FIT_XY);
        img3.setImageResource(R.mipmap.mao3);
        mImageViews.add(img3);

        ImageView img4 = new ImageView(this);
        img4.setScaleType(ImageView.ScaleType.FIT_XY);
        img4.setImageResource(R.mipmap.mao4);
        mImageViews.add(img4);

    }

    private void initView() {
        //找到控制元件id
        mAutoscrollViewPager = (AutoScrollViewPager) findViewById(R.id.main_autoscrollviewpager);
        //new出Adapter
        mMyViewPagerAdapter = new MyViewPagerAdapter(this);
        //傳入資料
        mMyViewPagerAdapter.setDatas(mImageViews);
        //繫結ViewPager和adapter
        mAutoscrollViewPager.setAdapter(mMyViewPagerAdapter);
        //啟動自動滑動
        mAutoscrollViewPager.startAutoScroll();

    }
}

adapter程式碼

public class MyViewPagerAdapter extends PagerAdapter {
    private final Context context;
    private ArrayList<ImageView> mDatas;

    public MyViewPagerAdapter(Context context) {
        this.context = context;
    }

    public void setDatas(ArrayList<ImageView> imageViews){
       mDatas=imageViews;
    }

    @Override
    public int getCount() {
        return mDatas.size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    //還需要重寫兩個方法instantiateItem和destroyItem
    //將某一項檢視新增ViewPager中
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        ImageView imageView = mDatas.get(position);
        container.addView(imageView);
        //返回圖片檢視
        return imageView;
    }

    //將某一項檢視從ViewPager中銷燬
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        ImageView imageView = mDatas.get(position);
        container.removeView(imageView);
    }
}

③新增指示器

 /***
     * 初始化指示器
     */
    private void initAdBannerIndicator(int size) {
        //1.做一個for迴圈
        //2.建立圖片控制元件 要設定寬高  繫結shapDrawable  新增到容器中
        //3.預設讓第一個選中
        for (int i = 0; i < size; i++) {
            ImageView iv = new ImageView(this);
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(15, 15);//px
            params.setMargins(20, 0, 0, 0);
            iv.setLayoutParams(params);
            iv.setBackgroundResource(R.drawable.ad_indicator_bg);
            mAdIndicator.addView(iv);
        }
        //啟動時預設為第一個
        changeAdIndicator(0);
    }

    /**
     * 修改廣告欄的指示器
     */
    private void changeAdIndicator(int position) {
        int childCount = mAdIndicator.getChildCount();
        for (int i = 0; i < childCount; i++) {
            //getChildAt 獲取某個容器內部的位置為i的子控制元件
            mAdIndicator.getChildAt(i).setSelected(i == position);
        }
    }

要讓指示器隨著廣告的變化而變化,要給ViewPager設定監聽器,獲取ViewPager當前位置,然後修改指示器,從而達到效果

//找到指示器的容器id
        mAdIndicator = (LinearLayout) findViewById(R.id.ad_indicator);
        initAdBannerIndicator(mImageViews.size());
        //設定監聽器
        mAutoscrollViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                changeAdIndicator(position);
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });

但是這裡還有一點小問題,就是從最後一頁返回第一頁時,效果不太好,可以通過重寫某個方法達到想要的效果,原理與下面的方法相同,所以這裡就不重複了.

④其他屬性設定

setInterval(long) 設定自動滾動的間隔時間,單位為毫秒
setDirection(int) 設定自動滾動的方向,預設向右
setCycle(boolean) 是否自動迴圈輪播,預設為true
setScrollDurationFactor(double) 設定ViewPager滑動動畫間隔時間的倍率,達到減慢動畫或改變動畫速度的效果
setStopScrollWhenTouch(boolean) 當手指碰到ViewPager時是否停止自動滾動,預設為true
setSlideBorderMode(int) 滑動到第一個或最後一個Item的處理方式,支援沒有任何操作、輪播以及傳遞到父View三種模式
setBorderAnimation(boolean) 設定迴圈滾動時滑動到從邊緣滾動到下一個是否需要動畫,預設為true

2.自定義廣告輪播控制元件

採用自定義控制元件的方法,做出一個能達到想要的效果的廣告輪播控制元件

①建立一個新的類BannerScrollView,繼承RelativeLayout

實現構造方法,並模擬了資料

    public BannerScrollView(Context context) {
        super(context);
    }

    public BannerScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initData();
        initView();

    }

    private void initView() {
        //因為是繼承了系統的控制元件,所以在載入佈局的時候需要與父佈局繫結
        View view = View.inflate(getContext(), R.layout.view_banner, this);

        mBannerVp = (ViewPager) view.findViewById(R.id.banner_vp);
        mBannerRl = (RelativeLayout) view.findViewById(R.id.banner_rl);
        mBannerTvTitle = (TextView) view.findViewById(R.id.banner_tv_title);
        mBannerLlIndicator = (LinearLayout) view.findViewById(R.id.banner_ll_indicator);

        //建立adapter
        mBannerScrollAdapter = new BannerScrollAdapter();
        mBannerScrollAdapter.setDatas(mImageViews);
        //繫結ViewPager和adapter
        mBannerVp.setAdapter(mBannerScrollAdapter);
    }

    private void initData() {
        mImageViews = new ArrayList<>();

        //根據業務需求,把傳進來的資料進行網路請求,再轉為圖片格式放入imageView
        //現在只能模擬資料,直接放入圖片
        ImageView img1 = new ImageView(getContext());
        img1.setScaleType(ImageView.ScaleType.FIT_XY);
        img1.setImageResource(R.mipmap.mao1);
        mImageViews.add(img1);

        ImageView img2 = new ImageView(getContext());
        img2.setScaleType(ImageView.ScaleType.FIT_XY);
        img2.setImageResource(R.mipmap.mao2);
        mImageViews.add(img2);

        ImageView img3 = new ImageView(getContext());
        img3.setScaleType(ImageView.ScaleType.FIT_XY);
        img3.setImageResource(R.mipmap.mao3);
        mImageViews.add(img3);

        ImageView img4 = new ImageView(getContext());
        img4.setScaleType(ImageView.ScaleType.FIT_XY);
        img4.setImageResource(R.mipmap.mao4);
        mImageViews.add(img4);


    }

②建立介面卡adapter

public class BannerScrollAdapter extends PagerAdapter {

    private ArrayList<ImageView> mBannerImg;

    public void setDatas(ArrayList<ImageView> bannerImg) {
        mBannerImg = bannerImg;
    }

    @Override
    public int getCount() {
        //把數量寫成integer的最大值,這就能實現無限播放了
        return Integer.MAX_VALUE;
        //        return mBannerImg.size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        //防止數引越界
        position = position % mBannerImg.size();
        ImageView imageView = mBannerImg.get(position);
        container.addView(imageView);
        return imageView;
    }


    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        position = position%mBannerImg.size();
        ImageView imageView = mBannerImg.get(position);
        container.removeView(imageView);
    }
}

現在已經實現了ViewPager的效果,而且能夠無限滑動

③讓廣告自動輪播

讓廣告自動輪播的方法不只一種,我這裡用的是Handler傳送延遲訊息,來進行輪播

Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
           //① int position = msg.what;int position=mBannerVp.getCurrentItem();
            position++;
            mBannerVp.setCurrentItem(position);
            sendEmptyMessageDelayed(position, 2000);
        }
    };

這裡有一個bug,①中position值是從handler傳送過來的mBannerVp.getCurrentItem(),但是如果使用這個值的話,當廣告欄往回滑的時候就會報錯,而使用②中再次獲取mBannerVp.getCurrentItem()值後就可以正常執行.
經過列印log得知,①中的資料不是期望的值,具體的原因可能需要檢視原始碼才能知道.

④新增ViewPager的觸控事件

現在已經實現了廣告的輪播效果,但是現在的程式碼還有很多的問題
1.當你想手動滑動廣告的時候,廣告還是會自動輪播.
2.當你往回滑時,程式會報錯,而且錯誤不只是一個.

給ViewPager新增觸控事件可以暫時解決這兩個問題,讓程式能進行下去,但是有時還是會報錯,暫時還沒找到原因.

mBannerVp.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int action = event.getAction();
                switch (action) {
                    //當按下時,停止給handler傳送訊息
                    case MotionEvent.ACTION_DOWN:
                        mHandler.removeCallbacksAndMessages(null);
                        break;
                    //當鬆開或者手指已經離開ViewPager範圍後,會重新發送訊息,繼續輪播
                    case MotionEvent.ACTION_CANCEL:
                    case MotionEvent.ACTION_UP:
                        mHandler.sendEmptyMessageDelayed(mBannerVp.getCurrentItem(), 1000);
                        break;
                }
                return false;
            }
        });

效果:
這裡寫圖片描述

⑤最後加上指示器

//初始化指示器
    private void initDot() {
        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        layoutParams.setMargins(0, 0, 8, 0);

        for (int i = 0; i < mImageViews.size(); i++) {
            ImageView imageView = new ImageView(getContext());
            imageView.setImageResource(R.drawable.bg_dot_selected);
            mBannerLlIndicator.addView(imageView, layoutParams);
        }
        //從第一個開始
        selectDot(0);
    }

    //改變指示器的顯示,顯示當前位置
    private void selectDot(int position) {
        int size = mImageViews.size();
        position = position % size;
        for (int i = 0; i < size; i++) {
            ImageView childAt = (ImageView) mBannerLlIndicator.getChildAt(i);
            if (position == i) {
                childAt.setImageResource(R.drawable.bg_dot);
            } else {
                childAt.setImageResource(R.drawable.bg_dot_selected);
            }
        }
    }


    //設定ViewPager的監聽器,監聽當前pager的位置,並修改指示器位置
        mBannerVp.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                selectDot(position);
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });

完成,最終效果如圖:
![enter description here][4]