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;
}
到这里,广告控件就写完了,只需几行代码就可以用起来了,需要的朋友可以拿去集成到项目中。