Android 3D旋转 Layout

来源:互联网 发布:linux grub命令进win 编辑:程序博客网 时间:2024/05/29 05:00

一款3D Layout,他可以让任何view拥有3D效果,可以触摸展示3D效果,或者执行翻转动画。

废话不多说,先上图:

这里写图片描述
这里写图片描述
这里写图片描述

如何使用

  • 将ThreeDLayout包裹你想要的布局(注意:ThreeDlayout只能有一个子view)
<com.wingsofts.threedlayout.ThreeDLayout      android:background="@color/colorPrimary"      android:id="@+id/td_header"      android:layout_width="match_parent"      android:layout_height="wrap_content"      >   <TextView       android:id="@+id/textView"      android:text="30℃"      android:textColor="#fff"      android:gravity="center"      android:textSize="80sp"      android:layout_width="match_parent"      android:layout_height="wrap_content"      />  </com.wingsofts.threedlayout.ThreeDLayout>

之后,调用以下方法有对应效果

//开启触摸模式layout.setTouchable(true);//改变触摸模式layout.setTouchMode(ThreeDLayout.MODE_BOTH_X_Y);//开始执行动画startVerticalAnimate(long duration);startVerticalAnimateDelayed(final long delayed, final long duration)startHorizontalAnimate(long duration)startHorizontalAnimateDelayed(final long delayed, final long duration)//开启循环动画startHorizontalAnimate()//关闭循环动画stopAnimate()

ThreeLayout代码:粘贴到项目中即可使用:

