基于ViewFlipper实现图片浏览组件

转载请说明出处:http://blog.csdn.net/ff20081528

前段时间一个朋友问我有没有做过手机商城的广告浏览的功能,如下图:

我也看了下,基本上所有的商城也都有衣蛾这样的东西。在网上搜了下,开源的也有,网友自己写的也有。但是没有找到完全符合朋友需求的一个组件。为此也就花了点时间帮朋友写了这么一个组件,在此分享出来,希望对一些朋友有用,能省一些开发时间。

组件的功能

1,自动播放功能(带有切换动画);

2,手指滑动切换(手指效果和动画效果同步);

3,能够循环滑动和播放;

4,有图片浏览指示标;

组件的实现我在代码里面都有详细的注释,但是要看懂这个组件的源码我还是建议去看看我的上一篇文章《深入了解ViewFlipper工作机制》,要不看起来会很吃力。下面直接贴出源码  转载请说明出处:http://blog.csdn.net/ff20081528

ImageBrowsingViewFlipper.java

package org.sunday.myflipper;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.Animation;
import android.widget.ImageView;
import android.widget.ViewFlipper;

/**
 * 图片浏览类
 * @author sunday
 * 2014-1-13
 * zhengchao1937@163.com
 * qq:804935743
 */
public class ImageBrowsingViewFlipper extends ViewFlipper {
	private final static String TAG = "ImageBrowsingViewFlipper";
	
	/**
	 * VIEW滚动时的默认速度
	 */
	private final static int DEFAULT_CROLL_SPEED = 30;
	
	/**
	 * View滚动时,让线程休眠时间,目的让用户的眼睛可以看到图片滚动的效果
	 */
	private final static int SLEEP_TIME = 20;
	
	/**
	 * 图片资源
	 */
	private Drawable[] imgsDraw;
	
	private Context mContext;
	
	/**
	 * VIEW滚动时的速度,默认值为DEFAULT_CROLL_SPEED
	 */
	private int crollSpeed = DEFAULT_CROLL_SPEED;
	
	/**
	 * 记录手指按下时的X轴的坐标
	 */
	private float xDown;
	
	/**
	 * 记录手指移动的时候的X轴的坐标
	 */
	private float xMove;
	
	/**
	 * 记录手指抬起时的X轴的坐标
	 */
	private float xUp;
	
	/**
	 * ViewFlipperde的宽度
	 */
	private int vfWidth;
	
	/**
	 * 图片的数量
	 */
	private int imgsLen;
	/**
	 * 当前显示的子View
	 */
	private ImageView ivCurr;
	
	/**
	 * 下一个将要显示的子View
	 */
	private ImageView ivNext;
	
	/**
	 * 之前已经显示过的子View
	 */
	private ImageView ivLast;
	
	/**
	 * 当前子View的位置
	 */
	private int currViewPosition;
	
	/**
	 * 回调接口
	 */
	private IImageBrowsingMark mImgBrowsingMark;
	
	/**
	 * ViewFlipper子View切换时将要显示的View的进入动画
	 */
	private Animation lInAnim;
	
	/**
	 * ViewFlipper子View切换时当前显示的View的退出动画
	 */
	private Animation lOutAnim;
	
	public ImageBrowsingViewFlipper(Context context) {
		super(context);
		mContext = context;
		init();
	}
	
	public ImageBrowsingViewFlipper(Context context, AttributeSet attrs) {
		super(context, attrs);
		mContext = context;
		init();
	}
	
	/**
	 * 设置View滚动时的速度
	 * @param crollSpeed
	 */
	public void setCrollSpeed(int crollSpeed) {
		this.crollSpeed = crollSpeed;
	}

	public int getVfWidth() {
		return vfWidth;
	}
	
	public void setImgsDraw(Drawable[] imgsDraw) {
		this.imgsDraw = imgsDraw;
		initImages();
	}

	public void setVfWidth(int vfWidth) {
		this.vfWidth = vfWidth;
	}
	
