Android—过渡按钮的简单实现

news2024/12/24 8:06:29

Android—过渡按钮的简单实现

    • 前言
    • 准备工作
      • 登录页面(activity_main.xml)
      • 登录成功页面(activity_new.xml)
    • 主要代码
      • 给登录按钮设置监听事件(MainActivity.xml)
      • 点击登录按钮出现加载动画(TransitionButton.java)
      • 当isSuccessful判断为true时(MainActivity.xml)
      • 加载动画结束时切入跳转新页面动画(TransitionButton.java)
      • 当isSuccessful判断为false时(MainActivity.xml)
      • 加载动画结束时按钮复原并切入抖动动画(TransitionButton.java)
    • 效果展示
      • 登录成功
      • 登录失败

前言

Android 包含过渡框架,它使开发者能够轻松地为两个视图层次结构之间的变化设置动画。该框架通过随时间更改视图的某些属性值,在运行时为视图设置动画。该框架包括用于常见效果的内置动画,并允许开发者创建自定义动画和过渡生命周期回调。本项目基于此实现了一个过渡按钮。

准备工作

登录页面(activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    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:background="#00BCD4"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="44dp"
        android:layout_marginStart="32dp"
        android:layout_marginTop="80dp"
        android:layout_marginEnd="32dp"
        android:background="@drawable/rounded_background"
        android:hint="@string/main_email_hint"
        android:paddingLeft="16dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageView" />

    <EditText
        android:id="@+id/editText2"
        android:layout_width="match_parent"
        android:layout_height="44dp"
        android:layout_marginStart="32dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="32dp"
        android:background="@drawable/rounded_background"
        android:hint="@string/main_password_hint"
        android:paddingLeft="16dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/editText" />

    <Button
        android:id="@+id/transition_button"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="32dp"
        android:layout_marginTop="32dp"
        android:layout_marginEnd="32dp"
        android:text="@string/main_button"
        android:textColor="@android:color/white"
        app:defaultColor="#FF5722"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/editText2"
        app:loaderColor="@android:color/white" />
   
</android.support.constraint.ConstraintLayout>

登录成功页面(activity_new.xml)

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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"
    android:background="#3894ba"
    tools:context=".NewActivity">

</android.support.constraint.ConstraintLayout>

主要代码

给登录按钮设置监听事件(MainActivity.xml)

        transitionButton = findViewById(R.id.transition_button);
        transitionButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                transitionButton.startAnimation();

点击登录按钮出现加载动画(TransitionButton.java)

    public void startAnimation() {
        currentState = State.PROGRESS;
        isMorphingInProgress = true;

        initialWidth = getWidth();
        initialHeight = getHeight();
        initialText = getText().toString();

        setText(null);
        setClickable(false);

        startWidthAnimation(initialHeight, new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationCancel(animation);
                isMorphingInProgress = false;
            }
        });
    }
    private void startWidthAnimation(int to, AnimatorListenerAdapter onAnimationEnd) {
        startWidthAnimation(getWidth(), to, onAnimationEnd);
    }

    private void startWidthAnimation(int from, int to, AnimatorListenerAdapter onAnimationEnd) {
        ValueAnimator widthAnimation = ValueAnimator.ofInt(from, to);
        widthAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                int val = (Integer) valueAnimator.getAnimatedValue();
                ViewGroup.LayoutParams layoutParams = getLayoutParams();
                layoutParams.width = val;
                setLayoutParams(layoutParams);
            }
        });

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.setDuration(WIDTH_ANIMATION_DURATION);
        animatorSet.playTogether(widthAnimation);
        if (onAnimationEnd != null)
            animatorSet.addListener(onAnimationEnd);

        animatorSet.start();
    }

ValueAnimator.ofInt():由于值的变化手动对对象的属性赋值导致对象的属性发生改变,从而实现动画效果,也就是说ValueAnimator只关心数值如何发生改变的过程

setDuration(WIDTH_ANIMATION_DURATION):设置每个内部子动画的时长,默认每个子动画使用自己默认的时长,如果AnimatorSet设置了时长,子动画将继承这个时长,而子动画自己设置的duration将失效

playTogether(Animator… items):添加一组动画,播放顺序为一起播放

