如何用MotionLayout实现王者荣耀团战效果

发布时间:2021-10-27 11:22:44 作者:iii
来源:亿速云 阅读:176

本篇内容介绍了“如何用MotionLayout实现王者荣耀团战效果”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

动画效果

如何用MotionLayout实现王者荣耀团战效果    

功能详解

“  

MotionLayout 是一种布局类型,可帮助您管理应用中的运动和微件动画。MotionLayout 是 ConstraintLayout 的子类,在其丰富的布局功能基础之上构建而成。

”  

如上述介绍,MotionLayoutConstraintLayout的子类,相当于加了动画功能的ConstraintLayout。MotionLayout作为一个动画控件的好处就在于基本不用写java代码,全部在xml文件中搞定。而且我们只需要设定起始位置,结束位置以及一些中间状态,就能自动生成动画。

先分析下我们的团战,主要分为三个场景:

    场景一

包含控件:后羿,亚瑟,鲁班,后羿的箭动画描述:走位的亚瑟,后羿射箭

首先在布局文件中,添加第一个MotionLayout,并添加上所有的控件,后羿和鲁班由于是静止状态,所以要写上位置约束,其他包含动画的控件可以暂时不用写位置约束:

    <androidx.constraintlayout.motion.widget.MotionLayout
        android:id="@+id/motionLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutDescription="@xml/scene_01"
        app:showPaths="false"
        tools:showPaths="true">

        <ImageView
            android:id="@+id/houyi"
            android:layout_width="66dp"
            android:layout_height="66dp"
            android:layout_marginLeft="180dp"
            android:src="@drawable/houyi_model"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.8" />

        <ImageView
            android:id="@+id/houyi_arrow"
            android:layout_width="66dp"
            android:layout_height="66dp"
            android:src="@drawable/arrow" />

        <ImageView
            android:id="@+id/yase"
            android:layout_width="66dp"
            android:layout_height="66dp"
            android:src="@drawable/yase_model" />

        <ImageView
            android:id="@+id/luban"
            android:layout_width="66dp"
            android:layout_height="66dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.58"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.26"
            android:src="@drawable/luban_model" />

    </androidx.constraintlayout.motion.widget.MotionLayout>
 

由于MotionLayout继承自ConstraintLayout,所以可以用ConstraintLayout的属性。这里可以看到有两个新的属性:

后羿射箭

接下来就可以写动画场景(MotionScene)了,新建res-xml-scene_01.xml。

<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <Transition
        app:constraintSetEnd="@+id/end"
        app:constraintSetStart="@+id/start"
        app:duration="2000">

    </Transition>

    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@+id/houyi_arrow"
            android:layout_width="66dp"
            android:layout_height="66dp"
            android:layout_marginLeft="190dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.8">

        </Constraint>
    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@+id/houyi_arrow"
            android:layout_width="66dp"
            android:layout_height="66dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.65"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.35">
        </Constraint>
    </ConstraintSet>

</MotionScene>

 

可以看到,MotionScene有两个主要的标签TransitionConstraintSet

其中Constraint属性指定了端点位置中某一个元素的位置和属性:

    <Constraint
        android:id="@+id/button" ...>
        <CustomAttribute
            motion:attributeName="backgroundColor"
            motion:customColorValue="#D81B60"/>
    </Constraint>
   
 

attributeName属性就是与具有gettersetter方法的对象匹配,比如这里的backgroundColor就对应了view本身的基本方法getBackgroundColor()setBackgroundColor()

好了,回到后裔这边,由于后羿的箭是从后羿位置到亚瑟位置,所以我们设定好后羿箭的两个端点状态,配置好后,MotionLayout就会自动帮我们生成从起始状态到结束状态的动画了,后羿箭从后羿位置飞到了亚瑟位置。等等,运行怎么没反应呢?动画怎么触发啊?

Motion提供了三动画触发方法:1)onClick标签,表示点击场景中的某个控件来触发动画效果。其中有两个属性。

2)OnSwipe标签,表示通过用户轻触控制动画,有点手势滑动的感觉

3)java代码控制.

这里我们就设置点击后羿触发动画:

        <OnClick
            app:clickAction="toggle"
            app:targetId="@id/houyi" />
 

好了,运行,点击后羿,后羿的箭成功射出去了。

