【Android初级】如何实现一个比相册更高大上的左右滑动特效(附源码)

在Android里面,想要实现一个类似相册的左右滑动效果,我们除了可以用Gallery、HorizontalScrollView、ViewPager等控件,还可以用一个叫做 ViewFlipper 的类来代替实现,它继承于 ViewAnimator。如见其名,这个类是跟动画有关,会将添加到它里面的两个或者多个View做一个动画,然后每次只显示一个子View,通过在 View 之间切换时执行动画,最终达到一个类似相册能左右滑动的效果。

本次功能要实现的两个基本效果

  1. 最基本的左右滑动效果
  2. 从屏幕的45度方向进入和退出的效果

实现思路

  1. 按照 ViewFlipper 的源码说明,它是将两个或多个View用动画展示出来。那么我就在 ViewFlipper 内放入两个布局,每个布局都包含一个 TextView 和 ImageView,分别用于显示文字和图片
  2. 既然要有动画效果,我准备使用Android的位移动画类 TranslateAnimation,设置起始的横纵坐标值
  3. 为了让效果明显,我会设置 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)。大家可以按照这个思路去实现自己想要的动效。

欢迎交流~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,192评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,186评论 1 303
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,844评论 0 252
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,471评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,876评论 3 294
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,891评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,068评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,791评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,539评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,772评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,250评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,577评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,244评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,146评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,949评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,995评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,812评论 2 276

推荐阅读更多精彩内容

  • 前言 自定义View作为Android进阶的基础,是我们开发者不得不学习的知识,而酷炫的自定义View效果,都离不...
    maoqitian阅读 1,552评论 0 6
  • 动画基础概念 动画分类 Android 中动画分为两种,一种是 Tween 动画、还有一种是 Frame 动画。 ...
    Rtia阅读 1,142评论 0 6
  • 【Android 动画】 动画分类补间动画(Tween动画)帧动画(Frame 动画)属性动画(Property ...
    Rtia阅读 5,971评论 1 38
  • 补间动画有四种,分别是淡入淡出(Alpha),旋转(Rotate),移动(Translate),缩放(Scale)...
    疯子一般的勇士阅读 352评论 0 0
  • 推荐指数: 6.0 书籍主旨关键词:特权、焦点、注意力、语言联想、情景联想 观点: 1.统计学现在叫数据分析,社会...
    Jenaral阅读 5,661评论 0 5