Android Compose状态改变动画animateXxxAsState使用详解

目录
  • 前言
  • animateXxxAsState
    • 基础使用
    • 动画监听
    • 使用示例
    • animateFloatAsState
    • animateIntAsState
    • animateColorAsState
    • animateSizeAsState/animateIntSizeAsState
    • animateOffsetAsState/animateIntOffsetAsState
    • animateRectAsState
  • 实战
  • 最后

前言

上一篇文章我们探索了 Compose 中属性动画的使用,发现属性动画确实是可以在 Compose 中使用的,虽然使用方式跟传统 Android 开发中有所区别,但也不难用,甚至对于已经熟悉了属性动画的我们来说学习成本更低,那么为什么 Compose 又要单独搞一套 动画 Api 呢?为了搞清楚这个问题,首先我们得先学会 Compose 动画的使用。

实践是检验真理的唯一标准,我们将从这一篇开始一步步深入学习 Compose 动画的使用,看看它到底好不好用。本篇将首先从animateXxxAsState这一组动画 Api 开始进入 Compose 的动画世界。

animateXxxAsState

在 Compose 中提供了一系列动画 API,其中有一类 API 跟属性动画非常类似,它就是 animateXxxAsState,我翻译成状态改变动画,其中 Xxx对应的是 DpFloatIntSizeOffsetRectIntOffsetIntSizeColor等数据类型,即当状态改变时触发对应数据类型的值的发生改变,从而执行数据从当前值到目标值变化的动画。

对应 Api 如图:

接下来就看看这些 Api 到底是如何使用的。

基础使用

我们首先以 animateDpAsState为例来看一下 animateXxxAsState 动画到底如何使用。

Dp是 Compose 提供的一个封装数据类型,作用跟在传统 Android 开发中 xml 使用的 dp单位是一样的,是与屏幕像素密度相关的抽象单位。Compose 中为其提供了基础数据类型的扩展,可以直接使用数值.dp进行使用,如:10.dp12.5.dp等。

在 Compose 中跟长度相关的参数类型基本上都是 Dp,如宽高、圆角、间距等等。

animateDpAsState的定义如下:

fun animateDpAsState(
    targetValue: Dp,
    animationSpec: AnimationSpec<Dp> = dpDefaultSpring,
    finishedListener: ((Dp) -> Unit)? = null
): State<Dp>

参数说明:

  • targetValue:目标值
  • animationSpec:动画规格
  • finishedListener:动画完成监听

返回值是一个 State 对象,即当其内部 value 值发生改变时会触发 Compose 的重组,从而刷新界面。

前面说了 animateXxxAsState 跟属性动画类似,但是好像不对呀,这里参数只有一个 targetValue即目标值,熟悉属性动画的都知道,属性动画的数值参数是一个可变参数,当为 1 个的时候,初始值为属性当前值,目标值为传入参数值,多个参数时初始值为第一个参数值,那这里只有一个 targetValue参数是不是也是初始值是从组件中获取呢?

我们来试试,创建一个 Box 通过改变其左边距实现向右移动的动画:

val startPadding = animateDpAsState(10.dp)
Box(Modifier
    .padding(start = startPadding.value, top = 10.dp)
    .size(100.dp, 100.dp)
    .background(Color.Blue)
)

因为需要对左边距进行改变,所以将 padding 的 start 提取为 startPadding 变量,如上面的代码,但是这样的话那初始值就是 animateDpAsState传入的值,也就是这里的 10.dp ,先运行一下看看是不是这样:

运行效果确实是这样,那怎么实现动画效果呢?是修改 startPadding 的值么?我们给 Box 添加一个点击事件修改 startPadding 的值看看:

val startPadding = animateDpAsState(10.dp)
Box(Modifier
    .padding(start = startPadding.value, top = 10.dp)
    .size(100.dp, 100.dp)
    .background(Color.Blue)
    // 添加点击事件
    .clickable {
        // 修改值 报错
        startPadding.value = 100.dp
    }
)

