Android-循环广告位组件

循环广告位也是一种非常常见的组件,网上有各种各样的实现,那天看了singwhatiwanna的一种实现,非常简单,然后结合之前见过的一种,稍微整理了一下。

转载请标明出处:http://blog.csdn.net/goldenfish1919/article/details/46811889

先看下使用方式:

<com.xjs.demo.view.BannerView
	android:id="@+id/bannerView"
	android:layout_width="match_parent"
	android:layout_height="150dp" 
	android:paddingLeft="10dp"
	android:paddingRight="10dp">
	<android.support.v4.view.ViewPager
		android:id="@+id/banner_viewpager"
		android:layout_width="match_parent"
		android:layout_height="match_parent" />
	<com.xjs.demo.view.DotView
		android:id="@+id/banner_dotview"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:layout_gravity="bottom|center_horizontal"
		android:layout_marginBottom="10dp"
		app:dot_number="5"
		app:dot_radius="4dp"
		app:dot_selected_color="0xffffffff"
		app:dot_span="8dp"
		app:dot_unselected_color="0x80ffffff" />
</com.xjs.demo.view.BannerView>

自定义的BannerView,内部有两个子元素,一个是ViewPager,一个是自定义的DotView,使用的时候:

BannerView banner = (BannerView) this.findViewById(R.id.bannerView);
banner.setOnBannerClickListener(new OnBannerClickListener(){
	@Override
	public void OnBannerClicked(int pos) {
		Toast.makeText(MainActivity.this, "OnBannerClickListener:" + pos,Toast.LENGTH_SHORT).show();
	}
});
int[] imagesSrc = new int[] { 
		R.mipmap.img1, 
		R.mipmap.img2,
		R.mipmap.img3, 
		R.mipmap.img4, 
		R.mipmap.img5 };
banner.update(imagesSrc);
可以给Banner添加点击事件,然后传递图片id,调用banner的update()方法就可以了。

下面重点来看下BannerView:


public class BannerView extends FrameLayout{

	private DotView mBannerDotView;
	private ViewPager mBannerViewPager;
	private BannerAdapter mBannerAdapter;
	/**当前的position*/
	private int mBannerPosition = 0;
	/**Banner点击后的回调*/
	private OnBannerClickListener mBannerClickListener;
	/**自动播放相关*/
    private Handler mHandler = new Handler();
	private Runnable task = new Runnable(){
		@Override
		public void run() {
              mBannerPosition = (mBannerPosition + 1) % mBannerAdapter.getCount();
              mBannerViewPager.setCurrentItem(mBannerPosition);
              Log.d(TAG, "tname:" + Thread.currentThread().getName());
              mHandler.postDelayed(task, 3000);
		}
	};
	
	private static final String TAG = BannerView.class.getSimpleName();
	
	public BannerView(Context context) {
		this(context, null);
	}

	public BannerView(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}
	
	public BannerView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init(context);
	}

	private void init(Context context) {
	}
	
	@Override
	protected void onFinishInflate() {
		super.onFinishInflate();
		//注意这里的潜规则
		mBannerViewPager = (ViewPager)getChildAt(0);
        mBannerDotView = (DotView)getChildAt(1);
        mBannerDotView.setDotNumber(0);
        mBannerAdapter = new BannerAdapter(getContext(), new int[0]);
        mBannerViewPager.setAdapter(mBannerAdapter);
        mBannerViewPager.setOnPageChangeListener(mBannerAdapter);
	}

	public void update(int[] imagesSrc){
		if(imagesSrc == null || imagesSrc.length <= 0){
			return;
		}
		mBannerDotView.setDotNumber(imagesSrc.length);
		mBannerDotView.setSelected(0);
		mBannerAdapter.update(imagesSrc);
        mHandler.postDelayed(task, 3000);
	}
	
	private void setIndicator(int position) {
        position %= mBannerAdapter.getSize();
        mBannerDotView.setSelected(position);
    }
	
	private int mDownX;
    private int mDownY;
    private long mDownTime;
	@Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        int action = event.getAction();
        if (action == MotionEvent.ACTION_DOWN) {
            mHandler.removeCallbacks(task);
            mDownX = (int)event.getX();
            mDownY = (int)event.getY();
            mDownTime = System.currentTimeMillis();
        } else if (action == MotionEvent.ACTION_UP) {
            if (System.currentTimeMillis() - mDownTime < 500 && Math.abs(mDownX - event.getX()) < 5 && Math.abs(mDownY - event.getY()) < 5) {
                // 接口回调
                if (mBannerClickListener != null) {
                	mBannerClickListener.OnBannerClicked(mBannerPosition%mBannerAdapter.getSize());
                }
            }
            mHandler.postDelayed(task, 3000);
        } else if(action == MotionEvent.ACTION_CANCEL){
        	 mHandler.postDelayed(task, 3000);
        } else if(action == MotionEvent.ACTION_MOVE){
        	// do nothing
        }
        return super.dispatchTouchEvent(event);
    }

	private class BannerAdapter extends PagerAdapter implements ViewPager.OnPageChangeListener {

		private Context mContext;
        private int[] mImagesSrc;
        private int mSize;
        private int mFakeSize;

        public BannerAdapter(Context context, int[] imagesSrc) {
            mContext = context;
            update(mImagesSrc);
        }

        public void update(int[] imagesSrc) {
        	if(imagesSrc == null || imagesSrc.length <= 0){
        		return;
        	}
        	this.mImagesSrc = imagesSrc;
        	this.mSize = imagesSrc.length;
            this.mFakeSize = mSize * 10;
        	notifyDataSetChanged();
		}

		@Override
        public int getCount() {
            return mFakeSize;
        }

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

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            position %= mSize;
            ImageView imageView = new ImageView(mContext);
            imageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
            imageView.setScaleType(ScaleType.CENTER_CROP);
            imageView.setImageResource(mImagesSrc[position]);
            container.addView(imageView);
            return imageView;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
        }

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

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        }

        @Override
        public void onPageSelected(int position) {
            mBannerPosition = position;
            setIndicator(position);
        }

        @Override
        public void onPageScrollStateChanged(int state) {
        }
    }
	
	public interface OnBannerClickListener{
		public void OnBannerClicked(int pos);
	}

	public void setOnBannerClickListener(OnBannerClickListener bannerClickListener) {
		this.mBannerClickListener = bannerClickListener;
	}

	@Override
	public void onDetachedFromWindow(){
		mHandler.removeCallbacksAndMessages(null);
		this.removeAllViews();
		this.mBannerClickListener = null;
		super.onDetachedFromWindow();
	}
}
然后看下DotView:

