1. 程式人生 > 程式設計 >Android實現層疊卡片式banner

Android實現層疊卡片式banner

本文例項為大家分享了Android實現層疊卡片式banner的具體程式碼,供大家參考,具體內容如下

效果圖如下:

Android實現層疊卡片式banner

背景

由於公司VIP模組專案需要,本著對ui設計師的尊重,需要實現以上效果圖,在網上找了很多部落格,都不能滿足上面的需求,所以就只能自己硬著頭皮自定義了,下面就是我自定義的view程式碼,做個記錄:

package cn.com.cunw.familydesk.view.vipBanner;

import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import androidx.annotation.NonNull;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AnimationUtils;
import android.widget.RelativeLayout;
import android.widget.Scroller;

import java.util.ArrayList;

import cn.com.cunw.familydesk.R;

/**
 * @Description:
 * @Author: wuJie
 * @CreateDate: 2020/1/4 10:14
 * Copyright (C),2015-2020,*/
public class CoverFlowView extends RelativeLayout {

 public enum CoverFlowGravity {
  TOP,BOTTOM,CENTER_VERTICAL
 }

 public enum CoverFlowLayoutMode {
  MATCH_PARENT,WRAP_CONTENT
 }

 protected CoverFlowGravity mGravity;

 protected CoverFlowLayoutMode mLayoutMode;

 private Scroller mScroller;
 /**
  * To store reflections need to remove
  */
 private ArrayList<View> removeViewArray;

 private SparseArray<View> showViewArray;

 private int paddingLeft;
 private int paddingRight;
 private int paddingTop;
 private int paddingBottom;

 private int mWidth; // 控制元件的寬度

 private float reflectHeightFraction;
 private int reflectGap;

 private int mChildHeight; // child的高度
 private int mChildTranslateY;
 //private int mReflectionTranslateY;

 private int mVisibleChildCount; // 一屏顯示的圖片數量

 protected int VISIBLE_VIEWS = 3; // the visible views left and right 左右兩邊顯示的個數

 private ICoverFlowAdapter mAdapter;

 private float mOffset;
 //private int mLastOffset;

 private final int ALPHA_DATUM = 200; // 基礎alphaֵ
 private int STANDARD_ALPHA;
 // 基礎縮放值
 //private static final float CARD_SCALE = 0.15f;

 private static float MOVE_POS_MULTIPLE = 3.0f;
 private static final int TOUCH_MINIMUM_MOVE = 5;
 private static final float MOVE_SPEED_MULTIPLE = 1;
 private static final float MAX_SPEED = 6.0f;
 private static final float FRICTION = 10.0f;

 private VelocityTracker mVelocity;

 private int firstIndex = 0;

 public CoverFlowView(Context context) {
  super(context);
  init();
 }

 public CoverFlowView(Context context,AttributeSet attrs) {
  super(context,attrs);
  initAttributes(context,attrs);
  init();
 }

 public CoverFlowView(Context context,AttributeSet attrs,int defStyle) {
  super(context,attrs,defStyle);
  initAttributes(context,attrs);
  init();
 }

 private void initAttributes(Context context,AttributeSet attrs) {
  TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.ImageCoverFlowView);
  int totalVisibleChildren = a.getInt(
    R.styleable.ImageCoverFlowView_visibleImage,3);
  if (totalVisibleChildren % 2 == 0) { // 一螢幕必須是奇數顯示
   throw new IllegalArgumentException("visible image must be an odd number");
  }

  VISIBLE_VIEWS = totalVisibleChildren >> 1; // 計算出左右兩兩邊的顯示個數

  reflectHeightFraction = a.getFraction(
    R.styleable.ImageCoverFlowView_reflectionHeight,100,0.0f);

  if (reflectHeightFraction > 100) {
   reflectHeightFraction = 100;
  }
  reflectHeightFraction /= 100;
  reflectGap = a.getDimensionPixelSize(
    R.styleable.ImageCoverFlowView_reflectionGap,0);

