转载请说明出处: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