当前位置: 首页 > news >正文

Compose TextField详解

首先明确Compose TextField的底层依赖是:

TextField \rightarrow BasicTextField \rightarrow CoreTextField

相较于Text,TextField需要提供可输入的能力以及渲染效果动态更新的能力。 

  // CompositionLocals// If the text field is disabled or read-only, we should not deal with the input service// !!!用于请求焦点的对象。通过调用 focusRequester.requestFocus(),可以请求将焦点设置到与之关联的 TextField 上,但如何设置的???val textInputService = LocalTextInputService.current// 输入框显示的内容的密度val density = LocalDensity.current// 字体的管理val fontFamilyResolver = LocalFontFamilyResolver.currentval selectionBackgroundColor = LocalTextSelectionColors.current.backgroundColor// 管理焦点的对象val focusManager = LocalFocusManager.current// 获取当前窗口的信息。窗口是什么???val windowInfo = LocalWindowInfo.current// 用于控制键盘的对象val keyboardController = LocalSoftwareKeyboardController.current

针对所谓的文本内容超过TextField的显示区域,会出现Scroller滚动条来动态查看所输入的内容;默认情况下,次效果不显示;且Scroller不算TextField的核心的内容。

 // Scroll stateval singleLine = maxLines == 1 && !softWrap && imeOptions.singleLineval orientation = if (singleLine) Orientation.Horizontal else Orientation.Verticalval scrollerPosition = textScrollerPosition ?: rememberSaveable(orientation,saver = TextFieldScrollerPosition.Saver) { TextFieldScrollerPosition(orientation) }if (scrollerPosition.orientation != orientation) {throw IllegalArgumentException("Mismatching scroller orientation; " + (if (orientation == Orientation.Vertical)"only single-line, non-wrap text fields can scroll horizontally"else"single-line, non-wrap text fields can only scroll horizontally"))}

代码的作用是创建和初始化一个 TextFieldState 对象,并更新其属性。首先通过currentRecomposeScope获取当前重新组合的作用域(recompose scope)。

使用 remember 函数创建一个 TextFieldState 对象,并将其赋值给变量 state;其中keyboardController 是一个键盘控制器对象,它被传递给 remember 函数作为键,以确保在重新组合时 TextFieldState 对象可与输入内容保持一致。

state.update 方法,更新 TextFieldState 对象的属性。这些属性包括文本内容、样式、软换行、密度等,以及一些回调函数和其他对象。通过更新这些属性,可以确保 TextFieldState 对象的状态与传递的参数保持一致。

    val scope = currentRecomposeScope// 产生一个关键的对象 stateval state = remember(keyboardController) {TextFieldState(TextDelegate(text = visualText,style = textStyle,softWrap = softWrap,density = density,fontFamilyResolver = fontFamilyResolver),recomposeScope = scope,keyboardController = keyboardController)}state.update(value.annotatedString,visualText,textStyle,softWrap,density,fontFamilyResolver,onValueChange,keyboardActions,focusManager,selectionBackgroundColor)

TextFieldState是CoreTextField完成构建各类组件的对象以及声明剩余输入框样式及内容的状态state之后开始构建支持TextField样式渲染的各种Modifier。以此可以理解,Compose布局的过程是先测量到布局到渲染,所以构建各类对象再构建各种Modifier的顺序理应如此。

// Focusval focusModifier = Modifier.textFieldFocusModifier(enabled = enabled,focusRequester = focusRequester,interactionSource = interactionSource) {if (state.hasFocus == it.isFocused) {return@textFieldFocusModifier}state.hasFocus = it.isFocusedif (textInputService != null) {if (state.hasFocus && enabled && !readOnly) {startInputSession(textInputService,state,value,imeOptions,offsetMapping)} else {endInputSession(state)}// The focusable modifier itself will request the entire focusable be brought into view// when it gains focus – in this case, that's the decoration box. However, since text// fields may have their own internal scrolling, and the decoration box can do anything,// we also need to specifically request that the cursor itself be brought into view.// TODO(b/216790855) If this request happens after the focusable's request, the field//  will only be scrolled far enough to show the cursor, _not_ the entire decoration//  box.if (it.isFocused) {state.layoutResult?.let { layoutResult ->coroutineScope.launch {bringIntoViewRequester.bringSelectionEndIntoView(value,state.textDelegate,layoutResult.value,offsetMapping)}}}}if (!it.isFocused) manager.deselect()}

