Android自己定义控件之应用程序首页轮播图
如今基本上大多数的Android应用程序的首页都有轮播图。就是像下图这种(此图为转载的一篇博文中的图。拿来直接用了):
像这种组件我相信大多数的应用程序都会使用到,本文就是自己定义一个这种组件,能够动态设置图片的张数。
以下就開始本次的自己定义之旅吧。首先看一下自己定义控件的的布局文件:
<?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" /> <span style="white-space:pre"> </span><!--此LinearLayout用来小圆点--> <LinearLayout android:id="@+id/linearlayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:gravity="center" android:orientation="horizontal" android:padding="5dp" > </LinearLayout> </RelativeLayout>布局文件看完之后,我们再来看一下自己定义控件相相应的java类吧:
详细代码例如以下:
<pre name="code" class="java">package com.gc.flashview; import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import com.gc.flashview.effect.AccordionTransformer; import com.gc.flashview.effect.CubeTransformer; import com.gc.flashview.effect.DefaultTransformer; import com.gc.flashview.effect.DepthPageTransformer; import com.gc.flashview.effect.InRightDownTransformer; import com.gc.flashview.effect.InRightUpTransformer; import com.gc.flashview.effect.RotateTransformer; import com.gc.flashview.effect.ZoomOutPageTransformer; import com.gc.flashview.listener.FlashViewListener; import android.annotation.SuppressLint; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Message; import android.os.Parcelable; import android.provider.ContactsContract.CommonDataKinds.Im; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.support.v4.view.ViewPager.PageTransformer; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.ViewParent; import android.view.animation.AccelerateInterpolator; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ImageView.ScaleType; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.Scroller; import android.widget.Toast; /** * * @author Android将军 * * */ @SuppressLint("HandlerLeak") public class FlashView extends FrameLayout{ private ImageLoaderTools imageLoaderTools; private ImageHandler mhandler = new ImageHandler(new WeakReference<FlashView>(this)); private List<String> imageUris; private List<ImageView> imageViewsList; private List<ImageView> dotViewsList; private LinearLayout mLinearLayout; private ViewPager mViewPager; private FlashViewListener mFlashViewListener;//向外提供接口 private int effect;//图片切换的动画效果 public FlashView(Context context) { this(context, null); } public FlashView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public FlashView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub //读取该自己定义控件自己定义的属性 TypedArray mTypedArray=context.obtainStyledAttributes(attrs, R.styleable.FlashView); effect=mTypedArray.getInt(R.styleable.FlashView_effect, 2); initUI(context); if (!(imageUris.size() <= 0)) { setImageUris(imageUris);// } } private void initUI(Context context) { imageViewsList = new ArrayList<ImageView>(); dotViewsList = new ArrayList<ImageView>(); imageUris = new ArrayList<String>(); imageLoaderTools = ImageLoaderTools.getInstance(context.getApplicationContext()); LayoutInflater.from(context).inflate(R.layout.layout_slideshow, this,true); mLinearLayout = (LinearLayout) findViewById(R.id.linearlayout); mViewPager = (ViewPager) findViewById(R.id.viewPager); //mFlashViewListener必须实例化 try { mFlashViewListener = (FlashViewListener) context; } catch (ClassCastException e) { throw new ClassCastException(context.toString()+ " must implement mPhotoListener"); } } public void setImageUris(List<String> imageuris) { if (imageuris.size() <= 0)// 假设得到的图片张数为0,则添加一张默认的图片 { imageUris.add("drawable://" + R.drawable.defaultflashview); } else { for (int i = 0; i < imageuris.size(); i++) { imageUris.add(imageuris.get(i)); } } LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT); lp.setMargins(5, 0, 0, 0); for (int i = 0; i < imageUris.size(); i++) { ImageView imageView = new ImageView(getContext()); imageView.setScaleType(ScaleType.FIT_XY);// X和Y方向都填满 imageLoaderTools.displayImage(imageUris.get(i), imageView); imageViewsList.add(imageView); ImageView viewDot = new ImageView(getContext()); if (i == 0) { viewDot.setBackgroundResource(R.drawable.dot_white); } else { viewDot.setBackgroundResource(R.drawable.dot_light); } viewDot.setLayoutParams(lp); dotViewsList.add(viewDot); mLinearLayout.addView(viewDot); } mViewPager.setFocusable(true); mViewPager.setAdapter(new MyPagerAdapter()); mViewPager.setOnPageChangeListener(new MyPageChangeListener()); setEffect(effect); if (imageUris.size() <= 1) { } else { // 利用反射改动自己主动轮播的动画持续时间 try { Field field = ViewPager.class.getDeclaredField("mScroller"); field.setAccessible(true); FixedSpeedScroller scroller = new FixedSpeedScroller( mViewPager.getContext(), new AccelerateInterpolator()); field.set(mViewPager, scroller); scroller.setmDuration(1000); mViewPager.setCurrentItem(100 * imageViewsList.size()); mhandler.sendEmptyMessageDelayed(ImageHandler.MSG_UPDATE_IMAGE, ImageHandler.MSG_DELAY); } catch (Exception e) { } } } /** * 切换轮播小点的显示 * * @param selectItems */ private void setImageBackground(int selectItems) { for (int i = 0; i < dotViewsList.size(); i++) { if (i == selectItems % dotViewsList.size()) { dotViewsList.get(i).setBackgroundResource(R.drawable.dot_white); } else { dotViewsList.get(i).setBackgroundResource(R.drawable.dot_light); } } } /** * * 数据适配器 * */ private class MyPagerAdapter extends PagerAdapter { @Override public void destroyItem(View container, int position, Object object) { } @Override public Object instantiateItem(View container, int position) { position = position % imageViewsList.size(); if (position < 0) { position = position + imageViewsList.size(); } final int pos=position; View view = imageViewsList.get(position); view.setTag(position); view.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub mFlashViewListener.onClick(pos); } }); ViewParent vp = view.getParent(); if (vp != null) { ViewPager pager = (ViewPager) vp; pager.removeView(view); } ((ViewPager) container).addView(view); return view; } @Override public int getCount() { if (imageUris.size() <= 1) { return 1; } else { return Integer.MAX_VALUE; } } @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; } } private class MyPageChangeListener implements OnPageChangeListener { @Override public void onPageScrollStateChanged(int arg0) { // TODO Auto-generated method stub switch (arg0) { case ViewPager.SCROLL_STATE_DRAGGING: mhandler.sendEmptyMessage(ImageHandler.MSG_KEEP_SILENT); break; case ViewPager.SCROLL_STATE_IDLE: mhandler.sendEmptyMessageDelayed(ImageHandler.MSG_UPDATE_IMAGE,ImageHandler.MSG_DELAY); break; default: break; } } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { // TODO Auto-generated method stub } @Override public void onPageSelected(int pos) { // TODO Auto-generated method stub mhandler.sendMessage(Message.obtain(mhandler,ImageHandler.MSG_PAGE_CHANGED, pos, 0)); setImageBackground(pos); } } @SuppressWarnings("unused") 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); } } } public void setEffect(int selectEffect) { switch (selectEffect) { case 0: setPageTransformer(true,new AccordionTransformer()); break; case 1: setPageTransformer(true,new CubeTransformer()); break; case 2: setPageTransformer(true,new DefaultTransformer()); break; case 3: setPageTransformer(true,new DepthPageTransformer()); break; case 4: setPageTransformer(true,new InRightDownTransformer()); break; case 5: setPageTransformer(true,new InRightUpTransformer()); break; case 6: setPageTransformer(true,new RotateTransformer()); break; case 7:setPageTransformer(true,new ZoomOutPageTransformer()); break; default: break; } } /** * 设置切换效果 * @param b * @param rotateTransformer */ public void setPageTransformer(boolean b, PageTransformer rotateTransformer) { // TODO Auto-generated method stub mViewPager.setPageTransformer(b, rotateTransformer); } /** * * FixedSpeedScroller类的源代码来源于网络。在此谢过贡献此代码的道友 * */ public class FixedSpeedScroller extends Scroller { private int mDuration = 1500; public FixedSpeedScroller(Context context) { super(context); } public FixedSpeedScroller(Context context, Interpolator interpolator) { super(context, interpolator); } @Override public void startScroll(int startX, int startY, int dx, int dy,int duration) { super.startScroll(startX, startY, dx, dy, mDuration); } @Override public void startScroll(int startX, int startY, int dx, int dy) { super.startScroll(startX, startY, dx, dy, mDuration); } public void setmDuration(int time) { mDuration = time; } public int getmDuration() { return mDuration; } } private static class ImageHandler extends Handler { 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 = 2000; private WeakReference<FlashView> weakReference; private int currentItem = 0; protected ImageHandler(WeakReference<FlashView> wk) { weakReference = wk; System.out.println("dsfdsfdsf:::" + currentItem); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); FlashView activity = weakReference.get(); if (activity == null) { return; } if (activity.mhandler.hasMessages(MSG_UPDATE_IMAGE)) { if (currentItem > 0)// 这里必须添加currentItem>0的推断,否则不能完美的自己主动轮播 { activity.mhandler.removeMessages(MSG_UPDATE_IMAGE); } } switch (msg.what) { case MSG_UPDATE_IMAGE: System.out.println("cccccc:::" + currentItem); currentItem++; activity.mViewPager.setCurrentItem(currentItem); activity.mhandler.sendEmptyMessageDelayed(MSG_UPDATE_IMAGE,MSG_DELAY); break; case MSG_KEEP_SILENT: break; case MSG_BREAK_SILENT: activity.mhandler.sendEmptyMessageDelayed(MSG_UPDATE_IMAGE,MSG_DELAY); break; case MSG_PAGE_CHANGED: currentItem = msg.arg1; break; default: break; } } } }
说过自己定义控件的布局和对应类之后。我们就要来使用它了,那么我们怎么去使用这个呢,请看以下的内容。在你的project中假设想要使用该自己定义控件,你须要把自己定义控件的布局文件复制到你的layout目录下,然后将上面的类复制到你的project里去,在你自己的布局文件里这样引用该控件。代码。例如以下:
<com.gc.flashview.FlashView android:id="@+id/flash_view" android:layout_width="match_parent" android:layout_height="300dp" android:layout_margin="10dp" app:effect="cube" />然后在对应的Activity或Fragment中这样动态设置图片:
(1)先通过findviewbyid获得该控件】
(2)调用该控件的setImageUris的方法
详细代码例如以下所看到的:
flashView=(FlashView)findViewById(R.id.flash_view); imageUrls=new ArrayList<String>(); imageUrls.add("http://www.qipaox.com/tupian/200810/20081051924582.jpg"); imageUrls.add("http://www.bz55.com/uploads1/allimg/120312/1_120312100435_8.jpg"); imageUrls.add("http://img3.iqilu.com/data/attachment/forum/201308/21/192654ai88zf6zaa60zddo.jpg"); imageUrls.add("http://img2.pconline.com.cn/pconline/0706/19/1038447_34.jpg"); // imageUrls.add("http://www.kole8.com/desktop/desk_file-11/2/2/2012/11/2012113013552959.jpg"); // imageUrls.add("http://www.237.cc/uploads/pcline/712_0_1680x1050.jpg"); // imageUrls.add("http://pic3.bbzhi.com/fengjingbizhi/gaoqingkuanpingfengguangsheyingps/show_fengjingta_281299_11.jpg"); flashView.setImageUris(imageUrls); 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,请及时反馈,以便于我更好的完好它,谢谢!
Android Studio版Demo下载地址:http://download.csdn.net/detail/gc_gongchao/9366745