这样写编辑器直接报错了,错误信息如下:

说 val 变量不能重新赋值,是因为 startPadding 变量定义成了 val 所以不能修改么?并不是,因为我们重新赋值的不是 startPadding 变量,而是其内部的 value,而 startPadding 是 State 类型,State 内部的 value 是 val 的,定义如下:

interface State<out T> {
    val value: T
}

所以并不能通过重新赋值修改 animateDpAsState创建的 State 的 value 值,那么怎么修改这个值让其产生动画呢?

前面说了 animateXxxAsState 是依赖状态改变而产生值的变化,所以实际上我们这里还需要定义一个额外的状态变量,targetValue 参数根据这个状态传入不同的值,修改上面代码如下:

@Composable
fun DpAnimationBox(){
    // 是否移动到右边
    var moveToRight by remember { mutableStateOf(false) }
    //根据 moveToRight 变量传入参数,true 代表在右边则传入 100.dp,false 在左边则传入 10.dp
    val startPadding = animateDpAsState(if (moveToRight) 100.dp else 10.dp)
    Box(Modifier
        .padding(start = startPadding.value, top = 10.dp)
        .size(100.dp, 100.dp)
        .background(Color.Blue)
        .clickable {
            // 改变 moveToRight 状态,这里直接取反
            moveToRight = !moveToRight
        }
    )
}

修改点如下:

  • 使用 mutableStateOf 创建 moveToRight 变量,内部值为 Boolean 类型,即 MutableState,因为是在 Compose 函数中使用,需要用 remember 函数包裹,防止重组时重复创建
  • 修改 animateDpAsState 传入参数的固定值为根据 moveToRight 传入,即 if (moveToRight) 100.dp else 10.dp
  • 修改点击事件处理,修改 moveToRight 的值

运行看一下效果:

终于有效果了。所以实际是根据 moveToRight 的值改变导致传入 animateDpAsState 的 targetValue 参数的值发生改变,而动画执行的就是之前旧的值到当前设置最新值的动画效果。

上面的 moveToRight 是 MutableState 类型, 内部的 value 是 Boolean 类型,那是不是只能是 Boolean 类型呢,当然不是,可以是任何类型,只要在传入 animateDpAsState 的参数值时根据这个类型的值进行自定义条件判断传入不同的数据即可,比如定义一个枚举类型,根据不同类型传入不同的参数,如下:

enum class CustomState{
    STATE1,
    STATE2,
    STATE3,
}
var customState by remember { mutableStateOf(CustomState.STATE1) }
val paddingValue = when(customState){
    CustomState.STATE1 -> 0.dp
    CustomState.STATE2 -> 100.dp
    CustomState.STATE3 -> 200.dp
}
val startPadding = animateDpAsState(paddingValue)

甚至你可以直接创建一个跟动画值相同的数据类型,比如这里可以直接创建一个 Dp 类型的状态变量,然后在点击时直接改变其值来驱动动画执行,如下:

@Composable
fun DpAnimationBox(){
    // 动画目标值
    var startPaddingValue by remember { mutableStateOf(10.dp) }
    // 蒋其设置给 animateDpAsState
    val startPadding = animateDpAsState(startPaddingValue)
    Box(Modifier
        .padding(start = startPadding.value, top = 10.dp)
        .size(100.dp)
        .background(Color.Blue)
        .clickable {
            // 改变动画目标值
            if(startPaddingValue == 10.dp){
                startPaddingValue = 100.dp
            }else{
                startPaddingValue = 10.dp
            }
        }
    )
}

上面代码同样能实现跟之前一样的效果。使用还是相当灵活的,开发中可以根据实际的需求定义不同的状态来完成我们想要的动画效果。

动画监听

animateXxxAsState提供了动画完成时的监听 finishedListener,可以通过监听动画完成进行自定义的业务处理,比如修改界面的显示状态或者开启下一个动画等。

