在Android裡面,想要實現一個類似相簿的左右滑動效果,我們除了可以用Gallery、HorizontalScrollView、ViewPager等控制元件,還可以用一個叫做 ViewFlipper 的類來代替實現,它繼承於 ViewAnimator。如見其名,這個類是跟動畫有關,會將新增到它裡面的兩個或者多個View做一個動畫,然後每次只顯示一個子View,通過在 View 之間切換時執行動畫,最終達到一個類似相簿能左右滑動的效果。
本次功能要實現的兩個基本效果
- 最基本的左右滑動效果
- 從螢幕的45度方向進入和退出的效果
實現思路
- 按照 ViewFlipper 的原始碼說明,它是將兩個或多個View用動畫展示出來。那麼我就在 ViewFlipper 內放入兩個佈局,每個佈局都包含一個 TextView 和 ImageView,分別用於顯示文字和圖片
- 既然要有動畫效果,我準備使用Android的位移動畫類 TranslateAnimation,設定起始的橫縱座標值
- 為了讓效果明顯,我會設定 ViewFlipper 的進入和退出螢幕的動畫,並且在左滑時呈現一個動畫、右滑時呈現另一個動畫(需要判斷是左滑還是右滑:重寫 onTouchEvent 方法,比較橫座標X的值的變化)
原始碼如下:
1、主Activity
// import語句省略
public class ViewFlipperDemo extends Activity {
private static final String TAG = "ViewFlipperDemo";
private ViewFlipper mViewFlipper;
private float mOldTouchValue;
@Override
protected void onCreate(Bundle onSavedInstance) {
super.onCreate(onSavedInstance);
// 設定為全屏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.view_flipper_demo);
mViewFlipper = findViewById(R.id.viewFlipper1);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mOldTouchValue = event.getX();
break;
case MotionEvent.ACTION_UP:
float currentX = event.getX();
// 手指向右滑動: 手指向右滑動時橫座標 X 的值會變大,因此 currentX 的值更大
if (mOldTouchValue < currentX) {
// 進入螢幕的動效
mViewFlipper.setInAnimation(AnimationHelper.inFromLeftAnimation());
// 退出螢幕的動效
mViewFlipper.setOutAnimation(AnimationHelper.outToRightAnimation());
mViewFlipper.showNext();
}
// 橫座標的值變小,說明是左滑
if (mOldTouchValue > currentX) {
// 進入螢幕的動效
mViewFlipper.setInAnimation(AnimationHelper.inFromRightAnimation());
// 退出螢幕的動效
mViewFlipper.setOutAnimation(AnimationHelper.outToLeftAnimation());
mViewFlipper.showPrevious();
}
break;
default:
break;
}
return super.onTouchEvent(event);
}
}
2、對應的佈局檔案 view_flipper_demo.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/colorBlack"
android:gravity="center"
android:text="這是一個ViewFlipper樣例"
android:paddingTop="20dp"/>
<ViewFlipper android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/viewFlipper1">
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<TextView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/colorBlue"
android:gravity="center"
android:text="這是第一個ViewFlipper頁面"/>
<ImageView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/avasterdr"/>
</LinearLayout>
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center" >
<TextView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/colorBlue"
android:gravity="center"
android:text="這是第二個ViewFlipper頁面"/>
<ImageView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/avastertony"/>
</LinearLayout>
</ViewFlipper>
</LinearLayout>
3、動畫輔助類 AnimationHelper.java
public class AnimationHelper {
// 左滑的進入動畫
public static Animation inFromRightAnimation() {
Animation inFromRight = new TranslateAnimation(
Animation.RELATIVE_TO_PARENT,
1.0f,
Animation.RELATIVE_TO_PARENT,
0.0f,
Animation.RELATIVE_TO_PARENT,
0.0f,
Animation.RELATIVE_TO_PARENT,
0.0f);
inFromRight.setDuration(500);
inFromRight.setInterpolator(new AccelerateInterpolator());
return inFromRight;
}
// 左滑的退出動畫
public static Animation outToLeftAnimation() {
Animation outToLeft = new TranslateAnimation(
Animation.RELATIVE_TO_PARENT,
0.0f,
Animation.RELATIVE_TO_PARENT,
-1.0f,
Animation.RELATIVE_TO_PARENT,
0.0f,
Animation.RELATIVE_TO_PARENT,
0.0f);
outToLeft.setDuration(500);
outToLeft.setInterpolator(new AccelerateInterpolator());
return outToLeft;
}
// 右滑的進入動畫
public static Animation inFromLeftAnimation() {
Animation inFromLeft = new TranslateAnimation(
Animation.RELATIVE_TO_PARENT,
-1.0f,
Animation.RELATIVE_TO_PARENT,
0.0f,
Animation.RELATIVE_TO_PARENT,
0.0f,
Animation.RELATIVE_TO_PARENT,
0.0f);
inFromLeft.setDuration(500);
inFromLeft.setInterpolator(new AccelerateInterpolator());
return inFromLeft;
}
// 右滑的退出動畫
public static Animation outToRightAnimation() {
Animation outToRight = new TranslateAnimation(
Animation.RELATIVE_TO_PARENT,
0.0f,
Animation.RELATIVE_TO_PARENT,
1.0f,
Animation.RELATIVE_TO_PARENT,
0.0f,
Animation.RELATIVE_TO_PARENT,
0.0f);
outToRight.setDuration(500);
outToRight.setInterpolator(new AccelerateInterpolator());
return outToRight;
}
}
4、對應的效果圖如下
可以看到,這個左右滑動效果沒有任何酷炫的地方。我們不妨先來看看跟動畫相關的幾個重點地方:
(1)函式 setInAnimation:是指 View 進入螢幕的動效
(2)函式 setOutAnimation:是指 View 退出螢幕的動效
(3)TranslateAnimation的建構函式的引數解釋:
1、fromXType/toXType/fromYType/toYType,取值共有三個:
- Animation.ABSOLUTE
- Animation.RELATIVE_TO_SELF
- Animation.RELATIVE_TO_PARENT
我這裡用的是 Animation.RELATIVE_TO_PARENT,當傳入該引數時,其餘幾個座標值需要傳入百分比引數(1.0表示100%);如果傳入 Animation.ABSOLUTE,座標值需要傳入螢幕上的絕對位置(比如1000,1000)
2、fromXValue:起點的橫座標值
3、toXValue:終點的橫座標值
4、fromYValue:起點的縱座標值
5、toYValue:終點的縱座標值
如果我們想讓這個效果變成45度從螢幕的四個角進入和退出,那程式碼就應該這麼寫(注意程式碼中傳入的 4 個橫縱座標值):
// 左滑的進入動畫
public static Animation inFromRightAnimation() {
Animation inFromRight = new TranslateAnimation(
Animation.RELATIVE_TO_PARENT,
1.0f,
Animation.RELATIVE_TO_PARENT,
0.0f,
Animation.RELATIVE_TO_PARENT,
-1.0f,
Animation.RELATIVE_TO_PARENT,
0.0f);
inFromRight.setDuration(500);
inFromRight.setInterpolator(new AccelerateInterpolator());
return inFromRight;
}
// 左滑的退出動畫
public static Animation outToLeftAnimation() {
Animation outToLeft = new TranslateAnimation(
Animation.RELATIVE_TO_PARENT,
0.0f,
Animation.RELATIVE_TO_PARENT,
-1.0f,
Animation.RELATIVE_TO_PARENT,
0.0f,
Animation.RELATIVE_TO_PARENT,
1.0f);
outToLeft.setDuration(500);
outToLeft.setInterpolator(new AccelerateInterpolator());
return outToLeft;
}
// 右滑的進入動畫
public static Animation inFromLeftAnimation() {
Animation inFromLeft = new TranslateAnimation(
Animation.RELATIVE_TO_PARENT,
-1.0f,
Animation.RELATIVE_TO_PARENT,
0.0f,
Animation.RELATIVE_TO_PARENT,
-1.0f,
Animation.RELATIVE_TO_PARENT,
0.0f);
inFromLeft.setDuration(500);
inFromLeft.setInterpolator(new AccelerateInterpolator());
return inFromLeft;
}
// 右滑的退出動畫
public static Animation outToRightAnimation() {
Animation outToRight = new TranslateAnimation(
Animation.RELATIVE_TO_PARENT,
0.0f,
Animation.RELATIVE_TO_PARENT,
1.0f,
Animation.RELATIVE_TO_PARENT,
0.0f,
Animation.RELATIVE_TO_PARENT,
1.0f);
outToRight.setDuration(500);
outToRight.setInterpolator(new AccelerateInterpolator());
return outToRight;
}
對應的效果如下:
之所以有 -1.0f 這個值,是因為螢幕上的橫縱座標值的分佈可以用如下象限來表示:
ViewFlipper中的 View 就位於象限的中心位置。因此,如果動畫從左上角進入,那麼它的起始橫縱座標就是(-1,-1)。大家可以按照這個思路去實現自己想要的動效。
歡迎交流~