您的位置:首页 > 移动开发 > Android开发

Android轮播循环Banner修正进度条同步图片切换

2016-08-13 14:16 411 查看
上次更新的一个Banner的轮播循环,经过测试,发现存在一定的问题,就是当用户手动切换banner图片的时候,banner的计时没有重新开始。

具体说一下问题所在,设置3s更换一张banner,如果我在2s的时候手动滑动banner,到下一张banner的图片,那么只需要1s就对当前的图片进行切换了,对于追求完美的程序员来说,是不可以忍受的,所以我查阅了多方资料,进行了修正更改。

具体分析原因的话就是因为Thread线程,当你手动的时候,这个线程并没有暂停结束,还在继续运行着,所以当用户手动滑动的话,线程还在继续,3s的时间跑完继续currentItem+1,导致问题的所在,我们现在要解决的问题就是当用户滑动的时候,要将线程暂停,然后重新计时3s,重新开始运行这个线程。

原因分析完了,最新的这部分代码,加了一个进度条来进行监控,可以让我们的进度条跟随着图片一起进行切换,图片切换,进度条走满,手动切换图片,进度条重新开始走,并且图片计时重新开始3s的计时。

废话了这么多了,上ImageHandler的代码吧:

import android.os.Handler;
import android.os.Message;
import java.lang.ref.WeakReference;

/**
* Created by Administrator on 2016/8/12 0012.
*/
public class ImageHandler extends Handler {

/**
* 请求更新显示的View
*/
protected static final int MSG_UPDATE_IMAGE = 1;
/**
* 请求暂停轮播
*/
protected static final int MSG_KEEP_SILENT = 2;
/**
* 请求恢复轮播
*/
protected static final int MSG_BREAK_SILENT = 3;
/**
* 记录最新的页号,当用户手动滑动时需要记录新页号,否则会使轮播的页面出错。
* 例如当前如果在第一页,本来准备播放的是第二页,而这时候用户滑动到了末页,
* 则应该播放的是第一页,如果继续按照原来的第二页播放,则逻辑上有问题。
*/
protected static final int MSG_PAGE_CHANGED = 4;

//轮播间隔时间
protected static final long MSG_DELAY = 6000;

//使用弱引用避免Handler泄露.这里的泛型参数可以不是Activity,也可以是Fragment等
private WeakReference<IndexActivity> weakReference;
private int currentItem = 0;

protected ImageHandler(WeakReference<IndexActivity> wk) {
weakReference = wk;
}

@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
final IndexActivity activity = weakReference.get();
if (activity == null) {
//Activity已经回收,无需再处理UI了
return;
}
//检查消息队列并移除未发送的消息,这主要是避免在复杂环境下消息出现重复等问题。
if (activity.handler.hasMessages(MSG_UPDATE_IMAGE)) {
activity.handler.removeMessages(MSG_UPDATE_IMAGE);
}
switch (msg.what) {
case MSG_UPDATE_IMAGE:
currentItem++;
activity.viewPager.setCurrentItem(currentItem);
new Thread(new Runnable() {

@Override
public void run() {

for (int i = 0; i <= 100; i++) {
if (Onn.isOff) {
activity.progressBar.setProgress(0);
i=0;
Onn.isOff = false;
continue;
}
activity.progressBar.setProgress(i);
try {
Thread.sleep(60);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

}
}).start();
//准备下次播放
activity.handler.sendEmptyMessageDelayed(MSG_UPDATE_IMAGE, MSG_DELAY);

break;
case MSG_KEEP_SILENT:
//只要不发送消息就暂停了
break;
case MSG_BREAK_SILENT:
activity.handler.sendEmptyMessageDelayed(MSG_UPDATE_IMAGE, MSG_DELAY);
break;
case MSG_PAGE_CHANGED:
//记录当前的页号,避免播放的时候页面显示不正确。
currentItem = msg.arg1;
break;
default:
break;
}
}
}

个人重点记录一下线程中的东西,其他地方的代码很好理解。以后可以参考使用。

线程中的Onn.isOff,是我们自己定义的一个全局变量。

/**
* Created by Administrator on 2016/8/12 0012.
*/
public class Onn {

public static boolean isOff = false;

}

这个全局变量是判断我们的线程状态。默认状态是false。for循环中,走的就是我们的进度条的一个动态效果。但是手动切换图片的话,我们的进度条要归零,并且从0开始重新走。这是我们的需求。实现的逻辑就是,当我们手动切换图片的时候,isOff设为true,然后将进度条归零,再将isOff设为false,continue,就继续开始走我们的进度条了。如果正常状态,没有切换,那我们就不走if,直接走我们的进度条啦。

具体的activity中的操作代码如下:

ImageHandler handler = new ImageHandler(new WeakReference<IndexActivity>(this));


LayoutInflater inflater = LayoutInflater.from(this);
ImageView view1 = (ImageView) inflater.inflate(R.layout.item_viewpager, null);
ImageView view2 = (ImageView) inflater.inflate(R.layout.item_viewpager, null);
ImageView view3 = (ImageView) inflater.inflate(R.layout.item_viewpager, null);
view1.setImageResource(R.mipmap.banner_test);
view2.setImageResource(R.mipmap.banner_test);
view3.setImageResource(R.mipmap.banner_test);
ArrayList<ImageView> views = new ArrayList<ImageView>();
views.add(view1);
views.add(view2);
views.add(view3);
viewPager.setAdapter(new ImageAdapter(views));
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

//配合Adapter的currentItem字段进行设置。
@Override
public void onPageSelected(int arg0) {
handler.sendMessage(Message.obtain(handler, ImageHandler.MSG_PAGE_CHANGED, arg0, 0));
}

@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}

