iis服务器助手广告广告
返回顶部
首页 > 资讯 > 移动开发 >Jetpack Compose实现对角线滚动效果
  • 505
分享到

Jetpack Compose实现对角线滚动效果

摘要

目录缘起初试探索学习FreeScrollStatefreeScroll总结缘起 不久前刷到 newki 前辈的文章,用自定义 viewGroup的方式实现了如图效果: Android

缘起

不久前刷到 newki 前辈的文章,用自定义 viewGroup的方式实现了如图效果: Android自定义ViewGroup嵌套与交互实战,幕布全屏滚动效果

我当时的反应: new bee ! new bee ! 这效果不错

初试

大佬用 Android View 出来了,那能否用 Google 新一代 UI Compose 来整一个呢?

正好手上有本 fun 神写得书 《Jetpack Compose 从入门到实战》。这不就好办了么!

正当我 啪的一下,很快啊,吭! 开始行动之后,

拿着书翻到了手势处理这一章节,找到了这个:

Scrollable,当视图组件的宽度或长度超出屏幕边界时,我们希望能滑动查看更多的内容... 这不就完事了么,随便写个 composable 加一个 Modifier.scrollable即可实现滑动效果

但是,紧接着一句话 “Orientation 仅有 Horizontal 与 Vertical 可供选择,这说明我们只能监听水平或垂直方向的滚动。”

那我们如果给一个组合同时添加两个方向的scrollable呢? 比如这样:

private fun TwoOrientaionScrollView(modifier: Modifier = Modifier) {
    val horizontalScrollState = rememberScrollState()
    val verticalScrollState = rememberScrollState()
    Column(modifier = modifier
        .horizontalScroll(horizontalScrollState)
        .verticalScroll(verticalScrollState)
    ) {
        ...
    }
}

经过测试,这种方法只能实现在两个方向滑动(垂直,水平)且每次手势只有一个方向在滑动,我们要达到目标效果,那必须是要支持斜着滑动的。

大意了,没有闪,被 Android 官方摆了一道。

探索

既然官方提供的开箱即用的 api 无法满足我们的要求,那我们就需要动手去定制一个特殊的手势处理规则去实现。

那万能的互联网中有没有大佬已经用compose自定义手势实现了呢?

可是找遍了 google 百度 chatGPT 也没有找到什么有价值的文章值得去参考,倒是在Stack Overflow上一番翻箱倒柜之后,找到了一个线索————这种需求叫做 对角线滚动 / diagonal scroll ,并且外国同行已经提了 issue 给 google 质问他们为何没有对角线滚动。但截止到今天 2023/2/7 仍旧google没有提供新的api也没有关闭这个问题。

插一句,不知道为何隔壁鸿蒙原本是支持自由方向滚动的,鸿蒙称之为 Orientation.free , 但是在 api v9 时却把这个方向给废弃了

当我愈发苦恼时,我把 diagonal scroll键入交友网站GitHub时,一道闪光出现了

chihsuanwu/compose-free-scroll:提供可让组合自由滚动的 modifier

这是来自台湾省的开发者的开源项目,作者也已经发布到远程仓,可以让大家一键导入并极速使用

测试效果:

完美!

学习

接下来一起学习一下大佬的代码吧 ,核心代码:

  • FreeScrollState.kt 用来表示滑动状态,并提供了滑动到指定位置的方法
  • FreeScroll.kt实现允许对角线滚动的 modifier

FreeScrollState

内部使用两个 ScrollState 分别控制水平和垂直滚动的 state

class FreeScrollState(
    val horizontalScrollState: ScrollState,
    val verticalScrollState: ScrollState,
) { 
        ...
}
// 用rememberScrollState 分别创建两个方向的 scrollState
@Composable
fun rememberFreeScrollState(initialX: Int = 0, initialY: Int = 0): FreeScrollState {
    val horizontalScrollState = rememberScrollState(initialX)
    val verticalScrollState = rememberScrollState(initialY)
    return FreeScrollState(
        horizontalScrollState = horizontalScrollState,
        verticalScrollState = verticalScrollState,
    )
}

值得一提的是,可以学习到作者使用协程来处理 scrollBy, scrollTo 以及 animateScrollBy animateScrollTo , 例如:

suspend fun scrollTo(
    x: Int,
    y: Int,
): Offset = coroutineScope {
    val xOffset = async {
        horizontalScrollState.scrollTo(x)
    }
    val yOffset = async {
        verticalScrollState.scrollTo(y)
    }
    // 使用 async.awawit() 来同时获取两个结果
    Offset(xOffset.await(), yOffset.await()) 
}

freeScroll

这是一个Modifier的拓展方法,在这个方法中,实现了自定义手势逻辑。

