Android自定义控件之应用程序首页轮播图

http://blog.csdn.net/android_jiangjun/article/details/39638129


现在基本上大多数的Android应用程序的首页都有轮播图,就是像下图这样的(此图为转载的一篇博文中的图,拿来直接用了):


像这样的组件我相信大多数的应用程序都会使用到,本文就是自定义一个这样的组件,可以动态设置图片的张数。下面就开始本次的自定义之旅吧,首先看一下自定义控件的的布局文件:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent" >  
  5.   
  6.     <android.support.v4.view.ViewPager  
  7.         android:id="@+id/viewPager"  
  8.         android:layout_width="match_parent"  
  9.         android:layout_height="match_parent" />  
  10. <span style="white-space:pre">    </span><!--此LinearLayout用来小圆点-->  
  11.     <LinearLayout  
  12.         android:id="@+id/linearlayout"  
  13.         android:layout_width="match_parent"  
  14.         android:layout_height="wrap_content"  
  15.         android:layout_alignParentBottom="true"  
  16.         android:gravity="center"  
  17.         android:orientation="horizontal"  
  18.         android:padding="5dp" >  
  19.     </LinearLayout>  
  20.   
  21. </RelativeLayout>  
布局文件看完之后,我们再来看一下自定义控件相对应的java类吧:
具体代码如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <pre name="code" class="java">package com.gc.flashview;  
  2.   
  3. import java.lang.ref.WeakReference;  
  4. import java.lang.reflect.Field;  
  5. import java.util.ArrayList;  
  6. import java.util.List;  
  7. import java.util.concurrent.Executors;  
  8. import java.util.concurrent.ScheduledExecutorService;  
  9. import java.util.concurrent.TimeUnit;  
  10.   
  11.   
  12.   
  13. import com.gc.flashview.effect.AccordionTransformer;  
  14. import com.gc.flashview.effect.CubeTransformer;  
  15. import com.gc.flashview.effect.DefaultTransformer;  
  16. import com.gc.flashview.effect.DepthPageTransformer;  
  17. import com.gc.flashview.effect.InRightDownTransformer;  
  18. import com.gc.flashview.effect.InRightUpTransformer;  
  19. import com.gc.flashview.effect.RotateTransformer;  
  20. import com.gc.flashview.effect.ZoomOutPageTransformer;  
  21. import com.gc.flashview.listener.FlashViewListener;  
  22.   
  23. import android.annotation.SuppressLint;  
  24. import android.content.Context;  
  25. import android.content.res.TypedArray;  
  26. import android.graphics.drawable.Drawable;  
  27. import android.os.Handler;  
  28. import android.os.Message;  
  29. import android.os.Parcelable;  
  30. import android.provider.ContactsContract.CommonDataKinds.Im;  
  31. import android.support.v4.view.PagerAdapter;  
  32. import android.support.v4.view.ViewPager;  
  33. import android.support.v4.view.ViewPager.OnPageChangeListener;  
  34. import android.support.v4.view.ViewPager.PageTransformer;  
  35. import android.util.AttributeSet;  
  36. import android.view.LayoutInflater;  
  37. import android.view.View;  
  38. import android.view.ViewParent;  
  39. import android.view.animation.AccelerateInterpolator;  
  40. import android.view.animation.Animation;  
  41. import android.view.animation.AnimationUtils;  
  42. import android.view.animation.Interpolator;  
  43. import android.widget.FrameLayout;  
  44. import android.widget.ImageView;  
  45. import android.widget.ImageView.ScaleType;  
  46. import android.widget.LinearLayout;  
  47. import android.widget.RelativeLayout;  
  48. import android.widget.Scroller;  
  49. import android.widget.Toast;  
  50.   
  51. /** 
  52.  *  
  53.  * @author Android将军 
  54.  *  
  55.  *  
  56.  */  
  57. @SuppressLint("HandlerLeak")  
  58. public class FlashView extends FrameLayout{  
  59.   
  60.     private ImageLoaderTools imageLoaderTools;  
  61.     private ImageHandler mhandler = new ImageHandler(new WeakReference<FlashView>(this));  
  62.     private List<String> imageUris;  
  63.     private List<ImageView> imageViewsList;  
  64.     private List<ImageView> dotViewsList;  
  65.     private LinearLayout mLinearLayout;  
  66.     private ViewPager mViewPager;  
  67.     private FlashViewListener mFlashViewListener;//向外提供接口  
  68.     private int effect;//图片切换的动画效果  
  69.     public FlashView(Context context)   
  70.     {  
  71.         this(context, null);  
  72.            
  73.     }  
  74.     public FlashView(Context context, AttributeSet attrs)   
  75.     {  
  76.         this(context, attrs, 0);  
  77.     }  
  78.     public FlashView(Context context, AttributeSet attrs, int defStyle)  
  79.     {  
  80.         super(context, attrs, defStyle);  
  81.         // TODO Auto-generated constructor stub  
  82.         //读取该自定义控件自定义的属性  
  83.         TypedArray mTypedArray=context.obtainStyledAttributes(attrs, R.styleable.FlashView);  
  84.         effect=mTypedArray.getInt(R.styleable.FlashView_effect, 2);  
  85.           
  86.         initUI(context);  
  87.         if (!(imageUris.size() <= 0))   
  88.         {  
  89.             setImageUris(imageUris);//  
  90.         }  
  91.   
  92.     }  
  93.     private void initUI(Context context)   
  94.     {  
  95.         imageViewsList = new ArrayList<ImageView>();  
  96.         dotViewsList = new ArrayList<ImageView>();  
  97.         imageUris = new ArrayList<String>();  
  98.         imageLoaderTools = ImageLoaderTools.getInstance(context.getApplicationContext());  
  99.         LayoutInflater.from(context).inflate(R.layout.layout_slideshow, this,true);  
  100.         mLinearLayout = (LinearLayout) findViewById(R.id.linearlayout);  
  101.         mViewPager = (ViewPager) findViewById(R.id.viewPager);  
  102.         //mFlashViewListener必须实例化  
  103.         try   
  104.         {  
  105.             mFlashViewListener = (FlashViewListener) context;  
  106.         }   
  107.         catch (ClassCastException e)   
  108.         {  
  109.                 throw new ClassCastException(context.toString()+ " must implement mPhotoListener");  
  110.         }  
  111.     }  
  112.     public void setImageUris(List<String> imageuris) {  
  113.         if (imageuris.size() <= 0)// 如果得到的图片张数为0,则增加一张默认的图片  
  114.         {  
  115.             imageUris.add("drawable://" + R.drawable.defaultflashview);  
  116.         }  
  117.         else   
  118.         {  
  119.             for (int i = 0; i < imageuris.size(); i++)   
  120.             {  
  121.                 imageUris.add(imageuris.get(i));  
  122.   
  123.             }  
  124.         }  
  125.   
  126.         LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT);  
  127.         lp.setMargins(5000);  
  128.         for (int i = 0; i < imageUris.size(); i++)   
  129.         {  
  130.             ImageView imageView = new ImageView(getContext());  
  131.             imageView.setScaleType(ScaleType.FIT_XY);// X和Y方向都填满  
  132.             imageLoaderTools.displayImage(imageUris.get(i), imageView);  
  133.             imageViewsList.add(imageView);  
  134.             ImageView viewDot = new ImageView(getContext());  
  135.             if (i == 0)   
  136.             {  
  137.                 viewDot.setBackgroundResource(R.drawable.dot_white);  
  138.             } else   
  139.             {  
  140.                 viewDot.setBackgroundResource(R.drawable.dot_light);  
  141.             }  
  142.             viewDot.setLayoutParams(lp);  
  143.             dotViewsList.add(viewDot);  
  144.             mLinearLayout.addView(viewDot);  
  145.         }  
  146.         mViewPager.setFocusable(true);  
  147.         mViewPager.setAdapter(new MyPagerAdapter());  
  148.         mViewPager.setOnPageChangeListener(new MyPageChangeListener());  
  149.         setEffect(effect);  
  150.         if (imageUris.size() <= 1)  
  151.         {  
  152.   
  153.         } else   
  154.         {  
  155.             // 利用反射修改自动轮播的动画持续时间  
  156.             try   
  157.             {  
  158.                 Field field = ViewPager.class.getDeclaredField("mScroller");  
  159.                 field.setAccessible(true);  
  160.                 FixedSpeedScroller scroller = new FixedSpeedScroller(  
  161.                         mViewPager.getContext(), new AccelerateInterpolator());  
  162.                 field.set(mViewPager, scroller);  
  163.                 scroller.setmDuration(1000);  
  164.                 mViewPager.setCurrentItem(100 * imageViewsList.size());  
  165.   
  166.                 mhandler.sendEmptyMessageDelayed(ImageHandler.MSG_UPDATE_IMAGE,  
  167.                         ImageHandler.MSG_DELAY);  
  168.             } catch (Exception e)   
  169.             {  
  170.   
  171.             }  
  172.         }  
  173.   
  174.     }  
  175.   
  176.     /** 
  177.      * 切换轮播小点的显示 
  178.      *  
  179.      * @param selectItems 
  180.      */  
  181.     private void setImageBackground(int selectItems)   
  182.     {  
  183.         for (int i = 0; i < dotViewsList.size(); i++)   
  184.         {  
  185.             if (i == selectItems % dotViewsList.size())   
  186.             {  
  187.                 dotViewsList.get(i).setBackgroundResource(R.drawable.dot_white);  
  188.             } else   
  189.             {  
  190.                 dotViewsList.get(i).setBackgroundResource(R.drawable.dot_light);  
  191.             }  
  192.         }  
  193.     }  
  194.   
  195.     /** 
  196.      *  
  197.      * 数据适配器 
  198.      *  
  199.      */  
  200.     private class MyPagerAdapter extends PagerAdapter   
  201.     {  
  202.         @Override  
  203.         public void destroyItem(View container, int position, Object object)   
  204.         {  
  205.   
  206.         }  
  207.         @Override  
  208.         public Object instantiateItem(View container,  int position)   
  209.         {  
  210.             position = position % imageViewsList.size();  
  211.               
  212.             if (position < 0)   
  213.             {  
  214.                 position = position + imageViewsList.size();  
  215.   
  216.             }  
  217.             final int pos=position;  
  218.             View view = imageViewsList.get(position);  
  219.             view.setTag(position);  
  220.             view.setOnClickListener(new OnClickListener() {  
  221.                   
  222.                 @Override  
  223.                 public void onClick(View v)   
  224.                 {  
  225.                     // TODO Auto-generated method stub  
  226.                     mFlashViewListener.onClick(pos);  
  227.                 }  
  228.             });  
  229.             ViewParent vp = view.getParent();  
  230.             if (vp != null)   
  231.             {  
  232.                 ViewPager pager = (ViewPager) vp;  
  233.                 pager.removeView(view);  
  234.             }  
  235.             ((ViewPager) container).addView(view);  
  236.             return view;  
  237.         }  
  238.   
  239.         @Override  
  240.         public int getCount() {  
  241.             if (imageUris.size() <= 1)   
  242.             {  
  243.                 return 1;  
  244.             } else {  
  245.                 return Integer.MAX_VALUE;  
  246.             }  
  247.   
  248.         }  
  249.   
  250.         @Override  
  251.         public boolean isViewFromObject(View arg0, Object arg1) {  
  252.             return arg0 == arg1;  
  253.         }  
  254.     }  
  255.     private class MyPageChangeListener implements OnPageChangeListener   
  256.     {  
  257.   
  258.         @Override  
  259.         public void onPageScrollStateChanged(int arg0)   
  260.         {  
  261.             // TODO Auto-generated method stub  
  262.   
  263.             switch (arg0)   
  264.             {  
  265.             case ViewPager.SCROLL_STATE_DRAGGING:  
  266.                 mhandler.sendEmptyMessage(ImageHandler.MSG_KEEP_SILENT);  
  267.                 break;  
  268.             case ViewPager.SCROLL_STATE_IDLE:  
  269.                 mhandler.sendEmptyMessageDelayed(ImageHandler.MSG_UPDATE_IMAGE,ImageHandler.MSG_DELAY);  
  270.                 break;  
  271.             default:  
  272.                 break;  
  273.             }  
  274.   
  275.         }  
  276.   
  277.         @Override  
  278.         public void onPageScrolled(int arg0, float arg1, int arg2) {  
  279.             // TODO Auto-generated method stub  
  280.   
  281.         }  
  282.   
  283.         @Override  
  284.         public void onPageSelected(int pos) {  
  285.             // TODO Auto-generated method stub  
  286.             mhandler.sendMessage(Message.obtain(mhandler,ImageHandler.MSG_PAGE_CHANGED, pos, 0));  
  287.             setImageBackground(pos);  
  288.   
  289.         }  
  290.   
  291.     }  
  292.   
  293.     @SuppressWarnings("unused")  
  294.     private void destoryBitmaps()   
  295.     {  
  296.         for (int i = 0; i < imageViewsList.size(); i++)   
  297.         {  
  298.             ImageView imageView = imageViewsList.get(i);  
  299.             Drawable drawable = imageView.getDrawable();  
  300.             if (drawable != null)   
  301.             {  
  302.                 drawable.setCallback(null);  
  303.             }  
  304.         }  
  305.     }  
  306.   
  307.     public void setEffect(int selectEffect)  
  308.     {  
  309.         switch (selectEffect) {  
  310.         case 0:  
  311.             setPageTransformer(true,new AccordionTransformer());  
  312.             break;  
  313.         case 1:  
  314.             setPageTransformer(true,new CubeTransformer());  
  315.             break;  
  316.         case 2:  
  317.             setPageTransformer(true,new DefaultTransformer());  
  318.             break;  
  319.         case 3:  
  320.             setPageTransformer(true,new DepthPageTransformer());  
  321.             break;  
  322.         case 4:  
  323.             setPageTransformer(true,new InRightDownTransformer());  
  324.             break;  
  325.         case 5:  
  326.             setPageTransformer(true,new InRightUpTransformer());  
  327.             break;  
  328.         case 6:  
  329.             setPageTransformer(true,new RotateTransformer());  
  330.             break;  
  331.         case 7:setPageTransformer(true,new ZoomOutPageTransformer());  
  332.               
  333.             break;  
  334.         default:  
  335.             break;  
  336.         }  
  337.     }  
  338.     /** 
  339.      * 设置切换效果 
  340.      * @param b 
  341.      * @param rotateTransformer 
  342.      */  
  343.     public void setPageTransformer(boolean b, PageTransformer rotateTransformer)  
  344.     {  
  345.         // TODO Auto-generated method stub  
  346.         mViewPager.setPageTransformer(b, rotateTransformer);  
  347.     }  
  348.   
  349.     /** 
  350.      *  
  351.      * FixedSpeedScroller类的源码来源于网络,在此谢过贡献此代码的道友 
  352.      *  
  353.      */  
  354.     public class FixedSpeedScroller extends Scroller   
  355.     {  
  356.         private int mDuration = 1500;  
  357.   
  358.         public FixedSpeedScroller(Context context)   
  359.         {  
  360.             super(context);  
  361.         }  
  362.   
  363.         public FixedSpeedScroller(Context context, Interpolator interpolator)   
  364.         {  
  365.             super(context, interpolator);  
  366.         }  
  367.   
  368.         @Override  
  369.         public void startScroll(int startX, int startY, int dx, int dy,int duration)   
  370.         {  
  371.   
  372.             super.startScroll(startX, startY, dx, dy, mDuration);  
  373.         }  
  374.   
  375.         @Override  
  376.         public void startScroll(int startX, int startY, int dx, int dy)   
  377.         {  
  378.   
  379.             super.startScroll(startX, startY, dx, dy, mDuration);  
  380.         }  
  381.   
  382.         public void setmDuration(int time)   
  383.         {  
  384.             mDuration = time;  
  385.         }  
  386.   
  387.         public int getmDuration()   
  388.         {  
  389.             return mDuration;  
  390.         }  
  391.     }  
  392.   
  393.     private static class ImageHandler extends Handler   
  394.     {  
  395.   
  396.         protected static final int MSG_UPDATE_IMAGE = 1;  
  397.   
  398.         protected static final int MSG_KEEP_SILENT = 2;  
  399.   
  400.         protected static final int MSG_BREAK_SILENT = 3;  
  401.   
  402.         protected static final int MSG_PAGE_CHANGED = 4;  
  403.   
  404.         protected static final long MSG_DELAY = 2000;  
  405.   
  406.         private WeakReference<FlashView> weakReference;  
  407.         private int currentItem = 0;  
  408.   
  409.         protected ImageHandler(WeakReference<FlashView> wk)   
  410.         {  
  411.             weakReference = wk;  
  412.             System.out.println("dsfdsfdsf:::" + currentItem);  
  413.         }  
  414.   
  415.         @Override  
  416.         public void handleMessage(Message msg)   
  417.         {  
  418.             super.handleMessage(msg);  
  419.   
  420.             FlashView activity = weakReference.get();  
  421.             if (activity == null)   
  422.             {  
  423.                 return;  
  424.             }  
  425.             if (activity.mhandler.hasMessages(MSG_UPDATE_IMAGE))  
  426.             {  
  427.                 if (currentItem > 0)// 这里必须加入currentItem>0的判断,否则不能完美的自动轮播  
  428.                 {  
  429.                     activity.mhandler.removeMessages(MSG_UPDATE_IMAGE);  
  430.                 }  
  431.             }  
  432.             switch (msg.what)  
  433.             {  
  434.             case MSG_UPDATE_IMAGE:  
  435.                 System.out.println("cccccc:::" + currentItem);  
  436.                 currentItem++;  
  437.                 activity.mViewPager.setCurrentItem(currentItem);  
  438.                 activity.mhandler.sendEmptyMessageDelayed(MSG_UPDATE_IMAGE,MSG_DELAY);  
  439.                 break;  
  440.             case MSG_KEEP_SILENT:  
  441.                 break;  
  442.             case MSG_BREAK_SILENT:  
  443.                 activity.mhandler.sendEmptyMessageDelayed(MSG_UPDATE_IMAGE,MSG_DELAY);  
  444.                 break;  
  445.             case MSG_PAGE_CHANGED:  
  446.                 currentItem = msg.arg1;  
  447.                 break;  
  448.             default:  
  449.                 break;  
  450.             }  
  451.         }  
  452.     }  
  453. }  

 
说过自定义控件的布局和相应类之后,我们就要来使用它了,那么我们怎么去使用这个呢,请看下面的内容。在你的工程中如果想要使用该自定义控件,你需要把自定义控件的布局文件拷贝到你的layout文件夹下,然后将上面的类拷贝到你的工程里去,在你自己的布局文件中这样引用该控件,代码,如下: 

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1.  <com.gc.flashview.FlashView  
  2.          android:id="@+id/flash_view"  
  3.         android:layout_width="match_parent"  
  4.         android:layout_height="300dp"  
  5.         android:layout_margin="10dp"  
  6.         app:effect="cube"          
  7.         />  
然后在相应的Activity或Fragment中这样动态设置图片:
(1)先通过findviewbyid获得该控件】

(2)调用该控件的setImageUris的方法

具体代码如下所示:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1.     flashView=(FlashView)findViewById(R.id.flash_view);  
  2.         imageUrls=new ArrayList<String>();  
  3.         imageUrls.add("http://www.qipaox.com/tupian/200810/20081051924582.jpg");  
  4.         imageUrls.add("http://www.bz55.com/uploads1/allimg/120312/1_120312100435_8.jpg");  
  5.         imageUrls.add("http://img3.iqilu.com/data/attachment/forum/201308/21/192654ai88zf6zaa60zddo.jpg");  
  6.         imageUrls.add("http://img2.pconline.com.cn/pconline/0706/19/1038447_34.jpg");  
  7. //        imageUrls.add("http://www.kole8.com/desktop/desk_file-11/2/2/2012/11/2012113013552959.jpg");  
  8. //        imageUrls.add("http://www.237.cc/uploads/pcline/712_0_1680x1050.jpg");  
  9. //        imageUrls.add("http://pic3.bbzhi.com/fengjingbizhi/gaoqingkuanpingfengguangsheyingps/show_fengjingta_281299_11.jpg");  
  10.         flashView.setImageUris(imageUrls);  
  11.         flashView.setEffect(EffectConstants.CUBE_EFFECT);//更改图片切换的动画效果  

