欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android动画(七)实战使用

程序员文章站 2022-06-22 08:43:06
今天给大家带来动画的实战练习,今天是一年一度的高考,祝各位考生能梦寐以求.完成效果ListView滑动进入动画**android:animationOrder = "normal"** 正序播放效果:**android:animationOrder="reverse"** 倒序播放效果**android:animationOrder="random"** 随机效果动态代码实现菜单弹框效果:完成效果今天给大家带来2个效果:一个是ListView的滑动进入另一个是右下角的点击弹框效果ListVi...

完成效果

Android动画(七)实战使用
今天给大家带来2个效果:

  • 一个是ListView的滑动进入
  • 另一个是右下角的点击弹框效果

ListView滑动进入动画

第一步,先在布局中使用LIstView,在res/layout_animation创建文件,并使用android:layoutAnimation="@anim/layout_animation"引用到ListView中

Android动画(七)实战使用

第二步:layout_animation文件根目录为layoutAnimation

<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:delay="0.3"
    android:animationOrder="normal"
    android:animation="@anim/set_buttonanimator_activity"
    >
</layoutAnimation>
  • android:delay= “float” 可以理解为每个个item相隔滑动的时间
  • android:animationOrder= “normal | random | reverse”
    • normal 按顺序弹出
    • random 随机弹出
    • reverse 倒序弹出
  • android:animation = “@anim/XXX” 弹出的动画

第三步: 在anim下创建set_buttonanimator_activity.xml设置向右滑动,并且透明度由0-1,时长为1s

<set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" >
    <translate android:fromXDelta="-50%p" android:toXDelta="0"/>
    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"/>
</set>

第四步:在布局中使用ListView

		ListView listView = findViewById(R.id.listview);

        ArrayList<String> list = new ArrayList<>();
        list.add("测试数据1");
        list.add("测试数据2");
        list.add("测试数据3");
        list.add("测试数据4");
        list.add("测试数据5");
        list.add("测试数据6");
																			这里使用的布局是android中自带的
        ArrayAdapter<String> stringArrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_expandable_list_item_1, list);

        listView.setAdapter(stringArrayAdapter);
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:delay="0.3"
    android:animationOrder="normal"
    android:animation="@anim/set_buttonanimator_activity"
    >
</layoutAnimation>

android:animationOrder = “normal” 正序播放效果:

Android动画(七)实战使用

android:animationOrder=“reverse” 倒序播放效果

Android动画(七)实战使用

android:animationOrder=“random” 随机效果

Android动画(七)实战使用

动态代码实现

        //代码设置通过加载XML动画设置文件来创建一个Animation对象;
        Animation animation= AnimationUtils.loadAnimation(this,R.anim.set_buttonanimator_activity);   //得到一个LayoutAnimationController对象;
        LayoutAnimationController controller = new LayoutAnimationController(animation);   //设置控件显示的顺序;
        controller.setOrder(LayoutAnimationController.ORDER_RANDOM);   //设置控件显示间隔时间;
        controller.setDelay(0.3f);   //为ListView设置LayoutAnimationController属性;
        listView.setLayoutAnimation(controller);
        listView.startLayoutAnimation();
  • ORDER_NORMAL = 0 正常顺序
  • ORDER_REVERSE = 1倒序
  • ORDER_RANDOM = 2 随机顺序

大家可以从源码中找到注释来看是什么意思;

Android动画(七)实战使用

菜单弹框效果:

Android动画(七)实战使用
滑动的效果很简单,alpha从0 - 1 , scale 从0 - 1,最复杂的就是找到每个控件对应的X,和Y的位置,接下来给大家简单分析一下.

Android动画(七)实战使用

从这张图中可以简单地看出,想要求得X和Y的距离,就必须获得半径r,和夹角a,半径默认为600,那么每个a的夹角是多少呢?从黄色控件和,紫色控件来看,他们的夹角为直角,就是90°,那么他们吧5个控件分为了4等份,那么每一份的夹角就是90 / 4 = 22.5°,那么蓝色与紫色的夹角就是22.5 * 2 = 45°,红色与紫色就是 22.5 * 3 = 67.5黄色与紫色就是22.5 * 4 = 90°.然后通过数学公式:

X = r * sin(a)
Y = r * cos(a)

即可获得X和Y的坐标
想必大家知道Java提供了一个Math类:

