深入剖析 Android Compose 框架的自动动画:AnimatedVisibility 与 AnimatedContent(二十四)
深入剖析 Android Compose 框架的自动动画:AnimatedVisibility 与 AnimatedContent
引言
在 Android 应用开发中,动画是提升用户体验的重要手段。它能够让界面元素的显示与隐藏、状态的切换变得更加自然和流畅,避免生硬的变化给用户带来不佳的感受。Android Compose 作为新一代的 Android UI 工具包,为开发者提供了强大而便捷的动画支持,其中 AnimatedVisibility
和 AnimatedContent
这两个组件是实现自动动画的关键部分。
AnimatedVisibility
主要用于实现元素的显示与隐藏动画,开发者只需控制元素的可见性状态,Compose 会自动为其添加过渡动画。而 AnimatedContent
则专注于内容的动态变化动画,当内容发生改变时,能够平滑地过渡到新的内容。
本文将从源码级别深入分析 AnimatedVisibility
和 AnimatedContent
这两个组件,详细解读它们的实现原理、使用方法以及如何进行性能优化,帮助开发者更好地掌握 Android Compose 中的自动动画技术。
一、Android Compose 自动动画概述
1.1 自动动画在 Android 开发中的重要性
在现代 Android 应用中,用户对于界面的交互体验要求越来越高。自动动画能够为应用带来以下优势:
- 提升用户体验:通过自然流畅的动画效果,让用户在操作界面时感受到更加舒适和愉悦,增强用户对应用的好感度。例如,在显示或隐藏一个菜单时,使用动画过渡可以避免界面的突然变化,让用户更容易理解操作的结果。
- 增强界面的可读性:动画可以引导用户的注意力,使重要的信息更加突出。比如,在更新界面内容时,使用动画过渡可以让用户更清晰地看到哪些内容发生了变化。
- 提高应用的专业性:精美的动画效果能够让应用看起来更加专业和高端,与竞争对手形成差异化。
1.2 Android Compose 中的自动动画特性
Android Compose 为自动动画提供了一系列简洁而强大的 API,具有以下特性:
- 声明式编程:与传统的 Android 动画开发方式相比,Compose 采用声明式编程模型,开发者只需描述动画的起始和结束状态,Compose 会自动处理中间的过渡过程,大大简化了动画的实现。
- 高性能:Compose 对动画进行了优化,能够高效地利用系统资源,确保动画的流畅性。它采用智能的重组机制,只有当动画相关的状态发生变化时,才会重新计算和绘制界面。
- 可组合性:Compose 的动画组件可以轻松地与其他组件组合使用,开发者可以根据需要创建复杂的动画效果。
1.3 AnimatedVisibility
和 AnimatedContent
的基本概念
-
AnimatedVisibility
:该组件用于控制元素的可见性,并在元素显示或隐藏时添加动画效果。开发者可以通过设置visible
参数来控制元素的可见性,Compose 会自动应用预设的动画或自定义动画。 -
AnimatedContent
:这个组件用于在内容发生变化时添加动画过渡。当传递给AnimatedContent
的内容发生改变时,它会平滑地过渡到新的内容,而不是直接替换。
下面是一个简单的 AnimatedVisibility
示例:
kotlin
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.*@OptIn(ExperimentalAnimationApi::class)
@Composable
fun SimpleAnimatedVisibilityExample() {// 定义一个可变状态,用于控制元素的可见性var isVisible by remember { mutableStateOf(false) }// 创建一个按钮,点击时切换元素的可见性Button(onClick = { isVisible = !isVisible }) {Text(text = if (isVisible) "Hide" else "Show")}// 使用 AnimatedVisibility 组件,根据 isVisible 的值控制元素的显示与隐藏,并添加淡入淡出动画AnimatedVisibility(visible = isVisible,enter = fadeIn(), // 元素显示时的动画exit = fadeOut() // 元素隐藏时的动画) {Text(text = "This is a visible text.")}
}
在这个示例中,我们通过一个按钮来控制 Text
组件的可见性。当点击按钮时,isVisible
的值会发生变化,AnimatedVisibility
会根据这个值决定是否显示 Text
组件,并应用相应的淡入淡出动画。
二、AnimatedVisibility
源码分析
2.1 AnimatedVisibility
的基本定义与结构
AnimatedVisibility
是一个 Composable 函数,其定义如下:
kotlin
@ExperimentalAnimationApi
@Composable
fun AnimatedVisibility(visible: Boolean, // 控制元素的可见性modifier: Modifier = Modifier, // 修饰符,用于设置组件的布局和样式enter: EnterTransition = fadeIn() + expandVertically(), // 元素显示时的动画exit: ExitTransition = fadeOut() + shrinkVertically(), // 元素隐藏时的动画initiallyVisible: Boolean = visible, // 初始可见性content: @Composable () -> Unit // 要显示的内容
) {// 内部实现逻辑val transition = updateTransition(targetState = visible, label = "AnimatedVisibility")transition.AnimatedVisibilityScope(modifier = modifier,enter = enter,exit = exit,initiallyVisible = initiallyVisible,content = content)
}
从代码中可以看出,AnimatedVisibility
接受多个参数:
-
visible
:一个布尔值,用于控制元素的可见性。 -
modifier
:用于设置组件的布局和样式。 -
enter
:元素显示时的动画,默认为淡入和垂直展开动画。 -
exit
:元素隐藏时的动画,默认为淡出和垂直收缩动画。 -
initiallyVisible
:初始可见性,默认为visible
的值。 -
content
:要显示的内容,是一个 Composable 函数。
在函数内部,首先调用 updateTransition
函数创建一个 Transition
对象,用于管理动画的过渡状态。然后调用 AnimatedVisibilityScope
函数,将过渡状态、动画和内容传递给它。
2.2 updateTransition
函数源码解读
updateTransition
函数用于创建一个 Transition
对象,其源码如下:
kotlin
@Composable
fun <T> updateTransition(targetState: T, // 目标状态label: String = "Transition" // 过渡的标签,用于调试
): Transition<T> {// 创建一个可变状态,用于存储当前状态val transitionState = remember { MutableTransitionState(targetState) }// 更新当前状态为目标状态transitionState.targetState = targetState// 返回一个 Transition 对象return remember(transitionState) {Transition(transitionState = transitionState,label = label)}
}
updateTransition
函数接受两个参数:
-
targetState
:目标状态,即动画要过渡到的状态。 -
label
:过渡的标签,用于调试目的。
在函数内部,首先使用 remember
函数创建一个 MutableTransitionState
对象,用于存储当前状态。然后将目标状态赋值给 targetState
属性。最后,使用 remember
函数创建一个 Transition
对象,并返回它。
2.3 AnimatedVisibilityScope
函数源码分析
AnimatedVisibilityScope
函数用于处理元素的显示与隐藏动画,其源码如下:
kotlin
@ExperimentalAnimationApi
@Composable
fun Transition<Boolean>.AnimatedVisibilityScope(modifier: Modifier = Modifier,enter: EnterTransition = fadeIn() + expandVertically(),exit: ExitTransition = fadeOut() + shrinkVertically(),initiallyVisible: Boolean = currentState,content: @Composable () -> Unit
) {// 根据当前状态和初始可见性计算是否需要执行动画val shouldAnimate = initiallyVisible != currentState || initiallyVisible != targetState// 创建一个动画状态,用于控制元素的显示与隐藏val visibleState = remember { MutableTransitionState(initiallyVisible) }visibleState.targetState = currentState// 根据是否需要执行动画,决定是否应用动画if (shouldAnimate) {val enterTransition = enter.createInitialValues(visibleState)val exitTransition = exit.createInitialValues(visibleState)val transition = updateTransition(visibleState, label = "AnimatedVisibilityScope")transition.AnimatedContent(modifier = modifier,transitionSpec = {if (targetState) {enterTransition} else {exitTransition}},content = content)} else {// 如果不需要执行动画,直接显示或隐藏内容if (currentState) {content()}}
}
AnimatedVisibilityScope
函数是 Transition<Boolean>
的扩展函数,接受多个参数:
-
modifier
:用于设置组件的布局和样式。 -
enter
:元素显示时的动画。 -
exit
:元素隐藏时的动画。 -
initiallyVisible
:初始可见性。 -
content
:要显示的内容。
在函数内部,首先计算是否需要执行动画。如果需要执行动画,则创建进入和退出动画的初始值,并使用 updateTransition
函数创建一个新的 Transition
对象。然后调用 AnimatedContent
函数,根据目标状态选择合适的动画进行过渡。如果不需要执行动画,则直接根据当前状态显示或隐藏内容。
2.4 AnimatedVisibility
的使用示例与代码解析
下面是一个更复杂的 AnimatedVisibility
使用示例:
kotlin
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.expandHorizontally
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkHorizontally
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp@OptIn(ExperimentalAnimationApi::class)
@Composable
fun ComplexAnimatedVisibilityExample() {// 定义一个可变状态,用于控制元素的可见性var isVisible by remember { mutableStateOf(false) }// 创建一个 Column 组件,用于布局按钮和要显示的内容Column(modifier = Modifier.fillMaxWidth().padding(16.dp),horizontalAlignment = Alignment.CenterHorizontally) {// 创建一个按钮,点击时切换元素的可见性Button(onClick = { isVisible = !isVisible }) {Text(text = if (isVisible) "Hide" else "Show")}// 使用 AnimatedVisibility 组件,根据 isVisible 的值控制元素的显示与隐藏,并添加水平展开和收缩动画AnimatedVisibility(visible = isVisible,enter = fadeIn() + expandHorizontally(), // 元素显示时的动画exit = fadeOut() + shrinkHorizontally() // 元素隐藏时的动画) {// 创建一个 Box 组件,设置背景颜色和高度Box(modifier = Modifier.fillMaxWidth().height(100.dp).background(Color.Blue).padding(16.dp)) {// 在 Box 中显示文本Text(text = "This is a visible box.", color = Color.White)}}}
}
代码解析:
- 首先,使用
remember
函数创建一个可变状态isVisible
,用于控制元素的可见性。 - 然后,创建一个
Column
组件,用于布局按钮和要显示的内容。 - 接着,创建一个按钮,点击时切换
isVisible
的值。 - 最后,使用
AnimatedVisibility
组件,根据isVisible
的值控制Box
组件的显示与隐藏。在显示时,应用淡入和水平展开动画;在隐藏时,应用淡出和水平收缩动画。
三、AnimatedContent
源码分析
3.1 AnimatedContent
的基本定义与结构
AnimatedContent
是一个 Composable 函数,用于在内容发生变化时添加动画过渡,其定义如下:
kotlin
@ExperimentalAnimationApi
@Composable
fun <T> AnimatedContent(targetState: T, // 目标状态modifier: Modifier = Modifier, // 修饰符,用于设置组件的布局和样式transitionSpec: AnimatedContentScope<T>.() -> ContentTransform = {fadeIn() with fadeOut()}, // 过渡动画的规范contentAlignment: Alignment = Alignment.TopStart, // 内容的对齐方式content: @Composable AnimatedContentScope<T>.(T) -> Unit // 要显示的内容
) {// 内部实现逻辑val transition = updateTransition(targetState, label = "AnimatedContent")transition.AnimatedContent(modifier = modifier,transitionSpec = transitionSpec,contentAlignment = contentAlignment,content = content)
}
AnimatedContent
接受多个参数:
-
targetState
:目标状态,即内容要过渡到的状态。 -
modifier
:用于设置组件的布局和样式。 -
transitionSpec
:过渡动画的规范,定义了内容变化时的动画效果。 -
contentAlignment
:内容的对齐方式,默认为左上角对齐。 -
content
:要显示的内容,是一个 Composable 函数,接受当前状态作为参数。
在函数内部,首先调用 updateTransition
函数创建一个 Transition
对象,用于管理动画的过渡状态。然后调用 AnimatedContent
函数的扩展方法,将过渡状态、过渡动画规范、内容对齐方式和内容传递给它。
3.2 transitionSpec
参数的作用与实现
transitionSpec
参数是一个 AnimatedContentScope<T>.() -> ContentTransform
类型的函数,用于定义内容变化时的动画效果。ContentTransform
是一个包含进入动画和退出动画的对象。
下面是一个自定义 transitionSpec
的示例:
kotlin
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment@OptIn(ExperimentalAnimationApi::class)
@Composable
fun CustomTransitionSpecExample() {// 定义一个可变状态,用于控制内容的变化var state by remember { mutableStateOf(1) }// 自定义过渡动画规范val customTransitionSpec = {// 定义进入动画为淡入和缩放进入val enterTransition = fadeIn() + scaleIn()// 定义退出动画为淡出和缩放退出val exitTransition = fadeOut() + scaleOut()// 定义大小变换动画val sizeTransform = SizeTransform(clip = false)// 返回一个 ContentTransform 对象,包含进入动画、退出动画和大小变换动画ContentTransform(targetContentEnter = enterTransition,initialContentExit = exitTransition,sizeTransform = sizeTransform)}// 使用 AnimatedContent 组件,根据 state 的值显示不同的内容,并应用自定义过渡动画AnimatedContent(targetState = state,transitionSpec = customTransitionSpec,contentAlignment = Alignment.Center) { currentState ->// 根据当前状态显示不同的文本Text(text = "State: $currentState")}// 创建一个按钮,点击时切换状态Button(onClick = { state = if (state == 1) 2 else 1 }) {Text(text = "Change State")}
}
在这个示例中,我们自定义了一个 transitionSpec
,定义了进入动画为淡入和缩放进入,退出动画为淡出和缩放退出,并添加了大小变换动画。当点击按钮时,state
的值会发生变化,AnimatedContent
会根据新的状态显示不同的内容,并应用自定义的过渡动画。
3.3 AnimatedContent
的内容更新与动画触发机制
AnimatedContent
的内容更新和动画触发机制主要依赖于 targetState
参数。当 targetState
的值发生变化时,AnimatedContent
会检测到这个变化,并根据 transitionSpec
中定义的动画效果进行过渡。
在 AnimatedContent
内部,updateTransition
函数会监听 targetState
的变化,并创建一个 Transition
对象。当 targetState
发生变化时,Transition
对象会自动触发动画过渡。
3.4 AnimatedContent
的使用示例与代码解析
下面是一个更详细的 AnimatedContent
使用示例:
kotlin
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp@OptIn(ExperimentalAnimationApi::class)
@Composable
fun DetailedAnimatedContentExample() {// 定义一个可变状态,用于控制内容的变化var state by remember { mutableStateOf("A") }// 自定义过渡动画规范val customTransitionSpec = {// 定义进入动画为淡入和缩放进入val enterTransition = fadeIn() + scaleIn()// 定义退出动画为淡出和缩放退出val exitTransition = fadeOut() + scaleOut()// 定义大小变换动画val sizeTransform = SizeTransform(clip = false)// 返回一个 ContentTransform 对象,包含进入动画、退出动画和大小变换动画ContentTransform(targetContentEnter = enterTransition,initialContentExit = exitTransition,sizeTransform = sizeTransform)}// 创建一个 Column 组件,用于布局按钮和 AnimatedContent 组件Column(modifier = Modifier.fillMaxWidth().padding(16.dp),horizontalAlignment = Alignment.CenterHorizontally) {// 使用 AnimatedContent 组件,根据 state 的值显示不同的内容,并应用自定义过渡动画AnimatedContent(targetState = state,transitionSpec = customTransitionSpec,contentAlignment = Alignment.Center) { currentState ->// 根据当前状态显示不同的文本Box(modifier = Modifier.fillMaxWidth().padding(16.dp).background(if (currentState == "A") androidx.compose.ui.graphics.Color.Red else androidx.compose.ui.graphics.Color.Blue)) {Text(text = "State: $currentState", color = androidx.compose.ui.graphics.Color.White)}}// 创建两个按钮,分别用于切换到状态 A 和状态 BButton(onClick = { state = "A" }) {Text(text = "Change to State A")}Button(onClick = { state = "B" }) {Text(text = "Change to State B")}}
}
代码解析:
- 首先,使用
remember
函数创建一个可变状态state
,用于控制内容的变化。 - 然后,自定义一个
transitionSpec
,定义了进入动画、退出动画和大小变换动画。 - 接着,创建一个
Column
组件,用于布局按钮和AnimatedContent
组件。 - 在
AnimatedContent
组件中,根据state
的值显示不同的内容,并应用自定义的过渡动画。 - 最后,创建两个按钮,分别用于切换到状态 A 和状态 B。
四、AnimatedVisibility
与 AnimatedContent
的对比与结合
4.1 AnimatedVisibility
与 AnimatedContent
的功能对比
-
功能侧重点
AnimatedVisibility
:主要侧重于控制元素的可见性,并在显示和隐藏元素时添加动画效果。它关注的是元素的整体显示与隐藏状态的变化。AnimatedContent
:主要侧重于在内容发生变化时添加动画过渡。它关注的是内容的动态更新,而不仅仅是元素的可见性。
-
使用场景
AnimatedVisibility
:适用于需要显示或隐藏某个元素的场景,如菜单的展开与收缩、提示信息的显示与隐藏等。AnimatedContent
:适用于内容频繁变化的场景,如列表项的更新、文本内容的切换等。
4.2 如何在项目中结合使用 AnimatedVisibility
与 AnimatedContent
在实际项目中,可以将 AnimatedVisibility
和 AnimatedContent
结合使用,以实现更复杂的动画效果。下面是一个结合使用的示例:
kotlin
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp@OptIn(ExperimentalAnimationApi::class)
@Composable
fun CombinedExample() {// 定义一个可变状态,用于控制元素的可见性var isVisible by remember { mutableStateOf(false) }// 定义一个可变状态,用于控制内容的变化var state by remember { mutableStateOf("A") }// 自定义过渡动画规范val customTransitionSpec = {// 定义进入动画为淡入和缩放进入val enterTransition = fadeIn() + scaleIn()// 定义退出动画为淡出和缩放退出val exitTransition = fadeOut() + scaleOut()// 定义大小变换动画val sizeTransform = SizeTransform(clip = false)// 返回一个 ContentTransform 对象,包含进入动画、退出动画和大小变换动画ContentTransform(targetContentEnter = enterTransition,initialContentExit = exitTransition,sizeTransform = sizeTransform)}// 创建一个 Column 组件,用于布局按钮、AnimatedVisibility 组件和 AnimatedContent 组件Column(modifier = Modifier.fillMaxWidth().padding(16.dp),horizontalAlignment = Alignment.CenterHorizontally) {// 创建一个按钮,点击时切换元素的可见性Button(onClick = { isVisible = !isVisible }) {Text(text = if (isVisible) "Hide" else "Show")}// 使用 AnimatedVisibility 组件,根据 isVisible 的值控制元素的显示与隐藏,并添加淡入淡出动画AnimatedVisibility(visible = isVisible,enter = fadeIn(),exit = fadeOut()) {// 使用 AnimatedContent 组件,根据 state 的值显示不同的内容,并应用自定义过渡动画AnimatedContent(targetState = state,transitionSpec = customTransitionSpec,contentAlignment = Alignment.Center) { currentState ->// 根据当前状态显示不同的文本Box(modifier = Modifier.fillMaxWidth().padding(16.dp).background(if (currentState == "A") androidx.compose.ui.graphics.Color.Red else androidx.compose.ui.graphics.Color.Blue)) {Text(text = "State: $currentState", color = androidx.compose.ui.graphics.Color.White)}}}// 创建两个按钮,分别用于切换到状态 A 和状态 BButton(onClick = { state = "A" }) {Text(text = "Change to State A")}Button(onClick = { state = "B" }) {Text(text = "Change to State B")}}
}
在这个示例中,我们使用 AnimatedVisibility
控制整个内容区域的显示与隐藏,同时使用 AnimatedContent
控制内容区域内的内容变化。当点击 “Show/Hide” 按钮时,内容区域会淡入淡出显示或隐藏;当点击 “Change to State A” 或 “Change to State B” 按钮时,内容区域内的内容会根据状态的变化进行平滑过渡。
五、自动动画的应用场景与案例分析
5.1 常见的应用场景举例
菜单的展开与收缩
在很多应用中,会有菜单的展开与收缩功能。使用 AnimatedVisibility
可以轻松实现菜单的平滑展开和收缩动画,提升用户体验。
kotlin
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp@OptIn(ExperimentalAnimationApi::class)
@Composable
fun MenuExpandCollapseExample() {// 定义一个可变状态,用于控制菜单的可见性var isMenuVisible by remember { mutableStateOf(false) }// 创建一个 Column 组件,用于布局按钮和菜单Column(modifier = Modifier.fillMaxWidth().padding(16.dp),horizontalAlignment = Alignment.CenterHorizontally) {// 创建一个按钮,点击时切换菜单的可见性Button(onClick = { isMenuVisible = !isMenuVisible }) {Text(text = if (isMenuVisible) "Collapse Menu" else "Expand Menu")}// 使用 AnimatedVisibility 组件,根据 isMenuVisible 的值控制菜单的显示与隐藏,并添加淡入淡出和垂直滑动动画AnimatedVisibility(visible = isMenuVisible,enter = fadeIn() + slideInVertically(),exit = fadeOut() + slideOutVertically()) {// 创建一个 Column 组件,用于布局菜单项Column(modifier = Modifier.fillMaxWidth().padding(16.dp),verticalArrangement = Arrangement.spacedBy(8.dp)) {// 菜单项 1Text(text = "Menu Item 1")// 菜单项 2Text(text = "Menu Item 2")// 菜单项 3Text(text = "Menu Item 3")}}}
}
数据加载提示
当应用需要加载数据时,可以使用 AnimatedVisibility
显示加载提示,数据加载完成后隐藏提示。
kotlin
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Button
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.delay@OptIn(ExperimentalAnimationApi::class)
@Composable
fun DataLoadingExample() {// 定义一个可变状态,用于控制加载提示的可见性var isLoading by remember { mutableStateOf(false) }// 创建一个 Box 组件,用于布局按钮和加载提示Box(modifier = Modifier.fillMaxSize(),contentAlignment = Alignment.Center) {// 创建一个按钮,点击时模拟数据加载Button(onClick = {isLoading = true// 模拟 2 秒的数据加载时间LaunchedEffect(Unit) {delay(2000)isLoading = false}}) {Text(text = "Load Data")}// 使用 AnimatedVisibility 组件,根据 isLoading 的值控制加载提示的显示与隐藏,并添加淡入淡出动画AnimatedVisibility(visible = isLoading,enter = fadeIn(),exit = fadeOut()) {// 创建一个 Box 组件,用于布局加载进度指示器Box(modifier = Modifier.fillMaxWidth().padding(16.dp),contentAlignment = Alignment.Center) {// 加载进度指示器CircularProgressIndicator()}}}
}
列表项的更新
在列表中,当列表项的数据发生变化时,可以使用 AnimatedContent
实现平滑的过渡动画。
kotlin
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp@OptIn(ExperimentalAnimationApi::class)
@Composable
fun ListItemUpdateExample() {// 定义一个可变状态,用于存储列表项的数据var itemData by remember { mutableStateOf("Initial Data") }// 自定义过渡动画规范val customTransitionSpec = {// 定义进入动画为淡入和缩放进入val enterTransition = fadeIn() + scaleIn()// 定义退出动画为淡出和缩放退出val exitTransition = fadeOut() + scaleOut()// 定义大小变换动画val sizeTransform = SizeTransform(clip = false)// 返回一个 ContentTransform 对象,包含进入动画、退出动画和大小变换动画ContentTransform(targetContentEnter = enterTransition,initialContentExit = exitTransition,sizeTransform = sizeTransform)}// 创建一个 Column 组件,用于布局按钮和列表项Column(modifier = Modifier.fillMaxWidth().padding(16.dp),horizontalAlignment = Alignment.CenterHorizontally) {// 创建一个按钮,点击时更新列表项的数据Button(onClick = {itemData = "Updated Data"}) {Text(text = "Update Item")}// 使用 AnimatedContent 组件,根据 itemData 的值显示不同的内容,并应用自定义过渡动画AnimatedContent(targetState = itemData,transitionSpec = customTransitionSpec,contentAlignment = Alignment.Center) { currentData ->// 根据当前数据显示不同的文本Text(text = "Item Data: $currentData")}}
}
5.2 实际项目案例分析
社交应用的消息列表更新
在社交应用的消息列表中,当有新消息到来时,需要更新列表并显示新消息。可以使用 AnimatedContent
实现列表项的平滑更新动画,让用户更清晰地看到新消息的到来。
kotlin
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.delay@OptIn(ExperimentalAnimationApi::class)
@Composable
fun SocialMessageListExample() {// 定义一个可变状态,用于存储消息列表var messages by remember { mutableStateOf(listOf("Message 1", "Message 2")) }// 自定义过渡动画规范val customTransitionSpec = {// 定义进入动画为淡入和缩放进入val enterTransition = fadeIn() + scaleIn()// 定义退出动画为淡出和缩放退出val exitTransition = fadeOut() + scaleOut()// 定义大小变换动画val sizeTransform = SizeTransform(clip = false)// 返回一个 ContentTransform 对象,包含进入动画、退出动画和大小变换动画ContentTransform(targetContentEnter = enterTransition,initialContentExit = exitTransition,sizeTransform = sizeTransform)}// 模拟新消息到来LaunchedEffect(Unit) {delay(3000)messages = messages + "New Message"}// 创建一个 Column 组件,用于布局消息列表Column(modifier = Modifier.fillMaxWidth().padding(16.dp),verticalArrangement = Arrangement.spacedBy(8.dp)) {// 使用 AnimatedContent 组件,根据 messages 的值显示不同的消息列表,并应用自定义过渡动画AnimatedContent(targetState = messages,transitionSpec = customTransitionSpec,contentAlignment = Alignment.TopStart) { currentMessages ->// 遍历消息列表,显示每个消息current
五、自动动画的应用场景与案例分析
5.2 实际项目案例分析
社交应用的消息列表更新
kotlin
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.delay@OptIn(ExperimentalAnimationApi::class)
@Composable
fun SocialMessageListExample() {// 定义一个可变状态,用于存储消息列表var messages by remember { mutableStateOf(listOf("Message 1", "Message 2")) }// 自定义过渡动画规范val customTransitionSpec = {// 定义进入动画为淡入和缩放进入val enterTransition = fadeIn() + scaleIn()// 定义退出动画为淡出和缩放退出val exitTransition = fadeOut() + scaleOut()// 定义大小变换动画val sizeTransform = SizeTransform(clip = false)// 返回一个 ContentTransform 对象,包含进入动画、退出动画和大小变换动画ContentTransform(targetContentEnter = enterTransition,initialContentExit = exitTransition,sizeTransform = sizeTransform)}// 模拟新消息到来LaunchedEffect(Unit) {delay(3000)messages = messages + "New Message"}// 创建一个 Column 组件,用于布局消息列表Column(modifier = Modifier.fillMaxWidth().padding(16.dp),verticalArrangement = Arrangement.spacedBy(8.dp)) {// 使用 AnimatedContent 组件,根据 messages 的值显示不同的消息列表,并应用自定义过渡动画AnimatedContent(targetState = messages,transitionSpec = customTransitionSpec,contentAlignment = Alignment.TopStart) { currentMessages ->// 遍历消息列表,显示每个消息currentMessages.forEach { message ->Text(text = message,modifier = Modifier.fillMaxWidth().padding(8.dp))}}}
}
代码分析:
- 状态管理:通过
remember
创建可变状态messages
来存储消息列表。初始时,消息列表包含两条消息。 - 过渡动画规范:
customTransitionSpec
自定义了进入和退出动画,使用fadeIn
和scaleIn
组合作为进入动画,fadeOut
和scaleOut
组合作为退出动画,同时使用SizeTransform
处理大小变换。 - 模拟新消息:使用
LaunchedEffect
模拟 3 秒后有新消息到来,更新messages
列表。 - 消息列表显示:使用
AnimatedContent
组件,根据messages
的变化更新显示的消息列表。当新消息到来时,新消息会以淡入和缩放的动画效果显示出来,旧消息则以淡出和缩放的动画效果消失。
电商应用的商品筛选动画
在电商应用中,用户可能会使用筛选功能来查找特定的商品。可以使用 AnimatedVisibility
和 AnimatedContent
结合实现筛选条件的显示与隐藏,以及筛选结果的平滑过渡。
kotlin
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp@OptIn(ExperimentalAnimationApi::class)
@Composable
fun EcommerceProductFilterExample() {// 定义一个可变状态,用于控制筛选条件的可见性var isFilterVisible by remember { mutableStateOf(false) }// 定义一个可变状态,用于存储筛选条件var filter by remember { mutableStateOf("All") }// 模拟商品列表val allProducts = listOf("Product 1", "Product 2", "Product 3", "Product 4")// 根据筛选条件过滤商品列表val filteredProducts = when (filter) {"All" -> allProducts"Even" -> allProducts.filterIndexed { index, _ -> index % 2 == 0 }"Odd" -> allProducts.filterIndexed { index, _ -> index % 2 != 0 }else -> allProducts}// 自定义过渡动画规范val customTransitionSpec = {// 定义进入动画为淡入和缩放进入val enterTransition = fadeIn() + scaleIn()// 定义退出动画为淡出和缩放退出val exitTransition = fadeOut() + scaleOut()// 定义大小变换动画val sizeTransform = SizeTransform(clip = false)// 返回一个 ContentTransform 对象,包含进入动画、退出动画和大小变换动画ContentTransform(targetContentEnter = enterTransition,initialContentExit = exitTransition,sizeTransform = sizeTransform)}// 创建一个 Column 组件,用于布局筛选按钮、筛选条件和商品列表Column(modifier = Modifier.fillMaxWidth().padding(16.dp),verticalArrangement = Arrangement.spacedBy(8.dp)) {// 创建一个按钮,点击时切换筛选条件的可见性Button(onClick = { isFilterVisible = !isFilterVisible }) {Text(text = if (isFilterVisible) "Hide Filters" else "Show Filters")}// 使用 AnimatedVisibility 组件,根据 isFilterVisible 的值控制筛选条件的显示与隐藏,并添加淡入淡出动画AnimatedVisibility(visible = isFilterVisible,enter = fadeIn(),exit = fadeOut()) {// 创建一个 Column 组件,用于布局筛选条件按钮Column(modifier = Modifier.fillMaxWidth().padding(8.dp),verticalArrangement = Arrangement.spacedBy(8.dp)) {// 全部筛选条件按钮Button(onClick = { filter = "All" }) {Text(text = "All Products")}// 偶数索引商品筛选条件按钮Button(onClick = { filter = "Even" }) {Text(text = "Even Index Products")}// 奇数索引商品筛选条件按钮Button(onClick = { filter = "Odd" }) {Text(text = "Odd Index Products")}}}// 使用 AnimatedContent 组件,根据 filteredProducts 的值显示不同的商品列表,并应用自定义过渡动画AnimatedContent(targetState = filteredProducts,transitionSpec = customTransitionSpec,contentAlignment = Alignment.TopStart) { currentProducts ->// 遍历商品列表,显示每个商品currentProducts.forEach { product ->Text(text = product,modifier = Modifier.fillMaxWidth().padding(8.dp))}}}
}
代码分析:
-
状态管理:
isFilterVisible
用于控制筛选条件的可见性。filter
用于存储当前的筛选条件。allProducts
模拟了所有商品的列表,filteredProducts
根据filter
的值进行筛选。
-
筛选条件显示:使用
AnimatedVisibility
组件,根据isFilterVisible
的值控制筛选条件的显示与隐藏,添加淡入淡出动画。 -
筛选结果显示:使用
AnimatedContent
组件,根据filteredProducts
的变化更新显示的商品列表,应用自定义的过渡动画。当筛选条件改变时,新的商品列表会以平滑的动画效果显示出来。
5.3 自动动画在提升用户体验方面的作用
- 增强交互反馈:自动动画可以为用户的操作提供直观的反馈。例如,在点击按钮展开菜单时,菜单以动画的形式平滑展开,让用户清楚地知道操作已经生效。这种反馈能够增强用户与界面的交互感,使用户更加自信地操作应用。
- 引导用户注意力:通过动画效果,可以引导用户的注意力到重要的信息或操作上。例如,在有新消息到来时,消息提示以闪烁或缩放的动画效果显示,吸引用户的注意力,让用户及时发现新消息。
- 提升界面的流畅感:自动动画可以使界面元素的显示和隐藏、状态的切换更加自然流畅,避免界面的突然变化给用户带来的不适感。例如,在切换列表项内容时,使用动画过渡可以让用户感觉界面的变化是连续的,提升了界面的整体流畅感。
- 增加应用的趣味性:精美的动画效果可以为应用增添趣味性,使应用更具吸引力。例如,在游戏应用中,角色的移动、技能的释放等都可以通过动画来表现,让用户在游戏过程中获得更好的体验。
六、自动动画的性能优化与注意事项
6.1 性能优化策略
合理选择动画类型
不同的动画类型对性能的影响不同。例如,简单的淡入淡出动画相对来说性能开销较小,而复杂的缩放、旋转动画可能会消耗更多的资源。在选择动画类型时,应根据实际需求进行权衡,优先选择性能开销较小的动画。
kotlin
// 简单的淡入淡出动画
AnimatedVisibility(visible = isVisible,enter = fadeIn(),exit = fadeOut()
) {// 内容
}// 复杂的缩放和旋转动画
// 这种动画可能会消耗更多资源,需要谨慎使用
AnimatedVisibility(visible = isVisible,enter = scaleIn() + rotateIn(),exit = scaleOut() + rotateOut()
) {// 内容
}
控制动画时长和帧率
动画的时长和帧率也会影响性能。过长的动画时长会增加用户的等待时间,而过短的动画时长可能会导致动画效果不明显。帧率方面,过高的帧率会增加 CPU 和 GPU 的负担,一般将帧率控制在 60fps 左右即可。
kotlin
// 设置动画时长为 300 毫秒
val enterTransition = fadeIn(animationSpec = tween(durationMillis = 300))
val exitTransition = fadeOut(animationSpec = tween(durationMillis = 300))AnimatedVisibility(visible = isVisible,enter = enterTransition,exit = exitTransition
) {// 内容
}
避免不必要的动画
在开发过程中,应避免添加不必要的动画。只有在确实需要增强用户体验的地方才使用动画,避免过度使用动画导致性能下降。例如,在一些静态页面中,不需要添加动画效果。
优化动画状态管理
合理管理动画的状态可以减少不必要的动画计算和重绘。例如,使用 remember
函数来缓存可变状态,避免在每次重组时重新创建状态。
kotlin
// 使用 remember 缓存可变状态
var isVisible by remember { mutableStateOf(false) }AnimatedVisibility(visible = isVisible,enter = fadeIn(),exit = fadeOut()
) {// 内容
}
6.2 注意事项
兼容性问题
不同的 Android 设备和版本可能对动画的支持有所不同。在开发过程中,应进行充分的测试,确保动画在各种设备和版本上都能正常显示。特别是在使用一些新的动画特性时,要注意其兼容性。
内存管理
动画可能会占用一定的内存资源,特别是在处理复杂动画或大量动画时。要注意及时释放不再使用的动画资源,避免内存泄漏。例如,在组件销毁时,停止正在运行的动画。
动画冲突
在一个界面中,如果同时存在多个动画,可能会出现动画冲突的问题。例如,一个元素正在进行淡入动画,同时又要进行缩放动画,可能会导致动画效果不理想。在设计动画时,要避免这种冲突的发生,或者使用合适的动画组合方式来解决冲突。
七、总结与展望
7.1 总结
Android Compose 中的 AnimatedVisibility
和 AnimatedContent
为开发者提供了强大而便捷的自动动画功能。通过这两个组件,开发者可以轻松实现元素的显示与隐藏动画,以及内容的动态变化动画,从而提升应用的用户体验。
AnimatedVisibility
主要用于控制元素的可见性,通过设置 visible
参数和动画效果,可以让元素在显示和隐藏时具有平滑的过渡。其内部通过 updateTransition
函数管理动画的过渡状态,利用 AnimatedVisibilityScope
函数处理动画的执行。
AnimatedContent
则专注于内容的动态更新,当传递给它的内容发生变化时,会根据 transitionSpec
中定义的动画效果进行平滑过渡。开发者可以自定义过渡动画,实现淡入淡出、缩放、旋转等多种效果。
在实际项目中,AnimatedVisibility
和 AnimatedContent
可以结合使用,以实现更复杂的动画效果。同时,合理运用自动动画可以增强交互反馈、引导用户注意力、提升界面的流畅感和增加应用的趣味性。
7.2 展望
更多动画效果和特性
未来,Android Compose 可能会提供更多丰富的动画效果和特性。例如,支持更多基于物理模拟的动画,如弹性动画、重力动画等,让动画更加逼真和自然。同时,可能会增加更多的动画插值器和过渡类型,为开发者提供更多的选择。
性能进一步优化
随着 Android 系统和硬件的不断发展,Android Compose 的动画性能也有望得到进一步优化。例如,采用更高效的动画计算和渲染算法,减少动画对 CPU 和 GPU 的负担,提高动画的流畅度和响应速度。
跨平台动画支持
随着跨平台开发的趋势不断增强,Android Compose 可能会提供更好的跨平台动画支持。开发者可以使用相同的代码在不同的平台上实现一致的动画效果,降低开发成本和维护难度。
更便捷的动画调试工具
目前,Android Compose 的动画调试相对来说还比较困难。未来,可能会提供更便捷的动画调试工具,帮助开发者快速定位和解决动画问题,提高开发效率。
总之,Android Compose 的自动动画功能为开发者带来了很多便利,未来也有着广阔的发展前景。开发者可以充分利用这些功能,为用户打造更加出色的 Android 应用。
相关文章:
深入剖析 Android Compose 框架的自动动画:AnimatedVisibility 与 AnimatedContent(二十四)
深入剖析 Android Compose 框架的自动动画:AnimatedVisibility 与 AnimatedContent 引言 在 Android 应用开发中,动画是提升用户体验的重要手段。它能够让界面元素的显示与隐藏、状态的切换变得更加自然和流畅,避免生硬的变化给用户带来不佳…...
【线程安全问题的原因和方法】【java形式】【图片详解】
在本章节中采用实例图片的方式,以一个学习者的姿态进行描述问题解决问题,更加清晰明了,以及过程中会发问的问题都会一一进行呈现 目录 线程安全演示线程不安全情况图片解释: 将上述代码进行修改【从并行转化成穿行的方式】不会出…...
Cocos Creator Shader入门实战(六):使用setProperty动态设置材质属性,以及材质常用接口
引擎:3.8.5 您好,我是鹤九日! 回顾 上篇文章,我们主要讲解了关于材质的使用,主要有这么几点: 一、没有Effect资源,材质无从说起。 二、材质的构建,支持编译器和代码的动态构建 三…...
编程题记录3
九宫幻方 题目链接:https://www.lanqiao.cn/problems/100/learning/?page1&first_category_id1&second_category_id3&tags%E7%9C%81%E8%B5%9B&tag_relationintersection 先旋转、镜像得到所有的情况,可以发现情况是可以暴力得出的。…...
Geotools自动识别SLD并生成图例图片实战-以Polygon数据为例
目录 前言 一、Geotools与SLD制图基础 1、SLD是什么 2、SLD有什么用 二、SLD文件的解析与读取 1、SLD结构介绍 2、SLD实例展示 3、SLD读取方法 三、图例生成与展示 1、图例生成流程 2、图例生成实战 3、图例生成展示 四、结论 前言 在地理信息系统(GIS&…...
windows docker如何修改 默认的Container memory usage
参考:https://forums.docker.com/t/docker-on-windows-11-with-wsl2-does-not-use-the-memory-i-set-in-wslconfig/144404/3 参考:https://learn.microsoft.com/en-us/windows/wsl/wsl-config...
LabVIEW液压传动系统教学仿真平台
本文介绍了一种基于LabVIEW的液压传动系统教学仿真平台,该平台采用“老师讲解、线上仿真、线下操作”的复合实验模式,旨在提高实验教学的效率与安全性。通过实例验证,展示了该平台在教学和实际操作中的应用效果,同时也为液压传动系…...
Java实习生面试题(2025.3.23 be)
一、v-if与v-show的区别 v-show 和 v-if 都是 Vue 中的条件渲染指令,它们的主要区别在于渲染策略:v-if 会根据条件决定是否编译元素,而 v-show 则始终编译元素,只是通过改变 CSS 的 display 属性来控制显示与隐藏。 二、mybatis-…...
OpenCV第2课 OpenCV的组成结构与图片/视频的加载及展示
1.OpenCV 的组成结构 2.OpenCV 的具体模块 3. 图像的读取 4. 视频的读取 1.OpenCV 的组成结构 OpenCV 是由很多模块组成的,这些模块可以分成很多层: 最底层是基于硬件加速层(HAL)的各种硬件优化。再上一层是opencv_contrib 模块所包含的OpenCV 由其他开发人员所贡献的代…...
Blender导出fbx到Unity找不到贴图的问题
fbx导入Unity材质能不能找到贴图是一件玄学的事情。常见的情况是有些材质能找到,有些找不到: 可能有用的方法 解决方法1:把贴图文件复制过去,模型reimport; 解决方法2:导出时路径模式选复制,内…...
kafka的文章
1.面试的问题 要点 至多一次、恰好一次数据一致性超时重试、幂等消息顺序消息挤压延时消息 1.1 kafaka 生产消息的过程。 在消息发送的过程中,涉及到了两个线程,一个是main 线程,一个是sender 线程。在main 线程中创建了一个双端队列 Reco…...
Go常见问题与回答(下)
文章目录 1、通过指针变量 p 访问其成员变量 name,有哪几种方式?2、代码,说出结果3、扩容提,代码,说出结果4、指出下面这段代码的错误之处5、是否通过编译6、关于字符串连接,下面语法正确的是7、关于iota&a…...
vue3中如何缓存路由组件
在 Vue3 中缓存路由组件,主要借助<keep-alive>组件来实现,具体方法如下: 1. 全局缓存路由组件 在 App.vue 等根组件中,直接将<router-view>包裹在<keep-alive>标签内,这样所有的路由组件都会被缓存…...
云服务器怎么防御ddos攻击呢?
防御DDoS攻击是保障云服务器稳定运行的关键措施,以下是综合多种防护策略的详细方案: 1. 启用云服务商提供的DDoS防护服务 高防IP/流量清洗: 将业务流量接入云服务商的高防IP,由专业清洗中心过滤恶意流量,仅放行正常请求…...
Log4j2 的核心实现和源码分析
Log4j2 的核心实现和源码分析 1. 核心组件 1.1 Logger 功能:负责记录日志信息。实现:org.apache.logging.log4j.Logger 接口,org.apache.logging.log4j.core.Logger 类。1.2 Appender 功能:负责将日志信息输出到不同的目的地,如文件、控制台等。实现:org.apache.loggin…...
【深度学习】【目标检测】【OnnxRuntime】【C++】YOLOV3模型部署
【深度学习】【目标检测】【OnnxRuntime】【C】YOLOV3模型部署 提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论 文章目录 【深度学习】【目标检测】【OnnxRuntime】【C】YOLOV3模型部署前言Windows平台搭建依赖环境模型转换--pytorch转onnxONNXRuntime推…...
四种跨模态行人重识别可视化方法
1.Gradcam 2.检索可视化 3.tsne图 4.距离分布 需要的私聊,代码需要付费...
8个DeepSeek文章润色指令
今天道叔给各位文字工作者安利DeepSeek的8个神仙级润色指令(附真实案例拆解),建议搭配冰美式食用更佳↓↓↓ 一、【学术黑话翻译器】 适用场景:给投资人看的BP/行业白皮书/专家访谈实录 指令公式:"将以下内容转化为通俗易懂的行业洞察…...
解决PowerShell下Git中文乱码问题
解决PowerShell下Git中文乱码问题 在使用Git进行版本控制时,许多开发者可能会遇到中文乱码的问题,尤其是在Windows环境下使用PowerShell时。这不仅影响代码的阅读和提交,还可能导致一些不可预见的错误。本文将详细探讨如何在PowerShell下解决…...
oracle数据库(数据库启动关闭/sqlplus登录及基本操作/设置字符集/distinct去重)
目录 1. Oracle数据库启动 2. Oracle数据库关闭 3. sqlplus登录Oracle数据库 3.1 使用sqlplus登录Oracle数据库 3.2 使用sqlplus登录Oracle数据库 3.3 远程登录 3.4 解锁用户 3.5 修改用户密码 3.6 查看当前语言环境 4. sqlplus基本操作 4.1 显示当前用户 4.2 查看当前用户…...
mapreduce时,客户端做哪些事
在MapReduce过程中,客户端(Client)是用户提交作业的入口,负责作业的初始化、配置、资源提交和作业监控。以下是客户端在整个流程中的具体职责和操作步骤: 1. 作业配置与参数解析 设置作业属性: 定义MapRed…...
DeepBI:重构流量逻辑,助力亚马逊广告实现高效流量增长
在日益激烈的跨境电商竞争环境中,广告投放早已从“粗放撒网”走向“精细化运营”。尤其是在亚马逊这样一个成熟且竞争白热化的平台,如何在广告预算有限的前提下实现高效曝光、精准触达、稳定转化,成为众多卖家和运营团队面临的核心挑战。 De…...
Linux内核的页面错误:原因与解决方案
当程序访问虚拟内存中的一个页面时,如果该页面当前不在物理内存中,就会触发一个称为"page fault"(页异常)的异常。操作系统需要处理这个异常,并将所需页面从磁盘加载到内存中。实现虚存管理的一个关键是page…...
LORA 中的 梯度外积是什么意思; 方差和协方差的实际含义:衡量变量的离散程度和变量间的线性相关性
LORA 中的 梯度外积是什么意思 目录 LORA 中的 梯度外积是什么意思**一、梯度外积的定义****二、示例说明****步骤1:计算单样本梯度****步骤2:计算梯度外积****三、梯度外积的作用****四、总结**方差和协方差的实际含义:衡量变量的离散程度和变量间的线性相关性**一、方差(…...
XSS复现漏洞简单前八关靶场
靶场不需要安装任意环境 链接如下:XSS Game - Learning XSS Made Simple! | Created by PwnFunction 目录 XSS Game 第一关:Ma Spaghet! 第二关:Jefff 第三关:Ugandan Knuckles 第四关:Ricardo Milos 第五关&am…...
3.24-3 接口测试断言
一.postman 断言 1.断言再test中 #状态码是否等于200 tests["Status code is 200"] responseCode.code 200; #断言响应时间小于200ms tests["Response time is less than 200ms"] responseTime < 200; #断言响应体包含内容 tests["Body…...
《鸿蒙携手AI:解锁智慧出行底层逻辑》
在科技飞速发展的当下,智慧出行成为人们对未来交通的美好期许,而鸿蒙系统与人工智能的深度融合,正为这一愿景的实现提供强大助力。从技术原理角度深入剖析,鸿蒙系统究竟如何支撑人工智能在智慧出行场景中的应用呢?这背…...
【AVRCP】探寻AVRCP控制互操作性:连接、命令与设备交互
目录 一、AVCTP连接管理 1.1 AVCTP连接建立 1.2 AVCTP连接释放 二、AV/C命令的操作流程 2.1 AV/C命令交换流程 2.2 AV/C命令类型 三、AVRCP特定命令 四、AVRCP浏览命令 五、OBEX连接管理 5.1 OBEX连接建立 5.2 OBEX连接释放 六、总结 七、参考资料 AVRCP对于实现设…...
Mybatis-Plus知识点详解
Mybatis-plus(简称MP),基于Mybatis的增强工具,保留了Mybatis的所有功能,同时增加了通用的CRUD,条件构造器,分页插件等等实用工具 特性 即拿即用:通过通用Mapper和Service,无需编写XML既可以完成单表CURE操作 Lambda支持:使用Lambda表达式构建查询条件,避免硬编码字段名,提升代…...
紧凑交叉引用表
嗯,用户问的是“compact xref table”,也就是紧凑型交叉引用表。我之前在回答中提到过交叉引用流(XRef Stream),但可能需要更详细地解释两者的区别和联系。根据搜索结果中的网页1,传统的Xref表以文本形式存…...
CMake 详解:跨平台构建系统的入门与进阶
目录 一、相关知识点 1. 什么是cmake,为什么使用? 2. 构建过程 二、CMake使用流程 1. 创建 CMakeLists.txt 文件 2. 配置构建目录 3. 运行cmake 4. 运行make编译 一、相关知识点 1. 什么是cmake,为什么使用? CMake 是一个开…...
【架构设计】学习路径
掌握前置知识后,学习架构设计需要从理论认知到实践落地逐步推进。以下是系统化的学习路径,结合具体案例与实操建议,帮助你快速进阶: 一、构建架构思维基础 1. 理解架构设计的核心目标 关键问题驱动设计: 每个架构决策…...
14、Python 枚举与类型注解进阶
Python 枚举与类型注解进阶 文章概述 本文深入探讨Python中枚举(Enum)与类型注解的高级应用场景。通过剖析Enum类的核心特性、dataclass装饰器的工程实践、静态类型检查工具mypy的集成使用,结合状态机等实际案例,系统性地提升代…...
C语言 【实现电脑关机小游戏】非常好玩
引言 在时间限制内做出正确的回答,时间一到,电脑自动关机,听起来是不是很有意思,下面来看看怎么实现吧。 注意:该游戏只在windows系统下可以玩, 一、游戏原理: 在Windows系统下,通…...
【蓝桥杯速成】| 11.回溯 之 子集问题
题目一:子集 问题描述 78. 子集 - 力扣(LeetCode) 给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例…...
统计矩的高阶推广:经验还是理论推导?
矩的发展既是经验总结的结果,也是数学理论推导的产物。研究者们在分析数据、描述物理现象的过程中,发现了低阶矩与日常物理概念(如质心、惯性)之间的紧密联系,而高阶矩的应用往往出现在更复杂的数学体系中,…...
SpringBoot2集成Elasticsearch8(使用spring-boot-starter-data-elasticsearch)
写在前面 使用spring-boot-starter-data-elasticsearch集成Elasticsearch8? What? 官方写的不支持啊?让我们来看下官方给出的版本建议。 官方地址: https://docs.spring.io/spring-data/elasticsearch/reference/elasticsearch/versions.…...
Postgresql源码(142)子查询提升pull_up_sublinks
1 案例 drop table t_fun01; create table t_fun01 (image_id numeric primary key, content_id varchar(50), file_code varchar(20)); create index idx3 on t_fun01(content_id); create index idx4 on t_fun01(file_code); insert into t_fun01 select t.i, t.i%10, t.i%1…...
sonar代码检测研究及平台搭建
为了实现提交代码自动检测代码缺陷,本文介绍了一种将jenkins与gitlab集成的自动检测机制,如需应用于生产级开发流程,可在此基础上进行功能丰富和扩展,本文仅进行了原理性搭建。 一、基础环境准备 与sonar配合使用的jenkins和gitlab基础软件…...
清华大学:DeepSeek从入门到精通系列教程1-9讲(持续更新中)|大礼包免费下载
导 读INTRODUCTION 今天分享由清华大学新闻与传播学院、人工智能学院双聘教授沈阳老师团队倾力打造的《DeepSeek从入门到精通系列教程1-9讲(持续更新中)》,包含:《DeepSeek:从入门到精通》《DeepSeek如何赋能职场应用》…...
使用Python可视化图结构:从GraphML文件生成节点关系图(lightrag 生成)
引言 在数据可视化领域,图结构(Graph)常用于展示实体间的复杂关系。例如,文学分析中的角色关系、社交网络中的用户互动等。本文将通过一个实际案例,演示如何使用 NetworkX 和 Matplotlib 从 GraphML 文件生成节点关系…...
排序复习_代码纯享
头文件 #pragma once #include<iostream> #include<vector> #include<utility> using std::vector; using std::cout; using std::cin; using std::endl; using std::swap;//插入排序 //1、直接插入排序(稳定) void InsertSort(vecto…...
Docker Hub Mirror 终极解决方案——0成本,超高速!
CNB Docker Mirror (cdm) CNB Docker Mirror 是一个基于 CNB 的 Docker 镜像加速工具,提供本地镜像加速功能。 功能特性 镜像加速:在本地启动连接到 CNB 环境的 Docker 镜像加速服务,然后通过配置 Docker 客户端实现镜像加速下载自动重连&…...
2000-2019年各省地方财政车船税数据
2000-2019年各省地方财政车船税数据 1、时间:2000-2019年 2、来源:国家统计局、统计年鉴 3、指标:行政区划代码、地区、年份、地方财政车船税 4、范围:31省 5、指标说明:车船税作为地方财政的重要组成部分&#x…...
c#处理算数溢出的情况
在C#中,算术运算的溢出处理可以通过 checked 和 unchecked 关键字控制,默认行为是 静默截断(unchecked模式),但可以通过配置或代码块显式调整。以下是详细说明: 1. 默认行为(unchecked模式&…...
Java「Deque」 方法详解:从入门到实战
Java Deque 各种方法解析:从入门到实战 在 Java 编程中,Deque(双端队列)是一个功能强大的数据结构,允许开发者从队列的两端高效地添加、删除和检查元素。作为 java.util 包中的一部分,Deque 接口继承自 Qu…...
简记_FPGA 硬件最小系统设计
一、FPGA板级设计的五要素 1.1、电源电路 核心电压:一般为固定值 IO电压:FPGA的IO分为多个bank,同一个bank的不同IO引脚电压相同,不同bank的电压可以不同 辅助电压:除了核心电压和IO电压,FPGA工作所需的…...
C++题目
1、内存管理 1.内存模型 栈:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。 堆:就是那些由new分配的内存块,其释放由程序员控制(一个new对应一个delete)…...
Vulhub-jangow-01-1.0.1通关攻略
第0步: 打开靶机,按下shift,出现下图界面 在此页面按下e键,进入如下界面, 将ro 替换为 rw signie init/bin/bash 替换完毕后,按下Ctrl键X键,进入如下页面 ip a查看网卡信息 编辑配置文件网卡信…...
入剖析 Android Compose 框架的关键帧动画(keyframes、Animatable)(二十三)
深入剖析 Android Compose 框架的关键帧动画(keyframes、Animatable) 引言 在当今的 Android 应用开发领域,用户体验已成为衡量一款应用成功与否的关键因素之一。而动画作为提升用户体验的重要手段,能够为应用增添生动性和交互性…...