  mGravity = CoverFlowGravity.values()[a.getInt(
    R.styleable.ImageCoverFlowView_coverflowGravity,CoverFlowGravity.CENTER_VERTICAL.ordinal())];

  mLayoutMode = CoverFlowLayoutMode.values()[a.getInt(
    R.styleable.ImageCoverFlowView_coverflowLayoutMode,CoverFlowLayoutMode.WRAP_CONTENT.ordinal())];

  a.recycle();
 }

 private void init() {
  removeAllViews();
  setWillNotDraw(false);
  setClickable(true);

  if (mScroller == null) {
   mScroller = new Scroller(getContext(),new AccelerateDecelerateInterpolator());
  }
  if (showViewArray == null) {
   showViewArray = new SparseArray<View>();
  } else {
   showViewArray.clear();
  }
  if (removeViewArray == null) {
   removeViewArray = new ArrayList<View>();
  } else {
   removeViewArray.clear();
  }

  firstIndex = 0;
  mChildHeight = 0;
  mOffset = 0;
  //mLastOffset = -1;

  isFirstIn = true;
  lastMid = 1;
  isChange = true;

  // 計算透明度
  STANDARD_ALPHA = (255 - ALPHA_DATUM) / VISIBLE_VIEWS;

  if (mGravity == null) {
   mGravity = CoverFlowGravity.CENTER_VERTICAL;
  }

  if (mLayoutMode == null) {
   mLayoutMode = CoverFlowLayoutMode.WRAP_CONTENT;
  }

  // 一屏 顯示的圖片數量
  int visibleCount = (VISIBLE_VIEWS << 1) + 1;

  for (int i = 0; i < visibleCount && mAdapter != null && i < mAdapter.getCount(); ++i) {

   View convertView = null;
   if (removeViewArray.size() > 0) {
    convertView = removeViewArray.remove(0);
   }
   View view = mAdapter.getView(i,convertView,this);
   showViewArray.put(i,view);
   addView(view);
  }

  requestLayout();
 }

 @Override
 protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec) {
  super.onMeasure(widthMeasureSpec,heightMeasureSpec);

  if (mAdapter == null || showViewArray.size() <= 0) {
   return;
  }

  paddingLeft = getPaddingLeft();
  paddingRight = getPaddingRight();
  paddingTop = getPaddingTop();
  paddingBottom = getPaddingBottom();

  int heightMode = MeasureSpec.getMode(heightMeasureSpec);
  int widthSize = MeasureSpec.getSize(widthMeasureSpec);
  int heightSize = MeasureSpec.getSize(heightMeasureSpec);

  // 一屏顯示的圖片數量
  int visibleCount = (VISIBLE_VIEWS << 1) + 1;

  // 控制元件高度
  int availableHeight = heightSize - paddingTop - paddingBottom;

  int maxChildTotalHeight = 0;
  for (int i = 0; i < getChildCount() && i < visibleCount && i < showViewArray.size(); ++i) {

   //View view = showViewArray.get(i+firstIndex);
   View view = getChildAt(i);
   measureChild(view,widthMeasureSpec,heightMeasureSpec);

   //final int childHeight = ScreenUtil.dp2px(getContext(),110);
   final int childHeight = view.getMeasuredHeight();
   final int childTotalHeight = (int) (childHeight + childHeight
     * reflectHeightFraction + reflectGap);

   // 孩子的最大高度
   maxChildTotalHeight = (maxChildTotalHeight < childTotalHeight) ? childTotalHeight
     : maxChildTotalHeight;
  }

  // 如果控制元件模式為確切值 或者 最大時
  if (heightMode == MeasureSpec.EXACTLY || heightMode == MeasureSpec.AT_MOST) {
   // if height which parent provided is less than child need,scale
   // child height to parent provide
   // 如果控制元件高度小於孩子控制元件高度,則縮放孩子高度為控制元件高度
   if (availableHeight < maxChildTotalHeight) {
    mChildHeight = availableHeight;
   } else {
    // if larger than,depends on layout mode
    // if layout mode is match_parent,scale child height to parent
    // provide
    // 如果是填充父窗體模式 則將孩子的高度 設為控制元件高度
    if (mLayoutMode == CoverFlowLayoutMode.MATCH_PARENT) {
     mChildHeight = availableHeight;
     // if layout mode is wrap_content,keep child's original
     // height
     // 如果是包裹內容 則將孩子的高度設為孩子允許的最大高度
    } else if (mLayoutMode == CoverFlowLayoutMode.WRAP_CONTENT) {
     mChildHeight = maxChildTotalHeight;

     // adjust parent's height
     // 計算出控制元件的高度
     if (heightMode == MeasureSpec.AT_MOST) {
      heightSize = mChildHeight + paddingTop + paddingBottom;
     }
    }
   }
  } else {
   // height mode is unspecified
   // 如果空間高度 沒有明確定義
   // 如果孩子的模式為填充父窗體
   if (mLayoutMode == CoverFlowLayoutMode.MATCH_PARENT) {
    mChildHeight = availableHeight;
    // 如果孩子的模式為包裹內容
   } else if (mLayoutMode == CoverFlowLayoutMode.WRAP_CONTENT) {
    mChildHeight = maxChildTotalHeight;

    // 計算出控制元件的高度
    // adjust parent's height
    heightSize = mChildHeight + paddingTop + paddingBottom;
   }
  }

  // Adjust movement in y-axis according to gravity
  // 計算出孩子的原點 Y座標
  if (mGravity == CoverFlowGravity.CENTER_VERTICAL) {// 豎直居中
   mChildTranslateY = (heightSize >> 1) - (mChildHeight >> 1);
  } else if (mGravity == CoverFlowGravity.TOP) {// 頂部對齊
   mChildTranslateY = paddingTop;
  } else if (mGravity == CoverFlowGravity.BOTTOM) {// 底部對齊
   mChildTranslateY = heightSize - paddingBottom - mChildHeight;
  }

  //mReflectionTranslateY = (int) (mChildTranslateY + mChildHeight - mChildHeight
  //  * reflectHeightFraction);

  setMeasuredDimension(widthSize,heightSize);
  mVisibleChildCount = visibleCount;
  mWidth = widthSize;

 }

 boolean isFirstIn = true; // 第一次初始化該控制元件
 int lastMid = 1;
 boolean isChange = true;

 @Override
 protected void onLayout(boolean changed,int l,int t,int r,int b) {
  if (mAdapter == null || mAdapter.getCount() <= 0 || showViewArray.size() <= 0) {
   return;
  }

  final float offset = mOffset;
  int i = 0;
  int mid = (int) Math.floor(offset + 0.5);

  //右邊孩子的數量
  int rightChild = (mVisibleChildCount % 2 == 0) ? (mVisibleChildCount >> 1) - 1
    : mVisibleChildCount >> 1;
  //左邊孩子的數量
  int leftChild = mVisibleChildCount >> 1;

  if (!isFirstIn) {
   if (lastMid + 1 == mid) {
    int actuallyPositionStart = getActuallyPosition(lastMid - leftChild);
    View view = showViewArray.get(actuallyPositionStart);
    showViewArray.remove(actuallyPositionStart);
    removeViewArray.add(view);
    removeView(view);

    View convertView = null;
    if (removeViewArray.size() > 0) {
     convertView = removeViewArray.remove(0);
    }
    int actuallyPositionEnd = getActuallyPosition(mid + rightChild);

    //TODO
    View viewItem = mAdapter.getView(actuallyPositionEnd,this);

    showViewArray.put(actuallyPositionEnd,viewItem);
    addView(viewItem);

    isChange = true;

   } else if (lastMid - 1 == mid) {
    int actuallyPositionEnd = getActuallyPosition(lastMid + rightChild);
    View view = showViewArray.get(actuallyPositionEnd);
    showViewArray.remove(actuallyPositionEnd);
    removeViewArray.add(view);
    removeView(view);

    View convertView = null;
    if (removeViewArray.size() > 0) {
     convertView = removeViewArray.remove(0);
    }
    int actuallyPositionStart = getActuallyPosition(mid - leftChild);

    //TODO
    View viewItem = mAdapter.getView(actuallyPositionStart,this);

    showViewArray.put(actuallyPositionStart,viewItem);
    addView(viewItem,0);

    isChange = true;
   }

  } else {
   isFirstIn = false;
  }

  lastMid = mid;

  // draw the left children
  // 計算左邊孩子的位置
  int startPos = mid - leftChild;
  for (i = startPos; i < mid; ++i) {
   //TODO 計算左邊孩子的位置
   View child = layoutLeftChild(i,i - offset);

   if (isChange) {
    int actuallyPosition = getActuallyPosition(i);
    mAdapter.getData(child,actuallyPosition);
   }
  }

  // 計算 右邊 和 中間
  int endPos = mid + rightChild;

  int j = -VISIBLE_VIEWS;
  for (i = endPos; i >= mid; --i,j = j + 2) {
   //TODO 計算右邊和中間孩子的位置
   View child = layoutRightChild(i + j,actuallyPosition);
   }
  }

  isChange = false;
 }

 private View layoutLeftChild(int position,float offset) {
  //獲取實際的position
  int actuallyPosition = getActuallyPosition(position);
  View child = showViewArray.get(actuallyPosition);
  if (child != null) {
   makeChildTransfromer(child,actuallyPosition,offset);
  }
  return child;
 }

 private View layoutRightChild(int position,float offset) {

  //獲取實際的position
  int actuallyPosition = getActuallyPosition(position);
  View child = showViewArray.get(actuallyPosition);
  if (child != null) {
   makeChildTransfromer(child,offset);
  }

  return child;
 }

 /**
  * 對 bitmap 進行偽 3d 變換
  *
  * @param child
  * @param position
  * @param offset
  */
 private void makeChildTransfromer(View child,int position,float offset) {
  //child.layout(0,ScreenUtil.dp2px(getContext(),200),110));
  child.layout(0,child.getMeasuredWidth(),child.getMeasuredHeight());

  float scale = 0;
  scale = 1 - Math.abs(offset) * 0.25f;

  // 延x軸移動的距離應該根據center圖片決定
  float translateX = 0;

  final int originalChildHeight = (int) (mChildHeight - mChildHeight
    * reflectHeightFraction - reflectGap);

  //final int childTotalHeight = (int) (child.getHeight()
  //  + child.getHeight() * reflectHeightFraction + reflectGap);

  final float originalChildHeightScale = (float) originalChildHeight / child.getHeight();

  final float childHeightScale = originalChildHeightScale * scale;

  final int childWidth = (int) (child.getWidth() * childHeightScale);

  final int centerChildWidth = (int) (child.getWidth() * originalChildHeightScale);

  //final int centerChildWidth = (int) (child.getWidth() * childHeightScale);

  int leftSpace = ((mWidth >> 1) - paddingLeft) - (centerChildWidth >> 1);
  int rightSpace = (((mWidth >> 1) - paddingRight) - (centerChildWidth >> 1));

  //計算出水平方向的x座標
  if (offset <= 0)
   translateX = ((float) leftSpace / VISIBLE_VIEWS)
     * (VISIBLE_VIEWS + offset) + paddingLeft;

  else
   translateX = mWidth - ((float) rightSpace / VISIBLE_VIEWS)
     * (VISIBLE_VIEWS - offset) - childWidth - paddingRight;

  //根據offset 算出透明度
  float alpha = 254 - Math.abs(offset) * STANDARD_ALPHA;

  child.setAlpha(0);
  if (alpha < 0) {
   alpha = 0;
  } else if (alpha > 254) {
   alpha = 254;
  }
  child.setAlpha(alpha / 254.0f);

  float adjustedChildTranslateY = 0;

  ObjectAnimator anim1 = ObjectAnimator.ofFloat(child,"scaleX",1.0f,childHeightScale);
  ObjectAnimator anim2 = ObjectAnimator.ofFloat(child,"scaleY",childHeightScale);
  AnimatorSet animSet = new AnimatorSet();
  animSet.setDuration(0);
  //兩個動畫同時執行
  animSet.playTogether(anim1,anim2);
  child.setPivotX(0);
  child.setPivotY(child.getHeight() / 2);
  //顯示的呼叫invalidate
  child.invalidate();
  animSet.setTarget(child);
  animSet.start();

  child.setTranslationX(translateX);
  child.setTranslationY(mChildTranslateY + adjustedChildTranslateY);

 }

 /**
  * 獲取頂部Item position
  *
  * @return
  */
 public int getTopViewPosition() {
  return getActuallyPosition(lastMid);
 }

 /**
  * 獲取頂部Item View
  *
  * @return
  */
 public View getTopView() {
  return showViewArray.get(getActuallyPosition(VISIBLE_VIEWS + lastMid));
 }

 /**
  * Convert draw-index to index in adapter
  *
  * @param position position to draw
  * @return
  */
 private int getActuallyPosition(int position) {
  if (mAdapter!=null){

  int max = mAdapter.getCount();
  position += VISIBLE_VIEWS;
  while (position < 0 || position >= max) {
   if (position < 0) {
    position += max;
   } else if (position >= max) {
    position -= max;
   }
   }
  }
  return position;
 }

 public void setAdapter(@NonNull ICoverFlowAdapter adapter) {
  mAdapter = adapter;
  init();
 }

 public ICoverFlowAdapter getAdapter() {
  return mAdapter;
 }

 private boolean onTouchMove = false; //是否正在執行觸控移動邏輯

 private View touchViewItem = null;
 private boolean isOnTopView = false;

 @Override
 public boolean onTouchEvent(MotionEvent event) {
  if (getParent() != null) {
   getParent().requestDisallowInterceptTouchEvent(true);
  }

  if (isOnAnimator) {
   return false;
  }
  int action = event.getAction();

  switch (action) {
   case MotionEvent.ACTION_DOWN:
    if (mAdapter==null){
     return false;
    }
    onTouchMove = true;
    if (mScroller.computeScrollOffset()) {
     mScroller.abortAnimation();
     invalidate();
     requestLayout();
    }
    touchBegan(event);
    touchViewItem = getTopView();
    isOnTopView = inRangeOfView(touchViewItem,event);
    if (isOnTopView) {
     sendLongClickAction();
    }
    return true;
   case MotionEvent.ACTION_MOVE:
    touchMoved(event);
    removeLongClickAction();
    touchViewItem = null;
    isOnTopView = false;
    return true;
   case MotionEvent.ACTION_UP:
    removeLongClickAction();
    if (isOnTopView && touchViewItem == getTopView()
      && inRangeOfView(touchViewItem,event)) {

     if (mTopViewClickListener != null) {
      mTopViewClickListener.onClick(getTopViewPosition(),getTopView());
     }
    }
    touchViewItem = null;
    isOnTopView = false;
    touchEnded(event);
    return true;
  }

  return false;
 }

 private Runnable longClickRunnable = null;

 /**
  * 傳送長點選事件 Runnable
  */
 private void sendLongClickAction() {
  removeLongClickAction();
  longClickRunnable = new Runnable() {
   @Override
   public void run() {
    touchViewItem = null;
    isOnTopView = false;
    if (mTopViewLongClickListener != null) {
     mTopViewLongClickListener.onLongClick(getTopViewPosition(),getTopView());
    }
   }
  };
  postDelayed(longClickRunnable,600);
 }

 /**
  * 移除長點選事件 Runnable
  */
 private void removeLongClickAction() {
  if (longClickRunnable != null) {
   removeCallbacks(longClickRunnable);
   longClickRunnable = null;
  }
 }

 private boolean inRangeOfView(View view,MotionEvent ev) {
  Rect frame = new Rect();
  view.getHitRect(frame);
  if (frame.contains((int) ev.getX(),(int) ev.getY())) {
   return true;
  }
  return false;
 }

 private OnTopViewClickListener mTopViewClickListener;
 private OnTopViewLongClickListener mTopViewLongClickListener;
 private OnTopViewChangeListener mTopViewChangeListener;

 /**
  * 設定 TopView 的點選監聽
  *
  * @param topViewClickListener
  */
 public void setOnTopViewClickListener(OnTopViewClickListener topViewClickListener) {
  this.mTopViewClickListener = topViewClickListener;
 }

 /**
  * 獲取 TopView 的點選監聽
  *
  * @return
  */
 public OnTopViewClickListener getOnTopViewClickListener() {
  return this.mTopViewClickListener;
 }

 /**
  * 設定 TopView 的長點選監聽
  *
  * @param topViewLongClickListener
  */
 public void setOnTopViewLongClickListener(OnTopViewLongClickListener topViewLongClickListener) {
  this.mTopViewLongClickListener = topViewLongClickListener;
 }

 /**
  * 設定 TopView 的長點選監聽
  *
  * @param mTopViewChangeListener
  */
 public void setOnTopViewChangeListener(OnTopViewChangeListener mTopViewChangeListener) {
  this.mTopViewChangeListener = mTopViewChangeListener;
 }

 /**
  * 獲取 TopView 的長點選監聽
  *
  * @return
  */
 public OnTopViewLongClickListener getOnTopViewLongClickListener() {
  return this.mTopViewLongClickListener;
 }

 public interface OnTopViewClickListener {

  void onClick(int position,View itemView);

 }

 public interface OnTopViewLongClickListener {

  void onLongClick(int position,View itemView);

 }

 public interface OnTopViewChangeListener {

  void onItemChange(int position);

 }

 private boolean mTouchMoved;
 private float mTouchStartPos;
 private float mTouchStartX;
 private float mTouchStartY;

 private long mStartTime;
 private float mStartOffset;

 private void touchBegan(MotionEvent event) {
  endAnimation();

  float x = event.getX();
  mTouchStartX = x;
  mTouchStartY = event.getY();
  mStartTime = AnimationUtils.currentAnimationTimeMillis();
  mStartOffset = mOffset;

  mTouchMoved = false;

  mTouchStartPos = (x / mWidth) * MOVE_POS_MULTIPLE - 5;
  mTouchStartPos /= 2;

  mVelocity = VelocityTracker.obtain();
  mVelocity.addMovement(event);
 }

 private Runnable mAnimationRunnable;

 private void endAnimation() {
  if (mAnimationRunnable != null) {
   mOffset = (float) Math.floor(mOffset + 0.5);

   invalidate();
   requestLayout();

   removeCallbacks(mAnimationRunnable);
   mAnimationRunnable = null;
  }
 }

 private void touchMoved(MotionEvent event) {
  float pos = (event.getX() / mWidth) * MOVE_POS_MULTIPLE - 5;
  pos /= 2;

  if (!mTouchMoved) {
   float dx = Math.abs(event.getX() - mTouchStartX);
   float dy = Math.abs(event.getY() - mTouchStartY);
   if (dx < TOUCH_MINIMUM_MOVE && dy < TOUCH_MINIMUM_MOVE)
    return;
   mTouchMoved = true;
  }

  mOffset = mStartOffset + mTouchStartPos - pos;

  invalidate();
  requestLayout();
  mVelocity.addMovement(event);
 }

 private void touchEnded(MotionEvent event) {
  float pos = (event.getX() / mWidth) * MOVE_POS_MULTIPLE - 5;
  pos /= 2;

  if (mTouchMoved || (mOffset - Math.floor(mOffset)) != 0) {
   mStartOffset += mTouchStartPos - pos;
   mOffset = mStartOffset;

   mVelocity.addMovement(event);

   mVelocity.computeCurrentVelocity(1000);
   float speed = mVelocity.getXVelocity();

   speed = (speed / mWidth) * MOVE_SPEED_MULTIPLE;
   if (speed > MAX_SPEED)
    speed = MAX_SPEED;
   else if (speed < -MAX_SPEED)
    speed = -MAX_SPEED;

   startAnimation(-speed);

   if (mTopViewChangeListener != null) {
    mTopViewChangeListener.onItemChange(getTopViewPosition());
   }
  } else {
   Log.e("xyw"," touch ==>" + event.getX() + "," + event.getY());
   onTouchMove = false;
  }

  mVelocity.clear();
  mVelocity.recycle();
 }

 private float mStartSpeed;
 private float mDuration;

 private void startAnimation(float speed) {
  if (mAnimationRunnable != null) {
   onTouchMove = false;
   return;
  }

  float delta = speed * speed / (FRICTION * 2);
  if (speed < 0)
   delta = -delta;

  float nearest = mStartOffset + delta;
  nearest = (float) Math.floor(nearest + 0.5f);

  mStartSpeed = (float) Math.sqrt(Math.abs(nearest - mStartOffset) * FRICTION * 2);
  if (nearest < mStartOffset)
   mStartSpeed = -mStartSpeed;

  mDuration = Math.abs(mStartSpeed / FRICTION);
  mStartTime = AnimationUtils.currentAnimationTimeMillis();

  mAnimationRunnable = new Runnable() {
   @Override
   public void run() {
    driveAnimation();
   }
  };
  post(mAnimationRunnable);
 }

 private void driveAnimation() {
  float elapsed = (AnimationUtils.currentAnimationTimeMillis() - mStartTime) / 1000.0f;
  if (elapsed >= mDuration) {
   endAnimation();
   onTouchMove = false;
  } else {
   updateAnimationAtElapsed(elapsed);
   post(mAnimationRunnable);
  }
 }

 private void updateAnimationAtElapsed(float elapsed) {
  if (elapsed > mDuration)
   elapsed = mDuration;

  float delta = Math.abs(mStartSpeed) * elapsed - FRICTION * elapsed * elapsed / 2;
  if (mStartSpeed < 0)
   delta = -delta;

  mOffset = mStartOffset + delta;
  invalidate();
  requestLayout();
 }

 @Override
 public void computeScroll() {
  super.computeScroll();

  // 算出移動到某一個虛擬點時 mOffset 的值,然後 invalidate 重繪
  if (mScroller.computeScrollOffset()) {
   final int currX = mScroller.getCurrX();
   mOffset = (float) currX / 100;

   invalidate();
  }
 }

 private boolean isOnAnimator = false; //是否正在進行點選切換動畫

 /**
  * 翻到前頁
  */
 public void gotoPrevious() {
  doAnimator(-1.0f);

 }

 /**
  * 前進到後一頁
  */
 public void gotoForward() {
  doAnimator(1.0f);
 }

 public void doAnimator(float target) {
  if (isOnAnimator || onTouchMove) { //如果正在執行點選切換動畫 或者 正在執行觸控移動
   return;
  }
  isOnAnimator = true;
  ValueAnimator animator = ValueAnimator.ofFloat(mOffset,mOffset + target);
  animator.setDuration(300).start();
  animator.setInterpolator(new AccelerateDecelerateInterpolator());
  animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

   @Override
   public void onAnimationUpdate(ValueAnimator animation) {
    mOffset = (Float) animation.getAnimatedValue();

    invalidate();
    requestLayout();
   }
  });
  animator.addListener(new Animator.AnimatorListener() {
   @Override
   public void onAnimationStart(Animator animation) {
   }

   @Override
   public void onAnimationCancel(Animator animation) {
   }

   @Override
   public void onAnimationRepeat(Animator animation) {
   }

   @Override
   public void onAnimationEnd(Animator animation) {
    isOnAnimator = false;
   }
  });
 }

// @Override
// public boolean dispatchTouchEvent(MotionEvent ev) {
//  if (ev.getAction() == MotionEvent.ACTION_MOVE) {
//   return true; // 禁止滑動
//  }
//  return super.dispatchTouchEvent(ev);
// }
}

相關回調介面類

public interface ICoverFlowAdapter {

 int getCount();
 Object getItem(int position);
 long getItemId(int position);
 View getView(int position,View convertView,ViewGroup parent);

 void getData(View view,int position);
}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。