但是这还不够,后羿箭到亚瑟位置肯定就会消失了,怎么表示这个消失呢?用透明度,直接设置结束位置的透明度为0就会消失了。

      android:alpha="0"
 

看看效果:

如何用MotionLayout实现王者荣耀团战效果  
houyi_arrow_alhpa.gif

好像还是有点不对,箭在空中的时候就消失了,我们要的效果是射到亚瑟才消失。这是因为生成动画的时候是按照起始点到结束点过渡的流程平均分配到每个时间点,所以他就会从一开始就慢慢线性变化透明度,直到完全消失。

怎么办呢?就要用到关键帧KeyFrameSet了。

KeyFrameSet关键帧,可以设定动画过程中的某个关键位置或属性。设定关键帧后,MotionLayout会平滑地将视图从起点移至每个中间点,然后移至最终目标位置。所以这里,我们需要设置两个关键属性, 1)快射到亚瑟的时候,箭的透明度还是1。2)射到亚瑟的时候,透明度改成0。

        <KeyFrameSet>
            <KeyAttribute
                app:framePosition="98"
                app:motionTarget="@id/houyi_arrow"
                android:alpha="1" />
            <KeyAttribute
                app:framePosition="100"
                app:motionTarget="@id/houyi_arrow"
                android:alpha="0" />
        </KeyFrameSet>
 

KeyAttribute就是设置关键属性的标签,其中

这样设置好,后羿箭的动画也就完成了。

 
疯狂走位的亚瑟

到亚瑟了,亚瑟的动画效果是走位走位被射中。所以先设定好亚瑟的位置,从远处走到被射中的位置。

    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@+id/houyi_arrow"
            android:layout_width="66dp"
            android:layout_height="66dp"
            android:layout_marginLeft="190dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.8">

        </Constraint>

        <Constraint
            android:id="@+id/yase"
            android:layout_width="66dp"
            android:layout_height="66dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.8"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.2">

        </Constraint>
    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@+id/houyi_arrow"
            android:layout_width="66dp"
            android:layout_height="66dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.65"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.35">

        </Constraint>

        <Constraint
            android:id="@+id/yase"
            android:layout_width="66dp"
            android:layout_height="66dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.65"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.35">

        </Constraint>
    </ConstraintSet>

 

可以看到,一个端点状态,可以放置多个控件属性。

放好亚瑟的起始和结束状态后,再设定疯狂走位,怎么弄?——KeyCycle

KeyCycle,循环关键帧,可以给动画添加振动,其实就是波形图,比如sin,cos。这里我们就设定一个sin曲线给亚瑟,作为走位的路径。也是放到关键帧KeyFrameSet标签下。

    <KeyCycle
        android:translationY="50dp"
        app:framePosition="70"
        app:motionTarget="@id/yase"
        app:wavePeriod="0.5"
        app:waveShape="sin" />
 

好了,第一个场景搞定,看看效果:如何用MotionLayout实现王者荣耀团战效果

 
场景二

包含控件:妲己,钟无艳动画描述:从草丛走出来的妲己和钟无艳

这一个场景主要是描述在草丛蹲伏的妲己和钟无艳,看到后羿射箭后,走出草丛准备接技能。直接上代码:

    <androidx.constraintlayout.motion.widget.MotionLayout
        android:id="@+id/motionLayout2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutDescription="@xml/scene_02"
        tools:showPaths="true">


        <ImageView
            android:id="@+id/daji"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:src="@drawable/daji_model" />

        <ImageView
            android:id="@+id/zhongwuyan"
            android:layout_width="75dp"
            android:layout_height="75dp"
            android:src="@drawable/zhongwuyan_model" />

    </androidx.constraintlayout.motion.widget.MotionLayout>


//scene_02.xml
    <?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <Transition
        app:constraintSetEnd="@+id/end"
        app:constraintSetStart="@+id/start"
        app:duration="2000">

        <OnClick
            app:clickAction="toggle"
            app:targetId="@id/daji" />
    </Transition>

    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@+id/daji"
            android:layout_width="80dp"
            android:layout_height="80dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.75"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.85">

        </Constraint>

        <Constraint
            android:id="@+id/zhongwuyan"
            android:layout_width="70dp"
            android:layout_height="70dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.25"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.1">

        </Constraint>
    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@+id/daji"
            android:layout_width="80dp"
            android:layout_height="80dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.65"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.65">

        </Constraint>

        <Constraint
            android:id="@+id/zhongwuyan"
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:alpha="0"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.42"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.2">

        </Constraint>
    </ConstraintSet>

