首页 > 其他分享 >Android开发 Jetpack Compose 动画

Android开发 Jetpack Compose 动画

时间:2023-08-24 15:33:57浏览次数:45  
标签:modifier Compose val Jetpack value Android Modifier true imageVisible

前言

  此篇博客讲解Jetpack Compose的动画实现

  官网地址:https://developer.android.google.cn/jetpack/compose/animation?hl=zh-cn

 

AnimatedVisibility - 隐藏显示动画

默认效果

效果图

代码

@Composable
fun APage() {
    val imageVisible = remember {
        mutableStateOf(true)
    }
    //这边用一个协程,以1500毫秒反复显示与隐藏
    LaunchedEffect(true){
        for (i in 0..10){
            delay(1500)
            imageVisible.value = !imageVisible.value
        }
    }
    Box(modifier = Modifier.fillMaxSize()) {
        AnimatedVisibility(visible = imageVisible.value, modifier = Modifier.align(Alignment.Center)) {
            Image(
                painter = painterResource(id = R.mipmap.ic_fruit_apple),
                contentDescription = null,
                modifier = Modifier
                    .size(100.dp)
            )
        }
    }
}

淡入淡出效果 fadeIn与fadeOut

效果图

代码

@Composable
fun APage() {
    val imageVisible = remember {
        mutableStateOf(true)
    }
    //这边用一个协程,以1500毫秒反复显示与隐藏
    LaunchedEffect(true) {
        for (i in 0..50) {
            delay(1500)
            imageVisible.value = !imageVisible.value
        }
    }
    Box(
        modifier = Modifier.fillMaxSize()
    ) {
        //>>>>>>>>>淡入淡出效果 fadeIn与fadeOut
        AnimatedVisibility(
            modifier = Modifier.align(Alignment.Center),
            visible = imageVisible.value,
            enter = fadeIn(
                initialAlpha = 0f
            ),
            exit = fadeOut(targetAlpha = 0f)
        ) {
            Image(
                painter = painterResource(id = R.mipmap.ic_fruit_watermelon),
                contentDescription = null,
                modifier = Modifier
                    .size(100.dp)
            )
        }
    }
}

滑入滑出 slideIn与slideOut

效果图

代码

@Composable
fun APage() {
    val imageVisible = remember {
        mutableStateOf(true)
    }
    //这边用一个协程,以1500毫秒反复显示与隐藏
    LaunchedEffect(true) {
        for (i in 0..50) {
            delay(1500)
            imageVisible.value = !imageVisible.value
        }
    }
    Box(
        modifier = Modifier.fillMaxSize()
    ) {
        //>>>>>>>>>滑入滑出 slideIn与slideOut
        AnimatedVisibility(
            modifier = Modifier.align(Alignment.Center),
            visible = imageVisible.value,
            enter = slideIn { IntOffset(-100, -100) },
            exit = slideOut { IntOffset(100, 100) }
        ) {
            Image(
                painter = painterResource(id = R.mipmap.ic_fruit_watermelon),
                contentDescription = null,
                modifier = Modifier
                    .size(100.dp)
            )
        }
    }
}

水平滑入与水平滑出 slideInHorizontally与slideOutHorizontally

效果图

代码

@Composable
fun APage() {
    val imageVisible = remember {
        mutableStateOf(true)
    }
    //这边用一个协程,以1500毫秒反复显示与隐藏
    LaunchedEffect(true) {
        for (i in 0..50) {
            delay(1500)
            imageVisible.value = !imageVisible.value
        }
    }
    Box(
        modifier = Modifier.fillMaxSize()
    ) {
        //>>>>>>>>>水平滑入与水平滑出 slideInHorizontally与slideOutHorizontally
        AnimatedVisibility(
            modifier = Modifier.align(Alignment.Center),
            visible = imageVisible.value,
            enter = slideInHorizontally(initialOffsetX = {fullWidth->
                return@slideInHorizontally -(fullWidth/2)
            }),
            exit = slideOutHorizontally(targetOffsetX = {fullWidth->
                return@slideOutHorizontally fullWidth/2
            })
        ) {
            Image(
                painter = painterResource(id = R.mipmap.ic_fruit_watermelon),
                contentDescription = null,
                modifier = Modifier
                    .size(100.dp)
            )
        }
    }
}

垂直滑入与垂直滑出 slideInVertically与slideOutVertically

效果图

代码

