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

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-27 12:11:36

Android-循环广告位组件的相关文章

Android应用程序组件Content Provider的共享数据更新通知机制分析

在Android系统中,应用程序组件Content Provider为不同的应用程序实现数据共享提供了基础设施,它主要通过Binder进程间通信机制和匿名共享内存机制来实现的.关于数据共享的另一个 话题便是数据更新通知机制了,即如果一个应用程序对共享数据做了修改,它应该如何通知其它正在使用这些共享数据的应用程序呢?本文将分析Content Provider的共享数据更新通知机制,为读者解答这个问题. Android应用程序组件Content Provider中的数据更新通知机制和Android系

Android深入四大组件(四)广播的注册、发送和接收过程

相关文章 Android深入理解四大组件系列 前言 我们接着来学习Android四大组件中的BroadcastReceiver,广播主要就是分为注册.接收和发送过程.建议阅读此文前请先阅读Android深入理解四大组件系列的文章,知识重复的部分,本文不再赘述. 1.广播的注册过程 BroadcastReceiver的注册分为两种,分别是静态注册和动态注册,静态注册在应用安装时由PackageManagerService来完成注册过程,关于这一过程,我会在后续的介绍PackageManagerSe

Android深入四大组件(五)Content Provider的启动过程

"-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> Android深入四大组件(五)Content Provider的启动过程 - 刘望舒的专栏 - 博客频道 - CSDN.NET 刘望舒的专栏 欲为大树,莫与草争 目录视图 摘要视图 订阅 [活动]2017 CSDN博客专栏评选 &nbsp [5月书讯]流畅的Pyth

Android应用程序组件Content Provider的启动过程源代码分析

文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6963418 通过前面的学习,我们知道在Android系统中,Content Provider可以为不同的应用程序访问相同的数据提供统一的入口.Content Provider一般是运行在独立的进程中的,每一个Content Provider在系统中只有一个实例存在,其它应用程序首先要找到这个实例,然后才能访问它的数据.那么,系统中的Conten

在Android 窗口小组件(Widget)中显示(StackView,ListView,GridView)集合View

在Android 3.0 中引入了 Collection View Widget.用于在窗口小组件中添加了对集合View 的支持. 如下: (1)StackView 一个卡片View,以层叠的方式显示其子View. (2)ListView 和传统的ListView一样 (3)GridView 网格列表.具体用法和传统的一样. 第一步:创建Widget布局文件    (1)Wdiget的布局文件 路径:res/layout/my_widget_layout.xml <?xml version=&quo

Android四大基本组件(1)之Activity与BroadcastReceive广播接收器

Android四大基本组件分别是Activity,Service服务,Content Provider内容提供者,BroadcastReceiver广播接收器. 一.Activity (1)应用程序中,一个Activity通常就是一个单独的屏幕,它上面可以显示一些控件也可以监听并处理用户的事件做出响应. (2)Activity之间通过Intent进行通信.在Intent 的描述结构中,有两个最重要的部分:动作和动作对应的数据. (3)典型的动作类型有:M AIN(activity的门户).VIE

从零开始学android&lt;RatingBar评分组件.二十三.&gt;

如果现在用户要对某个应用程序打分往往会使用图所示的组件,通过选择的"五角星"的个数来决定最终的打分成绩 这样的功能在Android之中,可以使用RatingBar组件实现,使用此组件可以方便用户的输入,而且很直观,RatingBar类的定义结构如下: java.lang.Object ? android.view.View ? android.widget.ProgressBar ? android.widget.AbsSeekBar ? android.widget.RatingBa

Android四大基本组件介绍与生命周期

主要参考: 1.http://blog.csdn.net/android_tutor/article/details/5772285 2.http://www.cnblogs.com/bravestarrhu/archive/2012/05/02/2479461.html Android四大基本组件介绍与生命周期,布布扣,bubuko.com

Android开发四大组件之Service(实例篇)

关于Service的开发详解已经在上一篇:Android开发四大组件之Service(详解篇)讲的很清楚了,本篇主要对Service的开发实例做下讲解. 程序运行效果图: 程序代码: BindService: package com.jph.servicedemo; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; /**