文章目录
前言
Compose 非常适合构建单Activity应用, 本篇适合单Activity,多Composable,无Fragment的情况.
一、默认的navigation没有页面进出的动画
这里需要 accompanist-navigation-animation
库.
该部分出自: 动画实现更简单,Navigation Compose 帮您忙
1.导包 accompanist-navigation-animation
implementation "androidx.navigation:navigation-compose:2.4.2"
implementation "com.google.accompanist:accompanist-navigation-animation:0.24.10-beta"
2.自定义navigation-composable
这里默认 页面打开时从右侧进入; 注意这里 composable 导包, 是accompanist下的.
import androidx.compose.animation.*
import androidx.compose.runtime.Composable
import androidx.navigation.NamedNavArgument
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavDeepLink
import androidx.navigation.NavGraphBuilder
import com.google.accompanist.navigation.animation.composable
/**
* accompanist-navigation-animation
* navHostController.navigate() 时 右进左出
* navHostController.popBackStack() 时 左进右出
*/
@ExperimentalAnimationApi
fun NavGraphBuilder.myComposable(
route: String,
arguments: List<NamedNavArgument> = emptyList(),
deepLinks: List<NavDeepLink> = emptyList(),
enterTransition: (AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition?)? = {
slideInHorizontally(initialOffsetX = { it })
},
exitTransition: (AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition?)? = {
slideOutHorizontally(targetOffsetX = { -it })
},
popEnterTransition: (AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition?)? = {
slideInHorizontally(initialOffsetX = { -it })
},
popExitTransition: (AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition?)? = {
slideOutHorizontally(targetOffsetX = { it })
},
content: @Composable AnimatedVisibilityScope.(NavBackStackEntry) -> Unit
) {
composable(
route, arguments, deepLinks,
enterTransition = enterTransition,
exitTransition = exitTransition,
popEnterTransition = popEnterTransition,
popExitTransition = popExitTransition,
content = content
)
}
3.使用
注意:
- 需使用
AnimatedNavHost
替换NavHost
- 需使用
rememberAnimatedNavController()
替换rememberNavController()
// Activity
var navC: NavHostController? = null
@OptIn(ExperimentalAnimationApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyTheme {
navC = rememberAnimatedNavController()
MainNavHost(navC!!)
}
}
}
// MainNavHost
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun MainNavHost(
navC: NavHostController,
) {
AnimatedNavHost(
navController = navC,
startDestination = MainScreen.Home.name,
modifier = Modifier.fillMaxSize()
) {
myComposable(MainScreen.Home.name){
HomeMain(navC)
}
myComposable(MainScreen.Setting.name){
SettingMain(navC)
}
myComposable(MainScreen.AboutUs.name){
AboutUsMain(navC)
}
}
}
// MainScreen
enum class MainScreen {
Home, // 首页
Setting, // 设置
AboutUs, // 关于我们
}
OK, 默认 slide 动画的 navigation 已经实现;
除了: slide
还有 fade, scale, expand
等动画
二、首页回退问题
super.onBackPressed()
必须要调用, 否则 navigation
的回退就不生效了.
var navC: NavHostController? = null
// 1.5秒内的连击 退出应用
private var mBackTime by Delegates.observable(0L) { _, old, new ->
if (new - old > 1500) {
Toast.makeText(applicationContext, "再按一次退出", Toast.LENGTH_SHORT).show()
} else {
finish()
}
}
// 回退时, 如果已在 Home首页, 则1.5秒内连击退出;
override fun onBackPressed() {
if(navC?.currentDestination?.route == MainScreen.Home.name){
mBackTime = System.currentTimeMillis()
} else {
super.onBackPressed()
}
}
三、ViewModel 声明周期问题
在Compose中, 可以很方便的拿到 ViewModel 实例; 如下:
// @Composable 函数中
val vm = viewModel<MainVm>()
但在单 Activity, 无Fragment
的应用中, viewModel()
的声明周期默认与Activity相关
而我们希望 navC.popBackStack()
, 被退出页面的相关的 ViewModel 销毁
,释放内存;
这时候就需要借助 hilt
这个依赖注入库了.
1.配置 Hilt
// Project - build.gradle
buildscript {
ext {
...
hilt_version = "2.40.5"
}
// 1.加入依赖 hilt plugin
dependencies {
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
}
}
// app - build.gradle
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin' // 2.加入 dagger hilt plugin
}
// 3.引入库:
implementation "androidx.hilt:hilt-navigation-compose:1.0.0"
implementation "com.google.dagger:hilt-android:$hilt_version"
kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
2.加入注解
// Application; 1.加上 @HiltAndroidApp 注解
@HiltAndroidApp
class MyApplication : ComApplication()
// Activity; 2.加上 @AndroidEntryPoint 注解
@AndroidEntryPoint
class MyActivity: ComponentActivity()
// ViewModel; 3.加上 @HiltViewModel 和 @Inject 注解
@HiltViewModel
class MainVm @Inject constructor() : ViewModel()
3.使用 hiltViewModel() 函数
@Composable
fun SettingMain(
navC: NavHostController,
vm: SettingVm = hiltViewModel()
) { ... }
总结
没有总结!
上一篇: Compose-自定义输入框(BasicTextField)
下一篇: Compose-时间选择器