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;
			}
		}
	}
}

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

 <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

  • 8
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 59
    评论
评论 59
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值