打造Android一体式轮播广告条

轮播广告条在应用中非常广泛的使用,这次在看公司一个项目时,发现多处都使用到轮播广告条的功能,看到了很多重复的代码,所以萌生了整合的想法。先来看看常见的轮播广告条的样式。ps:标题有点吹牛逼了。嘎嘎

common

通过上面我们也可以发现,常见的轮播广告条的组成:

  • 一个ViewPager控件
  • 一个指示器控件

所以在整合的过程中,我就是将ViewPager和指示器部分封装起来了。根据上面的布局,所以我们继承RelativeLayout进行布局。所以我们定义类ViewPagerBarnner

    public class ViewPagerBarnner extends RelativeLayout implements OnPageChangeListener {
        /**
         * ViewPager对象
         */
        private ViewPager viewPager;
        /**
         * 指示器
         */
        private LinearLayout indicatorView;
        private Context context;
        /**
         * 图片url地址
         */
        private List<String> imageUrls = new ArrayList<String>();
        /**
         * 获取的ImageView对象集合
         */
        private List<ImageView> imageViews = new ArrayList<ImageView>();
        /**
         * 点击ViewPager中ImageView的回调事件
         */
        private ViewPagerClick viewPagerClick;
        /**
         * 指示器的默认大小
         */
        private float indicatorSize = 15;
        /**
         * 指示器的drawable对应的资源id
         */
        private int idBackgroud;
        /**
         * 指示器之间的距离
         */
        private float indicatorMargin = 20;

        ...
     }

上面就是我们需要的控件,我们定义了Viewpager和一个LinearLayout,其中LinearLayout用于存储我们的指示器。为了提高定制性,我们自定义了三个属性,如下:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="ViewPager">
            <attr name="containerHeight" format="dimension"/>           <!-- 容器的高度 -->
            <attr name="indicatorSize" format="dimension"/>         <!-- 指示器大小 -->
            <attr name="indicatorBackgroud" format="reference"/>    <!-- 指示器背景,可以说drawable对象 -->
            <attr name="indicatorMargin" format="dimension"/>       <!-- 指示器之间的间隔 -->
        </declare-styleable>  
    </resources>

有了自定义的属性,我们在构造函数中进行获取设定的值。这里,我们定义背景为一个reference类型,在使用的过程中我通过type

        public ViewPagerBarnner(Context context, AttributeSet attrs) {
            super(context, attrs);
            this.context = context;
            initViews();
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ViewPager);
            indicatorSize = typedArray.getDimension(R.styleable.ViewPager_indicatorSize, 10);
            indicatorMargin = typedArray.getDimension(R.styleable.ViewPager_indicatorMargin, 15);
            idBackgroud = typedArray.getResourceId(R.styleable.ViewPager_indicatorBackgroud, 0);
            containerHeight = typedArray.getDimension(R.styleable.ViewPager_containerHeight, 20);
            typedArray.recycle();
        }

        /**
         * 初始化View的视图
         */
        private void initViews(){
            viewPager = new ViewPager(context);
            LayoutParams viewPagerParams = new LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, 
                                                    RelativeLayout.LayoutParams.MATCH_PARENT);
            viewPager.setLayoutParams(viewPagerParams);
            viewPager.setAdapter(viewPagerAdapter);
            viewPager.setOnPageChangeListener(this);

            indicatorView = new LinearLayout(context);
            indicatorView.setOrientation(LinearLayout.HORIZONTAL);
            LayoutParams layoutParams = new LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,(int)containerHeight);
            layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
            layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
            indicatorView.setLayoutParams(layoutParams);
            addView(viewPager);
            addView(indicatorView);
        }

我们初始化ViewPager和LinearLayout,同时对它们进行布局。将LinearLayout放到最底部。接下来就是设置我们的监听事件以及为ViewPager设置Adapter。

        /**
         * ViewPager的适配器
         */
        private PagerAdapter viewPagerAdapter = new PagerAdapter() {

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

            @Override
            public int getCount() {
                return imageUrls == null ? 0 : imageUrls.size();
            }

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

            @Override
            public void finishUpdate(ViewGroup container) {
            }

            @Override
            public int getItemPosition(Object object) {
                return super.getItemPosition(object);
            }

            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                ImageView imageView = null;
                if(imageViews != null && imageViews.size() > 0){
                    imageView = imageViews.get(position);
                    imageView.setOnClickListener(new OnClickListener() {

                        @Override
                        public void onClick(View view) {
                            if(viewPagerClick != null){
                                viewPagerClick.viewPagerOnClick(view);
                            }
                        }
                    });
                }
                container.addView(imageView);
                return imageView;
            }
        };

        @Override
        public void onPageScrollStateChanged(int arg0) {
        }

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

        @Override
        public void onPageSelected(int location) {
            setSelectPage(location);
        }

