如何打造一个简单,强大的自动轮播图控件

GitHub地址:https://github.com/xuerui1993/AutoViewPager

自动轮播图是安卓开发常用控件,如果在需要开发时,每个地方去写,这样就比较耗时、费力,不妨可以封装成一个自定义控件,在需要使用使只去设置数据就可以了,这样在后续开发中不仅省时,而且可以更好的排错。上面github地址中提供了源码,需要更详细的了解可以去阅读源码一下。

如何打造一个简单,强大的自动轮播图控件_第1张图片
1507193217(1).jpg

一、实现自定义属性

虽然这个并不难,但也是自定义控件常用的特点

  1. 首先将控件继承RelativeLayout,并在values文件夹attrs.xml文件中声明
    
        
        
        
        
        
            
            
            
        
    
  1. 读取属性
    TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.AutoViewpager);
    mDuration = ta.getInteger(R.styleable.AutoViewpager_duration, NORMAL_DURATION);
    mDotSize = ta.getDimensionPixelSize(R.styleable.AutoViewpager_dotSize, DOT_NORAML_SIZE);
    mIsAuto = ta.getBoolean(R.styleable.AutoViewpager_isAuto, true);
    mDrawable = ta.getDrawable(R.styleable.AutoViewpager_dotSrc);
    mDotPosition = ta.getInteger(R.styleable.AutoViewpager_dotPosition, 2);
    //释放资源
    ta.recycle();
  1. 在代码使用读取出来的属性
注意:在小圆点使用Drawable图片时,由于涉及到图片的selected属性,所以每一个小圆点需要使用到一个新的Drawable,所以需要使用的图片的克隆,否则一个Drawable对象如果使用selected,会引起所有的图片selected,无法实现小圆点的选中状态。
Drawable newDrawable = mDrawable.getConstantState().newDrawable();
imageView.setImageDrawable(newDrawable);

二、设置Viewpager的适配器

  1. 为了能无限轮播,将getCount()方法返回Integer的最大值

     @Override
     public int getCount() {
         if (mList != null) {
             return Integer.MAX_VALUE;
         }
         return 0;
     }
    
  2. 做出ImageLoader接口让外部去实现这个接口去加载图片,减少对第三方库的依赖

     public interface ImageLoader extends Serializable {
         void displayImage(Context context, String url, ImageView imageView);
         void clearMemoryCache();
     }
    

3.在adapter的instantiateItem方法中设置图片和图片的点击事件,为了无限轮播需要将图片的position % mList.size();

    @Override
    public Object instantiateItem(ViewGroup container, final int position) {
        final int picPosition = position % mList.size();//为了无限轮播,需要将positon % mList.size();
        ImageView imageView = new ImageView(mContext);
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        String url = mList.get(picPosition);
        if (mImageloader==null){
            throw new IllegalArgumentException("图片加载类为null,需实现ImageLoader接口并赋值");
        }
        mImageloader.displayImage(mContext,url,imageView);
        imageView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mItemClickListener != null) {
                    mItemClickListener.OnItemClickListener(picPosition);
                }
            }
        });
        container.addView(imageView);
        return imageView;
    }
注意:为了实现无限轮播效果,需要新创建ImageView对象,否则ViewpagerAdapter会抛出异常
ImageView imageView = new ImageView(mContext);

三、初始化小圆点

private void initDotContaner(List list) {
    //设置小圆点在控件中的位置
    RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mLlDot.getLayoutParams();
    switch (mDotPosition) {
        case 0:
            layoutParams.addRule(RelativeLayout.ALIGN_LEFT);
            break;
        case 1:
            layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
            break;
        case 2:
            layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
            break;
    }
    mLlDot.removeAllViews();//将控件清楚干净
    ArrayList imageList = new ArrayList<>();
    for (int i = 0; i < list.size(); i++) {
        ImageView imageView = new ImageView(getContext());
        if (mDotDrawableRes != 0) {
            //代码中设置了mDotDrawableRes则优先设置
            imageView.setImageResource(R.drawable.dot_selector);
        } else {
            if (mDrawable != null) {
                //在布局中设置了,则显示布局中的
                Drawable newDrawable = mDrawable.getConstantState().newDrawable();  
                imageView.setImageDrawable(newDrawable);//克隆小圆点并设置
            } else {
                //若都没设置则,设置默认
                imageView.setImageResource(R.drawable.dot_selector);
            }
        }
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(mDotSize, mDotSize);
        imageList.add(imageView);
        if (i != 0) {
            params.leftMargin = mDotSize;
        } else {
            //默认第一个小圆点被选中
            mCurrentDot = imageView;
            imageView.setSelected(true);
        }
        imageView.setLayoutParams(params);
        mLlDot.addView(imageView);  //添加小圆点
    }
}

四、让图片开始轮播

  1. 为了开始就能够向左滑动和向右滑动,将图片选择为Integer最大值的中间值

     //选中中间的第一个
     int middle = Integer.MAX_VALUE / 2;
     int extra = middle % mCount;
     mViewPager.setCurrentItem(middle-extra);
    
  2. 做一个定时任务,让图片开始轮播

     class SwitchPagerTask extends Handler implements Runnable {
    
         @Override
         public void run() {
             int currentItem = mViewPager.getCurrentItem();
             if (currentItem == mAdvertAdapter.getCount() - 1) {
                 mViewPager.setCurrentItem(0);
             } else {
                 mViewPager.setCurrentItem(currentItem + 1);
             }
             //在执行一次post , 循环执行
             postDelayed(this, mDuration);  //使用读取出来的轮播切换时间duration
         }
    
         /**
          * 开始切换
          */
         public void start() {
             //停掉以前的任务
             removeCallbacks(this);
             //在执行一次post , 循环执行
             postDelayed(this, START_DURATION);
         }
    
         /**
          * 停止切换
          */
         public void stop() {
             //停掉以前的任务
             removeCallbacks(this);
         }
     }
    

3.设置小圆点的被选中状态,需要设置监听viewpager的滑动状态,mViewPager.addOnPageChangeListener(this);

@Override
public void onPageSelected(int position) {
    position = position % mLabelList.size();
    if (mLabelList != null && mLabelList.size() > position) {
        mTvLabel.setText(mLabelList.get(position) + "");
    }
    mCurrentDot.setSelected(false);
    ImageView imageView = (ImageView) mLlDot.getChildAt(position);
    imageView.setSelected(true);
    mCurrentDot = imageView;
}

五、细节完善

  1. 在滑动触摸式重新即时viewpager的轮播,监听viewpager的触摸事件,mViewPager.setOnTouchListener(this);

     @Override
     public boolean onTouch(View v, MotionEvent event) {
         switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN:
                 if (mSwitchPagerTask != null) {
                     mSwitchPagerTask.stop();
                 }
                 break;
             case MotionEvent.ACTION_MOVE:
                 if (mSwitchPagerTask != null) {
                     mSwitchPagerTask.stop();
                 }
                 break;
             case MotionEvent.ACTION_UP:
                 if (mSwitchPagerTask != null) {
                     mSwitchPagerTask.start();
                 }
                 break;
         }
         return false;
     }
    
  2. 防止内存泄漏,添加AutoViewPager的Ondestroy()方法

     public void onDestory() {
         mSwitchPagerTask.stop();
         mSwitchPagerTask = null;
         mViewPager.removeOnPageChangeListener(this);
         mItemClickListener = null;
     }
    

六、如果想可以在AndroidStudio的gradle配置中添加依赖使用

这里有我写的一篇如何发布你的GitHub开源库的文章。

你可能感兴趣的:(如何打造一个简单,强大的自动轮播图控件)