然后在应用程序中的效果如下:



好了,该自定义控件的使用就是这样的。相信大家也应该明白了,如果有不对的地方欢迎指出,或者有不明白可以回复留言。至此代码已经讲完了,本次更新主要是附上Demo下载地址。声明:由于本demo是侧重于该自定义控件的使用,故在Demo中去除了UIL的使用。还有不知道怎么搞的,上传的动态效果图老是自动打上水印了,只能是静态效果图了,这个应该是博客系统的原因吧,昨天的博文也是这样。

Demo下载地址:http://download.csdn.net/detail/gc_gongchao/8081433

下载需下载积分1分,勿喷我,呵呵!

转载请注明出处:http://blog.csdn.net/android_jiangjun/article/details/39638129
///

2014/12/28更新,更新以下部分:

(1)修改轮播时,轮播到最后一张,回退到首张,现在已经解决此部分bug

(2)利用反射修改自动轮播时动画的持续时间。

(3)将此功能打包成一个library,地址:https://github.com/gcgongchao/flashview ,至于用法,已经在readme阐述清楚,故不在此处多加叙述。

2015/01/15 22:20更新:

程序的修复:
(1)修改当图片为0张时,程序会报错并强制退出。

(2)修改当图片为1张时,图片还会轮播的不好效果。