至此,整体的框架已经完成,然后就是我们为Adapter赋予数据。具体处理如下:

        /**
         * 从url地址创建imageview对象,同时初始化指示器
         */
        private void createImageView(List<String> imageUrlList){
            if(imageUrlList != null && imageUrlList.size() > 0){
                ImageView imageView;
                View pointView;
                for(String url : imageUrlList){
                    imageView = new ImageView(context);
                    imageView.setScaleType(ScaleType.FIT_XY);
                    ImageLoader.getInstance().displayImage(url, imageView);
                    imageView.setTag(url);
                    imageViews.add(imageView);

                    pointView = new View(context);
                    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams((int)(indicatorSize),(int)(indicatorSize));
                    params.rightMargin = (int)indicatorMargin;
                    pointView.setLayoutParams(params);
                    pointView.setBackgroundDrawable(context.getResources().getDrawable(idBackgroud));
                    pointView.setEnabled(false);
                    indicatorView.addView(pointView);
                }
                setSelectPage(0);
            }
        }

        /**
         * 设置当前选中页面
         * @param position
         */
        private void setSelectPage(int position){
            for(int index=0; index < indicatorView.getChildCount();index++){
                if(position == index){
                    indicatorView.getChildAt(index).setEnabled(true);
                }else{
                    indicatorView.getChildAt(index).setEnabled(false);
                }
            }
        }

        /**
         * 设置图片的地址,从网络加载图片
         * @param imageUrls
         */
        public void addImageUrls(List<String> imageUrls) {
            this.imageUrls.addAll(imageUrls);
            createImageView(imageUrls);
            viewPagerAdapter.notifyDataSetChanged();
        }

至此,就完成了基本的广告条展示功能。我们看下MainActivity和布局中的使用。

        <com.lcwang.androidviews.ViewPagerBarnner
            android:id="@+id/viewPager"
            android:layout_height="160dp"
            android:layout_width="match_parent"
            viewpager:indicatorSize="8dp"
            viewpager:indicatorMargin="10dp"
            viewpager:indicatorBackgroud="@drawable/indicator_backgroud"
            />


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ViewPagerBarnner viewPagerBarnner = (ViewPagerBarnner) findViewById(R.id.viewPager);
        List<String> url = new ArrayList<String>();
        url.add("http://pic1.nipic.com/2008-12-25/2008122510134038_2.jpg");
        url.add("http://pic3.nipic.com/20090525/2416945_231841034_2.jpg");
        url.add("http://img3.3lian.com/2013/s1/20/d/57.jpg");
        url.add("http://pic1.nipic.com/2008-11-13/2008111384358912_2.jpg");
        url.add("http://img.61gequ.com/allimg/2011-4/201142614314278502.jpg");
        viewPagerBarnner.addImageUrls(url);
        viewPagerBarnner.setViewPagerClick(new ViewPagerClick() {

            @Override
            public void viewPagerOnClick(View view) {
                Toast.makeText(MainActivity.this, view.getTag().toString(), Toast.LENGTH_SHORT).show();
            }
        });
    }

我们自定义指示器的样式:

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android" >
        <item android:state_enabled="true">
            <shape android:shape="oval">
                <size android:width="3dp" android:height="3dp"/>
                <solid android:color="#00FF00"/>
            </shape>
        </item>
        <item android:state_enabled="false">
            <shape android:shape="oval">
                <size android:width="3dp" android:height="3dp"/>
                <solid android:color="#FFFFFF"/>
            </shape>
        </item>
    </selector>

first

通过上面的效果图,我们发现基本的效果已经有了,但是还没有实现无限循环以及自动播放的功能。所以接下来我们就是实现无限循环和自动播放的功能。网上流行的两种实现方法,我们先看一种,我画了一个草图:

fliper

为了方便我们增加头尾,我将存放url和imageview的集合改为LinkedList。

    private LinkedList<String> imageUrls = new LinkedList<String>();
    private LinkedList<ImageView> imageViews = new LinkedList<ImageView>();