/**
     * Returns the trigonometric sine of an angle.  Special cases:
     * <ul><li>If the argument is NaN or an infinity, then the
     * result is NaN.
     * <li>If the argument is zero, then the result is a zero with the
     * same sign as the argument.</ul>
     *
     * <p>The computed result must be within 1 ulp of the exact result.
     * Results must be semi-monotonic.
     *
     * @param   a   an angle, in radians.
     * @return  the sine of the argument.
     */
     求正弦值
    @CriticalNative
    public static native double sin(double a);
    
 /**
     * Returns the trigonometric cosine of an angle. Special cases:
     * <ul><li>If the argument is NaN or an infinity, then the
     * result is NaN.</ul>
     *
     * <p>The computed result must be within 1 ulp of the exact result.
     * Results must be semi-monotonic.
     *
     * @param   a   an angle, in radians.
     * @return  the cosine of the argument.
     */
     求余弦值
    @CriticalNative
    public static native double cos(double a);

 /**
     * Returns the trigonometric tangent of an angle.  Special cases:
     * <ul><li>If the argument is NaN or an infinity, then the result
     * is NaN.
     * <li>If the argument is zero, then the result is a zero with the
     * same sign as the argument.</ul>
     *
     * <p>The computed result must be within 1 ulp of the exact result.
     * Results must be semi-monotonic.
     *
     * @param   a   an angle, in radians.
     * @return  the tangent of the argument.
     */
     
	求正切值
    @CriticalNative
    public static native double tan(double a);

注意:这里的参数不是填的角度,而是填的角度对应的弧度

接下来看看什么是弧度:

Android动画(七)实战使用
简单的来说,夹角a对面的就是a的弧度;

使用Math类中的toRadians(flaot)方法,参数填的是角度

/**
     * Converts an angle measured in degrees to an approximately
     * equivalent angle measured in radians.  The conversion from
     * degrees to radians is generally inexact.
     *
     * @param   angdeg   an angle, in degrees
     * @return  the measurement of the angle {@code angdeg}
     *          in radians.
     * @since   1.2
     */
    public static double toRadians(double angdeg) {
        return angdeg / 180.0 * PI;
    }

这样就可以初略的得出:

X = r * sin (Math.toRadians(22))
Y = r * cos (Math.toRadians(22))

接下来直接上代码了:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ButtonAnimatorActivity">
    <Button
        android:id="@+id/openButton"
        style="@style/OpenButton"
        android:background="@color/colorPrimary"
        android:layout_margin="30dp"
        />
    <Button
        android:id="@+id/bt1"
        style="@style/OpenButton"
        android:background="#ff00ff"
        android:visibility="gone"
        android:layout_margin="30dp"
        />
    <Button
        android:id="@+id/bt2"
        style="@style/OpenButton"
        android:background="#00ffff"
        android:visibility="gone"
        android:layout_margin="30dp"
        />
    <Button
        android:id="@+id/bt3"
        style="@style/OpenButton"
        android:background="#0048FF"
        android:visibility="gone"
        android:layout_margin="30dp"
        />
    <Button
        android:id="@+id/bt4"
        style="@style/OpenButton"
        android:background="#FF003B"
        android:layout_margin="30dp"
        android:visibility="gone"
        />
    <Button
        android:id="@+id/bt5"
        style="@style/OpenButton"
        android:visibility="gone"
        android:background="#FFDD00"
        android:layout_margin="30dp"
        />
</RelativeLayout>

将共同的代码抽取到values/styles下,然后在引用,可以减少写很多重复代码;

 <style name="OpenButton" >
        <item name="android:layout_width">50dp</item>
        <item name="android:layout_height">50dp</item>
        <item name="android:layout_alignParentEnd">true</item>
        <item name="android:layout_alignParentBottom">true</item>
    </style>

接下来获取控件Id,并且设置点击事件:

private Button openButton;
    private Button bt1;
    private Button bt2;
    private Button bt3;
    private Button bt4;
    private Button bt5;

	
	openButton = findViewById(R.id.openButton);
	bt1 = findViewById(R.id.bt1);
	bt2 = findViewById(R.id.bt2);
	bt3 = findViewById(R.id.bt3);
	bt4 = findViewById(R.id.bt4);
	bt5 = findViewById(R.id.bt5);

 openButton.setOnClickListener(this);
        bt1.setOnClickListener(this);
        bt2.setOnClickListener(this);
        bt3.setOnClickListener(this);
        bt4.setOnClickListener(this);
        bt5.setOnClickListener(this);