</MotionScene>
        

 

这里,我想给钟无艳一个异形走位,就是先在草丛里走,再出来。这时候就要用到另一个关键帧标签——KeyPosition

KeyPosition,表示关键帧的位置,也就是动画必经的一个点。该属性用于调整默认的运动路径。

1) motion:percentX、motion:percentY指定视图应到达的位置。keyPositionType 属性指定如何解释这些值。

2) keyPositionType有三种设置

这里我们给钟无艳一个parentRelative。

    <KeyPosition
        app:motionTarget="@id/zhongwuyan"
        app:framePosition="30"
        app:keyPositionType="parentRelative"
        app:percentY="0"
        app:percentX="0.4"
        />
 

最后加上两个英雄从草丛走出来,由半透明到不透明的过程:

            <KeyAttribute
                app:framePosition="0"
                app:motionTarget="@id/daji"
                android:alpha="0.7" />
            <KeyAttribute
                app:framePosition="70"
                app:motionTarget="@id/daji"
                android:alpha="1" />

            <KeyAttribute
                app:framePosition="0"
                app:motionTarget="@id/zhongwuyan"
                android:alpha="0.7" />
            <KeyAttribute
                app:framePosition="60"
                app:motionTarget="@id/zhongwuyan"
                android:alpha="1" />

   
场景三

包含控件:妲己的一技能,妲己的二技能,钟无艳动画描述:钟无艳闪现到人群中使用大招转转转,妲己二技能晕眩住鲁班,一技能跟上。

钟无艳闪现,我用的是消失再出现的方式,也就是改变alpha。钟无艳的大招,用到的是android:rotationY,设定绕y轴旋转。

妲己的一技能和二技能都是用的普通位置移动,注意控制透明度也就是出现和消失即可。上代码:

//scene_03.xml
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <Transition
        app:constraintSetEnd="@+id/end"
        app:constraintSetStart="@+id/start"
        app:duration="4000">

        <KeyFrameSet>

            <!-- 钟无艳-->
            <KeyAttribute
                app:framePosition="20"
                app:motionTarget="@id/zhongwuyan2"
                android:rotationY="0" />

            <KeyAttribute
                app:framePosition="1"
                app:motionTarget="@id/zhongwuyan"
                android:alpha="1" />

            <!-- 妲己2技能-->

            <KeyPosition
                app:motionTarget="@id/daji_2"
                app:framePosition="20"
                app:keyPositionType="deltaRelative"
                app:percentY="0"
                app:percentX="0"
                />

            <KeyAttribute
                app:framePosition="20"
                app:motionTarget="@id/daji_2"
                android:alpha="1" />

            <KeyPosition
                app:motionTarget="@id/daji_2"
                app:framePosition="60"
                app:keyPositionType="deltaRelative"
                app:percentY="1"
                app:percentX="1"
                />

            <KeyAttribute
                app:framePosition="40"
                app:motionTarget="@id/daji_2"
                android:alpha="1" />

            <KeyAttribute
                app:framePosition="61"
                app:motionTarget="@id/daji_2"
                android:alpha="0" />


            <!-- 妲己1技能-->

            <KeyAttribute
                app:framePosition="55"
                app:motionTarget="@id/daji_1"
                android:alpha="1" />

            <KeyPosition
                app:motionTarget="@id/daji_1"
                app:framePosition="55"
                app:keyPositionType="deltaRelative"
                app:percentY="0"
                app:percentX="0"
                />

            <KeyAttribute
                app:framePosition="85"
                app:motionTarget="@id/daji_1"
                android:alpha="1" />

        </KeyFrameSet>

        <OnClick
            app:clickAction="toggle"
            app:targetId="@id/zhongwuyan2" />
    </Transition>

     //。。。
</MotionScene>
        

实际应用场景

其实做下来可以发现,Motionlayout实现动画真的很简便,大大提高了开发效率,这也是jetpack组件开发的初心。但是,Motionlayout还是有缺点的,比如直接通过xml代码的情况下,无法设置动画的衔接,设定动画的先后顺序。所以到底motionlayout应用场景是什么呢?

