基于Android實(shí)現(xiàn)3D翻頁效果
最近做了一個簡單的3D效果翻頁特效,先說說我的思路吧,首先我這個翻頁效果并不是兩個Activity之間的跳轉(zhuǎn),而是在同一個activity類切換不同的view而已。我現(xiàn)在的做法是單擊一個button然后Gone當(dāng)前的布局,然后把需要呈現(xiàn)的布局visible,在隱藏當(dāng)前布局的時候啟動動畫,然后給動畫添加監(jiān)聽,在動畫結(jié)束時開始另外一個view的入場動畫就行了。
下面來看下我的主頁面的布局文件:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/container" android:layout_width="fill_parent" android:layout_height="fill_parent" > <include android:layout_width="fill_parent" android:layout_height="fill_parent" layout="@layout/layout2" /> <include android:layout_width="fill_parent" android:layout_height="fill_parent" layout="@layout/layout1" /> </FrameLayout>
我這個布局文件使用<include>標(biāo)簽包含了另外2個布局文件,這些布局文件才是呈現(xiàn)數(shù)據(jù)的,下面是另外2個布局文件:
layout1:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/test1" android:orientation="vertical" android:id="@+id/container1" > <Button android:id="@+id/bt_towhile" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="白色" /> </LinearLayout>
layout2:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/container2" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/test2" android:orientation="vertical" > <Button android:id="@+id/bt_toblack" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="黑色" /> </LinearLayout>
我這里只是舉個例子并沒有放什么實(shí)際的類容,只是放了2個button,當(dāng)我點(diǎn)擊其中一個跳轉(zhuǎn)到另外一個layout。
有了布局文件那我們就開始要實(shí)現(xiàn)功能了,我們的想法是點(diǎn)擊按鈕的時候開始一個動畫等動畫結(jié)束時再開啟另外一個動畫并隱藏和展示layout1和layout2。
下面是我寫的一個動畫工具類源碼:
package com.test.view;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
public class RotateAnimationUtil {
private ViewGroup context;
private View[] views;
public RotateAnimationUtil(ViewGroup context, View... views) {
super();
this.context = context;
this.views = views;
}
/**
* 應(yīng)用自定義的Rotate3DAnimation動畫
*
* @param flag
* 當(dāng)前控件的順序坐標(biāo)
* @param startDegress
* 開始的角度
* @param endDegress
* 結(jié)束的角度
*/
public void applyRotateAnimation(int flag, float startDegress,
float endDegress) {
final float centerX = context.getWidth() / 2.0f;
final float centerY = context.getHeight() / 2.0f;
Rotate3DAnimation rotate = new Rotate3DAnimation(startDegress,
endDegress, centerX, centerY, 310.0f, true);
rotate.setDuration(1000);
rotate.setFillAfter(false);
rotate.setInterpolator(new DecelerateInterpolator());
rotate.setAnimationListener(new DisplayNextView(flag));
context.startAnimation(rotate);
}
private final class DisplayNextView implements Animation.AnimationListener {
private final int mFlag;
private DisplayNextView(int flag) {
mFlag = flag;
}
public void onAnimationStart(Animation animation) {
}
// 動畫結(jié)束
public void onAnimationEnd(Animation animation) {
context.post(new SwapViews(mFlag));
}
public void onAnimationRepeat(Animation animation) {
}
}
/**
* 新開一個線程動畫結(jié)束后再開始一次動畫效果實(shí)現(xiàn)翻屏特效
*
* @author yangzhiqiang
*
*/
private final class SwapViews implements Runnable {
private final int mFlag;
public SwapViews(int mFlag) {
this.mFlag = mFlag;
}
public void run() {
final float centerX = context.getWidth() / 2.0f;
final float centerY = context.getHeight() / 2.0f;
Rotate3DAnimation rotation;
if (mFlag > -1) {
views[0].setVisibility(View.GONE);
views[1].setVisibility(View.VISIBLE);
views[1].requestFocus();
rotation = new Rotate3DAnimation(270, 360, centerX, centerY,
310.0f, false);
} else {
views[1].setVisibility(View.GONE);
views[0].setVisibility(View.VISIBLE);
views[0].requestFocus();
rotation = new Rotate3DAnimation(90, 0, centerX, centerY,
310.0f, false);
}
rotation.setDuration(1000);
rotation.setFillAfter(false);
rotation.setInterpolator(new DecelerateInterpolator());
// 開始動畫
context.startAnimation(rotation);
}
}
}
解釋一下這個類的構(gòu)造方法:
public RotateAnimationUtil(ViewGroup context, View... views) {
super();
this.context = context;
this.views = views;
}
有2個參數(shù),第一個參數(shù)就是我們的主布局頁面的FrameLayout,第2個參數(shù)就是我們要進(jìn)行動畫切換的2個子layout,我這使用的是一個可變長參數(shù)只是為了方便而已。
public void applyRotateAnimation(int flag, float startDegress,float endDegress)方法第一個參數(shù)是標(biāo)記當(dāng)前是第是從哪個個layout跳轉(zhuǎn),因外我們必須知道當(dāng)前開始跳轉(zhuǎn)的layout才能推算角度。
下面是我自定義動畫的源碼:
package com.test.view;
import android.graphics.Camera;
import android.graphics.Matrix;
import android.view.animation.Animation;
import android.view.animation.Transformation;
public class Rotate3DAnimation extends Animation {
private final float mFormDegress;
private final float mToDegress;
private final float mCenterX;
private final float mCenterY;
/**
* 控制z軸的一個常量值,主要是控制動畫的升降距離
*/
private final float mDepthz;
/**
* 控制z軸是像上移動還是向下移動,從而實(shí)現(xiàn)升降效果
*/
private final boolean mReverse;
private Camera mCamera;
public Rotate3DAnimation(float formDegress, float toDegress, float centerX,
float centerY, float depthz, boolean reverse) {
super();
this.mFormDegress = formDegress;
this.mToDegress = toDegress;
this.mCenterX = centerX;
this.mCenterY = centerY;
this.mDepthz = depthz;
this.mReverse = reverse;
}
@Override
public void initialize(int width, int height, int parentWidth,
int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
mCamera = new Camera();
}
/**
* interpolatedTime 取值范圍是0-1之間當(dāng)每次,當(dāng)動畫啟動后會系統(tǒng)會不停的調(diào)用applyTransformation方法,
* 并改變interpolatedTime的值
*/
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
final float formDegress = mFormDegress;
// 通過差點(diǎn)值計(jì)算出轉(zhuǎn)變的角度
float degress = formDegress
+ ((mToDegress - formDegress) * interpolatedTime);
final float centerX = mCenterX;
final float centerY = mCenterY;
final Camera camera = mCamera;
// 得到當(dāng)前矩陣
Matrix matrix = t.getMatrix();
// 報錯當(dāng)前屏幕的狀態(tài)
camera.save();
// 判斷是降還是升
if (mReverse) {
// 正向改變Z軸角度
camera.translate(0.0f, 0.0f, mDepthz * interpolatedTime);
} else {
// 反向改變Z軸角度
camera.translate(0.0f, 0.0f, mDepthz * (1.0f - interpolatedTime));
}
// 旋轉(zhuǎn)Y軸角度
camera.rotateY(degress);
// 把當(dāng)前改變后的矩陣信息復(fù)制給Transformation的Matrix
camera.getMatrix(matrix);
// 根據(jù)改變后的矩陣信息從新恢復(fù)屏幕
camera.restore();
// 讓動畫在屏幕中間運(yùn)行
matrix.preTranslate(-centerX, -centerY);
matrix.postTranslate(centerX, centerY);
}
}
如果你不需要沉降效果那么你把下面的代碼刪除掉即可:
if (mReverse) {
// 正向改變Z軸角度
camera.translate(0.0f, 0.0f, mDepthz * interpolatedTime);
} else {
// 反向改變Z軸角度
camera.translate(0.0f, 0.0f, mDepthz * (1.0f - interpolatedTime));
}
好了核心代碼已經(jīng)上完,下面是主界面代碼:
package com.test.rotateanimation;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import com.test.view.RotateAnimationUtil;
public class MainActivity extends Activity {
private FrameLayout container;
private LinearLayout container1;
private LinearLayout container2;
private RotateAnimationUtil rotateAnimationUtil;
private Button bt_towhile;
private Button bt_toblack;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
bt_towhile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
rotateAnimationUtil.applyRotateAnimation(1, 0, 90);
}
});
bt_toblack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
rotateAnimationUtil.applyRotateAnimation(-1, 0, -90);
}
});
// 設(shè)置當(dāng)前View控件的緩存
container
.setPersistentDrawingCache(ViewGroup.PERSISTENT_ANIMATION_CACHE);
}
private void initView() {
container = (FrameLayout) findViewById(R.id.container);
bt_toblack = (Button) findViewById(R.id.bt_toblack);
bt_towhile = (Button) findViewById(R.id.bt_towhile);
container1 = (LinearLayout) findViewById(R.id.container1);
container2 = (LinearLayout) findViewById(R.id.container2);
rotateAnimationUtil = new RotateAnimationUtil(container, container1,
container2);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
下面是運(yùn)行效果,剪切效果不好,呵呵.




源碼下載:http://xiazai.jb51.net/201606/yuanma/RotateAnimation(jb51.net).rar
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- android中圖片翻頁效果簡單的實(shí)現(xiàn)方法
- 解析Android中實(shí)現(xiàn)滑動翻頁之ViewFlipper的使用詳解
- Android實(shí)現(xiàn)閱讀APP平移翻頁效果
- Android自定義左右或上下滑動翻頁效果
- Android自定義ViewPager實(shí)現(xiàn)縱向滑動翻頁效果
- Android?ViewPager實(shí)現(xiàn)左右滑動翻頁效果
- android ViewPager實(shí)現(xiàn)滑動翻頁效果實(shí)例代碼
- Android 仿日歷翻頁、仿htc時鐘翻頁、數(shù)字翻頁切換效果
- Android CardView+ViewPager實(shí)現(xiàn)ViewPager翻頁動畫的方法
- Android實(shí)現(xiàn)翻頁特效
相關(guān)文章
關(guān)于Android輸入法彈窗bug的優(yōu)雅處理
在Android應(yīng)用中,當(dāng)跳轉(zhuǎn)到某個Activity時,該Activity顯示頁面的EditText獲得焦點(diǎn),在某些機(jī)器中會觸發(fā)軟鍵盤的自動彈出,這篇文章主要給大家介紹了關(guān)于Android輸入法彈窗bug的優(yōu)雅處理,需要的朋友可以參考下2021-10-10
Android中訪問證書有問題的SSL網(wǎng)頁的方法
在WebView里加載SSL網(wǎng)頁很正常,也沒什么難度。但如果要加載的SSL頁面的證書有問題,比如過期、信息不正確、發(fā)行機(jī)關(guān)不被信任等,WebView就會拒絕加載該網(wǎng)頁2014-04-04
Android使用Retrofit實(shí)現(xiàn)自定義Converter解析接口流程詳解
Retrofit是一個RESTful的HTTP網(wǎng)絡(luò)請求框架的封裝,網(wǎng)絡(luò)請求的工作本質(zhì)上是OkHttp完成,而Retrofit僅負(fù)責(zé)網(wǎng)絡(luò)請求接口的封裝2023-03-03
Android自定義谷歌風(fēng)格ProgressBar
這篇文章主要為大家詳細(xì)介紹了Android自定義谷歌風(fēng)格ProgressBar的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-02-02
Android DragVideo實(shí)現(xiàn)播放視頻時任意拖拽的方法
這篇文章主要介紹了Android DragVideo實(shí)現(xiàn)播放視頻時任意拖拽的方法的相關(guān)資料,一種在播放視頻時,能夠拖拽的方案,需要的朋友可以參考下2016-12-12
Android 自定義view模板并實(shí)現(xiàn)點(diǎn)擊事件的回調(diào)
這篇文章主要介紹了Android 自定義view模板并實(shí)現(xiàn)點(diǎn)擊事件的回調(diào)的相關(guān)資料,需要的朋友可以參考下2017-01-01

