天天看點

Android基礎控件——Banner輪播圖的無限循環輪播功能、手動滑動功能

Banner輪播圖的無限循環輪播功能、手動滑動功能

輪播圖實作:(假如5張圖輪播)

1、在List中存好這5張圖,傳到ViewPager的Adapter中,相當于5張圖檔橫鋪在ViewPager控件中。

2、設定ViewPager一開始的起始位置為5*1000=5000,并用seletedBanner記錄該位置。

3、在PagerAdapter中将其getCount方法傳回Integer的最大值,讓它向左向右滑都不會越界。

4、在PagerAdapter中必須對目前位置%5(由于5張圖,%5結果在0-4之間,剛好是圖檔集合的下标,如5002%5=2,就是List[2]中的對象)。

5、ViewPager監聽滾動事件,用seletedBanner記錄新位置。

6、在onResume中開始輪播。

圓點實作:

1、在一個水準的布局中添加5個圓點View對象,并存入一個List中。

2、周遊圓點List,在ViewPager滾動回調中判斷seletedBanner(目前位置)%5,則該得到的值為選中圓點,其他為未選中圓點。

其效果圖:

Android基礎控件——Banner輪播圖的無限循環輪播功能、手動滑動功能

實作步驟

1、自定義RelativeLayout,編寫固定的構造方法

public class MyBannerView extends RelativeLayout implements View.OnTouchListener, ViewPager.OnPageChangeListener {

    public MyBannerView(Context context) {
        this(context, null);
    }

    public MyBannerView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyBannerView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //初始化工作
        initBannerViews(context, attrs, defStyleAttr);
    }
}
           

2、聲明需要用到的變量

//輪播圖控件
    private ViewPager targetVp;
    //輪播圖集合
    private ArrayList<View> bannerList;
    //訓示器圖集合
    private ArrayList<View> indicationList;
    //上下文
    private Context context;
    //目前輪播圖位置
    private int selectedBanner;
    //提示輪播
    private final static int BANNER_CHANGE = 0;
    //是否為網絡圖檔加載,作用是:如果是網絡圖檔加載就不滾動輪播圖,讓使用者自己手動滑動輪播圖
    boolean isNetImg = false;
           

3、初始化用到的元件

private void initBannerViews(Context context, AttributeSet attrs, int defStyleAttr) {
        this.context = context;
        //初始化ViewPager
        targetVp = new ViewPager(context);
        targetVp.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        targetVp.setOnTouchListener(this);
        targetVp.setOnPageChangeListener(this);
        //添加到View中
        addView(targetVp);
    }
           

4、提供方法加載圖檔和訓示器

這裡有兩個方法,加載本地圖檔和加載網絡圖檔,加載網絡圖檔用到Glide第三方架構,Glide的學習可以檢視我的部落格

/**
     * 在本地Drawable中加載輪播圖
     *
     * @param activity
     * @param img_urls 輪播圖drawable的ID
     */
    public void initShowImageForLocal(Activity activity, int[] img_urls) {
        //訓示器布局
        LinearLayout ly_indication = new LinearLayout(activity);
        LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        //訓示器邊距
        params.bottomMargin = 15;
        //訓示器位置
        params.addRule(ALIGN_PARENT_BOTTOM);
        params.addRule(CENTER_HORIZONTAL);
        //添加到View中
        addView(ly_indication, params);
        //圖檔集合和訓示器集合
        bannerList = new ArrayList<View>();
        indicationList = new ArrayList<View>();
        for (int i = 0; i < img_urls.length; i++) {
            //初始化圖檔
            ImageView iv = new ImageView(activity);
            iv.setScaleType(ImageView.ScaleType.FIT_XY);
            iv.setBackgroundResource(img_urls[i]);
            bannerList.add(iv);
            //初始化訓示器
            ImageView iv2 = new ImageView(activity);
            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            lp.setMargins(8, 0, 0, 0);
            iv2.setLayoutParams(lp);
            //初始化訓示器預設為第一張高亮
            if (i == 0) {
                iv2.setBackgroundResource(R.drawable.home_top_ic_point_on);
            } else {
                iv2.setBackgroundResource(R.drawable.home_top_ic_point_off);
            }
            indicationList.add(iv2);
            //添加到圓點布局
            ly_indication.addView(iv2);
        }
        //初始化輪播Adapter
        HomeBannerAdapter bannerAdapter = new HomeBannerAdapter(bannerList, activity);
        targetVp.setAdapter(bannerAdapter);
        //初始化目前位置
        targetVp.setCurrentItem(bannerList.size() * 1000);
        //目前position
        selectedBanner = bannerList.size() * 1000;
    }

    /**
     * 通過網絡Url加載輪播圖
     *
     * @param activity
     * @param img_urls 網絡圖檔的URL
     */
    public void initShowImageForNet(Activity activity, List<String> img_urls) {
        //辨別是網絡加載
        isNetImg = true;
        //訓示器布局
        LinearLayout ly_indication = new LinearLayout(activity);
        LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        // 訓示器邊距
        params.bottomMargin = 15;
        //訓示器位置
        params.addRule(ALIGN_PARENT_BOTTOM);
        params.addRule(CENTER_HORIZONTAL);
        //添加到View中
        addView(ly_indication, params);
        //圖檔集合和訓示器集合
        bannerList = new ArrayList<View>();
        indicationList = new ArrayList<View>();
        for (int i = 0; i < img_urls.size(); i++) {
            //初始化圖檔
            ImageView iv = new ImageView(activity);
            iv.setScaleType(ImageView.ScaleType.FIT_XY);
            GlideUtils.setImageView(context, img_urls.get(i), iv);
            bannerList.add(iv);
            //初始化訓示器
            ImageView iv2 = new ImageView(activity);
            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            lp.setMargins(8, 0, 0, 0);
            iv2.setLayoutParams(lp);
            if (i == 0) {
                iv2.setBackgroundResource(R.drawable.home_top_ic_point_on);
            } else {
                iv2.setBackgroundResource(R.drawable.home_top_ic_point_off);
            }
            indicationList.add(iv2);
            //添加到圓點布局
            ly_indication.addView(iv2);
        }
        //初始化輪播資料
        HomeBannerAdapter bannerAdapter = new HomeBannerAdapter(bannerList, activity);
        targetVp.setAdapter(bannerAdapter);
        //初始化目前位置
        targetVp.setCurrentItem(bannerList.size() * 1000);
        //目前position
        selectedBanner = bannerList.size() * 1000;
    }
           

