Android高效率实现广告图片循环播放,手把手教会你实现效果,项目中直接使用

转载请注明出处:http://blog.csdn.net/jakeyangchina/article/details/53691592

好多app上都会看到广告图片无限制的循环播放,今天带大家一步步实现自己定义的控件,项目中使用自己定义的控件那就是一个字帅

按照惯例,先看效果图:

这里写图片描述

功能介绍:

图片可以手动左右滑动,当手指抬起时图片间隔3秒时间自动播放,无缝隙循环播放

思路分析:

  1. 图片可以手动左右滑动
    这里采用ViewPager实现左右滑动,又因为当手指按下时,手动滑动,自动切换功能停止,这里采用自定义ViewPager类,把down和up事件提供给调用者,自己写个回调方法,当手指按下时通知调用者停止定时器,当手指抬起时,开启定时器,实现自动定时切换页面
  2. 松开手后图片间隔3秒时间自动切换
    这里采用定时器,当间隔3秒时执行任务,也可以使用handler(略),这里采用定时器
  3. 图片切换时对应下方圆点也对应改变
    这里是通过获取ViwePager当前显示的条目(索引)设置给对应圆点显示

步骤:

  1. 自定义类MyViewPager继承ViewPager
  2. 自定义类MyContainer继承RelativeLayout,将所有的逻辑处理等在这个类中进行,封装到这个类中
  3. 创建一个容器,存储圆点,根据页面数来创建圆点ImageView控件,再根据当前页面显示的条目指定对应圆点显示,获取到当前页面索引值是通过给ViewPager设置页面改变监听器来获取到
  4. 这里的原点采用shape通过xml绘制
  5. 在MyContainer视图显示在主MainActivity中

原理图:

这里写图片描述

具体代码实现:

自定义类MyViewPager继承ViewPager
public class MyViewPager extends ViewPager {
    public MyViewPager(Context context) {
        this(context,null);
    }

    public MyViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    public boolean onTouchEvent(MotionEvent ev) {

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:

                if(listener != null) {
                    listener.down();
                }
                break;
            case MotionEvent.ACTION_UP:

                if(listener != null) {
                    listener.up();
                }

                break;
            default:
                break;
        }


        return super.onTouchEvent(ev);
    }

    private OnTouchChangeListener listener;
    public void setTouchChangeListener(OnTouchChangeListener listener) {
        this.listener = listener;
    }

    public interface OnTouchChangeListener {
        public void down();
        public void up();
    }
}

上面代码很容易理解,这里主要是想办法获取到down和up事件
传递给外部调用,OnTouchChangeListener 是自己定义的接口提供回调方法通知调用者手指的动作

定义容器MyContainer类,继承RelativeLayout控件
/**
     * 存储圆点图片,原点的父容器
     */
    private LinearLayout linearLayout;
    /**
     * 自定义ViewPager类
     */
    private MyViewPager viewPager;
    /**
     * 适配器
     */
    private MyAdapter myAdapter;
    /**
     * 定时器
     */
    private Timer timer;
    /**
     * 定时器任务
     */
    private MyTimerTask task;
    /**
     * 原点父容器的高度
     */
    private int height = 50;
    /**
     * 设置原点的宽
     */
    private int circleWidth = 25;
    /**
     * 设置原点的高
     */
    private int circleHeight = 25;
    /**
     * 设置原点父容器的背景色
     */
    private int backgroundColor = Color.parseColor("#55aaaaaa");
    /**
     * 当前容器的高度
     */
    private int containerHeight = 300;
    /**
     * 弱引用,存储Activity,防止内存泄漏
     */
    private WeakReference<Activity> weak;
    /**
     * 集合存储外部传过来的数据
     */
    private List<ImageView> lists = new ArrayList<>();

上面定义的字段,标注很详细

public void init() {
        //设置当前容器布局大小
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
                LayoutParams.MATCH_PARENT,containerHeight);
        //给当前控件设置布局
        setLayoutParams(params);

        //创建自定义ViewPager
        viewPager = new MyViewPager(getContext());
        //设置自定义ViewPager布局大小
        RelativeLayout.LayoutParams paramsPager = new RelativeLayout.LayoutParams(
                LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
        //给自定义ViewPager添加布局
        viewPager.setLayoutParams(paramsPager);

        //创建适配器
        myAdapter = new MyAdapter();
        //设置适配器
        viewPager.setAdapter(myAdapter);
        //设置页面改变监听器
        viewPager.addOnPageChangeListener(this);
        //设置自定义的触摸监听器
        viewPager.setTouchChangeListener(this);

        //创建控件下方的视图容器,存储圆点图片,原点的父容器
        linearLayout = new LinearLayout(getContext());
        RelativeLayout.LayoutParams linearLayoutParams = new RelativeLayout.LayoutParams(
                LayoutParams.MATCH_PARENT,height);
        //设置背景颜色
        linearLayout.setBackgroundColor(backgroundColor);
        //设置子控件对齐方式
        linearLayout.setGravity(Gravity.CENTER_VERTICAL|Gravity.RIGHT);
        //设置本身在外部的对齐方式
        linearLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
        //设置布局
        linearLayout.setLayoutParams(linearLayoutParams);

        //将自定ViewPager控件添加到当前容器中
        addView(viewPager);
        //将圆点容器添加到当前容器中
        addView(linearLayout);
    }