比如 animateDpAsStatefinishedListener 定义如下:

(Dp) -> Unit

有一个 Dp 类型的参数,即动画完成时的目标值,使用如下:

val startPadding = animateDpAsState(if (moveToRight) 100.dp else 10.dp) {
   //TODO: do something
}

比如我们想在上面的动画结束时再让方块移动回去,那我们可以这么写:

val startPadding = animateDpAsState(if (moveToRight) 100.dp else 10.dp) {
    if(it == 100.dp){
        moveToRight = false
    }
}

效果如下:

或者我们想让这个方块往返重复执行,可以这么写:

val startPadding = animateDpAsState(if (moveToRight) 100.dp else 10.dp) {
    moveToRight = !moveToRight
}

效果如下:

通过对 animateXxxAsState动画的监听我们可以实现界面状态的刷新或进行动画的组合等自定义操作。

使用示例

前面讲了 animateDpAsState动画的使用,其他 animateXxxAsStateapi 的使用基本一样,只是动画作用的数据类型不一样,下面将通过一个个简单示例来看看其他几个 api 的使用。

animateFloatAsState

animateFloatAsState作用于 Float 类型数据的动画,比如 alpha 值,通过改变控件的 alpha 值可实现元素的显示与隐藏,使用示例如下:

@Composable
fun FloatAnimationBox() {
    var show by remember { mutableStateOf(true) }
    val alpha by animateFloatAsState(if (show) 1f else 0f)
    Box(Modifier
        .padding(10.dp)
        .size(100.dp)
        .alpha(alpha)
        .background(Color.Blue)
        .clickable {
            show = !show
        }
    )
}

动画效果:

animateIntAsState

animateIntAsState作用于 Int 数据类型,上面的 animateDpAsState实现的动画也可以使用 animateIntAsState实现,如下:

@Composable
fun IntAnimationBox() {
    var moveToRight by remember { mutableStateOf(false) }
    val startPadding by animateIntAsState(if (moveToRight) 100 else 10)
    Box(Modifier
        .padding(start = startPadding.dp, top = 10.dp)
        .size(100.dp)
        .background(Color.Blue)
        .clickable {
            moveToRight = !moveToRight
        }
    )
}

效果跟使用 animateDpAsState 实现的一样:

animateColorAsState

animateColorAsState是作用于 Color 上,可实现颜色的过渡动画,比如将上面的方块颜色从蓝色变为红色,代码如下:

@Composable
fun ColorAnimationBox() {
    var toRed by remember { mutableStateOf(false) }
    val color by animateColorAsState(if (toRed) Color.Red else Color.Blue)
    Box(Modifier
        .padding(10.dp)
        .size(100.dp)
        .background(color)
        .clickable {
            toRed = !toRed
        }
    )
}

效果如下:

animateSizeAsState/animateIntSizeAsState

animateSizeAsState作用于 Size 上,看到这个我们一下就想到了用于控件的 size 上,比如上面的 Modifier.size()上,但实际上 Modifier.size()的参数并不是 Size 类型,而是 Dp 类型或者 DpSize,而 DpSize 并不是 Size 的子类,所以不能直接将 Size 类型的数据直接传入 Modifier.size()中,而是需要转换一下:

@Composable
fun SizeAnimationBox() {
    var changeSize by remember { mutableStateOf(false) }
    // 定义 Size 动画
    val size by animateSizeAsState(if (changeSize) Size(200f, 50f) else Size(100f, 100f))
    Box(Modifier
        .padding(10.dp)
        // 设置 Size 值
        .size(size.width.dp, size.height.dp)
        .background(Color.Blue)
        .clickable {
            changeSize = !changeSize
        }
    )
}

效果如下:

animateIntSizeAsStateanimateSizeAsState几乎一样,只是它作用于 IntSize,跟 Size 的唯一区别就是参数是 Int 类型而不是 Float 类型,如下:

val size by animateIntSizeAsState(if (changeSize) IntSize(200, 50) else IntSize(100, 100))

animateOffsetAsState/animateIntOffsetAsState

animateOffsetAsState作用于 Offset 类型数据,用于控制偏移量,同样的它不能直接用于 Modifier.offset()上,因为 Modifier.offset()接收的也是 Dp 类型参数,所以也需要进行转换,如下:

@Composable
fun OffsetAnimationBox() {
    var changeOffset by remember { mutableStateOf(false) }
    // 定义 offset 动画
    val offset by animateOffsetAsState(if (changeOffset) Offset(100f, 100f) else Offset(0f, 0f))
    Box(Modifier
        // 设置 offset 数值
        .offset(offset.x.dp, offset.y.dp)
        .padding(10.dp)
        .size(100.dp)
        .background(Color.Blue)
        .clickable {
            changeOffset = !changeOffset
        }
    )
}

效果如下:

animateIntOffsetAsState则作用于 IntOffset类型数据,使用方法与上面一致,只是将 Float 类型换成 Int 类型:

val intOffset by animateIntOffsetAsState(if (changeOffset) IntOffset(100, 100) else IntOffset(0, 0))

Modifier.offset()提供了一个返回 IntOffset 的函数参数,可以如下使用:

Modifier.offset { intOffset }

animateRectAsState

animateRectAsState作用于 Rect数据,即可以同时控制位置和大小,通过 animateRectAsState可实现上面方块的位置和大小变化的动画,使用如下:

@Composable
fun RectAnimationBox() {
    var changeRect by remember { mutableStateOf(false) }
	// 定义 rect
    val rect by animateRectAsState(if (changeRect) Rect(100f, 100f, 310f, 150f) else Rect(10f, 10f, 110f, 110f))
    Box(Modifier
        // 设置位置偏移
        .offset(rect.left.dp, rect.top.dp)
        // 设置大小
        .size(rect.width.dp, rect.height.dp)
        .background(Color.Blue)
        .clickable {
            changeRect = !changeRect
        }
    )
}

效果如下:

实战

上面讲了 animateXxxAsState动画 api 的基本使用,下面就用这些 api 来完成一个实战效果,还是上一篇《Compose 中属性动画的使用》的效果:

前面说了animateXxxAsState是依赖于状态的动画,分析上面的动画一共存在 4 个状态:

  • 默认状态:显示蓝色矩形按钮,文字为 Upload
  • 开始上传状态:按钮变为圆形且中间为白色,边框为灰色,文字消失
  • 上传中状态:边框根据进度变为蓝色
  • 上传完成状态:按钮从圆形回到圆角矩形,且颜色变为红色,文字变为 Success

实现原理如下:

首先通过一个枚举定义上述四种状态:

enum class UploadState {
    Normal,
    Start,
    Uploading,
    Success
}

然后实现默认状态的界面展示:

@Composable
fun UploadAnimation() {
    val originWidth = 180.dp
    val circleSize = 48.dp
    var uploadState by remember { mutableStateOf(UploadState.Normal) }
    var text by remember { mutableStateOf("Upload") }
    val textAlpha by animateFloatAsState(1f)
    val backgroundColor by animateColorAsState(Color.Blue)
    val boxWidth by animateDpAsState(originWidth)
    val progressAlpha by animateFloatAsState(0f)
    val progress by animateIntAsState(0)
    // 界面布局
    Box(
        modifier = Modifier
            .padding(start = 10.dp, top = 10.dp)
            .width(originWidth),
        contentAlignment = Alignment.Center
    ) {
        // 按钮
        Box(
            modifier = Modifier
                .clip(RoundedCornerShape(circleSize / 2))
                .background(backgroundColor)
                .size(boxWidth, circleSize)
                .clickable {
                    // 点击时修改状态为开始上传
                    uploadState = UploadState.Start
                },
            contentAlignment = Alignment.Center,
        ) {
            // 进度
            Box(
                modifier = Modifier.size(circleSize).clip(ArcShape(progress))
                    .alpha(progressAlpha).background(Color.Blue)
            )
            // 白色蒙版
            Box(
                modifier = Modifier.size(40.dp).clip(RoundedCornerShape(20.dp))
                    .alpha(progressAlpha).background(Color.White)
            )
            // 文字
            Text(text, color = Color.White, modifier = Modifier.alpha(textAlpha))
        }
    }
}

