书到用时方恨少,技术到讲时才发现自己是真的会了、还是只是代码的搬运工。
现在APP首页上会有很多使用图片轮播的功能。同时,在包含底部菜单的情况使用图片轮播既是对手机内存的考验,也是对技术的一次摸底。
好了,废话不多说。
现在关于图片轮播,
网上的大多数方案是Thread+Handler 睡眠模式,那今天我们来了解的是一个定义好了通用方式下的单线程池+Handler模式
其中图片的加载我们使用的是Fresco ,当然你也可以试用一下Picasso或Glide
接下来,我们直接上代码
/** * 广告轮播 Created by zaric on 2016/5/17. */ public class Advert { private ScheduledExecutorService mScheduledExecutorService; private AdvertRunnable mAdvertRunnable; private int mPicNum = 0; private int mSize = 0; private ViewPager mViewPager; private Context mCtx; private ArrayList<SimpleDraweeView> mAdList; private ArrayList<String> mAdUrlList; private ArrayList<Integer> mAdLocalList; private ViewGroup mDotVg; private AdvertHandler mAdvertHandler; private boolean isStart = false; private boolean isLocal = false; /** * 装点点的ImageView数组 */ private ImageView[] mTips; public Advert(BaseActivity baseActivity) { this.mCtx = baseActivity; mViewPager = (ViewPager) baseActivity.findViewById(R.id.advertVp); mDotVg = (ViewGroup) baseActivity.findViewById(R.id.dotVg); mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { mAdvertHandler.setTipsSelected(position); } @Override public void onPageScrollStateChanged(int state) { } }); } public Advert(View view) { this.mCtx = view.getContext(); mViewPager = (ViewPager) view.findViewById(R.id.advertVp); mDotVg = (ViewGroup) view.findViewById(R.id.dotVg); mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { mAdvertHandler.setTipsSelected(position); } @Override public void onPageScrollStateChanged(int state) { } }); } private void init() { mAdList = new ArrayList<>(); if (mAdUrlList != null && mAdUrlList.size() > 0) { mSize = mAdUrlList.size(); for (int i = 0; i < mSize; i++) { String path = mAdUrlList.get(i); if (TextUtils.isEmpty(path)) { return; } SimpleDraweeView simpleDraweeView = new SimpleDraweeView(mCtx); simpleDraweeView.setScaleType(ImageView.ScaleType.FIT_XY); Uri uri = Uri.parse(path); simpleDraweeView.setImageURI(uri); mAdList.add(simpleDraweeView); } } else { if (mAdLocalList != null && mAdLocalList.size() > 0) { mSize = mAdLocalList.size(); for (int i = 0; i < mSize; i++) { int resId = mAdLocalList.get(i); if (resId <= 0) { return; } SimpleDraweeView simpleDraweeView = new SimpleDraweeView(mCtx); simpleDraweeView.setScaleType(ImageView.ScaleType.FIT_XY); simpleDraweeView.setBackgroundResource(resId); mAdList.add(simpleDraweeView); } } } initTips(); mScheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); mAdvertRunnable = new AdvertRunnable(); mAdvertHandler = new AdvertHandler(mViewPager, mTips); AdvertAdapter advertAdapter = new AdvertAdapter(mAdList); mViewPager.setAdapter(advertAdapter); mViewPager.setCurrentItem(0); } /** * 初始化 */ public void initNet(ArrayList<String> adUrlList) { isLocal = false; mAdUrlList = adUrlList; init(); } /** * 开始广告播放 */ public void startPlay() { // initialDelay 每隔多少秒执行一次 // period 周期 isStart = true; mScheduledExecutorService.scheduleAtFixedRate(mAdvertRunnable, 1, isLocal ? mAdLocalList .size() : mAdUrlList.size(), TimeUnit.SECONDS); } /** * 按秒循环执行本地图片广告 */ public void initLocal(ArrayList<Integer> adLocalList) { isLocal = true; mAdLocalList = adLocalList; init(); } public boolean isStart() { return isStart; } /** * 停止广告轮播 */ public void stopPlay() { if (mScheduledExecutorService != null) { isStart = false; mScheduledExecutorService.shutdownNow(); } } public void destroy() { if (mAdList != null) { mAdList.clear(); } if (mTips != null) { mTips = null; } if (mAdUrlList != null) { mAdUrlList.clear(); } } /** * 图片轮播热点 */ private void initTips() { //将点点加入到ViewGroup中 mTips = null; mDotVg.removeAllViews(); mTips = new ImageView[mSize]; for (int i = 0, length = mTips.length; i < length; i++) { ImageView imageView = new ImageView(mCtx); imageView.setLayoutParams(new ViewGroup.LayoutParams(20, 20)); mTips[i] = imageView; if (i == 0) { mTips[i].setImageResource(R.drawable.dot_selected); } else { mTips[i].setImageResource(R.drawable.dot_unselected); } LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(new ViewGroup .LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); layoutParams.leftMargin = 10; layoutParams.rightMargin = 10; mDotVg.addView(imageView, layoutParams); } }private class AdvertRunnable implements Runnable { @Override public void run() { mPicNum = (mPicNum + 1) % mSize; Message msg = mAdvertHandler.obtainMessage(); msg.arg1 = mPicNum; msg.sendToTarget(); } } private static class AdvertHandler extends Handler { private WeakReference<ViewPager> mWeakVp; private WeakReference<ImageView[]> mWeakIv; public AdvertHandler(ViewPager viewPager, ImageView[] tips) { mWeakVp = new WeakReference<>(viewPager); mWeakIv = new WeakReference<>(tips); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg == null) { return; } ViewPager mVp = mWeakVp.get(); if (mVp == null) { return; } int picNum = msg.arg1; mVp.setCurrentItem(picNum); setTipsSelected(picNum); } /** * 设置选中的tip的背景 * * @param selectItems 选中项 */ public void setTipsSelected(int selectItems) { ImageView[] mTips = mWeakIv.get(); if (mTips == null) { return; } for (int i = 0, length = mTips.length; i < length; i++) { if (i == selectItems) { mTips[i].setImageResource(R.drawable.dot_selected); } else { mTips[i].setImageResource(R.drawable.dot_unselected); } } } } }
/** * 广告轮播适配器 * Created by zaric on 2016/5/17. */ public class AdvertAdapter extends PagerAdapter { private ArrayList<SimpleDraweeView> mList; public AdvertAdapter(ArrayList<SimpleDraweeView> mList){ this.mList=mList; } @Override public int getCount() { return mList!=null&&mList.size()>0?mList.size():0; } @Override public boolean isViewFromObject(View view, Object object) { return view.equals(object); } @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(mList.get(position)); return mList.get(position); } @Override public void destroyItem(ViewGroup container, int position, Object object) { try { container.removeView(mList.get(position)); } catch (IndexOutOfBoundsException e) { e.printStackTrace(); } } /** * 修改ViewPager自带缓存的BUG */ private int mChildCount = 0; @Override public void notifyDataSetChanged() { mChildCount = getCount(); super.notifyDataSetChanged(); } @Override public int getItemPosition(Object object) { if ( mChildCount > 0) { mChildCount --; return POSITION_NONE; } return super.getItemPosition(object); } }
下面是使用到的布局
<?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="wrap_content" > <android.support.v4.view.ViewPager android:id="@+id/advertVp" android:layout_width="match_parent" android:layout_height="130dp" android:fadingEdge="none" /> <LinearLayout android:id="@+id/dotVg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@+id/advertVp" android:layout_centerHorizontal="true" android:layout_marginBottom="5dp" android:gravity="center_vertical" android:orientation="horizontal"/> </RelativeLayout>
那么接下来,我们就来来看看如何使用吧
首先,在需要广告轮播的布局页面中,添加
<include layout="@layout/layout_advert"/>
对应页面的代码中,Fragment 下
private Advert advert; private ArrayList<Integer> localImg ;
localImg = new ArrayList<>(); localImg.add(R.drawable.bg_splash); localImg.add(R.drawable.bg_splash); localImg.add(R.drawable.bg_splash); advert = new Advert(getView()); advert.initLocal(localImg); advert.startPlay();
好了,到此结束了,至于原理和思想的话,欢迎大家一起讨论