自定義view————Banner輪播

madreain發表於2019-03-04

今天給大家專案中應用很廣泛的Banner輪播,每一個app都會用到這個,並且有時候會在多處去應用,這時候就在想了,把Banner輪播寫成自定義view,直接傳顯示資料,接受點選事件的回撥。在自己的實際專案中,可以根據自身的效果稍作修改,客官們,先上圖(這次全部選擇的是女神劉亦菲的照片)

效果圖
效果圖

各位客官,效果看了是否滿意呀,來分析一下流程:viewpager+自身的監聽方法+Handler實現滑動切換banner和banner輪播自身迴圈

顯示view的選擇

根據效果圖,我們選取FrameLayout為父佈局,裡面用ViewPager+LinearLayout(程式碼中再去設定選擇和未選擇的狀態)

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:unselectedAlpha="1" />

    <LinearLayout
        android:id="@+id/layout_page"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center|bottom"
        android:gravity="center"
        android:orientation="horizontal"
        android:padding="10dip" />

</FrameLayout>複製程式碼

將需要顯示的view新增到自定義view中去顯示,因為FrameLayout是父佈局,我們這裡也是繼承FrameLayout去自定義view

這裡在onFinishInflate()方法中去新增view,可以去了解一下onFinishInflate()的用法

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        View view = LayoutInflater.from(mContext).inflate(R.layout.banner_layout, null);
        viewpager_banner = (ViewPager) view.findViewById(R.id.viewpager);
        layout_page = (LinearLayout) view.findViewById(R.id.layout_page);
        addView(view);

        bannerModelList = new ArrayList<>();
        bannerviewsList = new ArrayList<>();
    }複製程式碼

根據假資料顯示內容

實際專案中,資料都是傳遞過來的,我們也採用info傳值過來的,然後根據資料進行顯示的相關設定,後期可根基自己專案的info去修改


/**
 * Created by wujun on 2017/8/11.
 * banner的實體類,根據自己的實際專案去定製
 * @author madreain
 * @desc
 */

public class BannerModel {
    private int id;
    private String imgurl;

    public BannerModel() {
    }

    public BannerModel(int id, String imgurl) {
        this.id = id;
        this.imgurl = imgurl;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getImgurl() {
        return imgurl;
    }

    public void setImgurl(String imgurl) {
        this.imgurl = imgurl;
    }

    @Override
    public String toString() {
        return "BannerModel{" +
                "id=" + id +
                ", imgurl='" + imgurl + '\'' +
                '}';
    }
}複製程式碼

資料有了,就要有資料設定的方法和拿資料做展示

繼承PagerAdapter去顯示banner輪播中的照片

layout_page.addview()去新增效果圖中的小圓點

addOnPageChangeListener()實現左右切換

    /**
     * 第一次設定資料的方法
     *
     * @param mbannerModelList
     */
    public void setBannerModelList(List<BannerModel> mbannerModelList) {
        this.bannerModelList = mbannerModelList;
        // 本地
        if (bannerModelList != null) {
            if (bannerModelList.size() > 0) {
                //本地儲存
                bannerModelListSize = bannerModelList.size();

                for (BannerModel bannerModel : bannerModelList) {
                    ImageView imageView = new ImageView(mContext);
                    imageView.setScaleType(ImageView.ScaleType.FIT_XY);
                    // + "!thumb"  縮圖
                    Glide.with(mContext).load(bannerModel.getImgurl()).into(imageView);
                    bannerviewsList.add(imageView);
                }
            }
        }
        //新增小圓點的圖片
        if (bannerModelList != null) {
            imageViews = new ImageView[bannerModelListSize];
            for (int i = 0; i < bannerviewsList.size(); i++) {
                imageView = new ImageView(mContext);
                //設定小圓點imageview的引數
                LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(20, 20);
                layoutParams.setMargins(10, 0, 10, 0);
//            imageView.setLayoutParams(new ViewGroup.LayoutParams(20,20));//建立一個寬高均為20 的佈局
                imageView.setLayoutParams(layoutParams);//建立一個寬高均為20 的佈局
                imageView.setPadding(20, 0, 20, 0);
                //預設選中的是第一張圖片,此時第一個小圓點是選中狀態,其他不是
                if (i == 0) {
                    imageView.setBackgroundResource(R.drawable.shape_intro);
                } else {
                    imageView.setBackgroundResource(R.drawable.shape_intro_nor);
                }
                //將imageviews新增到小圓點檢視組
                layout_page.addView(imageView);
                imageViews[i] = imageView;

            }
            bannerViewPagerAdapter = new BannerViewPagerAdapter(bannerviewsList);
            viewpager_banner.setAdapter(bannerViewPagerAdapter);
            viewpager_banner.addOnPageChangeListener(new GuidePageChangeListener());
//            viewpager_banner.setOnPageChangeListener(new GuidePageChangeListener());
        }
    }複製程式碼

繼承PagerAdapter去顯示banner輪播中的照片

//照片輪播的介面卡
    private class BannerViewPagerAdapter extends PagerAdapter {
        private List<View> views;

        private BannerViewPagerAdapter(List<View> views) {
            this.views = views;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView(views.get(position));
        }

        @Override
        public void finishUpdate(ViewGroup container) {
        }

        @Override
        public int getCount() {
            if (views != null) {
                return views.size();
            }
            return 0;
        }

        @Override
        public Object instantiateItem(ViewGroup container, final int position) {
            container.addView(views.get(position));

            //單獨的點選事件
            views.get(position).setOnClickListener(new View.OnClickListener() {
                public void onClick(View view) {
                   //todo這裡後面將點選進行介面回撥返回
                }
            });

            return views.get(position);
        }

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

    }複製程式碼

addOnPageChangeListener()實現左右切換,實現OnPageChangeListener,來回切換,照片顯示改變,小圓點的選中與未選中也跟著改變

//viewpager 監聽   照片輪播
    private class GuidePageChangeListener implements ViewPager.OnPageChangeListener {

        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {

        }

        @Override
        public void onPageSelected(int position) {
            for (int i = 0; i < imageViews.length; i++) {
                //設定index 防止下次自動播放順序出錯
                index = viewpager_banner.getCurrentItem();
                imageViews[position].setBackgroundResource(R.drawable.shape_intro);
                //不是當前選中的page,其小圓點設定為未選中的狀態
                if (position != i) {
                    imageViews[i].setBackgroundResource(R.drawable.shape_intro_nor);
                }
            }

        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    }複製程式碼

無限迴圈輪播

實際專案中的banner輪播是無限迴圈輪播的,這裡我們使用Handler來達到預期的效果

  //自動播放
    private final int AUTO_MSG = 1;
    private final int HANDLE_MSG = AUTO_MSG + 1;
    private static final int PHOTO_CHANGE_TIME = 2000;//定時變數
    private int index = 0;


  //照片輪播設定無限迴圈播放
    private Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case AUTO_MSG:
                    //無線迴圈播放
                    if (index >= bannerModelListSize) {
                        index = 0;
                    }
                    viewpager_banner.setCurrentItem(index++);//收到訊息後設定當前要顯示的圖片
                    mHandler.sendEmptyMessageDelayed(AUTO_MSG, PHOTO_CHANGE_TIME);
                    break;
                case HANDLE_MSG:
                    mHandler.sendEmptyMessageDelayed(AUTO_MSG, PHOTO_CHANGE_TIME);
                    break;
                default:
                    break;
            }
        }
    };複製程式碼

方法寫完了,什麼去觸發了,我這裡是在設定資料後呼叫,呼叫方法如下

//設定自動播放
        mHandler.sendEmptyMessageDelayed(AUTO_MSG, PHOTO_CHANGE_TIME);複製程式碼

重新整理方法

實際專案中banner輪播是要有重新整理方法的,其實重新整理方法和設定資料方法類似

 /**
     * 重新整理的方法
     *
     * @param mbannerModelList
     */
    public void refreshBannerModelList(List<BannerModel> mbannerModelList) {
        this.bannerModelList = mbannerModelList;
        if (bannerModelList.size() > 0) {
            bannerModelListSize = bannerModelList.size();

            //重新整理時上一次的資料要進行清除
            if (bannerviewsList != null) {
                bannerviewsList.clear();
            } else {
                bannerviewsList = new ArrayList<View>();
            }

            for (BannerModel bannerModel : bannerModelList) {

                ImageView imageView = new ImageView(mContext);
                imageView.setScaleType(ImageView.ScaleType.FIT_XY);
                Glide.with(mContext).load(bannerModel.getImgurl()).into(imageView);

                bannerviewsList.add(imageView);

            }
        }

        //新增小圓點的圖片
        if (bannerModelList != null) {

            //照片輪播下方的小圓點重新整理時需要重新載入  並將上次的進行remove
            if (layout_page != null) {
                layout_page.removeAllViews();
            }
            //小圓點顯示的個數就是照片輪播的實體個數
            imageViews = new ImageView[bannerModelListSize];
            for (int i = 0; i < bannerviewsList.size(); i++) {
                imageView = new ImageView(mContext);
                //設定小圓點imageview的引數
                LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(20, 20);
                layoutParams.setMargins(10, 0, 10, 0);
//            imageView.setLayoutParams(new ViewGroup.LayoutParams(20,20));//建立一個寬高均為20 的佈局
                imageView.setLayoutParams(layoutParams);//建立一個寬高均為20 的佈局
                imageView.setPadding(20, 0, 20, 0);
                //預設選中的是第一張圖片,此時第一個小圓點是選中狀態,其他不是
                if (i == 0) {
                    imageView.setBackgroundResource(R.drawable.shape_intro);
                } else {
                    imageView.setBackgroundResource(R.drawable.shape_intro_nor);
                }
                //將imageviews新增到小圓點檢視組
                layout_page.addView(imageView);
                imageViews[i] = imageView;

            }

            bannerViewPagerAdapter = new BannerViewPagerAdapter(bannerviewsList);
            viewpager_banner.setAdapter(bannerViewPagerAdapter);
            viewpager_banner.addOnPageChangeListener(new GuidePageChangeListener());
//            viewpager_banner.setOnPageChangeListener(new GuidePageChangeListener());

        }
    }複製程式碼

點選事件回撥

我們將點選事件後的結果進行回撥,採用介面,設定相關監聽方法,在使用中直接拿到資料進行跳轉

    private OnSelectItemClickstener onSelectItemClickstener;

    /***
     * bannerview點選監聽方法
     * @param onSelectItemClickstener
     */
    public void setsetSelectItemClickstener(OnSelectItemClickstener onSelectItemClickstener) {
        this.onSelectItemClickstener = onSelectItemClickstener;
    }

    /**
     * 接受回撥引數
     */
    interface OnSelectItemClickstener {
        void onSelectItem(int position, BannerModel bannerModel);
    }複製程式碼

介面準備好了,在什麼時候去呼叫了,當然是在banner點選的時候去呼叫呀,上面註釋todo的地方去將介面進行回撥

 //單獨的點選事件
            views.get(position).setOnClickListener(new View.OnClickListener() {
                public void onClick(View view) {
                    if (onSelectItemClickstener != null) {
                        BannerModel bannerModel = bannerModelList.get(position);
                        onSelectItemClickstener.onSelectItem(position, bannerModel);
                    }
                }
            });複製程式碼

程式碼中使用

xml佈局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.bannerview.MainActivity">

    <com.bannerview.BannerView
        android:id="@+id/bannerView"
        android:layout_width="match_parent"
        android:layout_height="200dp" />

    <Button
        android:id="@+id/btn"
        android:text="重新整理"
        android:layout_width="368dp"
        android:layout_height="wrap_content" />

</LinearLayout>複製程式碼

java程式碼中使用,第一次設定資料,模擬重新整理資料,點選事件跳轉模擬

        btn = (Button) findViewById(R.id.btn);
        bannerView = (BannerView) findViewById(R.id.bannerView);

        final List<BannerModel> bannerModelList = new ArrayList<>();
        bannerModelList.add(new BannerModel(1, "http://bmob-cdn-10899.b0.upaiyun.com/2017/05/09/1add12e3407aa2ac80899838f5e5a097.jpg"));
        bannerModelList.add(new BannerModel(2, "http://bmob-cdn-10899.b0.upaiyun.com/2017/05/09/34b6d85c406894f3803d949a78c4546e.jpg"));
        bannerModelList.add(new BannerModel(3, "http://bmob-cdn-10899.b0.upaiyun.com/2017/05/09/1664c954400bf4d880fdd4d70b31ff2c.jpg"));
        //第一次設定資料
        bannerView.setBannerModelList(bannerModelList);
        //模擬執行重新整理
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                bannerView.refreshBannerModelList(bannerModelList);
            }
        });
        /**
         * 點選事件的資料回撥
         * 實際專案中根據資料挑戰到相應的介面
         */
        bannerView.setsetSelectItemClickstener(new BannerView.OnSelectItemClickstener() {
            @Override
            public void onSelectItem(int position, BannerModel bannerModel) {
                Toast.makeText(MainActivity.this, "第"+position +"個"+ bannerModel.toString(), Toast.LENGTH_SHORT).show();
            }
        });複製程式碼

BannerView github demo地址

個人部落格

相關文章