主要的判断处理就是增加头尾处,这里说一点,在为ImageView的集合增加首尾的时候,为什么重新获取而不是利用集合中已经存在的,这是因为如果我们将该对象进行利用后,持有该对象的引用,然后在切换时,报该ImageView已经有父容器了。(这是我理解的)

    @Override
    public void onPageSelected(int location) {
        if(location == this.imageUrls.size() -1){
            location = 1;
            viewPager.setCurrentItem(location,false);
        }else if(location == 0){
            location = this.imageUrls.size() -2;
            viewPager.setCurrentItem(location,false);
        }
        currentPostion = location;
        setSelectPage(location - 1);
    }


    /** 
     * 从url地址创建imageview对象,同时初始化指示器
     */
    private void createImageView(List<String> imageUrlList){
        if(imageUrlList != null && imageUrlList.size() > 0){
            ImageView imageView;
            View pointView;
            //清除头尾
            if(imageViews.size() > 1){
                imageViews.removeFirst();
                imageViews.removeLast();
            }
            for(String url : imageUrlList){
                imageView = new ImageView(context);
                imageView.setScaleType(ScaleType.FIT_XY);
                ImageLoader.getInstance().displayImage(url, imageView);
                imageView.setTag(url);
                imageViews.add(imageView);

                pointView = new View(context);
                LinearLayout.LayoutParams params = new LinearLayout.LayoutParams((int)(indicatorSize),(int)(indicatorSize));
                params.rightMargin = (int)indicatorMargin;
                pointView.setLayoutParams(params);
                pointView.setBackgroundDrawable(context.getResources().getDrawable(idBackgroud));
                pointView.setEnabled(false);
                indicatorView.addView(pointView);
            }
            //增加头尾
            if(imageViews.size() > 1){
                ImageView ivFirst = new ImageView(context);
                ImageView ivLast = new ImageView(context);
                ImageLoader.getInstance().displayImage(imageUrls.getLast(),ivLast);
                ImageLoader.getInstance().displayImage(imageUrls.getFirst(),ivFirst);
                imageViews.addFirst(ivFirst);
                imageViews.addLast(ivLast);
            }
            viewPagerAdapter.notifyDataSetChanged();
            viewPager.setCurrentItem(1);
        }
    }

    /**
     * 设置当前选中页面
     * @param position
     */
    private void setSelectPage(int position){
        for(int index=0; index < indicatorView.getChildCount();index++){
            if(position == index){
                indicatorView.getChildAt(index).setEnabled(true);
            }else{
                indicatorView.getChildAt(index).setEnabled(false);
            }
        }
    }

    /**
     * 设置图片的地址,从网络加载图片
     * @param imageUrls
     */
    public void addImageUrls(List<String> imageUrls) {
        if(this.imageUrls.size() > 1){//清除头尾
            this.imageUrls.removeFirst();
            this.imageUrls.removeLast();
        }
        this.imageUrls.addAll(imageUrls);
        if(this.imageUrls.size() >1){//增加头尾
            String first = this.imageUrls.getFirst();
            this.imageUrls.addFirst(this.imageUrls.getLast());
            this.imageUrls.addLast(first);
        }
        createImageView(imageUrls);
    }

这样就可以实现了ViewPager的循环,同时我们可以通过addImageUrls方法进行新增页。实现了循环,就开始自动播放,自动播放的实现无外乎几种:

  • 1、定时器:Timer
  • 2、开子线程 while true 循环
  • 3、ColckManager
  • 4、 用handler 发送延时信息,实现循环

我们通过Handler进行实现。

    private Handler mHandler = new Handler(){

        @Override
        public void handleMessage(Message msg) {
            viewPager.setCurrentItem(currentPostion + 1);
            mHandler.sendEmptyMessageDelayed(0, 3000);
        }
    };

    /**
     * 初始化View的视图
     */
    private void initViews(){
        ...
        mHandler.sendEmptyMessageDelayed(0, 3000);
    }

这样就完成了一个组合的ViewPager开发。来瞄一眼效果:

second

至此,这个控件就完成了,可以很方便使用,在也不用去搞很多逻辑判断了。这里面加载网络图片使用的ImageLoader库,需要添加,或者改源码自己修改。

源码下载地址

github

下篇地址:http://blog.csdn.net/Mr_dsw/article/details/50429396

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值