motionlayout作为一个过渡动画,应该适用于一些控件切换,界面变化之类的动画。比如DrawerLayout,viewpager切换的时候,可以设置一些view过渡的动画。官网有一个类似youtube中运动动画的案例,我这边搬过来简单说下。先看看效果

如何用MotionLayout实现王者荣耀团战效果  
youtube-motion2.gif

效果不错吧,特别是手势滑动的那个丝滑感,太爽了,以前做这种动画效果少说也要半个小时吧,想想就头疼。现在,MotionLayout:so easy。

来一起分析下:

包含控件:顶部布局控件topLayout(包含顶部图片topImage,播放按钮topPlay,关闭按钮topClose),中部布局midlayout(包含文字部分midView),下部菜单控件bottomView

动画描述(某些具体数值由代码中得知):

就这么多,分析好每个布局的起始位置,结束位置,再调整一下关键帧。一个跟随手势滑动的过渡动画布局就完成了。贴下MotionScene关键代码,想看完整源代码可以去文末附件自取,官网案例和我的demo都包含。


<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:motion="http://schemas.android.com/apk/res-auto">

    <Transition
        motion:constraintSetEnd="@+id/end"
        motion:constraintSetStart="@+id/start"
        motion:duration="1000"
        motion:motionInterpolator="linear">

        <OnSwipe
            motion:dragDirection="dragUp"
            motion:touchAnchorId="@+id/top_image_container"
            motion:touchAnchorSide="bottom" />

        <KeyFrameSet>
            <KeyPosition
                motion:curveFit="linear"
                motion:framePosition="90"
                motion:motionTarget="@id/top_image"
                motion:percentWidth="0"
                motion:percentX="0" />
            <KeyPosition
                motion:curveFit="linear"
                motion:framePosition="90"
                motion:motionTarget="@id/top_image_container"
                motion:percentWidth="0" />

            <KeyPosition
                motion:curveFit="linear"
                motion:framePosition="90"
                motion:motionTarget="@id/recyclerview_container"
                motion:percentWidth="0" />

            <KeyAttribute
                android:alpha="0"
                motion:framePosition="75"
                motion:motionTarget="@id/recyclerview_front" />

            <KeyAttribute
                android:alpha="0.10"
                motion:framePosition="90"
                motion:motionTarget="@id/image_clear" />

            <KeyAttribute
                android:alpha="0.10"
                motion:framePosition="90"
                motion:motionTarget="@id/image_play" />
        </KeyFrameSet>
    </Transition>

</MotionScene>

 

这里有几个新属性说下:

 

关于过渡动画

关于过渡动画,其实之前也是存在的——TransitionManagerTransitionManager可以提供不同场景之间的过渡转换动画,需要设定两个场景(布局文件),然后两个场景中对应的控件id要对应上。最后通过java代码执行过渡动画。

上个代码:

//两个场景的布局
    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/scene_root">

        <include layout="@layout/a_scene" />
    </FrameLayout>
    
//场景一
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/scene_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="26sp"
        android:id="@+id/text_view1"
        android:text="Text Line 1" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="26sp"
        android:id="@+id/text_view2"
        android:text="Text Line 2" />
</LinearLayout>

//场景二
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/scene_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/text_view2"
        android:textSize="22sp"
        android:text="Text Line 2" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="22sp"
        android:id="@+id/text_view1"
        android:text="Text Line 1" />
</LinearLayout>

//获取场景,开始场景间的动画,从场景一变化为场景二

        val sceneRoot: ViewGroup = findViewById(R.id.scene_root)
        val aScene: Scene = Scene.getSceneForLayout(sceneRoot, R.layout.a_scene, this)
        val anotherScene: Scene = Scene.getSceneForLayout(sceneRoot, R.layout.another_scene, this)

        titletv.setOnClickListener {
            TransitionManager.go(anotherScene)
        }

咦,跟MotionLayout还是蛮像的,思路也差不多,都是通过不同场景的控件完成过渡动画。那么问题来了,既然有为什么还要出个MotionLayout呢?

“如何用MotionLayout实现王者荣耀团战效果”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!

推荐阅读:
  1. 怎么禁止wiif下王者荣耀?
  2. python如何爬取王者荣耀全皮肤

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java

上一篇:c语言中预处理器是什么意思

下一篇:Mysql数据分组排名实现的示例分析

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》