通过自定义ListView实现元素前移后退的动画特效,被点击元素A向前移,A之前元素往后移动.

具体的动画效果如下(效果图是丑了点,有录制gif图片软件请推荐一下吧):




重点在于动画的,具体代码如下:

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;//当前页码,开始页码为1private 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 ArrayList<String> headList=new ArrayList<String>();    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<String> 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<headRectArray.length;i++)//随时滑动{headRectArray[i]=new Rect();}requestLayout();invalidate();}private void calculate(){if(getMeasuredWidth()<=0){return;}portraitNumberPerScreen=getMeasuredWidth()/headWidth;portraitNumberPerScreen--;//少一个元素,使不会那么拥挤paddingLeft=(int)((float)(getMeasuredWidth()-portraitNumberPerScreen*headWidth)/(float)(portraitNumberPerScreen+1)+0.5f);if(bitmapArray.length>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<maxPage;i++)//分页效果{int pageWidthPadding=i*getMeasuredWidth();for(int j=0;j<portraitNumberPerScreen&&(i*portraitNumberPerScreen+j)<bitmapArray.length;j++){left=pageWidthPadding+paddingLeft*(j+1)+j*headWidth;right=left+headWidth;headRectArray[i*portraitNumberPerScreen+j].set(left, top, right, bottom);}}}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int height=DensityUtil.dip2px(getContext(), 80);setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height); calculate();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if(null!=bitmapArray){if(current_clickIndex>0){canvas.setDrawFilter(pdf);for(int i=0;i<bitmapArray.length;i++){drawingRect.left=headRectArray[i].left+current_OffsetX+clickOffsetBackDx;drawingRect.top=headRectArray[i].top+cuurent_OffsetY;drawingRect.right=headRectArray[i].right+current_OffsetX+clickOffsetBackDx;drawingRect.bottom=headRectArray[i].bottom+cuurent_OffsetY;if(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<getLeft()){continue;}else if(drawingRect.left>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<bitmapArray.length;i++){drawingRect.left=headRectArray[i].left+current_OffsetX+moving_OffsetX;drawingRect.top=headRectArray[i].top+cuurent_OffsetY;drawingRect.right=headRectArray[i].right+current_OffsetX+moving_OffsetX;drawingRect.bottom=headRectArray[i].bottom+cuurent_OffsetY;if(drawingRect.right<getLeft()){continue;}else if(drawingRect.left>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() {@Overridepublic 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,保持不变为0if(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();@Overridepublic 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<bitmapArray.length;i++){mRect.left=headRectArray[i].left+current_OffsetX+moving_OffsetX;mRect.top=headRectArray[i].top+cuurent_OffsetY;mRect.right=headRectArray[i].right+current_OffsetX+moving_OffsetX;mRect.bottom=headRectArray[i].bottom+cuurent_OffsetY;if(!isInner){if(mRect.top<=y&&mRect.bottom>=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);}@Overridepublic 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<bitmapArray.length;i++){mRect.left=headRectArray[i].left+current_OffsetX+moving_OffsetX;mRect.top=headRectArray[i].top+cuurent_OffsetY;mRect.right=headRectArray[i].right+current_OffsetX+moving_OffsetX;mRect.bottom=headRectArray[i].bottom+cuurent_OffsetY;if(mRect.contains(x, y)){current_longPressIndex=i;return ;}}super.onLongPress(e);}@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY) {//Log.v("CusGestureListener", "onScroll");int tx=(int) e1.getRawX();int ty=(int) (e1.getRawY()-WindowMgr.getInstance().getStatusBarHeight(getContext()));int tx2=(int) e2.getRawX();int ty2=(int) (e2.getRawY()-WindowMgr.getInstance().getStatusBarHeight(getContext()));if(mDragRect.contains(tx, ty)&&mDragRect.contains(tx2, ty2)){moving_OffsetX=(int) (e2.getRawX()-e1.getRawX());}return super.onScroll(e1, e2, distanceX, distanceY);}@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) {//Log.d("CDH", "onFling currentPage:"+currentPage+" x1:"+e1.getRawX()+" x2:"+e2.getRawX()+" velocityX:"+velocityX+"velocityY:"+velocityY);if (Math.abs(velocityX) < 1000) return false;int direct=0;//往左边为1,右边为-1,保持不变为0if(velocityX > 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;}@Overridepublic void onShowPress(MotionEvent e) {//Log.v("CusGestureListener", "onShowPress");super.onShowPress(e);}@Overridepublic boolean onDown(MotionEvent e) {//Log.v("CusGestureListener", "onDown");moving_OffsetX=0;mDragRect.set(getLeft(), getTop(), getRight(), getBottom());return super.onDown(e);}@Overridepublic boolean onDoubleTap(MotionEvent e) {//Log.v("CusGestureListener", "onDoubleTap");return super.onDoubleTap(e);}@Overridepublic boolean onDoubleTapEvent(MotionEvent e) {//Log.v("CusGestureListener", "onDoubleTapEvent");return super.onDoubleTapEvent(e);}@Overridepublic 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;}@Overridepublic void run() {if(startTime==0){moving_OffsetX=0;startTime=System.currentTimeMillis();endTime=startTime+duration;}long currentTime=System.currentTimeMillis();if(currentTime<endTime){current_OffsetX=(int)(startDx+(endDx-startDx)*((float)(currentTime-startTime)/(float)(duration)));invalidate();mHandler.postDelayed(this, interval);}else{current_OffsetX=endDx;moving_OffsetX=0;invalidate();}}} private int clickOffsetforwarDx=0;private int clickOffsetBackDx;//点击移动到队头部,其他往后面移动private ClickRunnable mClickRunnable=null;private class ClickRunnable implements Runnable{private int current_clickIndex;private int forwardDx=0;//到队列头部的总长度private int backwardsDx=0;//到第二个的长度private long duration=300;private long interval=10;private long startTime;private long endTime;public ClickRunnable(int current_clickIndex){this.current_clickIndex=current_clickIndex;duration=Math.max((long) (duration*(float)current_clickIndex/(float)portraitNumberPerScreen),duration);duration=Math.min(duration, 700);}public void stop(){mHandler.removeCallbacks(this);}@Overridepublic void run() {if(startTime==0){Rect mRect=new Rect();mRect.left=headRectArray[current_clickIndex].left+current_OffsetX+moving_OffsetX;mRect.top=headRectArray[current_clickIndex].top+cuurent_OffsetY;mRect.right=headRectArray[current_clickIndex].right+current_OffsetX+moving_OffsetX;mRect.bottom=headRectArray[current_clickIndex].bottom+cuurent_OffsetY;forwardDx=mRect.left-headRectArray[0].left;int left=paddingLeft*2+headWidth;int top=DensityUtil.dip2px(getContext(), 10);Rect secord=new Rect(left,top, left+headWidth, top+headWidth);backwardsDx=secord.left-headRectArray[0].left+Math.abs(current_OffsetX);startTime=System.currentTimeMillis();endTime=startTime+duration;}long currentTime=System.currentTimeMillis();if(currentTime<endTime){clickOffsetforwarDx=(int) (forwardDx-forwardDx*((float)(currentTime-startTime)/(float)(duration)));clickOffsetBackDx=(int) (backwardsDx*((float)(currentTime-startTime)/(float)(duration)));invalidate();mHandler.postDelayed(this, interval);}else{clickOffsetforwarDx=0;clickOffsetBackDx=0;String tmp=headList.remove(current_clickIndex);headList.add(0, tmp);bitmapArray=WindowMgr.getInstance().getAllBitmaps(headList);HorImageListView.this.current_clickIndex=0;HorImageListView.this.current_Page=1;HorImageListView.this.current_OffsetX=0;HorImageListView.this.current_clickIndex=0;HorImageListView.this.current_foucsIndex=0;HorImageListView.this.current_longPressIndex=-1;invalidate();if(null!=headClickListener)headClickListener.onItemClick(current_clickIndex);}}}public void setOnHeadClickListener(IHeadClick headClickListener){this.headClickListener=headClickListener;}public static interface IHeadClick{public void onItemClick(int position);}}




Demo下载地址: http://download.csdn.net/detail/zz7zz7zz/6340747



更多相关文章

  1. linearlayout总结
  2. Android基础教程(二)之五大布局对象
  3. Android(安卓)PopupWindow与ListView配合使用
  4. Android滑动组件----RecyclerView并且实现点击事件(2)
  5. Android(安卓)实现通知栏显示多个notification
  6. 谈谈android大众常用的五种布局?
  7. 一段android跳转到web界面的代码
  8. Android(安卓)Studio 单元测试之简单版
  9. Android(安卓)studio安装与配置Butter knife过程

随机推荐

  1. A015-布局之LinearLayout
  2. Android数据存储方式:SharePreference、SQ
  3. androidManifest.xml之uses-permission(
  4. Android(安卓)app图标总是显示默认的机器
  5. Android(安卓)工具整合,让你的 Android(安
  6. 解决绕过android下apk使用usb设备权限查
  7. Android不兼容和版本混乱现象严重
  8. Android GPS (当前位置 & GPS信息更新)
  9. Android之AIDL进程之间的通信
  10. Android——ListView控件(Android Studio