自定义view————Banner轮播

2,999 阅读6分钟

今天给大家项目中应用很广泛的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地址

个人博客