public class ThreeDLayout extends ViewGroup {  private Camera mCamera;  private Matrix mMatrix;  //this viewgroup's center  private int mCenterX;  private int mCenterY;  //rotateDegree  private float mCanvasRotateY;  private float mCanvasRotateX;  private float mCanvasMaxRotateDegree = 50;  //the touch mode  public static int MODE_X = 0;  public static int MODE_Y = 1;  public static int MODE_BOTH_X_Y = 2;  private int mMode = MODE_BOTH_X_Y;  private float mDensity;  private float[] mValues = new float[9];  //the flag of touch  private boolean isCanTouch = false;  //the degree of animation  private float mDegreeY = 0;  private float mDegreeX = 0;  //the flag of animate  private boolean isPlaying = false;  //the degree of longer animate  private int mLoopAnimateY = 0;  public ThreeDLayout(Context context) {    this(context, null);  }  public ThreeDLayout(Context context, AttributeSet attrs) {    this(context, attrs, 0);  }  public ThreeDLayout(Context context, AttributeSet attrs, int defStyleAttr) {    super(context, attrs, defStyleAttr);    //set a default background to make sure onDraw() dispatch    if (getBackground() == null) {      setBackgroundColor(Color.parseColor("#ffffff"));    }    DisplayMetrics dm = new DisplayMetrics();    dm = getResources().getDisplayMetrics();    mDensity = dm.density;    mCamera = new Camera();    mMatrix = new Matrix();  }  @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    if (getChildCount() != 1) {      throw new IllegalStateException("ThreeDLayout can only have one child");    }    View child = getChildAt(0);    measureChild(child, widthMeasureSpec, heightMeasureSpec);    //only one child view,so give the same size    setMeasuredDimension(child.getMeasuredWidth(), child.getMeasuredHeight());  }  @Override protected void onLayout(boolean changed, int l, int t, int r, int b) {    View child = getChildAt(0);    child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());  }  @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {    super.onSizeChanged(w, h, oldw, oldh);    mCenterX = w / 2;    mCenterY = h / 2;  }  @Override protected void onDraw(Canvas canvas) {    mMatrix.reset();    mCamera.save();    if (mMode == MODE_Y || mMode == MODE_BOTH_X_Y) {      mCamera.rotateX(mCanvasRotateX);    }    if (mMode == MODE_X || mMode == MODE_BOTH_X_Y) {      mCamera.rotateY(mCanvasRotateY);    }    mCamera.rotateY(mDegreeY);    mCamera.rotateX(mDegreeX);    if (isPlaying) {      mCamera.rotateY(mLoopAnimateY++);      Log.e("wing", mLoopAnimateY + "");      if (mLoopAnimateY == 360) {        mLoopAnimateY = 0;      }      invalidate();    }    mCamera.getMatrix(mMatrix);    // fix the Camera bug,    mMatrix.getValues(mValues);    mValues[6] = mValues[6] / mDensity;    mValues[7] = mValues[7] / mDensity;    mMatrix.setValues(mValues);    mCamera.restore();    mMatrix.preTranslate(-mCenterX, -mCenterY);    mMatrix.postTranslate(mCenterX, mCenterY);    canvas.concat(mMatrix);    super.onDraw(canvas);  }  @Override public boolean onInterceptTouchEvent(MotionEvent ev) {    if (isCanTouch) {      return true;    } else {      return super.onInterceptTouchEvent(ev);    }  }  @Override public boolean onTouchEvent(MotionEvent event) {    if (isCanTouch) {      float x = event.getX();      float y = event.getY();      int action = event.getAction();      switch (action) {        case MotionEvent.ACTION_MOVE: {          rotateCanvasWhenMove(x, y);          invalidate();          return true;        }        case MotionEvent.ACTION_UP: {          mDegreeY = 0;          rotateCanvasWhenMove(mCenterX, mCenterY);          invalidate();          return true;        }      }      return true;    } else {      return super.onTouchEvent(event);    }  }  /**   * get the value to rotate   */  private void rotateCanvasWhenMove(float x, float y) {    float dx = x - mCenterX;    float dy = y - mCenterY;    float percentX = dx / mCenterX;    float percentY = dy / mCenterY;    if (percentX > 1f) {      percentX = 1f;    } else if (percentX < -1f) {      percentX = -1f;    }    if (percentY > 1f) {      percentY = 1f;    } else if (percentY < -1f) {      percentY = -1f;    }    mCanvasRotateY = mCanvasMaxRotateDegree * percentX;    mCanvasRotateX = -(mCanvasMaxRotateDegree * percentY);  }  public void setTouchable(boolean canTouch) {    isCanTouch = canTouch;  }  public void setTouchMode(int mode) {    mMode = mode;    isCanTouch = true;  }  /**   * set the max rotate degree   */  public void setMaxRotateDegree(int degree) {    mCanvasMaxRotateDegree = degree;  }  /**   * start horizontal turn animate   */  public void startHorizontalAnimate(long duration) {    final ValueAnimator animator = ValueAnimator.ofFloat(-180f, 0f);    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {      @Override public void onAnimationUpdate(ValueAnimator animation) {        mDegreeY = (float) animation.getAnimatedValue();        invalidate();      }    });    animator.addListener(new Animator.AnimatorListener() {      @Override public void onAnimationStart(Animator animation) {      }      @Override public void onAnimationEnd(Animator animation) {        mDegreeY = 0;        animator.removeAllUpdateListeners();      }      @Override public void onAnimationCancel(Animator animation) {      }      @Override public void onAnimationRepeat(Animator animation) {      }    });    animator.setDuration(duration);    animator.start();  }  /**   * start horizontal turn animate delayed   */  public void startHorizontalAnimateDelayed(final long delayed, final long duration) {    new Thread(new Runnable() {      @Override public void run() {        try {          Thread.sleep(delayed);        } catch (InterruptedException e) {          e.printStackTrace();        }        post(new Runnable() {          @Override public void run() {            startHorizontalAnimate(duration);          }        });      }    }).start();  }  /**   * start vertical turn animate   */  public void startVerticalAnimate(long duration) {    final ValueAnimator animator = ValueAnimator.ofFloat(-180f, 0f);    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {      @Override public void onAnimationUpdate(ValueAnimator animation) {        mDegreeX = (float) animation.getAnimatedValue();        invalidate();      }    });    animator.addListener(new Animator.AnimatorListener() {      @Override public void onAnimationStart(Animator animation) {      }      @Override public void onAnimationEnd(Animator animation) {        mDegreeX = 0;        animator.removeAllUpdateListeners();      }      @Override public void onAnimationCancel(Animator animation) {      }      @Override public void onAnimationRepeat(Animator animation) {      }    });    animator.setDuration(duration);    animator.start();  }  /**   * start vertical turn animate delayed   */  public void startVerticalAnimateDelayed(final long delayed, final long duration) {    new Thread(new Runnable() {      @Override public void run() {        try {          Thread.sleep(delayed);        } catch (InterruptedException e) {          e.printStackTrace();        }        post(new Runnable() {          @Override public void run() {            startVerticalAnimate(duration);          }        });      }    }).start();  }  /**   * start loop animate   */  public void startHorizontalAnimate() {    isPlaying = true;    invalidate();  }  /**   * stop the loop animate   */  public void stopAnimate() {    isPlaying = false;    mLoopAnimateY = 0;    invalidate();  }}

Demo下载地址

0 0