当isSuccessful判断为true时(MainActivity.xml)

        transitionButton = findViewById(R.id.transition_button);
        transitionButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                transitionButton.startAnimation();

                final Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        boolean isSuccessful = true;

                        if (isSuccessful) {
                            transitionButton.stopAnimation(TransitionButton.StopAnimationStyle.EXPAND, new TransitionButton.OnAnimationStopEndListener() {
                                @Override
                                public void onAnimationStopEnd() {
                                    Intent intent = new Intent(getBaseContext(), NewActivity.class);
                                    intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
                                    startActivity(intent);
                                }
                            });
                        }

加载动画结束时切入跳转新页面动画(TransitionButton.java)

            case EXPAND:
                currentState = State.TRANSITION;

                startScaleAnimation(new AnimationListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animation animation) {
                        super.onAnimationEnd(animation);
                        if (onAnimationStopEndListener != null)
                            onAnimationStopEndListener.onAnimationStopEnd();
                    }
                });
                break;
    private void startScaleAnimation(Animation.AnimationListener animationListener) {
        float ts = (float) (WindowUtils.getHeight(getContext()) / getHeight() * 2.1);
        Animation anim = new ScaleAnimation(1f, ts,
            1, ts,
            Animation.RELATIVE_TO_SELF, 0.5f,
            Animation.RELATIVE_TO_SELF, 0.5f);
        anim.setDuration(SCALE_ANIMATION_DURATION);
        anim.setFillAfter(true);
        anim.setAnimationListener(animationListener);
        startAnimation(anim);
    }

Animation.RELATIVE_TO_SELF, 0.5f:X轴移动的结束位置

setDuration(long durationMillis):设置动画持续事件(单位:毫秒)

setFillAfter(boolean fillAfter):如果fillAfter设为true,则动画执行后,控件将停留在动画结束的状态

setAnimationListener(animationListener):监听动画执行

startAnimation(anim):动画开始执行

当isSuccessful判断为false时(MainActivity.xml)

						else {
                            transitionButton.stopAnimation(TransitionButton.StopAnimationStyle.SHAKE, null);
                        }
                    }
                }, 2000);
            }

加载动画结束时按钮复原并切入抖动动画(TransitionButton.java)

    public void stopAnimation(StopAnimationStyle stopAnimationStyle, final OnAnimationStopEndListener onAnimationStopEndListener) {
        switch (stopAnimationStyle) {
            case SHAKE:
                currentState = State.ERROR;

                startWidthAnimation(initialWidth, new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        setText(initialText);
                        startShakeAnimation(new AnimationListenerAdapter() {
                            @Override
                            public void onAnimationEnd(Animation animation) {
                                currentState = State.IDLE;
                                setClickable(true);
                                if (onAnimationStopEndListener != null)
                                    onAnimationStopEndListener.onAnimationStopEnd();
                            }
                        });
                    }
                });
                break;
    private void startWidthAnimation(int to, AnimatorListenerAdapter onAnimationEnd) {
        startWidthAnimation(getWidth(), to, onAnimationEnd);
    }

    private void startWidthAnimation(int from, int to, AnimatorListenerAdapter onAnimationEnd) {
        ValueAnimator widthAnimation = ValueAnimator.ofInt(from, to);
        widthAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                int val = (Integer) valueAnimator.getAnimatedValue();
                ViewGroup.LayoutParams layoutParams = getLayoutParams();
                layoutParams.width = val;
                setLayoutParams(layoutParams);
            }
        });

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.setDuration(WIDTH_ANIMATION_DURATION);
        animatorSet.playTogether(widthAnimation);
        if (onAnimationEnd != null)
            animatorSet.addListener(onAnimationEnd);

        animatorSet.start();
    }
    private void startShakeAnimation(Animation.AnimationListener animationListener) {
        TranslateAnimation shake = new TranslateAnimation(0, 15, 0, 0);
        shake.setDuration(SHAKE_ANIMATION_DURATION);
        shake.setInterpolator(new CycleInterpolator(4));
        shake.setAnimationListener(animationListener);
        startAnimation(shake);
    }

setDuration(long durationMillis):设置动画持续事件(单位:毫秒)