然后根据上传按钮的状态定义不同状态时的数据值:

var textAlphaValue = 1f
var backgroundColorValue = Color.Blue
var boxWidthValue = originWidth
var progressAlphaValue = 0f
var progressValue = 0
when (uploadState) {
    // 默认状态不处理
    UploadState.Normal -> {}
    // 开始上传
    UploadState.Start -> {
        // 文字透明度变为0
        textAlphaValue = 0f
        // 按钮背景颜色变为灰色
        backgroundColorValue = Color.Gray
        // 按钮宽度变为圆的宽度
        boxWidthValue = circleSize
        // 中间进度的透明度变为 1
        progressAlphaValue = 1f
    }
    // 上传中状态
    UploadState.Uploading -> {
        textAlphaValue = 0f
        backgroundColorValue = Color.Gray
        boxWidthValue = circleSize
        progressAlphaValue = 1f
        // 进度值变为 100
        progressValue = 100
    }
    // 上传完成
    UploadState.Success -> {
        // 文字透明度变为 1
        textAlphaValue = 1f
        // 颜色变为红色
        backgroundColorValue = Color.Red
        // 按钮宽度变化默认时的原始宽度
        boxWidthValue = originWidth
        // 进度透明度变为 0f
        progressAlphaValue = 0f
    }
}
val textAlpha by animateFloatAsState(textAlphaValue)
val backgroundColor by animateColorAsState(backgroundColorValue)
val boxWidth by animateDpAsState(boxWidthValue)
val progressAlpha by animateFloatAsState(progressAlphaValue)
val progress by animateIntAsState(progressValue)

此时运行后点击按钮效果如下:

点击后只有开始上传的动画,没有后续的动画效果,这是因为我们在点击的时候只是将状态变为了 UploadState.Start 而没有进行后续状态的改变,所以需要监听动画完成然后继续改变按钮的状态来实现完整的动画效果,代码修改如下:

    val boxWidth by animateDpAsState(boxWidthValue){
        // 按钮宽度变化完成监听,当状态为 Start 则修改为 Uploading
        if(uploadState == UploadState.Start){
            uploadState = UploadState.Uploading
        }
    }
    val progress by animateIntAsState(progressValue){
        // 进度完成监听,当状态为 Uploading 则修改为 Success
        if(uploadState == UploadState.Uploading){
            uploadState = UploadState.Success
            // 文字内容修改为 Success
            text = "Success"
        }
    }

分别给按钮宽度变化动画和进度动画进行监听并修改其状态,这样就将整个动画串联起来了,最终效果如下:

最后

关于 animateXxxAsState的基本使用就讲得差不多了,并通过一系列 api 完成了上一篇使用属性动画实现的效果,细心的同学会发现关于 animateXxxAsState 其实还有两个知识点是没有介绍到的:

  • animateXxxAsState还有一个 api animateValueAsState
  • animateXxxAsState的参数 animationSpec参数

其中 animateValueAsStateanimateXxxAsState 的底层 api,上面介绍的一系列 animateXxxAsState 最终都是调用 animateValueAsState 来实现,关于 animateValueAsState 我们将在下一篇进行详细介绍。animationSpec是对动画进行更详细的配置,比如动画的时间、速度曲线等,将在后续文章中详细介绍