@Composable
fun APage() {
    val imageVisible = remember {
        mutableStateOf(true)
    }
    //这边用一个协程,以1500毫秒反复显示与隐藏
    LaunchedEffect(true) {
        for (i in 0..50) {
            delay(1500)
            imageVisible.value = !imageVisible.value
        }
    }
    Box(
        modifier = Modifier.fillMaxSize()
    ) {
        //>>>>>>>>>垂直滑入与垂直滑出 slideInVertically与slideOutVertically
        AnimatedVisibility(
            modifier = Modifier.align(Alignment.Center),
            visible = imageVisible.value,
            enter = slideInVertically(initialOffsetY = {fullHeight->
                return@slideInVertically -(fullHeight/2)
            }),
            exit = slideOutVertically(targetOffsetY = {fullHeight->
                return@slideOutVertically fullHeight/2
            })
        ) {
            Image(
                painter = painterResource(id = R.mipmap.ic_fruit_watermelon),
                contentDescription = null,
                modifier = Modifier
                    .size(100.dp)
            )
        }
    }
}

缩放进入与缩放退出 scaleIn与scaleOut

效果图

代码

@OptIn(ExperimentalAnimationApi::class)
@Composable
fun APage() {
    val imageVisible = remember {
        mutableStateOf(true)
    }
    //这边用一个协程,以1500毫秒反复显示与隐藏
    LaunchedEffect(true) {
        for (i in 0..50) {
            delay(1500)
            imageVisible.value = !imageVisible.value
        }
    }
    Box(
        modifier = Modifier.fillMaxSize()
    ) {
        //>>>>>>>>>缩放进入与缩放退出 scaleIn与scaleOut
        AnimatedVisibility(
            modifier = Modifier.align(Alignment.Center),
            visible = imageVisible.value,
            enter = scaleIn(animationSpec = spring(),initialScale = 0.1f, transformOrigin = TransformOrigin.Center),
            exit = scaleOut(animationSpec = spring(),targetScale = 0.1f, transformOrigin = TransformOrigin.Center)
        ) {
            Image(
                painter = painterResource(id = R.mipmap.ic_fruit_watermelon),
                contentDescription = null,
                modifier = Modifier
                    .size(100.dp)
            )
        }
    }
}

扩展与收缩 expandIn与shrinkOut

效果图

代码

@Composable
fun APage() {
    val imageVisible = remember {
        mutableStateOf(true)
    }
    //这边用一个协程,以1500毫秒反复显示与隐藏
    LaunchedEffect(true) {
        for (i in 0..50) {
            delay(1500)
            imageVisible.value = !imageVisible.value
        }
    }
    Box(
        modifier = Modifier.fillMaxSize()
    ) {
        //>>>>>>>>>扩展与收缩 expandIn与shrinkOut
        AnimatedVisibility(
            modifier = Modifier.align(Alignment.Center),
            visible = imageVisible.value,
            enter = expandIn(),
            exit = shrinkOut()
        ) {
            Image(
                painter = painterResource(id = R.mipmap.ic_fruit_watermelon),
                contentDescription = null,
                modifier = Modifier
                    .size(100.dp)
            )
        }
    }
}

水平扩展与水平收缩 expandHorizontally与shrinkHorizontally

效果图

代码

@Composable
fun APage() {
    val imageVisible = remember {
        mutableStateOf(true)
    }
    //这边用一个协程,以1500毫秒反复显示与隐藏
    LaunchedEffect(true) {
        for (i in 0..50) {
            delay(1500)
            imageVisible.value = !imageVisible.value
        }
    }
    Box(
        modifier = Modifier.fillMaxSize()
    ) {
        //>>>>>>>>>水平扩展与水平收缩 expandHorizontally与shrinkHorizontally
        AnimatedVisibility(
            modifier = Modifier.align(Alignment.Center),
            visible = imageVisible.value,
            enter = expandHorizontally(),
            exit = shrinkHorizontally()
        ) {
            Image(
                painter = painterResource(id = R.mipmap.ic_fruit_watermelon),
                contentDescription = null,
                modifier = Modifier
                    .size(100.dp)
            )
        }
    }
}

垂直扩展与垂直收缩 expandVertically与shrinkVertically

效果图

代码

@Composable
fun APage() {
    val imageVisible = remember {
        mutableStateOf(true)
    }
    //这边用一个协程,以1500毫秒反复显示与隐藏
    LaunchedEffect(true) {
        for (i in 0..50) {
            delay(1500)
            imageVisible.value = !imageVisible.value
        }
    }
    Box(
        modifier = Modifier.fillMaxSize()
    ) {
        //>>>>>>>>>垂直扩展与垂直收缩 expandVertically与shrinkVertically
        AnimatedVisibility(
            modifier = Modifier.align(Alignment.Center),
            visible = imageVisible.value,
            enter = expandVertically(),
            exit = shrinkVertically()
        ) {
            Image(
                painter = painterResource(id = R.mipmap.ic_fruit_watermelon),
                contentDescription = null,
                modifier = Modifier
                    .size(100.dp)
            )
        }
    }
}

属性动画

