做了很多的App,发现广告Banner非常的常用,在这里就总结一下我的做法,先看看一个应用的广告Banner
1. ViewPager中展示和下载图片
下面我们来实现一个类似的广告Banner,主布局界面
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="5dp" tools:context=".MyBannerActivity">
<com.example.liuwangshu.mybanner.SlideShowView android:id="@+id/sv_photo" android:layout_width="match_parent" android:layout_height="160dp" android:background="@android:color/darker_gray" />
</RelativeLayout>
在布局里引用了com.example.liuwangshu.mybanner.SlideShowView,这是自定义布局,继承FrameLayout,用来展示轮播图片和圆点。
SlideShowView构造函数为
public SlideShowView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
LayoutInflater.from(context).inflate(R.layout.layout_slideshow, this,
true);
imageViewsList = new ArrayList<ImageView>();
dotViewsList = new ArrayList<View>();
}
加载了布局文件,并且创建了两个List,分别存储图片和小圆点。
布局文件layout_slideshow.xml,里面定义了ViewPager用来显示图片,其他的用来显示圆点
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent">
<android.support.v4.view.ViewPager android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="match_parent" />
<LinearLayout android:id="@+id/dotLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="8dp" android:gravity="right" android:layout_alignParentBottom="true" android:orientation="horizontal">
<View android:id="@+id/v_dot1" android:layout_width="8dp" android:layout_height="8dp" android:background="@drawable/dot_focus" />
<View android:id="@+id/v_dot2" android:layout_width="8dp" android:layout_height="8dp" android:layout_marginLeft="5dp" android:background="@drawable/dot_blur" />
</LinearLayout>
</RelativeLayout>
这个自定义SlideShowView的核心方法为setView方法,用来接收将Activity传来imageUrls数组,初始化UI和实现轮播效果
public void setView(String[] imageUrls) {
this.imageUrls = imageUrls;
initUI(context);
if (isAutoPlay) {
startPlay();
}
}
startPlay方法我后面会讲解到,先来看看initUI方法,这个方法通过一个for循环将轮播需要的图片地址填充到imageViewsList中,将需要的小圆点填充到dotViewsList,并创建了viewPager将imageViewsList传进去展示轮播图。
private void initUI(Context context) {
if (imageUrls == null || imageUrls.length == 0)
return;
if (dotLayout != null) {
dotLayout.removeAllViews();
} else {
dotLayout = (LinearLayout) findViewById(R.id.dotLayout);
}
dotLayout.removeAllViews();
dotViewsList.clear();
imageViewsList.clear();
for (int i = 0; i < imageUrls.length; i++) {
ImageView view = new ImageView(context);
view.setTag(imageUrls[i]);
view.setScaleType(ScaleType.FIT_XY);
imageViewsList.add(view);
ImageView dotView = new ImageView(context);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.leftMargin = 4;
params.rightMargin = 4;
dotLayout.addView(dotView, params);
dotViewsList.add(dotView);
}
viewPager = (ViewPager) findViewById(R.id.viewPager);
viewPager.setFocusable(true);
viewPager.setAdapter(new PhotoAdapter(imageUrls));
viewPager.setOnPageChangeListener(new MyPageChangeListener());
}
PhotoAdapter接收需要播放的图片地址在instantiateItem方法中用volley来下载图片
private class PhotoAdapter extends PagerAdapter {
private String[] images;
private LayoutInflater inflater;
PhotoAdapter(String[] images) {
this.images = images;
}
@Override
public void destroyItem(View container, int position, Object object) {
((ViewPager) container).removeView(imageViewsList.get(position));
}
@Override
public Object instantiateItem(View container, final int position) {
if (position > imageViewsList.size() - 1
|| images.length < position + 1) {
return null;
}
ImageView imageView = imageViewsList.get(position);
if (!TextUtils.isEmpty(images[position])) {
loadImageByVolley(imageView,images[position]);
}
((ViewPager) container).addView(imageViewsList.get(position));
return imageViewsList.get(position);
}
...
}
这里之所以采用volley下载图片,因为volley是默认开启硬盘缓存的,如果我们把应用杀掉并关掉网络,重新打开引用发现我们之前下载的图片仍显示在Banner界面上,不需要重新下载。loadImageByVolley方法很简单:
private void loadImageByVolley(ImageView imageView ,String imageUrl){
RequestQueue mQueue = Volley.newRequestQueue(context);
final BitmapCache lruCache=new BitmapCache();
ImageLoader.ImageCache imageCache = new ImageLoader.ImageCache() {
@Override
public void putBitmap(String key, Bitmap value) {
lruCache.putBitmap(key, value);
}
@Override
public Bitmap getBitmap(String key) {
return lruCache.getBitmap(key);
}
};
ImageLoader imageLoader = new ImageLoader(mQueue, imageCache);
ImageLoader.ImageListener listener = ImageLoader.getImageListener(
imageView, 0,0);
imageLoader.get(imageUrl, listener);
}
2. 实现播放
我们已经将数据传给PhotoAdapter并下载图片,剩下的就是播放了让我们看看 startPlay方法
private void startPlay() {
scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.scheduleAtFixedRate(new SlideShowTask(), 1, 4,
TimeUnit.SECONDS);
}
startPlay方法创建了单线程化的线程池,并延时发送message来不断切换ViewPager的item:不清楚线程池的可以参考:android多线程(一)线程池
SlideShowTask中不断的发送message:
private class SlideShowTask implements Runnable {
@Override
public void run() {
synchronized (viewPager) {
currentItem = (currentItem + 1) % imageViewsList.size();
handler.obtainMessage().sendToTarget();
}
}
}
最后看看接收message的handler:
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
viewPager.setCurrentItem(currentItem);
}
};
看到这都明白了吧就是通过消息来不断的通知UI线程的ViewPager不断的切换显示的条目,SlideShowView.java 的源码:
package com.example.liuwangshu.mybanner;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.os.Parcelable;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.ImageRequest;
import com.android.volley.toolbox.Volley;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class SlideShowView extends FrameLayout {
private final static int IMAGE_COUNT = 5;
private final static int TIME_INTERVAL = 5;
private final static boolean isAutoPlay = true;
private String[] imageUrls;
private String[] urls;
private String[] titles;
private String[] contents;
private List<ImageView> imageViewsList;
private List<View> dotViewsList;
private ViewPager viewPager;
private int currentItem = 0;
private ScheduledExecutorService scheduledExecutorService;
private Context context;
// Handler
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
viewPager.setCurrentItem(currentItem);
}
};
private LinearLayout dotLayout;
public SlideShowView(Context context) {
this(context, null);
}
public SlideShowView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SlideShowView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
LayoutInflater.from(context).inflate(R.layout.layout_slideshow, this,
true);
imageViewsList = new ArrayList<ImageView>();
dotViewsList = new ArrayList<View>();
}
public void setView(String[] imageUrls) {
this.imageUrls = imageUrls;
initUI(context);
if (isAutoPlay) {
startPlay();
}
}
public void setUrl(String[] urls) {
this.urls = urls;
}
public void setTitles(String[] titles) {
this.titles = titles;
}
public void setContents(String[] contents) {
this.contents = contents;
}
private void startPlay() {
scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.scheduleAtFixedRate(new SlideShowTask(), 1, 4,
TimeUnit.SECONDS);
}
private void stopPlay() {
scheduledExecutorService.shutdown();
}
private void initUI(Context context) {
if (imageUrls == null || imageUrls.length == 0)
return;
if (dotLayout != null) {
dotLayout.removeAllViews();
} else {
dotLayout = (LinearLayout) findViewById(R.id.dotLayout);
}
dotLayout.removeAllViews();
dotViewsList.clear();
imageViewsList.clear();
for (int i = 0; i < imageUrls.length; i++) {
ImageView view = new ImageView(context);
view.setTag(imageUrls[i]);
view.setScaleType(ScaleType.FIT_XY);
imageViewsList.add(view);
ImageView dotView = new ImageView(context);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.leftMargin = 4;
params.rightMargin = 4;
dotLayout.addView(dotView, params);
dotViewsList.add(dotView);
}
viewPager = (ViewPager) findViewById(R.id.viewPager);
viewPager.setFocusable(true);
viewPager.setAdapter(new PhotoAdapter(imageUrls));
viewPager.setOnPageChangeListener(new MyPageChangeListener());
}
private class PhotoAdapter extends PagerAdapter {
private String[] images;
private LayoutInflater inflater;
PhotoAdapter(String[] images) {
this.images = images;
}
@Override
public void destroyItem(View container, int position, Object object) {
((ViewPager) container).removeView(imageViewsList.get(position));
}
@Override
public Object instantiateItem(View container, final int position) {
if (position > imageViewsList.size() - 1
|| images.length < position + 1) {
return null;
}
ImageView imageView = imageViewsList.get(position);
if (!TextUtils.isEmpty(images[position])) {
loadImageByVolley(imageView,images[position]);
}
((ViewPager) container).addView(imageViewsList.get(position));
return imageViewsList.get(position);
}
/** * 检查点击的轮播图是否可以跳转 * * @param position * @return */
private boolean isItemAvailable(int position) {
boolean isUrlsAvaiable = null != urls && urls.length > position;
boolean isTitiesAvaiable = null != titles && titles.length > position;
boolean isContentsAvaiable = null != contents && contents.length > position;
return isUrlsAvaiable && isTitiesAvaiable && isContentsAvaiable;
}
@Override
public int getCount() {
return imageViewsList.size();
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
@Override
public void restoreState(Parcelable arg0, ClassLoader arg1) {
}
@Override
public Parcelable saveState() {
return null;
}
@Override
public void startUpdate(View arg0) {
}
@Override
public void finishUpdate(View arg0) {
}
}
private class MyPageChangeListener implements OnPageChangeListener {
boolean isAutoPlay = false;
@Override
public void onPageScrollStateChanged(int arg0) {
switch (arg0) {
case 1:
isAutoPlay = false;
break;
case 2:
isAutoPlay = true;
break;
case 0:
if (viewPager.getCurrentItem() == viewPager.getAdapter()
.getCount() - 1 && !isAutoPlay) {
viewPager.setCurrentItem(0);
} else if (viewPager.getCurrentItem() == 0 && !isAutoPlay) {
viewPager
.setCurrentItem(viewPager.getAdapter().getCount() - 1);
}
break;
}
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageSelected(int pos) {
currentItem = pos;
for (int i = 0; i < dotViewsList.size(); i++) {
if (i == pos) {
dotViewsList.get(pos)
.setBackgroundResource(R.drawable.dot_focus);
} else {
dotViewsList.get(i)
.setBackgroundResource(R.drawable.dot_blur);
}
}
}
}
private class SlideShowTask implements Runnable {
@Override
public void run() {
synchronized (viewPager) {
currentItem = (currentItem + 1) % imageViewsList.size();
handler.obtainMessage().sendToTarget();
}
}
}
private void loadImageByVolley(ImageView imageView ,String imageUrl){
RequestQueue mQueue = Volley.newRequestQueue(context);
final BitmapCache lruCache=new BitmapCache();
ImageLoader.ImageCache imageCache = new ImageLoader.ImageCache() {
@Override
public void putBitmap(String key, Bitmap value) {
lruCache.putBitmap(key, value);
}
@Override
public Bitmap getBitmap(String key) {
return lruCache.getBitmap(key);
}
};
ImageLoader imageLoader = new ImageLoader(mQueue, imageCache);
ImageLoader.ImageListener listener = ImageLoader.getImageListener(
imageView, 0,0);
imageLoader.get(imageUrl, listener);
}
private void destoryBitmaps() {
for (int i = 0; i < imageViewsList.size(); i++) {
ImageView imageView = imageViewsList.get(i);
Drawable drawable = imageView.getDrawable();
if (drawable != null) {
drawable.setCallback(null);
}
}
}
}
源码下载