Jetpack Compose-1.3.0 alpha03 导航、手势、动画

上一篇写了基础布局,完后发现一个问题,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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值