这个方法里主要是进行初始化,创建ViewPager控件和LinearLayout容器存储圆点,需要注意的是,将这个两个容器创建完一定要添加到当前容器中,通addView方法添加当前布局

public void addImageData(List<ImageView> list, Activity activity) {
        if(weak == null) {
            //防止关闭时,引用外部对象造成内存泄漏
            weak = new WeakReference<Activity>(activity);
        }
        //添加数据时,先清空
        lists.clear();
        this.lists = list;
        //设置当前页面
        viewPager.setCurrentItem(3000*lists.size());
        myAdapter.notifyDataSetChanged();
        //添加圆点到容器中
        addImagePoint(0);
        //开启定时器
        startScrollPager();
    }

上方代码主要是外部调用设置数据,设置ViewPager当前显示的页面setCurrentItem(3000*lists.size());这里的3000*lists.size()是取页面数的整数倍,3000是随便设置的数,这样可以实现ViewPager左右循环无缝隙滑动,相当于取个中间页,左右都有页数,可以滑动,这里需要注意WeakReference弱引用,将外部传进来activity存在弱引用中,防止外部页面开始关闭了,但是activity页面对象被引用无法正常关闭页面导致内存泄漏

/**
     * 根据数据个数创建原点
     * @param curentPosition
     */
    private void addImagePoint(int curentPosition) {
        for(int i = 0; i < lists.size(); i++) {
            ImageView imageView = new ImageView(getContext());
            //设置图片控件布局,circleWidth和circleWidth指定图片大小
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                    circleWidth,circleHeight);
            //设置原点图片右边间距大小
            params.rightMargin = 15;
            if(curentPosition == i) {
                imageView.setImageResource(R.drawable.circle_a);
            }else {
                imageView.setImageResource(R.drawable.circle_b);
            }
            //设置布局
            imageView.setLayoutParams(params);
            //把原点添加到父容器中
            linearLayout.addView(imageView);
        }
    }

通过ViewPager页面数,动态创建原点,通过当前页面索引选中当前原点

/**
     * 页面改变时,同步显示的原点
     * @param position
     */
    private void changeImageState(int position) {
        for(int i = 0; i < linearLayout.getChildCount(); i++) {
            ImageView childAt = (ImageView) linearLayout.getChildAt(i);
            if(position == i) {
                childAt.setImageResource(R.drawable.circle_a);
            }else {
                childAt.setImageResource(R.drawable.circle_b);
            }
        }
    }

这个方法根据不同页面显示对应圆点,可以认为是同步原点显示

private class MyAdapter extends PagerAdapter {

        @Override
        public int getCount() {
            return Integer.MAX_VALUE;
        }

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

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            //网络请求图片在这里进行,注意防止图片错位
            ImageView imageView = lists.get(position % lists.size());
            //添加对应控件到ViewPager
            ((ViewPager)container).addView(imageView);
            return imageView;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            //从ViewPager中移除对应控件
            ((ViewPager)container).removeView((ImageView) object);
        }
    }

上方类是给ViewPager设置适配器,这里需要注意,通过instantiateItem方法给当前页面添加ImageView控件,在destroyItem方法中一定要移除对应ImageView控件,这里需要注意getCount() 方法返回最大页数,为了实现无限制页面播放,其实页面是有限制的,页面数为Integer.MAX_VALUE

    /**
     *创建定时器,方法多种,可以使用handler
     */
    private class MyTimerTask extends TimerTask {

        @Override
        public void run() {

            if(weak != null) {

                weak.get().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        //设置显示当前页面
                        viewPager.setCurrentItem(viewPager.getCurrentItem()+1);
                    }
                });
            }
        }
    }

这个类是创建定时器任务,当定时时间到了就会执行run方法,在这里设置显示下一个页面,当前页面加一

    /**
     * 开启定时器
     */
    public void startScrollPager() {
        timer = new Timer();
        task = new MyTimerTask();
        //执行定时器
        timer.schedule(task,3000,3000);
    }

    /**
     * 停止滚动
     */
    public void stopScrollPager() {
        if(timer != null) {
            timer.cancel();
            timer = null;
        }
        if(task != null) {
            task.cancel();
            task = null;
        }
    }

startScrollPager() 方法开启定时器,stopScrollPager() 关闭定时器

    @Override
    public void down() {
        //当手指按下时,取消定时器
        stopScrollPager();
    }

    @Override
    public void up() {
        //当手指抬起时,启动定时器
        startScrollPager();
    }

当手指按下时,关闭定时器,当手指抬起时,开启定时器

    /**
     * 当关闭页面时,取消定时器
     */
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        //取消定时器
        stopScrollPager();
    }

这个方法是当页面从当前窗体解除关联时会执行这个方法,在这里关闭定会器

绘制原点xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
    <corners android:radius="10dp" />
    <solid android:color="@android:color/white" />
</shape>

这里是绘制原点
这里MainActivity方法就不给列出了,详细下载Demo,代码里标注很详细

如果你觉得此文章对你有收获,那么就顶下,你的无意间的动作就是我写出好文章的动力,希望能够帮助到大家,共同进步

如果大家还有什么疑问,请在下方留言。

源码下载,请点击这里!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值