fun Modifier.freeScroll(
    state: FreeScrollState,
    enabled: Boolean = true
): Modifier = composed {
    val velocityTracker = remember { VelocityTracker() }
    val flingSpec = rememberSplineBasedDecay<Float>()
    this.verticalScroll(state = state.verticalScrollState, enabled = false)
        .horizontalScroll(state = state.horizontalScrollState, enabled = false)
        .pointerInput(enabled) {
            if (!enabled) return@pointerInput
            coroutineScope {
                detectDragGestures(
                    onDragStart = { },
                    onDrag = { change, dragAmount ->
                        change.consume()
                        //1 拖拽中
                        onDrag(change, dragAmount, state, velocityTracker, this) 
                      
                    },
                    onDragEnd = {
                        //2 拖拽结束时
                        onEnd(velocityTracker, state, flingSpec, this)
                        
                    }
                )
            }
        }
}

可以看到,核心就是PointerInput中采用detectDraGestures 拖拽监听,并声明了一个速度追踪 器velocityTracker,和一个衰减动画 rememberSplineBasedDecay 来使拖拽结束有一段惯性运动也就是fling

@OptIn(ExperimentalComposeUiApi::class)
private fun onDrag(
    change: PointerInputChange,
    dragAmount: Offset,
    state: FreeScrollState,
    velocityTracker: VelocityTracker,
    coroutineScope: CoroutineScope
) {
    // Add historical position to velocity tracker to increase accuracy
    val changeList = change.historical.map {
        it.uptimeMillis to it.position
    } + (change.uptimeMillis to change.position)

    changeList.forEach { (time, pos) ->
        val position = Offset(
            pos.x - state.horizontalScrollState.value,
            pos.y - state.verticalScrollState.value
        )
        velocityTracker.addPosition(time, position)
    }

    coroutineScope.launch {
        state.horizontalScrollState.scrollBy(-dragAmount.x)
        state.verticalScrollState.scrollBy(-dragAmount.y)
    }
}

onDrag抽出一个方法,方法中,我们将拖拽的过程中的手势点位添加到速度追踪 器velocityTracker中不断精确我们得滚动速度。并将位置点位更新到两个scrollState

private fun onEnd(
    velocityTracker: VelocityTracker,
    state: FreeScrollState,
    flingSpec: DecayAnimationSpec<Float>,
    coroutineScope: CoroutineScope
) {
    val velocity = velocityTracker.calculateVelocity()
    velocityTracker.resetTracking()

    // Launch two animation separately to make sure they work simultaneously.
    coroutineScope.launch {
        state.horizontalScrollState.fling(-velocity.x, flingSpec)
    }
    coroutineScope.launch {
        state.verticalScrollState.fling(-velocity.y, flingSpec)
    }
}
private suspend fun ScrollState.fling(initialVelocity: Float, flingDecay: DecayAnimationSpec<Float>) {
    if (abs(initialVelocity) < 0.1f) return // Ignore flings with very low velocity

    scroll {
        var lastValue = 0f
        AnimationState(
            initialValue = 0f,
            initialVelocity = initialVelocity,
        ).animateDecay(flingDecay) {
            val delta = value - lastValue
            val consumed = scrollBy(delta)
            lastValue = value
            // avoid rounding errors and stop if anything is unconsumed
            if (abs(delta - consumed) > 0.5f) this.cancelAnimation()
        }
    }
}

在拖拽结束后,从velocityTracker拿出估算的速度值,用来给设置fling的衰减滚动动画。 也就是说实际上滚动效果== 拖拽移动 + fling。

总结

JetPack Compose 是一个很强大很现代的 UI 工具,与使用自定义 View 来实现复杂手势以及动画效果时,代码量大大减少,更加灵活。但是现在由于一方面 Android 原生开发者不断减少,以及官方文档相对简陋,社区资料也比较匮乏,在出现不能覆盖需求的问题时,比较耗费时间去找到问题的答案,好在官方目前更新速度还是非常的快,目前也已经是达到可用甚至是易用的程度了,相信距离好用也不遥远。

到此这篇关于Jetpack Compose实现对角线滚动效果的文章就介绍到这了,更多相关Jetpack Compose对角线滚动内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Jetpack Compose实现对角线滚动效果