一共有如下类型值的属性动画函数,他们的使用都是类似的。此外这些属性动画函数还需要配合插值器使用。

  • animateValueAsState : 其他的animateXxxAsState内部都是调用的这个
  • animateRectAsState : 参数是传的一个Rect对象,Rect(left,top,right,bottom)
  • animateIntAsState : 参数传的是Int
  • animateDpAsState : 参数传的是Dp
  • animateFloatAsState : 参数传的是Float
  • animateColorAsState : 参数传的是Color
  • animateOffsetAsState : 参数传的是Offset,Offset(x,y),x和y是Float类型
  • animateIntOffsetAsState : 参数传的是IntOffset,IntOffset(x,y),x和y是Int类型
  • animateSizeAsState : 参数传的是Size,Size(width,height),width和height是Float类型
  • animateIntSizeAsState : 参数传的是IntSize,IntSize(width,height),width和height是Int类型

animateFloatAsState与spring插值器

上面的属性动画函数使用都是类似的,这里以animateFloatAsState与spring插值器来举例

y轴移动动画

效果图

代码

请注意!下面的代码中,设置动画属性的函数是graphicsLayer。 这里不建议直接使用offset或者scale等等这些函数来说实现动画(可以在graphicsLayer里调用offset),因为直接offset会引起父类容器的重组,导致整个页面都在重组刷新,有些时候还会引起移动时抖动或者拖影的现象。 这里建议使用graphicsLayer会将重组范围限制到当前组件里,避免父类与其他组件都连带重组。

@Composable
fun APage() {
    val startAnim = remember {
        mutableStateOf(false)
    }
    //创建y轴的动画数值
    val yAnimValue = animateDpAsState(
        //targetValue为动画的目标数值
        targetValue = if (startAnim.value) 200.dp else 0.dp,
        //animationSpec动画的可选插值器,目前的结尾弹跳效果就是spring这个插值器实现的
        animationSpec = spring(
            dampingRatio = Spring.DampingRatioHighBouncy,
            stiffness = Spring.StiffnessMedium
        )
    )

    Box(
        modifier = Modifier.fillMaxSize()
    ) {
        Surface(color = Color.Gray, modifier = Modifier
            .graphicsLayer {
                translationY = yAnimValue.value.toPx()
            }
            .size(50.dp)
            .align(Alignment.Center)
            .clickable {
                //点击启动动画
                startAnim.value = !startAnim.value
            }) {

        }
    }
}

tween插值器

tween插值器可以设置动画时间

效果图

代码

@Composable
fun Animation() {
    val position = remember {
        mutableStateOf(Offset(0f, 0f))
    }
    val duration = remember {
        mutableStateOf(3000)
    }
    //动画数值
    val animValue = animateOffsetAsState(
        targetValue = position.value,
        animationSpec = tween(durationMillis = duration.value, easing = LinearEasing)
    )
    //移动位置集合
    val starList = listOf(
        //第一个参数是坐标,第二个参数延迟时间
        Offset(-100f, -100f) to 1000,//左上
        Offset(-100f, 100f) to 1000,//左下
        Offset(100f, 100f) to 1000,//右下
        Offset(100f, -100f) to 1000,//右上
    )

    LaunchedEffect(true) {
        delay(2000)
        for (item in starList) {
            position.value = item.first
            duration.value = item.second
            delay(duration.value.toLong())
        }
    }
    Box(modifier = Modifier.fillMaxSize()) {
        Image(
            painter = painterResource(id = R.mipmap.ic_red_dot),
            contentDescription = null,
            modifier = Modifier
                .graphicsLayer {
                    translationX = animValue.value.x
                    translationY = animValue.value.y
                }
                .align(Alignment.Center)
        )
    }
}

 

 

在Canvas里的使用例子

效果图

代码


@Composable
fun AnimationBg() {
    //-400.dp 到 -1500.dp 动画范围值
    val yPosition = remember {
        mutableStateOf(-400.dp)
    }
    //y轴动画数值
    val yAnimValue = animateDpAsState(
        targetValue = yPosition.value,
        animationSpec = tween(durationMillis = 15_000, easing = LinearEasing)
    )
    val rotate = remember {
        mutableStateOf(0f)
    }
    //旋转动画,请注意这里使用的是animateFloatAsState
    val rotateAnimValue = animateFloatAsState(
        targetValue = rotate.value,
        animationSpec = tween(durationMillis = 5000, easing = LinearEasing)
    )
    LaunchedEffect(true) {
        var isFront = true
        val angleList = listOf<Float>(0f, 45f, 90f, 135f)
        var count = 0
        while (isActive) {
            isFront = !isFront
            if (isFront) {
                yPosition.value = -400.dp
            } else {
                yPosition.value = -1500.dp
            }
            delay(15_000)
            count++
            if (count > 2){
                count = 0
                rotate.value = angleList.random()
            }
        }
    }
    Canvas(
        modifier = Modifier
            .fillMaxSize()
            .rotate(rotateAnimValue.value)
    ) {
        val itemHeight = size.height / 30
        for (index in 0..200) {
            if (index % 2 == 0) {
                //黑色
                drawLine(
                    color = Color.Black,
                    start = Offset(-500f, itemHeight * index + yAnimValue.value.toPx()),
                    end = Offset(size.width + 500f, itemHeight * index + yAnimValue.value.toPx()),
                    strokeWidth = itemHeight
                )
            } else {
                //白色
                drawLine(
                    color = Color.White,
                    start = Offset(-500f, itemHeight * index + yAnimValue.value.toPx()),
                    end = Offset(size.width + 500f, itemHeight * index + yAnimValue.value.toPx()),
                    strokeWidth = itemHeight
                )
            }
        }
    }
}

 

