1. 程式人生 > >Android 3D旋轉 Layout

Android 3D旋轉 Layout

一款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();
  }
}

相關推薦

Android 3D旋轉 Layout

一款3D Layout,他可以讓任何view擁有3D效果,可以觸控展示3D效果,或者執行翻轉動畫。 廢話不多說,先上圖: 如何使用 將ThreeDLayout包裹你想要的佈局(注意:ThreeDlayout只能有一個子view)

Android 3D旋轉動畫之Camera 和 Matrix

前面兩篇博文講解的都是Android 的2D動畫效果,要想做出非常炫酷的3D動畫效果怎麼辦?android 並沒有提供3D動畫介面給使用者,所以我們得自己重寫這樣一個3D介面動畫。 效果圖: 介面如下: /* * @Title: My3dAnimation.java

Android 3D旋轉動畫效果

這篇文章主要介紹一下如何實現View的3D旋轉效果,實現的主要原理就是圍繞Y軸旋轉,同時在Z軸方面上有一個深入的縮放。 演示的demo主要有以下幾個重點: 1,自定義旋轉動畫 2,動畫做完後,重置ImageView 先看一下程式的執行效果:

Android 3D旋轉動畫庫

今天興趣來潮,擼了一個動畫特效,我把他應用在登入的介面,當然也可以用在其他地方,先來預覽一下我的特效吧 使用方法 1. 在build.gradle裡面配置如下 dependencies { compile 'com.jzp:

Android 3D旋轉動畫——Rotate3dAnimation

在Android中如果想要實現3D效果一般有兩種選擇,一是使用Open GL ES,二是使用Camera。Open GL ES使用起來太過複雜,一般是用於比較高階的3D特效或遊戲,像比較簡單的一些3D效果,使用Camera就足夠了。 Camera中提供了三種旋轉方法,分

從零開始打造一個Android 3D立體旋轉容器

嗯,2個月沒有寫部落格,是要好好反省下,趁著放暑假把這兩個月看的東西好好沉澱下。嗯,就立下這個Flag,希望不要自己再打自己臉。 1.概述 回到正題,這次帶來的效果,是一個Android 的3D立體旋轉的效果。 當然靈感的來源,來自早些時間

Android 3D立體旋轉效果實現

說明:之前在網上到處搜尋類似的旋轉效果 但搜到的結果都不是十分滿意 原因不多追述 (如果有人找到過相關 比較好的效果 可以發一下連線 一起共同進步)一 效果展示 :如非您所需要的效果 也希望能給些微幫助  具體操作以及實現 效果 請看專案例子二 使用方式此空間繼承與Frame

Android動畫(ViewHelp/3D旋轉

如果想具體瞭解Android動畫的可參考小編的上一篇部落格,在這裡我們僅為實現頁面的3D旋轉效果做一個小的實現。當然,要說這個3D效果與其他3D效果有哪些不同之處呢。也就是拉大了觀察者的攝像機與動畫之間的距離,避免旋轉效果因Y方向上的頁面旋轉而超出螢幕高度,使整

Android自定義控制元件----3D旋轉效果

3D效果在Android裡面應該不算新鮮了,不過現在市場上的Android APP很少應用有3d效果的。前幾天看到一個app裡面有一個3D的旋轉效果,於是就仿了一個。 其實實現3D效果挺簡單的,就是Camera的應用。Android的SDK自帶的sampl

android:3D垂直翻轉動畫-FlipAnimation

lns sta art tco car flat 2015年 imp 聯盟 需求 對ImageView進行相似於翻紙牌的動畫 解決 各種Animator的組合 第一步動畫: 動畫代碼文件1,card_flip_left_out.xml

使用純CSS3實現一個3D旋轉的書本

tom data -m 過去 截取 ood post clas kit 有一些前沿的電商站點已經開始使用3D模型來展示商品並支持在線定制,而當中圖書的展示是最為簡單的一種,無需復雜的建模過程,使用圖片和CSS3的一些變換就可

手機端3d旋轉木馬效果+保存圖片到本地

偏移 旋轉木馬 ndb AC fun AI tee com select <!DOCTYPE html> <html> <head> <title></title> <meta charse

WPF中3D旋轉的實現

css sca nba .com rac trac axis double wpf 原文:WPF中3D旋轉的實現 關於3D旋轉的原理,請看Daniel Lehenbauer的文章

Android bitmap旋轉、平移簡單幾何變換很方便

1.順時針旋轉90度 byte[] tmp = os.toByteArray(); Bitmap bmpt = BitmapFactory.decodeByteArray(tmp, 0,tmp.length); Matrix matrix = new Matrix(); matrix

android開發 在layout資料夾下面建資料夾進行xml檔案管理

在android專案比較大的時候,如果不進行分類管理,管理起來比較麻煩。當然也可以通過良好的命名規則進行區分。 1、android開發是不能直接新建資料夾的,需要配置。 2、在app的build.gradle資料夾新增要建資料夾的路徑,例如我要在layout下面新建一個aftersale資料

android螢幕旋轉禁止activity重新載入

android螢幕旋轉時預設會重新載入頁面,使用者體驗較差。 如果要禁止重新載入可以用如下方法: AndroidManifest.xml中對應的activity下增加一項 android:configChanges="orientation|screenSize" <act

jQuery自適應-3D旋轉輪播圖

3D旋轉輪播圖 本例源於(站長之家例項http://sc.chinaz.com/jiaoben/170215391070.htm) 其他相似示例(https://www.cnblogs.com/incredible-x/p/9688333.html) 自己研究重寫了一遍。 一、先寫靜態的初始樣式的cs

3D旋轉立方體

ora ext form gre query reserve transform true down <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <

CABasicAnimation 3D旋轉

//動畫為沿y軸旋轉 let animation = CABasicAnimation(keyPath: "transform.rotation.y") animation.fromValue = 0 animation.toValue =

荔枝派Licheepi nano裸機移植ZLG_GUI和3D旋轉立方體

   一:前言     以前申請到了荔枝派zero,在發了兩個開箱貼後就放在一邊吃灰了。後來又購買了荔枝派nano,刷了幾個教程中的系統之後又放到一邊吃灰了。雖然有屯板子的習慣,卻沒有使用板子的能力。     後來,經過斷斷續續的摸索和