public class DotView extends LinearLayout {
	
    private int mLittleDotWidth;
    private int mDotSpan = 36;
    private float mDotRadius = 6f;
    private int mDotNumber = 5;
    
    private int mCurrent = 0;

    private int mSelectedColor = 0xFF377BEE;
    private int mUnSelectedColor = 0xFFC5CEDB;

    public DotView(Context context) {
        super(context);
    }

    public DotView(Context context, AttributeSet attrs) {
        super(context, attrs);
        //获取自定义的属性
        TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.DotView, 0, 0);
        if (arr != null) {
            if (arr.hasValue(R.styleable.DotView_dot_radius)) {
                mDotRadius = arr.getDimension(R.styleable.DotView_dot_radius, mDotRadius);
            }

            if (arr.hasValue(R.styleable.DotView_dot_span)) {
                mDotSpan = (int) arr.getDimension(R.styleable.DotView_dot_span, mDotSpan);
            }
            
            if(arr.hasValue(R.styleable.DotView_dot_number)){
            	mDotNumber = (int) arr.getInt(R.styleable.DotView_dot_number, mDotNumber);
            }

            mSelectedColor = arr.getColor(R.styleable.DotView_dot_selected_color, mSelectedColor);
            mUnSelectedColor = arr.getColor(R.styleable.DotView_dot_unselected_color, mUnSelectedColor);
            arr.recycle();
        }
        mLittleDotWidth = (int) (mDotSpan / 2 + mDotRadius * 2);
        
        //把小点画出来
        addDotViews();
    }

    public void setDotNumber(int dotNumber){
    	this.mDotNumber = dotNumber;
    	addDotViews();
    }
    
    private void addDotViews(){
        setGravity(Gravity.CENTER_HORIZONTAL);
        setOrientation(HORIZONTAL);
        removeAllViews();
        for (int i = 0; i < mDotNumber; i++) {
            LittleDot dot = new LittleDot(getContext(), i);
            if (i == 0) {
                dot.setColor(mSelectedColor);
            } else {
                dot.setColor(mUnSelectedColor);
            }
            dot.setLayoutParams(new LayoutParams((int) mLittleDotWidth, (int) mDotRadius * 2, 1));
            addView(dot);
        }
    }
    
    public final void setSelected(int index) {
        if (index >= getChildCount() || index < 0 || mCurrent == index) {
            return;
        }
        if (mCurrent < getChildCount() && mCurrent >= 0) {
            ((LittleDot) getChildAt(mCurrent)).setColor(mUnSelectedColor);
        }
        ((LittleDot) getChildAt(index)).setColor(mSelectedColor);
        mCurrent = index;
    }

    private class LittleDot extends View {

        private int mColor;
        private Paint mPaint;

        public LittleDot(Context context, int index) {
            super(context);
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
        }

        public void setColor(int color) {
            if (color == mColor){
            	return;
            }
            mColor = color;
            invalidate();
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            mPaint.setColor(mColor);
            canvas.drawCircle(mLittleDotWidth / 2, mDotRadius, mDotRadius, mPaint);
        }
    }

    public void setSelectedColor(int color) {
        if (mSelectedColor != color) {
            mSelectedColor = color;
            invalidate();
        }
    }

    public void setUnSelectedColor(int color) {
        if (mUnSelectedColor != color) {
            mSelectedColor = color;
            invalidate();
        }
    }
    
    public void setColor(int selectedColor, int unSelectedColor) {
        if (mSelectedColor != selectedColor || mUnSelectedColor != unSelectedColor) {
            mSelectedColor = selectedColor;
            mUnSelectedColor = unSelectedColor;
            invalidate();
        }
    }
}
最后是attrs_dotview.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="DotView">
        <attr name="dot_number" format="integer" />
        <attr name="dot_radius" format="dimension" />
        <attr name="dot_span" format="dimension" />
        <attr name="dot_unselected_color" format="integer" />
        <attr name="dot_selected_color" format="integer" />
    </declare-styleable>
</resources>

这个控件的优点是:使用起来非常简单,只需要把图片传递到BannerView的update方法就可以了,而且源码修改起来也非常简单。

另外,DotView的实现非常巧妙,非常值得借鉴!

我们不生产代码,我们只是代码的搬运工,感谢这些无私奉献的人:

BannerView参考:http://blog.csdn.net/singwhatiwanna/article/details/46541225

DotView参考:https://github.com/etao-open-source/cube-sdk/tree/master/core/src/in/srain/cube/views/banner

touch拦截:http://blog.csdn.net/wuseyukui/article/details/46627961

你可能感兴趣的:(Android-循环广告位组件)