本文链接: https://www.lsjlt.com/news/195289.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Jetpack Compose实现对角线滚动效果
    目录缘起初试探索学习FreeScrollStatefreeScroll总结缘起 不久前刷到 newki 前辈的文章,用自定义 viewGroup的方式实现了如图效果: Android...
    99+
    2023-02-09
    Jetpack Compose对角线滚动效果 Jetpack Compose对角线滚动 Jetpack Compose滚动
  • Jetpack Compose怎么实现动画效果
    这篇文章将为大家详细讲解有关Jetpack Compose怎么实现动画效果,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。概述compose 为支持动画提供了大量的 api,通过这些 api 我们...
    99+
    2023-06-29
  • 利用Jetpack Compose实现绘制五角星效果
    目录说明自定义星行Modifier原理实现代码最终实现效果说明 compose中我们的所有ui操作,包括一些行为,例如:点击、手势等都需要使用Modifier来进行操作。因此对Mod...
    99+
    2024-04-02
  • 怎么利用Jetpack Compose实现绘制五角星效果
    本文小编为大家详细介绍“怎么利用Jetpack Compose实现绘制五角星效果”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么利用Jetpack Compose实现绘制五角星效果”文章能帮助大家解决疑惑,下面跟着小...
    99+
    2023-06-30
  • 如何通过Jetpack Compose实现双击点赞动画效果
    这篇文章主要介绍如何通过Jetpack Compose实现双击点赞动画效果,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!实现步骤先红色画个爱心Icon(    Ico...
    99+
    2023-06-28
  • Android Jetpack Compose如何实现列表吸顶效果
    这篇文章主要介绍“Android Jetpack Compose如何实现列表吸顶效果”,在日常操作中,相信很多人在Android Jetpack Compose如何实现列表吸顶效果问题上存在疑惑,小编...
    99+
    2023-06-29
  • css如何实现虚线边框滚动效果
    这篇文章将为大家详细讲解有关css如何实现虚线边框滚动效果,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。基本HTML<div class="box"> ...
    99+
    2023-06-08
  • Android实现3D滚动效果
    先上效果图 下载链接http://down.51cto.com/data/1076318...
    99+
    2023-01-31
    效果 Android
  • vue实现滑动和滚动效果
    本文实例为大家分享了vue实现滑动和滚动效果的具体代码,供大家参考,具体内容如下 面板滑动效果,父组件是resultPanel,子组件是resultOption,仿照了iview中,...
    99+
    2024-04-02
  • jQuery如何实现滚动效果
    这篇文章主要介绍了jQuery如何实现滚动效果,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1. 图片轮播:原理如下: 假设有三张图片,三张...
    99+
    2024-04-02
  • vue实现文字滚动效果
    本文实例为大家分享了vue实现文字滚动效果的具体代码,供大家参考,具体内容如下 项目需求:系统公告,要从右忘左循环播放的牛皮广告效果。 实现: 方案一:使用定时器和CSS3的过渡属性...
    99+
    2024-04-02
  • jquery实现全屏滚动效果
    本文实例为大家分享了jquery实现全屏滚动的具体代码,供大家参考,具体内容如下 效果图 思路 1.要全屏,给父级、body、html、高度设置为100%,自己的宽度也100%,...
    99+
    2024-04-02
  • Jetpack Compose怎么实现对话框和进度条
    这篇文章主要介绍“Jetpack Compose怎么实现对话框和进度条”,在日常操作中,相信很多人在Jetpack Compose怎么实现对话框和进度条问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对...
    99+
    2023-07-06
  • JavaScript实现长图滚动效果
    本文实例为大家分享了JavaScript之长图滚动的具体代码,供大家参考,具体内容如下 长图的滚动会涉及定时器: 我们先来回顾下定时器: <!DOCTYPE html&g...
    99+
    2024-04-02
  • js实现楼层滚动效果
    本文实例为大家分享了jquery实现滑动楼梯效果,实现楼层的滚动以及点击楼层按钮跳转到对应的楼层,代码如下 html代码: <div style="height: 500p...
    99+
    2024-04-02
  • css如何实现滚动效果
    本篇内容主要讲解“css如何实现滚动效果”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“css如何实现滚动效果”吧!css通过overflow属性设置滚动条示例:<html><h...
    99+
    2023-07-04
  • Android Jetpack结构运用Compose实现微博长按点赞彩虹效果
    目录原版1. Compose 动画 API 概览2. 长按点赞动画分解3. 彩虹动画3.1 状态管理AnimatedRainbowanimatedRainbows 列表3.2 内容绘...
    99+
    2024-04-02
  • js实现文字滚动的效果
    本文实例为大家分享了js实现文字滚动的效果的具体代码,供大家参考,具体内容如下 在之前小编已经和大家介绍了一些常用的js动画效果,在此,和大家介绍一种可能不太常用的动画效果。该动画效...
    99+
    2024-04-02
  • Angular实现表格自滚动效果
    目录表格自滚动效果图实现原理具体实现:表格自滚动效果图 实现原理 原理:每一次的滚动都是在其setInterval()定时器的作用下,每次将DOM.scrollTop++ 具体实现...
    99+
    2024-04-02
  • vue实现3D切换滚动效果
    本文实例为大家分享了vue实现3D切换滚动效果的具体代码,供大家参考,具体内容如下 今天写项目,遇到一个点击切换的滚动需求,贴出来,做一个记录 这个是最终的一个效果,点击左右小箭头...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作