//覆写该方法实现轮播效果的暂停和恢复
@Override
public void onPageScrollStateChanged(int arg0) {
switch (arg0) {
case ViewPager.SCROLL_STATE_DRAGGING:
handler.sendEmptyMessage(ImageHandler.MSG_KEEP_SILENT);
Onn.isOff = true;
break;
case ViewPager.SCROLL_STATE_IDLE:
handler.sendEmptyMessageDelayed(ImageHandler.MSG_UPDATE_IMAGE, ImageHandler.MSG_DELAY);
break;
default:
break;
}
}
});
viewPager.setCurrentItem(0);//默认在中间,使用户看不到边界
new Thread(new Runnable() {

@Override
public void run() {
for (int i = 0; i <= 100; i++) {
progressBar.setProgress(i);
try {
Thread.sleep(60);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
//开始轮播效果
handler.sendEmptyMessageDelayed(ImageHandler.MSG_UPDATE_IMAGE, ImageHandler.MSG_DELAY);

这里为什么又单独写了一个Thread线程来走我们的进度条呢,如果按照上述的操作完,你会发现,进来以后的第一张图片是没有进度条的,所以刚进到这个页面我们就需要单独跑一起这个进度条。

还有我们的ImageViewAdapter:

import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.ImageView;

import java.util.ArrayList;

/**
* Created by Administrator on 2016/8/10 0010.
*/
public class ImageAdapter extends PagerAdapter {

private ArrayList<ImageView> viewlist;

public ImageAdapter(ArrayList<ImageView> viewlist) {
this.viewlist = viewlist;
}

@Override
public int getCount() {
//设置成最大,使用户看不到边界
return Integer.MAX_VALUE;
}

@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0==arg1;
}
@Override
public void destroyItem(ViewGroup container, int position,
Object object) {
//Warning:不要在这里调用removeView
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
//对ViewPager页号求模取出View列表中要显示的项
position %= viewlist.size();
if (position<0){
position = viewlist.size()+position;
}
ImageView view = viewlist.get(position);
//如果View已经在之前添加到了一个父组件,则必须先remove,否则会抛出IllegalStateException。
ViewParent vp =view.getParent();
if (vp!=null){
ViewGroup parent = (ViewGroup)vp;
parent.removeView(view);
}
container.addView(view);
//add listeners here if necessary
return view;
}
}


这样就实现了我们的循环轮播加进度条监控的效果了。大家可以根据自己的需求进行修改,如果不需要进度条的可以自己将Thread的代码删除就可以单独的实现轮播循环的banner。我主要还是为了记录一下自己,所以加上了这个进度条的效果状态。

如果转载,请标明出处。谢谢。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: