Android 循环广告位轮播图的封装实现

描述

轮播图,也有叫Banner图,基础上大部分项目都会用到,它可以在有限的屏幕上尽可能的展示比较多的资源,刚开始的时候知道用ViewPager做,最近的项目中将其封装成一个独立View,方便复用!

实现

1. 适配器

主要是利用ViewPager,其是support-v4中的一个类,主要用于左右滑屏,因为主要是显示图片,所以直接选用PagerAdapter作为适配器(其子类FragmentPagerAdapter可以和Fragment组合使用使用页面滑动);ViewPager有左右预加载的功能,这样的实现方式,不至于滑到下一页的时候,不至于出现空白;PagerAdapter主要需要实现4个方法,用于控制图片的显示和销毁,还有控制起无限循坏的条件 :

private class MyAdapter extends PagerAdapter {

        //为了复用
        private List<ImageView> imgCache = new ArrayList<ImageView>();

        @Override
        public int getCount() {
            //无限滑动
            return Integer.MAX_VALUE;
        }

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

        @Override
        public Object instantiateItem(ViewGroup container,final int position) {

            ImageView iv;

            //获取ImageView对象
            if (imgCache.size() > 0) {
                iv = imgCache.remove(0);
            } else {
                iv = new ImageView(mContext);
            }
            iv.setScaleType(ScaleType.FIT_XY);

            iv.setOnTouchListener(new OnTouchListener() {
                private int downX = 0;
                private long downTime = 0;

                @Override
                public boolean onTouch(View v,MotionEvent event) {
                    switch (event.getAction()) {
                        case MotionEvent.ACTION_DOWN:
                            mAutoRollRunnable.stop();
                            //获取按下的x坐标
                            downX = (int) v.getX();
                            downTime = System.currentTimeMillis();
                            break;
                        case MotionEvent.ACTION_UP:
                            mAutoRollRunnable.start();
                            int moveX = (int) v.getX();
                            long moveTime = System.currentTimeMillis();
                            if (downX == moveX && (moveTime - downTime < 500)) {//点击的条件
                                //轮播图回调点击事件
                                headerViewClickListener.HeaderViewClick(position % mUrlList.size());
                            }
                            break;
                        case MotionEvent.ACTION_CANCEL://快速滑动不执行up
                            mAutoRollRunnable.start();
                            break;
                    }
                    return true;
                }
            });

            //加载图片
            Glide.with(mContext).load(mUrlList.get(position % mUrlList.size()))
                    .error(R.mipmap.ic_launcher).into(iv);

            ((ViewPager) container).addView(iv);

            return iv;
        }

        @Override
        public void destroyItem(ViewGroup container,int position,Object object) {
            if (object != null && object instanceof ImageView) {
                ImageView iv = (ImageView) object;
                ((ViewPager) container).removeView(iv);
                imgCache.add(iv);
            }
        }
    }

注意 :
(1) position % mUrlList.size(),因为getCount方法获取的是Integer.MAX_VALUE,所以这里所有的position都不是真正意义上的position;
(2) 之所以使用setOnTouchListener,没有用setOnClickListener主要是为了控制当手指触摸到轮播图上时停止轮播,过一定时间离开后继续轮播.

2. 自动轮播

每个一段时间做一个操作,有很多方式实现如Timer和TimerTask的组合,这里利用的是Handler的 boolean postDelayed(Runnable r,long delayMillis) 方法,此方法可以延时执行任务:

    private class AutoRollRunnable implements Runnable {
        // 标志
        boolean isRunning = false;

        public void start() {
            if (!isRunning) {
                isRunning = true;
                mHandler.removeCallbacks(this);
                mHandler.postDelayed(this3000);
            }
        }

        public void stop() {
            if (isRunning) {
                mHandler.removeCallbacks(this);
                isRunning = false;
            }
        }

        @Override
        public void run() {
            if (isRunning) {
                mViewPager.setCurrentItem(mViewPager.getCurrentItem() + 1);
                mHandler.postDelayed(this3000);
            }
        }
    }

    //开始轮播
    public void startRoll() {
        mAutoRollRunnable.start();
    }

    // 停止轮播
    public void stopRoll() {
        mAutoRollRunnable.stop();
    }

当页面离开时,停止轮播:

//停止轮播
@Override
protected void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    stopRoll();
}

3. 控制Banner的高度

由于手机的屏幕大小分别很多,如果直接写死肯定不好,我的做法是让Banner占整个手机屏幕高度的1/4,这样的适配能满足现在需求:

    //初始化view
    private void initView() {
        View.inflate(mContext,R.layout.view_header,this);
        mViewPager = (ViewPager) findViewById(R.id.vp);
        mDotLl = (LinearLayout) findViewById(R.id.ll_dot);

        //让banner的高度是屏幕的1/4
        ViewGroup.LayoutParams vParams = mViewPager.getLayoutParams();
        vParams.height = (int) (DisplayUtil.getMobileHeight(mContext) * 0.25);
        mViewPager.setLayoutParams(vParams);
    }

其中的view_header如下:

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

    <android.support.v4.view.ViewPager
        android:id="@+id/vp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:focusable="true"
        android:focusableInTouchMode="true" />

    <LinearLayout
        android:id="@+id/ll_dot"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|right"
        android:paddingRight="8dip"
        android:layout_marginBottom="8dip"
        android:gravity="center"
        android:orientation="horizontal" >
    </LinearLayout>

</FrameLayout>

4. 初始化Banner底部的点

这些点应该是有多少图片(图片链接),就应该有多少个点:

    //设置数据
    public void setImgUrlData(List<String> urlList) {
        this.mUrlList = urlList;
        if (mUrlList != null && !mUrlList.isEmpty()) {
            //清空数据
            dotList.clear();
            mDotLl.removeAllViews();
            ImageView dotIv;
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
            for (int i = 0; i < mUrlList.size(); i++) {
                dotIv = new ImageView(mContext);
                if (i == 0) {
                    dotIv.setBackgroundResource(R.mipmap.banner_dot_select);
                } else {
                    dotIv.setBackgroundResource(R.mipmap.banner_dot_normal);
                }
                //设置点的间距
                params.setMargins(00,DisplayUtil.dip2px(mContext,5),0);
                dotIv.setLayoutParams(params);

                //添加点到view上
                mDotLl.addView(dotIv);
                //添加到集合中,以便控制其切换
                dotList.add(dotIv);
            }
        }

        mAdapter = new MyAdapter();
        mViewPager.setAdapter(mAdapter);

        //设置viewpager初始位置,+10000就够了
        mViewPager.setCurrentItem(urlList.size() + 10000);
        startRoll();
    }

5. 用法

在上面的 setImgUrlData 方法后面, 我是直接初始化并设置了Adapter,并直接让轮播图滚动了起来,这样只需要少量的代码就可以用了,或者直接在布局文件中使用 :

        RollHeaderView rollHeaderView = new RollHeaderView(this);
        rollHeaderView.setImgUrlData(imgUrlList);
        rollHeaderView.setOnHeaderViewClickListener(new RollHeaderView.HeaderViewClickListener() {
            @Override
            public void HeaderViewClick(int position) {
                Toast.makeText(MainActivity.this"点击 : " + position,Toast.LENGTH_SHORT).show();
            }
        });

比起之前直接在Activity里面用ViewPager不知道简洁了多少倍!

6. 效果

7. 需改进

(1) 每次总是选中第一张图片和点;
(2) 可以加入文字信息说明;
(3) 不用xml,直接用代码写布局;
(4) ……

8. 源码:

点击查看源码

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值