下次更新:
(1)对外提供点击事件的接口
(2)加入可以在XML文件中设置其动画效果的功能。

程序的地址还是在上面的github地址,如果你有github账号,如果本文对你有帮助的话,请star一下,谢谢。你们的支持,将是我持续的动力。

2015/01/18 20:14

本次更新:

(1)对外提供点击事件的接口

下次更新:

(1)增加图片切换的动画效果

由于csdn的博客限制图片大小不超过2M,所以最新的动态图,还是到这里去看吧:https://github.com/gcgongchao/flashview

2015/01/28 22:09

本次更新:
(1)增加了图片切换的动画效果,这些动画效果的代码来源于网络,感谢贡献此动画效果的作者。
下次更新:
(1)加入自己写的动画效果。
更新之后的最新项目还是在本人的github上,地址上面都已给出,如果在使用过程中有bug或者有任何意见,请及时告知。

2015/01/29 22:00

本次更新:修改对外监听的bug,即轮播控件的监听的bug。

2015/04/08 20:37
改着改着网友反馈的bug,就过了8点了,就没抢上小米了。。。。。。

本次更新:修改当图片为2张时,ViewPager会出现空白页的bug。
下载地址就是上面所说的github上的地址,如果在使用过程中,出现bug,请及时反馈,以便于我更好的完善它,谢谢!

https://github.com/gcgongchao/flashview


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值