Android循环广告位是很常用的一个功能,很大一部分APP中都会使用到,之前看到过网上一些,要么实现起来很复杂,要么通用性不强,于是,决心自己写一个通用性强并且简单的,以后项目中用到直接拿过来即可!
在这里我们主要会用到ViewPager,谷歌在v4包中提供了这个类,这个类可以用于做一些页面滑动的UI,比如说APP第一次安装时的滑动翻页介绍,应用的导航功能等等。
这里还用到了第三方的一个开源控件,CirclePageIndicator,我们这里主要是用于实现广告下方的小圆点。
这里我把广告位做成了一个自定义的控件,以后可以在布局中使用,然后在代码中调用即可,非常方便!
如何自定义控件,不在这次的讨论范围之内,如果对这一方面还不了解的朋友,建议先去看看Android是如何自定义控件的。
这里先上代码:
public class CarouselView extends LinearLayout{ public CarouselView(Context context) { super(context); init(context); } public CarouselView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } @SuppressLint("NewApi") public CarouselView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } @SuppressLint("NewApi") public CarouselView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(context); } private ViewPager carouselpager; private CirclePageIndicator indicator ; private ScheduledExecutorService scheduledExecutorService; private void init(Context context) { scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); LayoutInflater.from(context).inflate(R.layout.carouselview_layout, this,true); carouselpager = (ViewPager) findViewById(R.id.carouselpager); indicator = (CirclePageIndicator) findViewById(R.id.indicator); } /** * 停止切换 */ public void stopScroller() { if (scheduledExecutorService != null && !scheduledExecutorService.isShutdown()) { scheduledExecutorService.shutdownNow(); } } public void startScroller() { if (scheduledExecutorService != null && !scheduledExecutorService.isShutdown()) { scheduledExecutorService.shutdownNow(); scheduledExecutorService = null; } scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); if (!scheduledExecutorService.isShutdown()) { scheduledExecutorService.scheduleAtFixedRate( new ScrollBannerTask(), 6, 6, TimeUnit.SECONDS); } } /** 当前轮播图的索引 */ private int currentItem = 0; private IPageOnPageChangeListener listener; private List<View> viewLists = null; public void setAdapter(BasePageAdapter<View> adapter) { carouselpager.setAdapter(adapter); this.viewLists = adapter.getList(); indicator.setViewPager(carouselpager); indicator.notifyDataSetChanged(); indicator.setOnPageChangeListener(new PageChangeListener()); } private class PageChangeListener implements OnPageChangeListener { @Override public void onPageScrollStateChanged(int arg0) { if (listener != null) { listener.onPageScrollStateChanged(arg0); } } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { if (listener != null) { listener.onPageScrolled(arg0, arg1, arg2); } } @Override public void onPageSelected(int arg0) { currentItem = arg0; if (listener != null) { listener.onPageSelected(arg0); } } } public interface IPageOnPageChangeListener { public void onPageScrollStateChanged(int arg0); public void onPageScrolled(int arg0, float arg1, int arg2); public void onPageSelected(int arg0); } private class ScrollBannerTask implements Runnable { public void run() { synchronized (carouselpager) { currentItem = (currentItem + 1) % viewLists.size(); currHandler.sendEmptyMessage(25); } } } private Handler currHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case 25: carouselpager.setCurrentItem(currentItem); break; default: break; } }; };
这里先初始化一个线程调度器,用于轮询,以切换要展示的视图。
代码中对外公开了几个方法,下面逐一讲解
startScroller ()看名字即可知道,这是开始轮询的方法,在activity或者fragment中,装载完数据,调用这个方法,视图就开始轮询了。
stopScroller() 停止视图的轮询
setAdapter() 设置适配器,给广告位设置适配器,这里我们的类型是BasePageAdapter<View>,传这个参数的目的,是为了通用,不仅仅局限于图片。
接下来我们看一下在activity或者fragment中如何去使用这个类。
public class MainActivity extends Activity { @ViewInject(R.id.carouseview) private CarouselView carouseview; private ArrayList<View> viewLists = new ArrayList<View>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //装载数据 ImageView image = new ImageView(this); image.setImageResource(R.drawable.img1); ImageView image2 = new ImageView(this); image2.setImageResource(R.drawable.img2); ImageView image3 = new ImageView(this); image3.setImageResource(R.drawable.img3); viewLists.add(image); viewLists.add(image2); viewLists.add(image3); BannerAdapter adapter = new BannerAdapter(); adapter.appendToList(viewLists); carouseview.setAdapter(adapter); carouseview.startScroller(); } public class BannerAdapter extends BasePageAdapter<View> {}
这个类非常的简单,这里以图片为例,当然也可以是其他的视图,先初始化一些图片资源,然后把图片资源放到一个集合中,接着给我们的适配器装载数据,接下来给广告控件设置适配器,最后调用适配器的startScroller()方法,广告位就可以轮询了。
布局也是很简单的,我们来看一下
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/bg_dark" android:clipToPadding="false" android:fitsSystemWindows="true" android:orientation="vertical" > <com.czlong.commonview.CarouselView android:id="@+id/carouseview" android:layout_width="match_parent" android:layout_height="146dp" /> </LinearLayout>
这里,直接引用广告位空间即可,非常简单。
最后,还有适配器跟一个布局的代码,下面给出。
carouselview_layout
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="146dp" android:background="#00000000" > <android.support.v4.view.ViewPager android:id="@+id/carouselpager" android:layout_width="match_parent" android:layout_height="match_parent" android:focusable="true" /> <com.viewpagerindicator.CirclePageIndicator android:id="@+id/indicator" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:gravity="center" android:padding="10dp" app:fillColor="#FF818F" app:pageColor="#EE4854" app:radius="3dp" app:strokeColor="@color/goldenrod" app:strokeWidth="0.1dp" /> </RelativeLayout>
BasePageAdapter,这里写得比较通用,其中可能有一些这里用不到的方法,就不逐一删除了。
public abstract class BasePageAdapter<T extends View> extends PagerAdapter { private List<T> mList = new LinkedList<T>(); private List<String> titles; @Override public int getCount() { return mList == null ? 0 : mList.size(); } @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(mList.get(position), 0); return mList.get(position); } @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(mList.get(position)); } /** * 获取数据集合 * * @return */ public List<T> getList() { return mList; } /** * 追加list数据集合 默认像末端追加 * * @param list */ public void appendToList(List<T> list) { if (list == null) { return; } mList.addAll(list); notifyDataSetChanged(); } /** * 追加到头部 * * @param list */ public void appendToTopList(List<T> list) { if (list == null) { return; } appendToList(list, 0); notifyDataSetChanged(); } /** * 追加到制定位置 * * @param list * @param postion */ public void appendToList(List<T> list, int postion) { if (postion < 0 || postion > list.size()) { throw new RuntimeException("illegal postion"); } mList.addAll(postion, list); } /** * 清空数据源 */ public void clear() { mList.clear(); notifyDataSetChanged(); } /** * @return the mList */ public List<T> getmList() { return mList; } /** * @param mList * the mList to set */ public void setmList(List<T> mList) { this.mList = mList; } /** * @return the titles */ public List<String> getTitles() { return titles; } /** * @param titles * the titles to set */ public void setTitles(List<String> titles) { this.titles = titles; }
到这里,广告控件就写完了,只需几行代码就可以用起来了,需要的朋友可以拿去集成到项目中。