5、實作監聽事件

@Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    }

    @Override
    public void onPageSelected(int position) {
        //改變目前位置指針
        selectedBanner = position;
        //改變訓示器變化
        bannerPointLight(position % indicationList.size());
    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }


    @Override
    public boolean onTouch(View v, MotionEvent event) {
        //如果是網絡加載則沒必要監聽
        if (isNetImg) {
            return false;
        }
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //結束輪播
                mHandler.removeCallbacksAndMessages(null);
                break;
            case MotionEvent.ACTION_UP:
                //開啟輪播
                mHandler.sendEmptyMessageDelayed(BANNER_CHANGE, 3000);
                break;
            case MotionEvent.ACTION_CANCEL:
                //開啟輪播
                mHandler.sendEmptyMessageDelayed(BANNER_CHANGE, 3000);
                break;
        }
        return false;
    }
           

6、提供開啟輪播和結束輪播的方法

/**
     * 開始輪播
     */
    public void startBanner() {
        //開啟輪播
        mHandler.sendEmptyMessageDelayed(BANNER_CHANGE, 3000);
    }

    /**
     * 結束輪播
     */
    public void endBanner() {
        //結束輪播
        mHandler.removeCallbacksAndMessages(null);
    }
           

7、處理輪播

/**
     * 消息處理器
     */
    private Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BANNER_CHANGE:
                    //形成輪播循環
                    targetVp.setCurrentItem(selectedBanner + 1);
                    mHandler.sendEmptyMessageDelayed(BANNER_CHANGE, 3000);
                    break;
            }
        }
    };
           

8、編寫HomeBannerAdapter

/**
     * 擴充卡
     */
    public class HomeBannerAdapter extends PagerAdapter {

        private List<View> views;
        private Context context;

        public HomeBannerAdapter(List<View> views, Context context) {
            this.context = context;
            this.views = views;
        }

        public Object instantiateItem(View container, int position) {
            final int currentItem = position % views.size();
            ((ViewPager) container).addView(views.get(currentItem));
            return views.get(currentItem);
        }

        public void destroyItem(View container, int position, Object object) {
            ((ViewPager) container).removeView((View) object);
        }

        public int getCount() {
            return Integer.MAX_VALUE;
        }

        public boolean isViewFromObject(View arg0, Object arg1) {
            return (arg0 == arg1);
        }
    }
           

9、編寫兩個圓點的xml檔案

① 紅點

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">

    <solid android:color="#FF5000"/>

    <stroke
        android:width="0.1dp"
        android:color="#8888" />
    <size
        android:width="6dp"
        android:height="6dp" />
</shape>
           

② 灰點

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">

    <solid android:color="#88ffffff"/>

    <stroke
        android:width="0.1dp"
        android:color="#8888" />
    <size
        android:width="6dp"
        android:height="6dp" />
</shape>
           

10、接着就可以在Acitivity中使用我們的自定義的BannerView

① 編寫布局檔案,使用我們的自定義BannerView

<com.handsome.didi.View.MyBannerView
                android:id="@+id/vp_banner"
                android:layout_width="match_parent"
                android:layout_height="120dp" />
           

② 在代碼中找到對應ID控件,并且初始化

vp_banner = findView(R.id.vp_banner);
vp_banner.initShowImageForNet(getActivity(), new ArrayList<String>{"","","",""});
           

③ 開啟輪播和停止輪播

@Override
    public void onResume() {
        super.onResume();
        //開始輪播
        vp_banner.startBanner();
    }

    @Override
    public void onPause() {
        super.onPause();
        //停止輪播
        vp_banner.endBanner();
    }
           

源碼下載下傳

源碼下載下傳說明

1、網絡圖檔加載要用到第三庫Glide

2、網絡加載預設是不會自動輪播的,如果需要自動輪播需要将if(isNetImg){return false};去掉