1️⃣ 为 TextField 添加一个修饰符(modifier):focusModifier,用于处理焦点相关的逻辑。

接下来,继续执行多个if语句,旨在判断是否提供可交互的TextField输入框组件。如果存在 textInputService(文本输入服务),并且 TextFieldState 对象具有焦点、启用且不是只读模式,那么会调用 startInputSession 函数来启动输入会话。这个函数会与文本输入服务进行交互,以处理文本输入和键盘事件。如果 TextFieldState 对象失去焦点,会调用 endInputSession 函数来结束输入会话。

coroutineScope.launchstartInputSession 函数分别用于在协程中异步执行将光标位置带入视图的请求和启动输入会话的操作。

因此focusModifier可以总结出必须具备这样的参数条件,页面中的TextField组件才是可输入进行交互的:

  1. 存在 textInputService(文本输入服务)。
  2. TextFieldState 对象具有焦点(state.hasFocus 为 true)。
  3. TextField 启用(enabled 为 true)。
  4. TextField 不是只读模式(readOnly 为 false)。
val pointerModifier = Modifier.textFieldPointer(manager,enabled,interactionSource,state,focusRequester,readOnly,offsetMapping)

 2️⃣ pointerModifier 是一个修饰符,用于处理与指针(例如鼠标)交互相关的逻辑。

它接受多个参数,包括 managerenabledinteractionSourcestatefocusRequesterreadOnlyoffsetMapping

这个修饰符的作用是为 TextField 添加指针交互的功能。它处理与指针相关的事件,例如鼠标点击、拖动等。通过使用这个修饰符,可以实现对 TextField 的指针交互进行控制和处理。

3️⃣ drawModifier 是一个修饰符,用于在 TextField 的绘制过程中进行自定义绘制操作。

这个修饰符使用了 drawBehind 函数,允许在组件的背后进行绘制操作。调用drawIntoCanvas 函数,获取 Canvas 对象,然后在这个 Canvas 上进行绘制操作。canvasvalueoffsetMappinglayoutResult.valuestate.selectionPaint。这些参数用于确定绘制的位置、内容和样式。

所以我们可以明确TextField不仅是会基于ResumableComposeNode作为渲染的基础,而且还是基于canvas进行渲染的。


http://www.mrgr.cn/news/3527.html

相关文章:

  • 什么是光伏电站气象站——气象监测
  • 【nginx】详细详细超详细,包括编译安装nginx+升级+回滚+核心配置+高级配置+反向代理+Nginx Rewrite相关功能等等
  • 一文搞懂数据标注
  • 【气象百科】光伏自动气象站的功能优势
  • 嘉立创PCB4层板
  • Docker核心技术和实现原理
  • 杂谈--微服务简介
  • 【mysql】mysql安装部署以及用户误删恢复
  • SpringBoot响应式编程(3)R2DBC
  • [Meachines] [Medium] poison LFI+日志投毒+VNC权限提升
  • 【物联网设备安全】物联网设备的安全管理与防护措施
  • seq2seq编码器encoder和解码器decoder详解
  • 「字符串」详解AC自动机并实现对应的功能 / 手撕数据结构(C++)
  • 【Hot100】LeetCode—206. 反转链表
  • Linux系统-打包重定向/管道符/进程shell脚本
  • C语言文件操作
  • 【秋招笔试】8.18大疆秋招(第一套)-后端岗
  • 作品集图片美化处理网站推荐
  • 初识C++:开启C++之旅
  • redis string类型