Android Compose对Window Insets的处理_rememberinsetspaddingvalues(2)

最后

我见过很多技术leader在面试的时候,遇到处于迷茫期的大龄程序员,比面试官年龄都大。这些人有一些共同特征:可能工作了5、6年,还是每天重复给业务部门写代码,工作内容的重复性比较高,没有什么技术含量的工作。问到这些人的职业规划时,他们也没有太多想法。

其实30岁到40岁是一个人职业发展的黄金阶段,一定要在业务范围内的扩张,技术广度和深度提升上有自己的计划,才有助于在职业发展上有持续的发展路径,而不至于停滞不前。

不断奔跑,你就知道学习的意义所在!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

LazyColumn(
    contentPadding = rememberInsetsPaddingValues(
        insets = LocalWindowInsets.current.systemBars,
        applyTop = true,
        applyBottom = true,
    )
) {} 

其实1和2的行为非常类似, 只是显示区域大小的区别. content padding只是在第一个item的上面和最后一个item的下面加上padding, 在滚动的中间过程中内容是可以全屏的, 只有到头或者到底了才会显示出padding.

lazycolumn-padding.png

content padding用动图更能说明情况:

content pading

内容区域处理总结

Insets这个库提供了这么几个Modifier:

  • Modifier.statusBarsPadding()
  • Modifier.navigationBarsPadding()
  • Modifier.systemBarsPadding()
  • Modifier.imePadding()
  • Modifier.navigationBarsWithImePadding()
  • Modifier.cutoutPadding() 可以直接在布局中用上, 就获取了应该有的padding, 比如statusBarPadding是top, navigationBarsPadding是bottom. 这都不用开发者自己想.

如果这些都不满足你的需求, 也可以直接用尺寸:

  • Modifier.statusBarsHeight()
  • Modifier.navigationBarsHeight()
  • Modifier.navigationBarsWidth()

或者更直接地用LocalWindowInsets.current自己获取想要inset类型的相关尺寸.

输入框元素和键盘

on-screen keyboard, 又叫IME (Input Method Editor), 一般点击输入框会弹出, IME也是一种Inset.

输入框被键盘遮挡问题

当输入框处于屏幕上半屏的时候, 基本不用考虑键盘遮挡的问题. 但是当输入框在屏幕下半屏, 我们需要在键盘弹出来的时候让输入框完全显示出来而不被盖住.

解决这个问题需要这么几个东西:

  • Activity的android:windowSoftInputMode="adjustResize", 表示在键盘弹出时, Activity会改变布局大小, 这种改变是挤压型的.
  • Modifier.imePadding的使用, 给布局加上一个恰好等于键盘高度的bottom padding. 通常是给输入框的父布局, 加在哪一层视情况而定.
  • 如果上面两个都设置了仍然不能把输入框完全显示出来, 可能需要再加入点强力的唤醒行为.

根据这个issue下的[这条comment], 可以用这个Modifier, 在这个ui获取到焦点的时候, 自己把自己bring into view.

@ExperimentalComposeUiApi
fun Modifier.bringIntoViewAfterImeAnimation(): Modifier = composed {
    val imeInsets = LocalWindowInsets.current.ime
    var focusState by remember { mutableStateOf<FocusState?>(null) }
    val relocationRequester = remember { RelocationRequester() }

    LaunchedEffect(
        imeInsets.isVisible,
        imeInsets.animationInProgress,
        focusState,
        relocationRequester
    ) {
        if (imeInsets.isVisible &&
            !imeInsets.animationInProgress &&
            focusState?.isFocused == true) {
            relocationRequester.bringIntoView()
        }
    }

    relocationRequester(relocationRequester)
        .onFocusChanged { focusState = it }
} 

这个ReloactionRequest已经deprecated了, Compose新版的叫BringIntoViewRequester.

IME padding计算和布置

.imePadding()的值是变化的, 在没有键盘的情况下是0, 等有键盘的时候变为键盘高度.

计算键盘弹出的高度要注意:

  • 最简单的情况直接用.imePadding()完事, 布局的bottom padding自动和IME贴合.
  • 如果整体已经有了navigation bar的高度, 可以考虑用.navigationBarsWithImePadding(), 它是取IME和navigation bar高度的最大值.
  • 如果键盘上方出现了白条, 说明padding算多了, 要么是布局中已经有inner padding, 要么就是已经加过navigationBarsPadding. 这时候可以自己做一个减法处理.

比如这个:

LazyColumn(
    contentPadding = PaddingValues(
        bottom = with(LocalDensity.current) {
            LocalWindowInsets.current.ime.bottom.toDp() - innerPadding.bottom
        }.coerceAtLeast(0.dp)
    )
) { /* ... */ } 

.imePadding放在哪里, 关系到什么样的区域会被显示出来, 被包裹的区域会显示在键盘上方.

来举个例子, 有个带输入框的界面.

我们给它整体设置一个.navigationBarsWithImePadding(), 表示没键盘的时候, 底部留navigation bar的高度, 有键盘的时候留键盘的高度:

Column(
    modifier = Modifier.fillMaxSize().statusBarsPadding().navigationBarsWithImePadding()
        .background(color = Color.Cyan.copy(alpha = 0.2f)),
    verticalArrangement = Arrangement.SpaceBetween
) {
    Text(
        modifier = Modifier.fillMaxWidth()
            .background(color = Color.Yellow.copy(alpha = 0.5f)),
        text = "Top Text",
        style = MaterialTheme.typography.h2
    )
    Text(text = "Content", style = MaterialTheme.typography.h2)
    MyTextField("Text Field 1")
    MyTextField("Text Field 2")
    Text(
        modifier = Modifier.fillMaxWidth()
            .background(color = Color.Yellow.copy(alpha = 0.5f)),
        text = "Bottom Text",
        style = MaterialTheme.typography.h2
    )
} 

键盘弹出时, Bottom Text也会被顶上去, 这是因为imePadding作用于整块的布局.

如果我们这样改, 只包裹输入框的部分, 那么键盘就不会把底部的UI顶上去:

Column(
    modifier = Modifier.fillMaxSize().statusBarsPadding()
        .background(color = Color.Cyan.copy(alpha = 0.2f)),
    verticalArrangement = Arrangement.SpaceBetween
) {
    Text(
        modifier = Modifier.fillMaxWidth()
            .background(color = Color.Yellow.copy(alpha = 0.5f)),
        text = "Top Text",
        style = MaterialTheme.typography.h2
    )
    Text(text = "Content", style = MaterialTheme.typography.h2)

    Text(
        modifier = Modifier.fillMaxWidth()
            .background(color = Color.Yellow.copy(alpha = 0.5f)),
        text = "Bottom Text",
        style = MaterialTheme.typography.h2
    )
} 


两种效果见图:

ime-handling.png

键盘部分总结延伸

总结: 输入框键盘的处理包括了:

  • adjustResize.
  • 设置合理的bottom padding: 在哪里设置, 需要设置多少.
  • 让View主动bring自己到可见位置.

Insets库里还提供了键盘随着滚动消失和出现的例子. 感兴趣可以看下.

accompanist insets使用总结

accompanist insets库帮我们做了两部分内容:

  • 获取各种insets信息然后用CompositionLocalProvider提供.
  • Provider内部, 通过Modifier获取直接可用的modifier或者尺寸, 也可以直接获取.

但是这个库用起来也有一些需要注意的地方, 比如:

  • 如果忘记设置WindowCompat.setDecorFitsSystemWindows(window, false), 得到的值都是0.
  • ProvideWindowInsets的参数: consumeWindowInsets这个值默认是true, 建议设置为false, 方便内层的ui继续用这些inset的值.
@Composable
fun ProvideWindowInsets(
    consumeWindowInsets: Boolean = true,
    windowInsetsAnimationsEnabled: Boolean = true,
    content: @Composable () -> Unit
) 


  • 如果在布局中嵌套使用ProvideWindowInsets, 可能就无法按照预期工作, (不知道是不是暂时性的issue).

文末

我总结了一些Android核心知识点,以及一些最新的大厂面试题、知识脑图和视频资料解析。

需要的直接点击文末小卡片可以领取哦!我免费分享给你,以后的路也希望我们能一起走下去。(谢谢大家一直以来的支持,需要的自己领取)

Android学习PDF+架构视频+面试文档+源码笔记

部分资料一览:

  • 330页PDF Android学习核心笔记(内含8大板块)

  • Android学习的系统对应视频

  • Android进阶的系统对应学习资料

最后

总而言之,Android开发行业变化太快,作为技术人员就要保持终生学习的态度,让学习力成为核心竞争力,所谓“活到老学到老”只有不断的学习,不断的提升自己,才能跟紧行业的步伐,才能不被时代所淘汰。

在这里我分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司20年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

]

还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值