当前位置 : 主页 > 手机开发 > android >

Android转场效果实现示例浅析

来源:互联网 收集:自由互联 发布时间:2023-03-22
目录 前言 Activity跳转动画 共享元素 通过window去实现 总结 前言 又没什么好的思路,还是随便写一些,所以这次就来整点活。 我们都知道Activity的跳转拥有默认的跳转动画,或者把这个
目录
  • 前言
    • Activity跳转动画
    • 共享元素
    • 通过window去实现
  • 总结

    前言

    又没什么好的思路,还是随便写一些,所以这次就来整点活。

    我们都知道Activity的跳转拥有默认的跳转动画,或者把这个默认的动画给取消,就会让跳转的效果让人觉得比较生硬。那我们能不能做出一些比较好的转场效果呢?本篇只介绍实现的思路,而不去深究某个思路的具体实现,因为有些知识点内容太多了,如果深入去看怕是很难一时半会讲明白。

    Activity跳转动画

    Activity是可以设置跳转动画的,有了动画之后,跳转的效果的体验就会比之前好一些。

    我这里先写两个动画,跳转时新页面进入的动画

    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <translate
            android:fromXDelta="100%"
            android:toXDelta="0%"
            android:fromYDelta="0%"
            android:toYDelta="0%"
            android:duration="1000"/>
    </set>
    

    和旧页面退出的动画

    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <translate
            android:fromXDelta="0%"
            android:toXDelta="-100%"
            android:fromYDelta="0%"
            android:toYDelta="0%"
            android:duration="1000"/>
    </set>
    

    然后在跳转时调用方法

    Intent intent = new Intent(TwoActivity.this, ThreeActivity.class);
    startActivity(intent);
    overridePendingTransition(R.anim.activity_start,R.anim.activity_end);
    

    这样就能实现页面切换时的动画效果,但是要有一点需要注意,这个动画一定要合理,因为是动画展示完之后第二个页面才展示,如果你动画的逻辑涉及得不合理,会出现动画结束之后再展示第二个页面这个过程会显得很生硬。

    但是如果仅仅只有页面切换的动画,还是觉得差点意思。这时候就需要发挥自己想象力了。我这里可以用一个自定义View和这个动画进行联动,让他们看起来是一个整体的效果。

    比如我这样写一个View

    <RelativeLayout
        android:id="@+id/btn"
        android:layout_width="120dp"
        android:layout_height="60dp"
        android:background="@drawable/test_start"
        android:layout_alignParentEnd="true"
        android:layout_marginTop="50dp"
        >
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="下一步"
            android:layout_centerInParent="true"
            android:textColor="#ffff"
            />
    </RelativeLayout>
    

    设置一个背景,颜色和第二个页面的颜色相同

    <shape xmlns:android="http://schemas.android.com/apk/res/android">
        <!--背景颜色-->
        <solid android:color="@color/jh_blue" />
        <corners
            android:topLeftRadius="100dp"
            android:bottomLeftRadius="100dp"
            />
    </shape>
    

    最终会展现出这样的效果

    共享元素

    在5.0之后,android提供了共享元素的实现。Material Design刚出来的时候我还没毕业,我觉得现在回去看它的这个思想和一些内容,确实能有一些其它的收获,这个概念的提出确实牛

    共享元素简单来说效果就是你两个页面之间的跳转,设置了共享的元素会做个动画,会让人感觉是这个页面的View做了一个动画移动到另一个页面,体现出现的效果就很好。

    那既然效果好,为什么不普遍使用呢?我觉得有两个原因,第一个是之前不像现在一样基本都是5.0以上的手机,之前要对4.4做适配,然后开发中,没那方面的需求,自然也不会往那个方向去想,甚至都不知道Android有提供这个东西。第二个原因是好用是好用,相对的坑也多。

    可以先看看如何实现,我这里写个简单点的Demo,首先在第一个页面创建一个view

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_horizontal"
        >
        <ImageView
            android:id="@+id/iv_test"
            android:layout_width="90dp"
            android:layout_height="90dp"
            android:layout_marginTop="500dp"
            android:src="@drawable/aaaaa"
            android:transitionName="test"
            />
    </RelativeLayout>
    

    看到这里有个属性transitionName,这个就是定义共享元素,然后在第二个页面也创建一个view

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/blue"
        android:gravity="center_horizontal"
        >
        <ImageView
            android:id="@+id/iv_test"
            android:layout_width="180dp"
            android:layout_height="180dp"
            android:layout_marginTop="20dp"
            android:src="@drawable/aaaaa"
            android:transitionName="test"
            />
    </RelativeLayout>
    

    看到他们的transitionName是一样的,然后在跳转时用ActivityOptions.makeSceneTransitionAnimation就行了,具体的它已经里面帮你封装好了

    ImageView imageView = findViewById(R.id.iv_test);
    imageView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(TwoActivity.this, ThreeActivity.class);
            Bundle bundle = ActivityOptions.makeSceneTransitionAnimation(TwoActivity.this, imageView, "test")
                    .toBundle();
            startActivity(intent, bundle);
        }
    });
    

    就这么简单,其中要注意的是你页面的style如果是用Material的style就没什么问题,但如果不是,你就需要在你的style中设置

    <item name="android:windowActivityTransitions">true</item>
    

    当然也可以在代码中动态设置

    getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
    

    最终的效果就是这样的

    这个动画效果是默认的,如果你要自己实现,就需要自己去写transition,比如我这里这样设置时间

    <fade xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="300"
        />
    
    <style name="test_style" parent="android:Theme.NoTitleBar.Fullscreen">
        <item name="android:windowActivityTransitions">true</item>
        <item name="android:windowEnterTransition">@transition/activity_fade</item>
        <item name="android:windowExitTransition">@transition/activity_fade</item>
    </style>
    

    它其实功能很庞大,同样的坑也会很多。我这里就不往下说了,前面也说了,这篇文章主要是写个思路,你要是能把它玩好了,就和自定义view一样,属性动画一样,想实现什么效果,就实现什么效果,我也不常用,对这个技术点也只是入门。

    通过window去实现

    这个思路是在activity上方有个图层,图层中有个view和下方图层的view的大小和位置相同,然后去改上图层的view。此时如果下图层做跳转,也不会影响,就是能实现和上面共享元素一样的效果。但是我以前用的window是系统级别的window,所以能实现效果,其它级别的不知道会不会有问题,得开发时候具体调试才知道,总之主要看思路,先不用在意细节。

    还是用一个Demo来举例,先写Activity的页面,两个textview是用做标识看效果的

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_horizontal"
        >
        <ImageView
            android:id="@+id/iv_test"
            android:layout_width="90dp"
            android:layout_height="90dp"
            android:layout_marginTop="500dp"
            android:src="@drawable/aaaaa"
            />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="在图片上方"
            android:layout_marginTop="480dp"
            />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="在图片下方"
            android:layout_below="@+id/iv_test"
            />
    </RelativeLayout>
    

    再写window的布局

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_horizontal"
        >
        <ImageView
            android:id="@+id/iv_test"
            android:layout_width="90dp"
            android:layout_height="90dp"
            android:layout_marginTop="500dp"
            android:src="@drawable/aaaaa"
            />
    </RelativeLayout>
    

    可以看到两个view的初始位置和大小都相同,然后看看具体的实现

    public class TwoActivity extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.test_two);
            ImageView imageView = findViewById(R.id.iv_test);
            imageView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    playWindow();
                }
            });
        }
        private void playWindow() {
            RelativeLayout relativeLayout = (RelativeLayout) LayoutInflater.from(this).inflate(R.layout.test_window, null);
            View windowView = relativeLayout.findViewById(R.id.iv_test);
            WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
            WindowManager.LayoutParams wlp = new WindowManager.LayoutParams(WindowManager.LayoutParams.MATCH_PARENT,
                    WindowManager.LayoutParams.MATCH_PARENT,
                    WindowManager.LayoutParams.TYPE_APPLICATION,
                    WindowManager.LayoutParams.FLAG_FULLSCREEN
                    , PixelFormat.RGBA_8888);
            windowManager.addView(relativeLayout, wlp);
            windowView.post(new Runnable() {
                @Override
                public void run() {
                    start(windowView);
                }
            });
        }
        private void start(final View view) {
            int w = view.getWidth();
            int h = view.getHeight();
            ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 300);
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    int v = (int) animation.getAnimatedValue();
                    RelativeLayout.LayoutParams rlp = (RelativeLayout.LayoutParams) view.getLayoutParams();
                    rlp.width = w + v;
                    rlp.height = h + v;
                    view.setLayoutParams(rlp);
                    view.invalidate();
                }
            });
            valueAnimator.setDuration(700).start();
        }
    }
    

    demo里面我为了方便用了TYPE_APPLICATION,但实际我这边开发用的是FIRST_SYSTEM_WINDOW以上的系统层级弹窗。

    然后我们来看看最终的效果

    这里是做了个放大的效果,但实际你可以放大后跳转Activity然后移动位置,再缩小,就有无缝转场的效果,其实和上面的共享元素的效果类似。

    总结

    能实现转场的方式很多,不用拘束于调用原生的方法,比如如果真依赖原生提供的方法,要是真要适配5.0以下的怎么做?最重要的是要发挥自己的想象力,去思考。当然,这个原生提供的系统确实也有很多学问在里边,想要玩得炉火纯青,也是需要不断的去尝试,不断的去踩坑。

    以上就是Android转场效果实现示例浅析的详细内容,更多关于Android转场效果的资料请关注自由互联其它相关文章!

    上一篇:Android ButterKnife依赖注入框架使用教程
    下一篇:没有了
    网友评论