• 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

  • 相关阅读:
    《面向模式的软件体系结构1模式系统》读书笔记(7) 通信
    《面向模式的软件体系结构2用于并发和网络化对象模式》读书笔记(5) 截取器
    Enum variable is used in switch sentencejava Anny
    How to create a dynamic range source(转) Anny
    Managing Range Names in Excel 2010(转) Anny
    Mixed Content Handling Issue on IE7/8 Anny
    How to resolve "skip non existing resourceDirectory" when using "mvn test" Anny
    Install chinese input method in Ubuntu12.04 Anny
    IDL(International Date Line) Anny
    Web Accessibility508(转) Anny
  • 原文地址:https://www.cnblogs.com/blfshiye/p/5207072.html
Copyright © 2020-2023  润新知