end

标签:modifier,Compose,val,Jetpack,value,Android,Modifier,true,imageVisible
From: https://www.cnblogs.com/guanxinjing/p/17617292.html

相关文章

  • 直播源码开发,Android判断网络是否可用
    直播源码开发,Android判断网络是否可用staticConnectivityManagermConnectivityManager; /** *判断网络是否可用 * *@paramcontext *@return */publicstaticbooleanisNetworkAvailed(finalContextcontext){  if(context==null)  {    return......
  • Android WiFi 扫描流程
    1.WiFiManagerpackages\modules\Wifi\framework\java\android\net\wifi\WifiManager.java startScan@DeprecatedpublicbooleanstartScan(){returnstartScan(null);}/**@hide*/@SystemApi@RequiresPermission(android.Ma......
  • 【GiraKoo】Android Studio编译时,提示java.nio.file.AccessDeniedException
    【问题解决】AndroidStudio编译时,提示java.nio.file.AccessDeniedException在使用AndroidStudio进行编译时,提示编译错误java.nio.file.AccessDeniedException。原因时当前使用Debug模式,停在断点上。导致编译程序无法替换被占用目标文件,输出该异常。【环境】AndroidStudio【......
  • linux服务器docker compose的使用步骤
    之前说了docker的安装,dockercompose的安装,还比较了dockerfile和dockercompose的区别,那么dockercompose的实际应用是怎么样呢?记录下我的实操步骤1、服务器上新建目录,目录情况如下,我的data目录是挂载到数据盘的/data/docker_config/nginx//存放nginx的配置文件/dat......
  • android studio 程序莫名其妙闪退 原来是TextView彩色字体设置惹祸
    androidstudio用listview显示item时,用下面的方法能设一行字不同的颜色,但其中一个小细节没注意,导致程序有时闪退,花了几个小时才找到问题的根源 SpannableStringBuildersb1=newSpannableStringBuilder(call);//修改化设置字体颜色 // sb1.setSpan(newForegroundColorSpan(......
  • 高级Android组件化、插件化强化实战,附大厂源码解析
    前言当今移动应用市场竞争激烈,为了在激烈的竞争中脱颖而出,开发人员需要不断提高应用性能,从而提高用户体验。而Android组件化和插件化技术则为优化性能提供了更好的方法。什么是组件化组件化技术是将一个大型的Android应用拆分成多个小模块或组件,每个组件负责不同的功能,通过组合不同......
  • docker compose 部署mysql数据库
    docker-compose.ymlversion:"3"services:mysql:image:mysql:5.7container_name:mysqlhostname:mysqlports:-3306:3306volumes:-/home/mysql/data:/var/lib/mysql-/home/mysql/conf/my.cnf:/etc/my.cnf......
  • Android开发行业零基础也可学,看似饱和但人才需求大!
    安卓开发难学吗?首先小编认为任何一门技术的学习,用心学就好学,不用心学再简单的技术你都觉得难学。这也是提醒大家:既然打算学习就要端正好心态。学安卓需要哪些基本知识?先学好Java基础:很多朋友一上手就开始学习Android,似乎太着急了一些。Android应用程序开发是以Java语言为基础的,所以......
  • Android 扫描WiFi
    代码:publicclassMainActivityextendsAppCompatActivity{StringTag="MainActivity";finalintPERMISSION_REQUEST_CODE=1;String[]permission=newString[]{Manifest.permission.ACCESS_FINE_LOCATION};@Overrideprotecte......
  • adb 命令查看 Android设备分辨率
    #查看机器分辨率adbshellwmsize#查看机器详细的分辨率adbshelldumpsyswindowdisplays result:¥adbshelldumpsyswindowdisplaysDumptime:2023-08-2303:54:43.075WINDOWMANAGERDISPLAYCONTENTS(dumpsyswindowdisplays)Display:mDisplayId=2init=......