以上就是Android Compose状态改变动画animateXxxAsState使用详解的详细内容,更多关于Android Compose状态改变动画的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android Jetpack Compose开发实用小技巧

    目录 前言 实用小技巧 如何移除View点击阴影 Text文本如何垂直居中 如何移除Button的点击阴影 Dialog宽度如何全屏 如何提升编码效率 前言 在Compose开发的过程中,我们会经常遇到一些看起来很简单却不知道如何处理的小问题,比如去除点击阴影.Dialog全屏等问题,本文记录了这些常见小问题的处理方式.如有更好方案欢迎大佬们交流探讨- 实用小技巧 如何移除View点击阴影 这里的View指的是除了Button系列的之外,如Button.TextButton等,也就是自身没有on

  • Android Compose 属性动画使用探索详解

    目录 前言 使用探索 ObjectAnimator 使用探索 ValueAnimator 使用探索 Compose 函数中使用属性动画 实战 上传开始动画 上传进度动画 上传完成动画 最后 前言 Jetpack Compose(简称 Compose )是 Google 官方推出的基于 Kotlin 语言的 Android 新一代 UI 开发框架,其采用声明式的 UI 编程特性使得 Android 应用界面的编写和维护变得更加简单. 本专栏将详细介绍在使用 Compose 进行 UI 开发中如何实

  • Android Compose衰减动画Animatable使用详解

    目录 前言 animateDecay splineBasedDecay rememberSplineBasedDecay exponentialDecay 实战 最后 前言 之前介绍了 Animatable 动画以及其 animateTo和 snapTo两个开启动画 api 的使用,实际上 Animatable 除了这两个 api 以外还有一个 animateDecay即本篇要介绍的衰减动画. 什么是衰减动画呢?就是动画速度由快到慢最后停止,最常见的应用场景就是惯性动画,比如滑动列表时手指松开后

  • Android开发Jetpack Compose元素Modifier特性详解

    目录 正文 有序性 不可变性 正文 本文将会介绍Jetpack Compose中的Modifier.在谷歌官方文档中它的描述是这么一句话:Modifier元素是一个有序.不可变的集合,它可以往Jetpack Compose UI元素中添加修饰或者各种行为.例如,背景.填充和单击事件监听器装饰或添加行为到文本或按钮.本文将会从修饰符的两个特性有序和不可变入手来探究修饰符的应用,以下是本文目录: 有序性 不可变性 有序性 官方对修饰符定义的这个特性包含两个层面的意思,一是修饰符的使用是链式的它是有先

  • Android动效Compose贝塞尔曲线动画规格详解

    目录 正文 贝塞尔曲线 解析动画曲线 曲线源码分析 总结 正文 写Compose动画的时候使用animateXAsState的时候会注意到一个参数——animationSpec,如下: val borderRadius by animateIntAsState( targetValue = if (isRound) 100 else 0, animationSpec = tween( durationMillis = 3000, easing = LinearEasing ) ) 此处就不深入探

  • Android JetpackCompose使用教程讲解

    目录 概况 开启新工程 文件结构 根结构 拆分方法 官方四节课教程细节剖析 data class 组件代码翻译 单例类 适配器的替代品 简单小动画 概况 compose 摒弃了原生开发模式中的 xml,代码结构类似于 flutter compose 仅支持 kotlin,虽然这玩意语法糖多但是也不难学 compose 可以通过极短的代码行数构建完善页面 开启新工程 首先请去 android 官网下载 android studio: 官网下载速度是正常的,别担心: 之后根据提示安装 android

  • Android Compose状态改变动画animateXxxAsState使用详解

    目录 前言 animateXxxAsState 基础使用 动画监听 使用示例 animateFloatAsState animateIntAsState animateColorAsState animateSizeAsState/animateIntSizeAsState animateOffsetAsState/animateIntOffsetAsState animateRectAsState 实战 最后 前言 上一篇文章我们探索了 Compose 中属性动画的使用,发现属性动画确实是可以

  • Android Compose实现伸缩ToolBar的思路详解

    目录 ScrollableAppBar 效果图 主要思路 布局预览 实现过程 ScrollableAppBar 效果图 当列表向上移动时,会先带动ToolBar向上位移,等ToolBar向上移动到最大位移量时列表向上滑动 当列表向下移动时,会先带动ToolBar向下位移,等ToolBar向下移动到最大位移量时列表向下滑动 主要思路 布局预览 伸缩前布局: 伸缩后布局: 实现过程 布局实现 首先我们要定义两个尺寸变量 // 应用栏高度 private val toolBarHeight = 56.

  • Android Flutter实现3D动画效果示例详解

    目录 前言 AnimatedWidget 简介 3D 旋转动画的实现 总结 前言 上一篇我们介绍了 Animation 和 AnimationController 的使用,这是最基本的动画构建类.但是,如果我们想构建一个可复用的动画组件,通过外部参数来控制其动画效果的时候,上一篇的方法就不太合适了.在 Flutter 中提供了 AnimatedWidget 组件用于构建可复用的动画组件.本篇我们用 AnimatedWidget 来实现组件的3D 旋转效果,如下图所示. AnimatedWidge

  • Android开发之Animations动画用法实例详解

    本文实例讲述了Android开发之Animations动画用法.分享给大家供大家参考,具体如下: 一.动画类型 Android的animation由四种类型组成:alpha.scale.translate.rotate XML配置文件中 alpha 渐变透明度动画效果 scale 渐变尺寸伸缩动画效果 translate 画面转换位置移动动画效果 rotate 画面转移旋转动画效果 Java Code代码中 AlphaAnimation 渐变透明度动画效果 ScaleAnimation 渐变尺寸

  • Jetpack Compose自定义动画与Animatable详解

    目录 AnimationSpec 1.spring 2.tween 3.keyframes 4.repeatable 5.snap Animatable 本篇主要是自定义动画与Animatable. AnimationSpec 上一篇中,出现了多次animationSpec属性,它是用来自定义动画规范的.例如: fun Modifier.animateContentSize( animationSpec: FiniteAnimationSpec<IntSize> = spring(), fin

  • Android 帧动画的实例详解

    Android 帧动画的实例详解 对于 Android 帧动画 大体上可以理解成 一张张图片 按一定顺序切换, 这样当连续几张图是一组动画时,就可以连起来了看成是一个小电影,你懂得 好得,比就装到这里,下面开始进入正题,由于产品需求 需要做一个 声音喇叭动态切换的样式,我特么第一就想到是帧动画切换,然后就百度了一些资料,发现 真的, 现在这个网上太多的资料是 copy粘贴过来的, 一错全错,对于这种情况我只想说,made,一群垃圾, 所以今天我将带你们走进Android 正确帧动画地址. 第一步

  • Android 逐帧动画创建实例详解

    Android 逐帧动画创建实例详解 前言: 我们看早期电影的时候,电影通常是一张一张播放,用我们现在专有名词来说,就是一帧帧来,安卓同样有这样动画效果的编排形式. 那么我们先定义逐帧动画xml文件 <?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" an

  • Android 控件自动贴边实现实例详解

    目录 正文 判断交互 隐藏与显示 示例 正文 最近接到个需求,需要在用户与App交互时,把SDK中之前实现过的悬浮控件贴边隐藏,结束交互后延迟一段时间再自动显示.本篇文章介绍一下实现的思路. 判断交互 用户与App交互.结束交互可以通过监听触摸事件来实现.建议使用的Activity的dispatchTouchEvent,Activity下的所有触摸事件分发时都会回调此方法,代码如下: class AutoEdgeHideActivity : BaseGestureDetectorActivity

  • IOS swift中的动画的实例详解

    IOS swift中的动画的实例详解 UIView的通用动画 let view = UIView(frame: CGRectMake(10.0, 10.0, 100.0, 40.0)) self.view.addSubview(view) view.backgroundColor = UIColor.lightGrayColor() // 位置改变 var frame = view.frame UIView.animateWithDuration(0.6, delay: 2.0, options

随机推荐