setAnimationListener(animationListener):监听动画执行

setInterpolator(Interpolator i):设置动画的变化速度

startAnimation(anim):动画开始执行

效果展示

登录成功

在这里插入图片描述

登录失败

在这里插入图片描述


作者:李海
原文链接:https://blog.csdn.net/Racdex/article/details/128112563?spm=1001.2014.3001.5502

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/59106.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言笔记-16-Linux基础-文件元数据

C语言笔记-16-Linux基础-文件元数据 文章目录C语言笔记-16-Linux基础-文件元数据前言一、概述二、ln 硬连接三、软连接四、stat 获取元数据总结前言 自学笔记&#xff0c;没有历史知识铺垫&#xff08;省略百度部分&#xff09;C语言笔记-16-Linux基础-文件元数据 一、概述 文…

Kaggle泰坦尼克号-决策树Top 3%-0基础代码详解

Titanic Disaster Kaggle&#xff0c;里的经典入门题目&#xff0c;因为在学决策树所以找了一个实例学习了一下&#xff0c;完全萌新零基础&#xff0c;所以基本每一句都做了注释。 原文链接&#xff1a;Titanic: Simple Decision Tree model score(Top 3%) | Kaggle 目录 1.…

SolidWorks如何绘制环形波纹垫片

环形波纹垫片主要用于螺纹式固定件或者防滑螺纹固定中,那这个环形垫片一般怎么用SolidWorks制作呢?首先我们观察到这样的垫片是上下此起彼伏的波纹状,厚度一般1MM左右,制作起来还是有点小难度,但是通过仔细观察,我们可以看到它的大概走向,如图 也就是特征就是这边凹下去…

获取Android签名MD5的方式

形而上者谓之道&#xff0c;形而下者谓之器 我们在申请百度云/腾讯云等第三方的各种服务时&#xff0c;经常会遇到需要提供包名和签名MD5的情况。这里特地总结一下&#xff1a; 1. 获取MD5的一般方式 1.1 有签名文件(.keystore)的情况下: keytool -list -v -keystore XXX.key…

【沐风老师】3DMAX一键生成圣诞树建模插件使用教程

圣诞节快到了&#xff0c;给大家分享一款3DMax一键生成圣诞树模型插件&#xff1a; 3DMAX一键生成圣诞树建模插件&#xff0c;可以生成定制和随机两种3D圣诞树模型&#xff0c;并自动赋予材质和贴图。 【安装方法】 方法一&#xff1a;解压后直接拖动插件脚本文件到3dMax窗口…

使用springboot实现jsonp|jsonp的实现|JSONP的实现使用springboot

1、服务端&#xff1a; 1.1、项目目录&#xff1a; 1.2、pom文件&#xff1a; <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instan…

从一到无穷大 #3 对象存储.浅谈

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 本作品 (李兆龙 博文, 由 李兆龙 创作)&#xff0c;由 李兆龙 确认&#xff0c;转载请注明版权。 文章目录引言Windows Azure StorageNosql&#xff1a;TiKV为例总结引言 天才的开源精神对于普…

67-94-hive-函数-开窗函数-常用函数-udf自定义函数

67-hive-函数&#xff1a; UDF:一进一出&#xff0c;普通函数 UDAF:多进一出&#xff0c;聚合函数 UDTF&#xff1a;一进多出&#xff0c;炸裂函数 一、多指的是输入数据的行数。一行变多行&#xff0c;多行变一行。 函数 #查看系统自带的函数 hive> show functions; …

Docker以标准方式安装部署Redis

Docker安装redis的命令很简单&#xff0c;但是很多都是半成品的命令&#xff0c;说白了&#xff0c;就是自己玩玩&#xff0c;一个demo级别的redis而已。 本篇文章以最全的命令方式安装部署Redis。 注意&#xff1a; 本篇只是单机版的&#xff0c;只是公司测试环境使用&…

解决npm的 EACCES: permission denied 问题

居上位而不骄&#xff0c;在下者而不忧。 平时项目开发使用npm都顺风顺水的&#xff0c;but今天新建项目时&#xff0c;就出现了权限错误&#xff0c;具体如下&#xff1a; 但是通过下面的提示就可以轻松解决。 sudo chown -R 502:20 “/Users/cheng.wang/.npm” 官网相关议题…