设置此变量是为了设置点击按钮出现不同的效果,因为这里需要打开和关闭
Boolean buttonType = false;

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.openButton) {
            if (!buttonType) {
                buttonType = true;
                打开bt1 - bt5
                setOpenButton(bt1,0,5,600);
                setOpenButton(bt2,1,5,600);
                setOpenButton(bt3,2,5,600);
                setOpenButton(bt4,3,5,600);
                setOpenButton(bt5,4,5,600);
            }else{
                buttonType = false;
                关闭bt1 - bt5 
                setCloseButton(bt1,0,5,600);
                setCloseButton(bt2,1,5,600);
                setCloseButton(bt3,2,5,600);
                setCloseButton(bt4,3,5,600);
                setCloseButton(bt5,4,5,600);
            }
        }else{
            Toast.makeText(this, "点击了"+v.getId(), Toast.LENGTH_SHORT).show();
        }
    }

打开按钮方法:

/**
     *
     * @param button    控件对象
     * @param index     当前按钮下标
     * @param number    按钮总个数
     * @param radio     圆的半径
     */
    private void setOpenButton(Button button, int index, int number, int radio) {
        button.setVisibility(View.VISIBLE);
        double degree = Math.toRadians(90)/(number - 1) * index;
       Log.i("setOpenButton",degree+"");
       这里需要注意,获取到结果之后要加负号(-),因为正数是往右下角弹出的,咋们现在需要向左上角弹出.
       float x = (float) -(radio * Math.sin(degree));
        float y = (float) -(radio * Math.cos(degree));

        Log.i("szjdegree"+index,x+"\t\t"+y);

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playTogether(
                ObjectAnimator.ofFloat(button,"translationX",0,x),
                ObjectAnimator.ofFloat(button,"translationY",0,y),
                ObjectAnimator.ofFloat(button,"alpha",0,1),
                ObjectAnimator.ofFloat(button,"scaleX",0,1),
                ObjectAnimator.ofFloat(button,"scaleY",0,1)

        );
		
        animatorSet.setDuration(500);
        animatorSet.start();
    }

按钮的关闭方法:

private void setCloseButton(final Button button, int index, int number, int radio) {
        double degree =   Math.toRadians(90) / (number - 1) * index;
        int x = (int) - (radio * Math.sin(degree));
        int y = (int) - (radio * Math.cos(degree));
        Log.i("setCloseButton",degree+"\n");
        Log.i("setXXX"+ index,x+"\t\t"+y);

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playTogether(
                ObjectAnimator.ofFloat(button,"translationX",x , 0),
                ObjectAnimator.ofFloat(button,"translationY",y , 0),
                ObjectAnimator.ofFloat(button,"alpha",1 , 0),
                ObjectAnimator.ofFloat(button,"scaleX",1 , 0),
                ObjectAnimator.ofFloat(button,"scaleY",1 , 0)

        );

        animatorSet.setDuration(500);
        animatorSet.start();
        
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                button.setVisibility(View.INVISIBLE);
            }
        },500);

    }

按钮的打开和关闭都是一样的,只是有一点不同:

  • 打开是从0 - X && 0 - Y
  • 关闭时从 X - 0 &* Y - 0

要有细心地朋友可能发现在关闭的时候还多了一个方法:

 new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                button.setVisibility(View.INVISIBLE);
            }
        },500);

为什么要加这个东西呢?咋们先看看不加这个东西的效果:
Android动画(七)实战使用
为什么会出现这种情况呢?因为在第二次缩放控件的时候,他只是回到了绿色控件的地方,并且透明度(alpha)由1变到了0,只是他的状态不存在了,可是他的值还有,所以他不显示的时候需要吧他隐藏掉,
我这里用到的是handler的延时操作:

 new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                button.setVisibility(View.INVISIBLE);
            }
        },500);

因为代码执行的很快很快,所以不用担心有什么问题,如果觉得不保险,也可以对animatorSet监听,当动画结束的时候会响应onAnimationEnd()事件

animatorSet.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                button.setVisibility(View.INVISIBLE);
            }

            @Override
            public void onAnimationCancel(Animator animation) {
            
            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });

菜单点击效果参考链接:

启舰.
ListView滑动效果参考文档:: 启舰.

Git地址链接: langyangyang.

请各位大佬留下宝贵的建议.

本文地址:https://blog.csdn.net/weixin_44819566/article/details/107174364