通过自定义ListView实现动画特效,被点击元素A向前移,A之前元素往后移动.
重点在于动画的实现:
具体代码如下:
package com.open.widget;import java.util.ArrayList;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.PaintFlagsDrawFilter;import android.graphics.PorterDuff;import android.graphics.PorterDuffXfermode;import android.graphics.Rect;import android.os.Handler;import android.util.AttributeSet;import android.util.Log;import android.view.GestureDetector;import android.view.GestureDetector.SimpleOnGestureListener;import android.view.MotionEvent;import android.view.View;/** * * @author yanglonghui * */public class HorImageListView extends View { private int current_OffsetX=0;//当前屏X轴的偏移量 private int cuurent_OffsetY=0;//当前屏Y轴的偏移量 private int moving_OffsetX=0;//当前S手势X轴偏移量 private int moving_OffsetY=0;//当前S手势Y轴偏移量 private int current_Page=1;//当前页码,开始页码为1 private int portraitNumberPerScreen;//每屏头像个数 private int charHeight=0;//一个字的高度 private int maxPage=1;//最大页码 private int current_foucsIndex=0;//当前焦点 private int current_longPressIndex=-1;//当前长按焦点 private int current_clickIndex=0;//当前点击 private int headWidth=0;//头像宽度 private int paddingLeft;//左边距 private Bitmap []bitmapArray;//头像数组 private Rect headRectArray[]=null;//头像位置 private Rect drawingRect=new Rect(); private Bitmap mCircleBitmap=null; private PorterDuffXfermode xfermode=new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY); private PaintFlagsDrawFilter pdf=new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG); private Paint paint = new Paint(); { paint.setStyle(Paint.Style.STROKE); paint.setFlags(Paint.ANTI_ALIAS_FLAG); paint.setAntiAlias(true);// 设置画笔的锯齿效果。 true是去除,大家一看效果就明白了 } private static final int LAYER_FLAGS = Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG; private IHeadClick headClickListener; private Handler mHandler=new Handler(); private ArrayListheadList=new ArrayList (); public HorImageListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public HorImageListView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public HorImageListView(Context context) { super(context); init(); } private void init() { try { if(android.os.Build.VERSION.SDK_INT>=11) { setLayerType(LAYER_TYPE_SOFTWARE, null); } } catch (Exception e) { e.printStackTrace(); } mGestureDetector=new GestureDetector(new CusGestureListener()); setLongClickable(true); setOnTouchListener(onTouchListener); } public void setAdapter(ArrayList headList) { this.headList=headList; current_Page=1; current_OffsetX=0; current_clickIndex=0; current_foucsIndex=0; current_longPressIndex=-1; if(headWidth==0) { headWidth=DensityUtil.dip2px(getContext(), 60); } mCircleBitmap=WindowMgr.getInstance().getCircleBitmap(headWidth, headWidth); bitmapArray=WindowMgr.getInstance().getAllBitmaps(headList); headRectArray=new Rect[bitmapArray.length]; for(int i=0;i portraitNumberPerScreen) { maxPage=(bitmapArray.length%portraitNumberPerScreen==0)?bitmapArray.length/portraitNumberPerScreen:this.bitmapArray.length/portraitNumberPerScreen+1; } else { maxPage=1; } int left = 0; int top = DensityUtil.dip2px(getContext(), 10); int right = 0; int bottom = top+headWidth; for(int i=0;i 0) { canvas.setDrawFilter(pdf); for(int i=0;i current_clickIndex)//还需要优化 { if(current_Page==1) { drawingRect.left=headRectArray[i].left+current_OffsetX; drawingRect.top=headRectArray[i].top+cuurent_OffsetY; drawingRect.right=headRectArray[i].right+current_OffsetX; drawingRect.bottom=headRectArray[i].bottom+cuurent_OffsetY; } else if(current_Page>1) { } } if(drawingRect.right getRight()) { break; } if(current_clickIndex!=i) { //绘制头像 canvas.drawBitmap(mCircleBitmap, null, drawingRect, paint); paint.setXfermode(xfermode); canvas.drawBitmap(bitmapArray[i], null, drawingRect, paint); paint.setXfermode(null); } } drawingRect.left=headRectArray[0].left+clickOffsetforwarDx; drawingRect.top=headRectArray[0].top; drawingRect.right=headRectArray[0].right+clickOffsetforwarDx; drawingRect.bottom=headRectArray[0].bottom; int sc = canvas.saveLayer(drawingRect.left, drawingRect.top, drawingRect.right, drawingRect.bottom, null,LAYER_FLAGS); //绘制头像 canvas.drawBitmap(mCircleBitmap, null, drawingRect, paint); paint.setXfermode(xfermode); canvas.drawBitmap(bitmapArray[current_clickIndex], null, drawingRect, paint); paint.setXfermode(null); canvas.restoreToCount(sc); } else { canvas.setDrawFilter(pdf); for(int i=0;i getRight()) { break; } if(current_longPressIndex==i) { int insetDx=(int)((float)drawingRect.height()/(float)8); drawingRect.inset(insetDx, insetDx); } //绘制头像 canvas.drawBitmap(mCircleBitmap, null, drawingRect, paint); paint.setXfermode(xfermode); canvas.drawBitmap(bitmapArray[i], null, drawingRect, paint); paint.setXfermode(null); } } } } private OnTouchListener onTouchListener=new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { boolean isConsumed =mGestureDetector.onTouchEvent(event); if (isConsumed) return true; if(event.getAction()==MotionEvent.ACTION_CANCEL||event.getAction()==MotionEvent.ACTION_UP) { //----分页代码 int direct=0;//往左边为1,右边为-1,保持不变为0 if(moving_OffsetX>getMeasuredWidth()/2)//向右边滑过半屏 { current_Page--; direct=1; if(current_Page<1) { current_Page=1; direct=0; } } else if(moving_OffsetX<-getMeasuredWidth()/2)//向左边滑过半屏 { current_Page++; direct=-1; if(current_Page>maxPage) { current_Page=maxPage; direct=0; } } int old=current_OffsetX+moving_OffsetX; int newX=current_OffsetX+direct*getMeasuredWidth(); if(direct!=0) { current_foucsIndex=(current_Page-1)*portraitNumberPerScreen; if(null!=headClickListener) headClickListener.onItemClick(current_foucsIndex); } Log.v("dx:"+current_OffsetX, "----------------------"); if(current_longPressIndex!=-1) { invalidate(); current_longPressIndex=-1;//恢复 return false; } else { mHandler.post(new SmoothRunnable(old, newX)); } return false; } invalidate(); return isConsumed; } }; private GestureDetector mGestureDetector; private class CusGestureListener extends SimpleOnGestureListener { private Rect mDragRect=new Rect(); @Override public boolean onSingleTapUp(MotionEvent e) { Log.v("CusGestureListener", "onSingleTapUp"); int x=(int) e.getX(); int y=(int) e.getY(); boolean isInner=false; Rect mRect=new Rect(); for(int i=0;i =y) { isInner=true; } else { break; } } if(mRect.contains(x, y)) { current_foucsIndex=i; current_clickIndex=i; //动画:被点击向前移动,未点击向后移动 if(null!=mClickRunnable) { mClickRunnable.stop(); } mClickRunnable=new ClickRunnable(current_clickIndex); mHandler.post(mClickRunnable); } } return super.onSingleTapUp(e); } @Override public void onLongPress(MotionEvent e) {// Log.v("CusGestureListener", "onLongPress"); int x=(int) e.getRawX(); int y=(int) (e.getRawY()-WindowMgr.getInstance().getStatusBarHeight(getContext())); Rect mRect=new Rect(); for(int i=0;i 0) { current_Page--; direct=1; if(current_Page<1) { current_Page=1; direct=0; } } else { current_Page++; direct=-1; if(current_Page>maxPage) { current_Page=maxPage; direct=0; } } int old=current_OffsetX+moving_OffsetX; int newX=current_OffsetX+direct*getMeasuredWidth(); mHandler.post(new SmoothRunnable(old, newX)); return true; } @Override public void onShowPress(MotionEvent e) {// Log.v("CusGestureListener", "onShowPress"); super.onShowPress(e); } @Override public boolean onDown(MotionEvent e) {// Log.v("CusGestureListener", "onDown"); moving_OffsetX=0; mDragRect.set(getLeft(), getTop(), getRight(), getBottom()); return super.onDown(e); } @Override public boolean onDoubleTap(MotionEvent e) {// Log.v("CusGestureListener", "onDoubleTap"); return super.onDoubleTap(e); } @Override public boolean onDoubleTapEvent(MotionEvent e) {// Log.v("CusGestureListener", "onDoubleTapEvent"); return super.onDoubleTapEvent(e); } @Override public boolean onSingleTapConfirmed(MotionEvent e) {// Log.v("CusGestureListener", "onSingleTapConfirmed"); return super.onSingleTapConfirmed(e); } } //平滑移动 private class SmoothRunnable implements Runnable { private int startDx; private int endDx; private long duration=250; private long interval=10; private long startTime; private long endTime; public SmoothRunnable(int startDx, int endDx) { super(); this.startDx = startDx; this.endDx = endDx; } @Override public void run() { if(startTime==0) { moving_OffsetX=0; startTime=System.currentTimeMillis(); endTime=startTime+duration; } long currentTime=System.currentTimeMillis(); if(currentTime
具体的动画效果如下(效果图是丑了点,有录制gif图片软件请推荐一下吧):
Demo下载地址: