上一篇写了基础布局,完后发现一个问题,activity的跳转咋整呢?通过官方文档发现,导航这块让官方也给整了一下和以前不一样了。
导航
新导航的方式和ios的导航很像,介绍说NavController 是 Navigation 组件的中心 API。此 API 是有状态的,可以跟踪组成应用屏幕的可组合项的返回堆栈以及每个屏幕的状态。
导航能做什么?
处理 Fragment 事务。
默认情况下,正确处理往返操作。(页面跳转)
为动画和转换提供标准化资源。
实现和处理深层链接。
包括导航界面模式(例如抽屉式导航栏和底部导航),用户只需完成极少的额外工作。
Safe Args - 可在目标之间导航和传递数据时提供类型安全的 Gradle 插件。
ViewModel 支持 - 您可以将 ViewModel 的范围限定为导航图,以在图表的目标之间共享与界面相关的数据。
此外,您还可以使用 Android Studio 的 Navigation Editor 来查看和编辑导航图。
看描述感觉和ios的导航一个作用。
1)引包
使用导航要引用的包还挺多
dependencies {
def nav_version = "2.3.3"
// Java language implementation
implementation "androidx.navigation:navigation-fragment:$nav_version"
implementation "androidx.navigation:navigation-ui:$nav_version"
// Kotlin
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
// Feature module Support
implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"
// Testing Navigation
androidTestImplementation "androidx.navigation:navigation-testing:$nav_version"
// Jetpack Compose Integration
implementation "androidx.navigation:navigation-compose:1.0.0-alpha07"
}
其中Kotlin和JAVA二选一
2)创建导航
这一步需要在as上手动配置:
1)在“Project”窗口中,右键点击 res 目录,然后依次选择 New > Android Resource File。此时系统会显示 New Resource File 对话框。
2)在 File name 字段中输入名称,例如“nav_graph”。
3)从 Resource type 下拉列表中选择 Navigation,然后点击 OK。
我测试了一下,图中的按钮只能添加fragment,
在可组合项中使用 rememberNavController() 方法来创建 NavController,官方介绍
互操作
手势
手势这个也是阅读的官方文档,分的比较细:点击、滚动、拖拽、滑动、多点触控。
点击
//点击事件(自带动画效果)
val count = remember { mutableStateOf(0) }//这个非常重要,变换状态是必须要借助它的
Modifier.clickable { count.value += 1 }//这里使用count.value
还有一个点击事件,有三个可用的重载,感觉功能比较复杂
.pointerInput("",{}){//
detectTapGestures (
onPress = {}
,onDoubleTap = {}
,onLongPress = {}
,onTap = {}
)
}
滚动
针对列表的 verticalScroll & horizontalScroll
Box(modifier = Modifier.fillMaxWidth().height(100.dp)){
// Smoothly scroll 100px on first composition
val state = rememberScrollState()
//加上会比较平滑,否则会有生涩感(不是卡顿)
LaunchedEffect(Unit) { state.animateScrollTo(100) }
Column(modifier = Modifier
.background(Color.LightGray)
.size(100.dp)
.padding(horizontal = 8.dp)
.verticalScroll(state)
) {
repeat(10) {
Text("Item $it", modifier = Modifier.padding(2.dp))
}
}
}
针对普通组件的全局滑动监听
Box(modifier = Modifier
.fillMaxWidth()
.height(100.dp)){
var offset = remember { mutableStateOf(0f) }
var state = rememberScrollableState(consumeScrollDelta = {
delta:Float->// scrolling delta and update offset
offset.value += delta
delta
})
Box(
Modifier
.size(80.dp)
.scrollable(
orientation = Orientation.Vertical,
// Scrollable state: describes how to consume
state = state
)
.background(Color.LightGray),
contentAlignment = Alignment.Center
) {
Text(offset.value.toString())
}
}
这个的滑动范围是整个屏幕,这个范围需要注意一下
嵌套滚动
Box(modifier = Modifier
.fillMaxWidth()
.height(100.dp)){
val gradient = Brush.verticalGradient(0f to Color.Gray,
1000f to Color.White)
Box(modifier = Modifier
.background(Color.LightGray)
.verticalScroll(rememberScrollState())
.padding(16.dp)
) {
Column {
repeat(6) {
Box(
modifier = Modifier
.background(brush = gradient)
.height(30.dp)
.verticalScroll(rememberScrollState())
) {
Text("Scroll here $it", modifier =
Modifier.padding(24.dp)
.height(60.dp))
}
}
}
}
}
外围布局限定100dp,内部有6个30dp的box,单个box的内部有60dp的text
测试发现如果拿到监听的是box这需要等内部text滚动到位了再滚动列表;否则直接滚动列表
拖拽
draggable 修饰符是向单一方向拖动手势的高级入口点,并且会报告拖动距离(以像素为单位)。draggable 仅检测手势,需要通过 offset 修饰符移动元素
var offsetX = remember { mutableStateOf(0f) }
Text(
modifier = Modifier
//x: Int, y: Int
.offset { IntOffset(offsetX.value.roundToInt(), 0) }
.draggable(
orientation = Orientation.Horizontal,
state = rememberDraggableState { delta ->
offsetX.value += delta
}
),
text = "Drag me!"
)
上述代码演示的是横向拖拽,如果需要控制整个拖动手势,则建议改为 pointerInput 修饰符使用拖动。
Box(modifier = Modifier.fillMaxSize()) {
var offsetX = remember { mutableStateOf(0f) }
var offsetY = remember { mutableStateOf(0f) }
Box(
Modifier
.offset { IntOffset(offsetX.value.roundToInt(), offsetY.value.roundToInt()) }
.background(Color.Blue)
.size(50.dp)
.pointerInput(Unit) {
// change: PointerInputChange, dragAmount: Offset
detectDragGestures { change, dragAmount ->
change.consumeAllChanges()
offsetX.value += dragAmount.x
offsetY.value += dragAmount.y
}
}
)
}
滑动
滑动使用 swipeable 修饰符,被拖动元素释放后,让元素通常朝一个方向定义的两个或多个锚点呈现动画效果。常见用途是实现“滑动关闭”模式。
swipeable 只检测手势,通过 offset 修饰符移动元素。
swipable 修饰符中必须提供手滑式状态,且该状态可以通过 rememberSwipeableState() 创建和记住。此状态还提供了一组有用的方法,用于以程序化方式为锚点添加动画效果(请参阅 snapTo、animateTo、performFling 和 performDrag),同时为属性添加动画效果,以观察拖动进度。
可以将滑动手势配置为具有不同的阈值类型,例如 FixedThreshold(Dp) 和 FractionalThreshold(Float),并且对于每个锚点的起始与终止组合,它们可以是不同的。
为了获得更大的灵活性,您可以配置滑动越过边界时的 resistance,还可以配置 velocityThreshold,即使尚未达到位置 thresholds,velocityThreshold 仍将以动画方式向下一个状态滑动。
其中rememberSwipeableState是个实验性的参数,使用需要谨慎
@ExperimentalMaterialApi //必要标记,并且需要标记在主入口上
@Composable
fun SwipeableSample() {
val width = 96.dp
val squareSize = 48.dp
val swipeableState = rememberSwipeableState(0)
val sizePx = with(LocalDensity.current) { squareSize.toPx() }
val anchors = mapOf(0f to 0, sizePx to 1) // Maps anchor points (in px) to states
Box(
modifier = Modifier
.width(width)
.swipeable(
state = swipeableState,
anchors = anchors,
thresholds = { _, _ -> FractionalThreshold(0.3f) },
orientation = Orientation.Horizontal
)
.background(Color.LightGray)
) {
Box(
Modifier
.offset { IntOffset(swipeableState.offset.value.roundToInt(), 0) }
.size(squareSize)
.background(Color.DarkGray)
)
}
}
多点触控:平移、缩放、旋转
transformable 用于平移、缩放和旋转的多点触控手势
@Composable
fun TransformableSample() {
// set up all transformation states
var scale by remember { mutableStateOf(1f) }
var rotation by remember { mutableStateOf(0f) }
var offset by remember { mutableStateOf(Offset.Zero) }
val state = rememberTransformableState { zoomChange, offsetChange, rotationChange ->
scale *= zoomChange
rotation += rotationChange
offset += offsetChange
}
Box(
Modifier
// apply other transformations like rotation and zoom
// on the pizza slice emoji
.graphicsLayer(
scaleX = scale,
scaleY = scale,
rotationZ = rotation,
translationX = offset.x,
translationY = offset.y
)
// add transformable to listen to multitouch transformation events
// after offset
.transformable(state = state)
.background(Color.Blue)
.fillMaxSize()
)
}
动画
这个我直接看的实践:https://blog.csdn.net/vitaviva/article/details/115257165
这部分还没有研究
官方指导 https://developer.android.google.cn/jetpack/compose/animation?hl=zh-cn