打造Android一体式轮播广告条

来源:互联网 发布:卡片战斗先导者g爱知 编辑:程序博客网 时间:2024/04/29 19:51

轮播广告条在应用中非常广泛的使用,这次在看公司一个项目时,发现多处都使用到轮播广告条的功能,看到了很多重复的代码,所以萌生了整合的想法。先来看看常见的轮播广告条的样式。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

0 0
原创粉丝点击