循环轮播

来源:互联网 发布:任我游一机多图软件 编辑:程序博客网 时间:2024/06/06 03:37

技术细节

实现这样一个广告位组件,其技术细节主要有3点: 
1. 如何使用ViewPager 
2. 如何实现循环播放 
3. 如何实现自动播放 
下面分别介绍这三点。

如何使用ViewPager

ViewPager是support-v4提供的一个类,它主要用于实现滑屏的效果,它和Fragment是一对完美的组合,通过FragmentPagerAdapter,ViewPager能够轻松地管理多个Fragment。对于本例来说,由于不需要使用Fragment,所以我们要用到ViewPager的另一个更加通用的Adapter:PagerAdapter。PagerAdapter是FragmentPagerAdapter的父类,其提供了更加一般的功能接口,当然这也意味着PagerAdapter使用起来稍微复杂些。

一般来说,使用PagerAdapter最少需要实现如下四个方法: 
1. int getCount() 
表示ViewPager的屏幕个数 
2. boolean isViewFromObject(View view, Object o) 
表示key:o和value:view是否属于同一个键值对,即o对应的值是否是view 
3. Object instantiateItem(ViewGroup Container, int position) 
初始化位置为position的屏幕的界面,返回值为键值对的key,而真正的View是key所对应的value。这个概念有点抽象,一般情况下我们采用View作为key,即key和value都是同一个View对象,在这个方法中,我们需要将View加载出来并作为返回值返回。考虑到ViewPager和AdapterView的使用场景的差异,本文中并没有采用View的复用机制,这是因为ViewPager不像AdapterView那样具有大量的内容,而且ViewPager的PagerAdapter在设计时就没有暴露出复用的接口,同时广告位组件中一般都是由图片组成,布局比较简单,因此每次都重新加载布局所带来的开销是可以接受的。 
4. void destroyItem(ViewGroup container, int position, Object object) 
当位置为position的屏幕不再使用时,销毁它,典型的行为是将此屏幕的View对象从container中remove掉。

对于本文的例子来说,对这4个方法的实现如下所示:

        @Override        public int getCount() {            return FAKE_BANNER_SIZE;        }        @Override        public boolean isViewFromObject(View view, Object o) {            return view == o;        }        @Override        public Object instantiateItem(ViewGroup container, int position) {            position %= DEFAULT_BANNER_SIZE;            View view = mInflater.inflate(R.layout.item, container, false);            ImageView imageView = (ImageView) view.findViewById(R.id.image);            imageView.setImageResource(mImagesSrc[position]);            final int pos = position;            view.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View v) {                    Toast.makeText(MainActivity.this, "click banner item :" + pos, Toast.LENGTH_SHORT).show();                }            });            container.addView(view);            return view;        }        @Override        public void destroyItem(ViewGroup container, int position, Object object) {            container.removeView((View) object);        }

从上面的代码可以看出,getCount返回了一个常量FAKE_BANNER_SIZE,这个常量被我定义为100,当然50、200和1000等等都可以,但是不能太大,比如Integer.MAX_VALUE,太大的数会以极大的概率导致程序ANR。然后在instantiateItem方法中如下一句话非常关键:

position %= DEFAULT_BANNER_SIZE

这句话完成了100到5的映射,即将ViewPager的屏幕下标映射为实际所需的下标,其中DEFAULT_BANNER_SIZE被定义为5,表示ViewPager真正的屏幕数量。

除此之外,为了实现从第一屏向前滑动到最后一屏的效果,还需要做如下处理:

        @Override        public void finishUpdate(ViewGroup container) {            int position = mBanner.getCurrentItem();            Log.d(TAG, "finish update before, position=" + position);            if (position == 0) {                position = DEFAULT_BANNER_SIZE;                mBanner.setCurrentItem(position, false);            } else if (position == FAKE_BANNER_SIZE - 1) {                position = DEFAULT_BANNER_SIZE - 1;                mBanner.setCurrentItem(position, false);            }            Log.d(TAG, "finish update after, position=" + position);        }

finishUpdate表示ViewPager的更新即将完成,因此在这个时候我们可以悄悄地替换一些东西,比如将屏幕0切换为屏幕5,同时为了实现无限地循环滑动,当下标达到99时,将其切换到第4屏,这样滑动就可以无限地进行下去,否则ViewPager达到第100屏时将无法再继续向后滑动。

如何实现自动播放

这个问题就稍微简单些了,比如采用Timer、Alarm甚至Handler都可以实现,思想就是以一定的时间间隔触发ViewPager的滑动即可,本文中采用轻量级的Timer来实现,理由如下:Alarm太重量级,有点大材小用的感觉,而Handler使用起来稍微复杂一点点。下面是具体的实现细节,每隔3000ms就触发一次自动播放。

   private TimerTask mTimerTask = new TimerTask() {
        @Override
        public void run() {
            if (!mIsUserTouched) {
                mBannerPosition++;
                runOnUiThread(MainActivity.this);
                Log.d(TAG, "tname:" + Thread.currentThread().getName());
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        mTimer.schedule(mTimerTask, 50003000);
    }

    @Override
    public void run() {
        mBanner.setCurrentItem(mBannerPosition);
    }
0 0
原创粉丝点击