	public IImageBrowsingMark getmImgBrowsingMark() {
		return mImgBrowsingMark;
	}
	
	public void setmImgBrowsingMark(IImageBrowsingMark mImgBrowsingMark) {
		this.mImgBrowsingMark = mImgBrowsingMark;
	}
	
	private void init() {
		//视图树观察者,用于获取ViewFlipper的宽度
		ViewTreeObserver vto = getViewTreeObserver();   
		//当一个视图树将要绘制时,所要调用的回调函数的接口类
		vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {   
			@Override
			public boolean onPreDraw() {
				int height = ImageBrowsingViewFlipper.this.getMeasuredHeight();   
			    int width =ImageBrowsingViewFlipper.this.getMeasuredWidth();
			    Log.e(TAG, "height = " + height + " ; width = " + width);
			    vfWidth = width;
				return true;
			}   
		});   
	}
	
	/**
	 * 初始化Image
	 */
	private void initImages() {
		imgsLen = imgsDraw.length;
		// 添加图片源
		for (int i = 0; i < imgsLen; i++) { 			
			ImageView iv = new ImageView(mContext);
			iv.setOnTouchListener(onTouchListener);
			iv.setImageDrawable(imgsDraw[i]);
			iv.setScaleType(ImageView.ScaleType.FIT_XY);
			addView(iv, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
		}
	}
	
	/**
	 * 停止滑动和动画并保存动画
	 */
	private void stopAndSaveAnimation() {
		ImageBrowsingViewFlipper.this.stopFlipping();
		if(lInAnim == null && lOutAnim == null) {
			lInAnim = ImageBrowsingViewFlipper.this.getInAnimation();
			lOutAnim = ImageBrowsingViewFlipper.this.getOutAnimation();
		}
		ImageBrowsingViewFlipper.this.setInAnimation(null);
		ImageBrowsingViewFlipper.this.setOutAnimation(null);
	}
	
	/**
	 * 开启滑动并使用动画
	 */
	private void startAndUseAnimation() {
		ImageBrowsingViewFlipper.this.startFlipping();
		ImageBrowsingViewFlipper.this.setInAnimation(lInAnim);
		ImageBrowsingViewFlipper.this.setOutAnimation(lOutAnim);
	}
	
	/**
	 * 实现OnTouchListener事件
	 */
	private OnTouchListener onTouchListener = new OnTouchListener() {
		@Override
		public boolean onTouch(View v, MotionEvent event) {
			switch (event.getAction()) {
			//手指按下时的逻辑
			case MotionEvent.ACTION_DOWN:
				Log.e(TAG, "MotionEvent.ACTION_DOWN" );
				xDown = event.getRawX();
				stopAndSaveAnimation();
				break;
			//手指移动时的逻辑
			case MotionEvent.ACTION_MOVE:
				Log.e(TAG, "ACTION_MOVE" );
				xMove = event.getRawX();
				//手指滑动的距离
				int xDistance = (int)(xMove - xDown);
				Log.e(TAG, "-----------------  xDown = " + xDown + "; xMove = " + xMove);
				//当前显示的ImageView
				ImageView ivCurr = (ImageView) ImageBrowsingViewFlipper.this.getCurrentView();
				currViewPosition = ImageBrowsingViewFlipper.this.getDisplayedChild();
				//下一个ImageView
				ImageView ivNext = getNextView(currViewPosition);
				//上一个ImageView
				ImageView ivLast = getLastView(currViewPosition);
				
				//在ViewFlipper工作机制中,某一个时间点只有当前的子View是VISIBLE状态,其他的子View都是GONE状态。
				//所以要在滑动的时候看见他们,必须将他们设置为VISIBLE状态
				ivNext.setVisibility(View.VISIBLE);
				ivLast.setVisibility(View.VISIBLE);
				//将当前的ImageView移动到这个(-xDistance, 0)位置
				ivCurr.scrollTo(-xDistance, 0);
				
				//将下一个ImageView移动到(xNext, 0)位置
				int xNext = - vfWidth - xDistance;
				Log.e(TAG, "xNext = " + xNext);
				ivNext.scrollTo(xNext, 0);
				//将上一个ImageView移动到(xLast, 0)位置
				int xLast = vfWidth - xDistance;
				Log.e(TAG, "xLast = " + xLast);
				ivLast.scrollTo(xLast, 0);
				break;
			//手指抬起时的逻辑
			case MotionEvent.ACTION_UP:
				Log.e(TAG, "ACTION_UP" );
				xUp = event.getRawX();
				//判断用户手指的意图,这块可以自己改写逻辑
				if(wantToNext()) {
					Log.e(TAG, "wantToNext-------------");
					new ScrollToNextTask().execute(crollSpeed);
				} else if(wantToLast()) {
					Log.e(TAG, "wantToLast-------------");
					new ScrollToLastTask().execute(crollSpeed);
				} else {
					new ScrollToLastTask().execute(crollSpeed);
				}
				break;
			default:
				break;
			}
			return true;
		}
	};
	
	/**
	 *  判断当前手势的意图是不是想显示上一个子View
	 * @return 当前手势想移动到上一个则返回true,否则返回false。
	 */
	protected boolean wantToLast() {
		return xUp - xDown > 0;
	}
	
	/**
	 *  判断当前手势的意图是不是想显示下一个子View
	 * @return 当前手势想移动到下一个则返回true,否则返回false。
	 */
	protected boolean wantToNext() {
		return xUp - xDown < 0;
	}
	
	/**
	 * 得到上一个子视图的ImageView对象
	 * @param currViewPosition 当前View的位置
	 * @return 子视图对象
	 */
	private ImageView getLastView(int currViewPosition) {
		int lastViewPosition = currViewPosition - 1;
		if(currViewPosition == 0) {
			lastViewPosition = imgsLen - 1;
		}
		Log.e(TAG, "lastViewPosition = " + lastViewPosition);
		return (ImageView) this.getChildAt(lastViewPosition);
	}
	
	/**
	 * 得到下一个子视图的ImageView对象
	 * @param currViewPosition 当前View的位置
	 * @return 子视图对象
	 */
	private ImageView getNextView(int currViewPosition) {
		int nextViewPosition = currViewPosition + 1;
		if(currViewPosition == imgsLen - 1) {
			nextViewPosition = 0;
		}
		Log.e(TAG, "nextViewPosition = " + nextViewPosition);
		return (ImageView) this.getChildAt(nextViewPosition);
	}
	
	/**
	 * 意图显示下一个子View
	 * @author sunday
	 *
	 */
	class ScrollToNextTask extends AsyncTask<Integer, Integer, Integer> {
		@Override
		protected Integer doInBackground(Integer... speed) {
			ivCurr = (ImageView) ImageBrowsingViewFlipper.this.getCurrentView();
			int currViewPosition = ImageBrowsingViewFlipper.this.getDisplayedChild();
			ivNext = getNextView(currViewPosition);
			ivLast = getLastView(currViewPosition);
			
			int xDistance = Math.abs((int)(xUp - xDown));
			while (true) {
				xDistance = xDistance + speed[0];
				if(xDistance > vfWidth) {
					xDistance = vfWidth;
					break;
				}
				publishProgress(xDistance);
				sleep(SLEEP_TIME);
			}
			return xDistance;
		}
		@Override
		protected void onProgressUpdate(Integer... xDistance) {
			int xNext = - vfWidth + xDistance[0];
			Log.e(TAG, "xNext = " + xNext);
			ivCurr.scrollTo(xDistance[0], 0);
			ivNext.scrollTo(xNext, 0);
		}
		@Override
		protected void onPostExecute(Integer xDistance) {
			int xNext = - vfWidth + xDistance;
			Log.e(TAG, "xNext = " + xNext);
			ivCurr.scrollTo(xDistance, 0);
			ivNext.scrollTo(xNext, 0);
			int currPosition = displayedNextChild(currViewPosition);
			ImageBrowsingViewFlipper.this.setDisplayedChild(currPosition);
			ivNext.setVisibility(View.VISIBLE);
			if(null != mImgBrowsingMark.getMarkView())
				mImgBrowsingMark.getMarkView().setMark(currPosition);
			ivCurr.setVisibility(View.GONE);
			ivLast.setVisibility(View.GONE);
			//将当前(移动发生之前)的ImageView移动到(0,0)位置因为在滑动时它的位置被改变
			ivCurr.scrollTo(0, 0);
			//将上一个(移动发生之前)的ImageView移动到(0,0)位置
			ivLast.scrollTo(0, 0);
			startAndUseAnimation();
		}
	}
	
	/**
	 * 意图显示上一个子View
	 * @author sunday
	 *
	 */
	class ScrollToLastTask extends AsyncTask<Integer, Integer, Integer> {
		@Override
		protected Integer doInBackground(Integer... speed) {
			ivCurr = (ImageView) ImageBrowsingViewFlipper.this.getCurrentView();
			int currViewPosition = ImageBrowsingViewFlipper.this.getDisplayedChild();
			ivNext = getNextView(currViewPosition);
			ivLast = getLastView(currViewPosition);
			int xDistance = Math.abs((int)(xUp - xDown));
			while (true) {
				xDistance = xDistance + speed[0];
				if(xDistance > vfWidth) {
					xDistance = vfWidth;
					break;
				}
				publishProgress(xDistance);
				sleep(SLEEP_TIME);
			}
			return xDistance;
		}
		@Override
		protected void onProgressUpdate(Integer... xDistance) {
			int xLast = vfWidth - xDistance[0];
			Log.e(TAG, "xLast = " + xLast);
			ivCurr.scrollTo(-xDistance[0], 0);
			ivLast.scrollTo(xLast, 0);
		}
		@Override
		protected void onPostExecute(Integer xDistance) {
			int xLast = vfWidth - xDistance;
			Log.e(TAG, "xLast = " + xLast);
			ivCurr.scrollTo(-xDistance, 0);
			ivLast.scrollTo(xLast, 0);
			int currPosition = displayedLastChild(currViewPosition);
			ImageBrowsingViewFlipper.this.setDisplayedChild(currPosition);
			ivLast.setVisibility(View.VISIBLE);
			if(null != mImgBrowsingMark.getMarkView())
				mImgBrowsingMark.getMarkView().setMark(currPosition);
			ivCurr.setVisibility(View.GONE);
			ivNext.setVisibility(View.GONE);
			ivCurr.scrollTo(0, 0);
			ivNext.scrollTo(0, 0);
			startAndUseAnimation();
		}
	}
	
	/**
	 * 视图向左滑动将要显示的子视图的位置
	 * @param currViewPosition
	 * @return
	 */
	private int displayedNextChild(int currViewPosition) {
		int nextViewPosition = currViewPosition + 1;
		if(currViewPosition == imgsLen - 1) {
			nextViewPosition = 0;
		}
		return nextViewPosition;
	}
	
	/**
	 * 视图向右滑动将要显示的子视图的位置
	 * @param currViewPosition
	 * @return
	 */
	private int displayedLastChild(int currViewPosition) {
		int lastViewPosition = currViewPosition - 1;
		if(currViewPosition == 0) {
			lastViewPosition = imgsLen - 1;
		}
		return lastViewPosition;
	}
	
	/**
	 * 使当前线程睡眠指定的毫秒数。
	 * 
	 * @param millis
	 *            指定当前线程睡眠多久,以毫秒为单位
	 */
	private void sleep(long millis) {
		try {
			Thread.sleep(millis);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 *  解决Receiver not registered: android.widget.ViewFlipper问题,在android2.1,2.2上
	 */
	@Override
	protected void onDetachedFromWindow () {
		try {
			super.onDetachedFromWindow();
		}	catch (IllegalArgumentException e) {
			stopFlipping();
		}
	}
	
	/**
	 * 重写showNext()方法,用于实现图片自动切换时,图片的指示标也跟着切换
	 */
	@Override
	public void showNext() {
		super.showNext();
		if(null != mImgBrowsingMark.getMarkView())
			mImgBrowsingMark.getMarkView().setMark(getDisplayedChild());
	}
	
	/**
	 * 图片浏览指示标的回调接口
	 * @author sunday
	 *
	 */
	public interface IImageBrowsingMark {
		public MarkView getMarkView();
	}
}


 MarkView.java类

package org.sunday.myflipper;

import org.sunday.myflipper.R;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;
import android.widget.LinearLayout;
/**
 * 图片浏览指示标
 * @author sunday
 *
 */
public class MarkView extends LinearLayout {
	private ImageView[] mImageView;
	private Context context;

	public MarkView(Context context){
		super(context);
		this.context = context;
	}

	public MarkView(Context context, AttributeSet attrs) {
		super(context, attrs);
		this.context = context;
	}

	public void setMarkCount(int iCount) {
		mImageView = new ImageView[iCount];
		LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
				LayoutParams.WRAP_CONTENT);
		for (int i = 0; i < iCount; i++) {
			ImageView image = new ImageView(context);
			image.setImageResource(R.drawable.unselected_dot);
			image.setLayoutParams(p);
			mImageView[i] = image;
			image.setId(i);
			addView(image);
		}
	}

	public void setMark(int position) {
		for (int i = 0; i < mImageView.length; i++) {
			if (i == position) {
				mImageView[i].setImageResource(R.drawable.select_dot);
			} else {
				mImageView[i].setImageResource(R.drawable.unselected_dot);
			}
		}
	}

}


 

DemoActivity.java类

package org.sunday.myflipper;

import org.sunday.myflipper.ImageBrowsingViewFlipper.IImageBrowsingMark;

import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;

public class DemoActivity extends Activity implements IImageBrowsingMark  {
	
	private MarkView markView;
	private Drawable[] imgs;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		imgs = new Drawable[5];
		imgs[0] =  getResources().getDrawable(R.drawable.img1);
		imgs[1] =  getResources().getDrawable(R.drawable.img2);
		imgs[2] =  getResources().getDrawable(R.drawable.img3);
		imgs[3] =  getResources().getDrawable(R.drawable.img4);
		imgs[4] =  getResources().getDrawable(R.drawable.img5);
		
		setContentView(R.layout.demo);
		
		ImageBrowsingViewFlipper ibvf = (ImageBrowsingViewFlipper) findViewById(R.id.viewflipper);
		//设置图片浏览指示标接口
		ibvf.setmImgBrowsingMark(this);
		//设置图片
		ibvf.setImgsDraw(imgs);
		
		markView = (MarkView) findViewById(R.id.markView);
		markView.setMarkCount(imgs.length);
		//起始位置设置为0
		markView.setMark(0);
		
		// 向左滑动左侧进入的渐变效果(alpha 0.1  -> 1.0)
		Animation lInAnim = AnimationUtils.loadAnimation(this, R.anim.push_left_in);		
		// 向左滑动右侧滑出的渐变效果(alpha 1.0  -> 0.1)
		Animation lOutAnim = AnimationUtils.loadAnimation(this, R.anim.push_left_out); 	

		ibvf.setInAnimation(lInAnim);
		ibvf.setOutAnimation(lOutAnim);
		// 设置自动播放功能
		ibvf.setAutoStart(true);			
		if(ibvf.isAutoStart() && !ibvf.isFlipping()){
			ibvf.startFlipping();
		}
	}
	
	@Override
	public MarkView getMarkView() {
		return markView;
	}
}


 demo:http://download.csdn.net/detail/ff20081528/6843885

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值