Redis源码篇(7)——哨兵模式

哨兵模式 哨兵模式即在主从复制的基础上增加哨兵监控以控制主从切换实现高可用的一种模式。 本篇主要介绍sentinel系统初始化&#xff0c;心跳检测&#xff0c;故障转移的过程 初始化 从最开始的 redis-server xxx.conf --sentinel 、 redis-sentinel xxx.conf 命令看起。当一…

CUDA 编程简介

参考资料&#xff1a; NVIDIA CUDA Programming Guide, NVIDIA. (https://docs.nvidia.com/cuda/cuda-c-programming-guide/)国科大《并行与分布式计算》课程、NVIDIA 在线实验平台 文章目录GPU & CUDAG80 Graphics ModeG80 CUDA ModeCUDA Programming ModelCUDA Extends …

重定向转发,接收请求参数及数据回显-P11,12

重定向和转发&#xff1a; 我们的实现本身就是转发 。 想删掉视图解析器的话&#xff0c;就需要在return把路径写全 重定向就改为redirect&#xff1a;而且重定向不走视图解析器&#xff0c;因为是新的请求&#xff0c;新的URL。 接收请求参数&#xff1a; 第一种是默认的方式…

【FreeRTOS(十二)】事件标志组

文章目录事件标志组创建事件标志组 xEventGroupCreate将指定的事件位清零 xEventGroupClearBits将指定的事件位置 1 xEventGroupSetBits获取事件标志组值 xEventGroupGetBits等待指定的事件位 xEventGroupWaitBits代码示例事件标志组 事件标志位 事件位用来表明某个事件是否发…

嵌入式Linux 开发经验:编写用户态应用程序打开 misc 设备

参考文章 VSCode SSH 连接远程ubuntu Linux 主机 ubuntu 20.04 qemu linux6.0.1 开发环境搭建 ubuntu 20.04 qemu linux6.0.1 制作ext4根文件系统 嵌入式Linux 开发经验&#xff1a;platform_driver_register 的使用方法 嵌入式Linux 开发经验&#xff1a;注册一个 misc 设…

创新案例|实现YouTube超速增长的3大敏捷组织运营机制(上)

从2008年到2014年YouTube进入超速增长模式。时任核心技术负责人的 Shishir Mehrotra回顾了当时公司面临的挑战&#xff0c;以及带领YouTube团队如何建立一套敏捷运营机制的先进实践&#xff0c;以保持战略对齐并运营复杂的业务。这直接推进公司每周高效的工作节奏&#xff0c;以…

【Pytorch】模型的可复现性

背景 在做研究的时候&#xff0c;通常我们希望同样的样本&#xff0c;同样的代码能够得到同样的实验效果&#xff0c;但由于代码中存在一些随机性&#xff0c;导致虽然是同样的样本和程序&#xff0c;但是得到的结果不一致。在pytorch的官方文档中为此提供了一些建议&#xff…

复现 MMDetection

文章目录MMDetection 复现一、环境配置服务器信息安装CUDA下载并安装CUDA配置环境变量多个Cuda版本切换 (可选)安装CUDNN安装Anaconda搭建虚拟环境新建虚拟环境安装pytorchPycharm 远程连接代码同步配置服务器解释器二、训练和推理自制COCO格式数据集训练修改数据集相关参数修改…

Problem C: 算法10-10,10-11:堆排序

Problem Description 堆排序是一种利用堆结构进行排序的方法&#xff0c;它只需要一个记录大小的辅助空间&#xff0c;每个待排序的记录仅需要占用一个存储空间。 首先建立小根堆或大根堆&#xff0c;然后通过利用堆的性质即堆顶的元素是最小或最大值&#xff0c;从而依次得出…

TMS FixInsight代码评估工具

TMS FixInsight代码评估工具 TMS Fix Insight被认为是Delphi程序员的代码评估工具&#xff0c;它也能够在Delphi的源代码中发现问题。它被认为是一个代码分析工具&#xff0c;用于划分过程以及问题的位置以及Delphi的应用。TMS Fix Insight基本上是一个静态的代码列表&#xff…