目錄
效果展示
關(guān)鍵知識(shí)點(diǎn)
這個(gè)3D翻轉(zhuǎn)效果的核心其實(shí)就是Rotate3DAnimation這個(gè)自定義的Animation類
public class Rotate3DAnimation extends Animation {
private int mCenterX,mCenterY;
private Camera mCamera;
private float mFromDegrees,mToDegrees;
private AnimationUpdateListener updateListener;
private int mWidth;
public AnimationUpdateListener getUpdateListener() {
return updateListener;
}
public void setUpdateListener(AnimationUpdateListener updateListener) {
this.updateListener = updateListener;
}
public Rotate3DAnimation(float mFromDegrees, float mToDegrees) {
this.mFromDegrees = mFromDegrees;
this.mToDegrees = mToDegrees;
}
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
mWidth = width;
mCenterX = width / 2;
mCenterY = height / 2;
mCamera = new Camera();
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
float degress = mFromDegrees + (interpolatedTime * (mToDegrees - mFromDegrees));
if(updateListener != null){
updateListener.onProgressUpdate(interpolatedTime,degress);
}
Matrix matrix = t.getMatrix();
mCamera.save();
//讓旋轉(zhuǎn)90度的時(shí)候不顯的太大
if(interpolatedTime >= 0.5){
mCamera.translate(0,0,(Math.abs(interpolatedTime - 1) / 0.5f) * mWidth / 2);
}else {
mCamera.translate(0,0,(interpolatedTime / 0.5f) * mWidth / 2);
}
//圖形繞Y軸旋轉(zhuǎn)
mCamera.rotateY(degress);
mCamera.getMatrix(matrix);
//將原點(diǎn)移動(dòng)到中心處
matrix.preTranslate(-mCenterX,-mCenterY);
matrix.postTranslate(mCenterX,mCenterY);
mCamera.restore();
super.applyTransformation(interpolatedTime, t);
}
/**
* 動(dòng)畫(huà)更新的回調(diào)
*/
public interface AnimationUpdateListener{
/**
* 進(jìn)度回調(diào)
*/
void onProgressUpdate(float progress,float value);
}
}
我們這里主要是通過(guò)對(duì)android.graphics.Camera的操作來(lái)實(shí)現(xiàn)3D的變化,Camera的坐標(biāo)系為三維左手坐標(biāo)系双吆,因此我們可以通過(guò)操作它來(lái)實(shí)現(xiàn)一些3D的效果
接下來(lái)我對(duì)各段代碼進(jìn)行詳細(xì)說(shuō)明觉痛。
下面這段代碼是為了防止當(dāng)圖像旋轉(zhuǎn)到90度的時(shí)候,圖像的側(cè)面剛好朝著我們導(dǎo)致看起來(lái)過(guò)大的問(wèn)題眷篇,因此我們需要將圖像沿著Z軸移動(dòng)一下例诀,就相當(dāng)于一輛車從你身后往前開(kāi)你會(huì)感覺(jué)車越來(lái)越小一個(gè)道理朽肥。
//讓旋轉(zhuǎn)90度的時(shí)候不顯的太大
if(interpolatedTime >= 0.5){
mCamera.translate(0,0,(Math.abs(interpolatedTime - 1) / 0.5f) * mWidth / 2);
}else {
mCamera.translate(0,0,(interpolatedTime / 0.5f) * mWidth / 2);
}
下面這段代碼是實(shí)現(xiàn)了圖像旋轉(zhuǎn)
//圖形繞Y軸旋轉(zhuǎn)
mCamera.rotateY(degress);
下面這段代碼是為了將原點(diǎn)移動(dòng)到圖像的中心點(diǎn)
//將原點(diǎn)移動(dòng)到中心處
matrix.preTranslate(-mCenterX,-mCenterY);
matrix.postTranslate(mCenterX,mCenterY);
如果不將圖像移動(dòng)到中心點(diǎn)則圖像會(huì)沿著圖像的左邊旋轉(zhuǎn)如下
這里還有一點(diǎn)要注意的是菇民,我們需要將旋轉(zhuǎn)后展示的頁(yè)面(效果圖的反面)提前先反轉(zhuǎn)尽楔,這樣在旋轉(zhuǎn)后展示反面的時(shí)候就不會(huì)出現(xiàn)展示鏡像的問(wèn)題了,這里我通過(guò)繼承FrameLayout并在dispatchDraw增加如下邏輯來(lái)實(shí)現(xiàn)的
@Override
protected void dispatchDraw(Canvas canvas) {
//將整個(gè)頁(yè)面水平翻轉(zhuǎn)第练,目的是為了抵消外布局翻轉(zhuǎn)后的左右倒置現(xiàn)象
mCamera.save();
canvas.save();
//鏡像反轉(zhuǎn)
mCamera.rotateY(180);
Matrix matrix = new Matrix();
mCamera.getMatrix(matrix);
matrix.preTranslate(-getWidth()/2,-getHeight()/2);
matrix.postTranslate(getWidth()/2,getHeight()/2);
canvas.setMatrix(matrix);
mCamera.restore();
super.dispatchDraw(canvas);
canvas.restore();
}
3D翻轉(zhuǎn)控件的使用方法
Rotate3DLayout內(nèi)必需包含DefaultLayout(默認(rèn)展示的頁(yè)面)和ReverseLayout(翻轉(zhuǎn)后展示的頁(yè)面)阔馋,然后以在DefaultLayout和ReverseLayout中進(jìn)行自己的布局即可
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/bt_rotate"
android:text="3D旋轉(zhuǎn)"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<com.example.rotate3dlayout.widget.Rotate3DLayout
android:id="@+id/rl_rotate"
android:background="@drawable/shape_bg"
android:padding="10dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:layout_width="300dp"
android:layout_height="400dp">
<com.example.rotate3dlayout.widget.DefaultLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="vertical"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:text="我是正面"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:text="我是正面"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText
android:hint="我是正面"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</com.example.rotate3dlayout.widget.DefaultLayout>
<com.example.rotate3dlayout.widget.ReverseLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="vertical"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:text="我是反面"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:text="我是反面"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText
android:hint="我是反面"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</com.example.rotate3dlayout.widget.ReverseLayout>
</com.example.rotate3dlayout.widget.Rotate3DLayout>
</LinearLayout>
通過(guò)rotate3D方法即可實(shí)現(xiàn)翻轉(zhuǎn)
public class MainActivity extends AppCompatActivity {
private Button btRotate;
private Rotate3DLayout rlRotate;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btRotate = (Button) findViewById(R.id.bt_rotate);
rlRotate = (Rotate3DLayout) findViewById(R.id.rl_rotate);
//點(diǎn)擊后翻轉(zhuǎn)
btRotate.setOnClickListener(v->rlRotate.rotate3D());
}
}