文本部分选中(SelectionContainer)

大约 4 分钟约 1344 字

文本部分选中(SelectionContainer)

View组件提供了跨多个文本组件的部分选中能力,类似系统原生交互,常用于AI聊天、富文本复制/分享等场景。任意View容器都可以通过selectable属性开启选中能力,容器内的TextRichText等文本组件即可参与连续选中。

支持的平台:Android、iOS、鸿蒙。

组件使用示例open in new window

关于弹出菜单

渲染层只负责选中区域绘制、游标交互、放大镜等显示效果。复制/分享等弹出菜单由业务侧自行实现,可结合selectStart / selectEnd事件回调的选区位置进行布局。

属性

支持所有基础属性,并支持以下选中相关属性:

selectable方法

设置容器是否启用文本选中。开启后,容器内的所有Text / RichText等文本节点都会被视为可选中文本,按渲染位置(先y后x)参与连续选区。

selectable方法

参数描述类型
option容器选中态。INHERIT继承父容器,ENABLE启用,DISABLE禁用SelectableOption

SelectableOption枚举:

枚举值说明
INHERIT跟随父容器(默认)
ENABLE启用文本选中
DISABLE禁用文本选中。可在已开启选中的容器内的子View上设置,用于排除特定区域

selectionColor方法

设置选区高亮颜色。该方法会根据传入颜色派生出选区底色(带透明度)与游标颜色,使两者保持一致。

selectionColor方法

参数描述类型
color选区颜色Color

事件

支持所有基础事件,并支持以下选中相关事件:

selectStartselectChangeselectEnd回调中均带有Frame类型参数,描述当前选区的位置(单位dp,相对于容器左上角)。

Frame

参数描述类型
x选区左上角x坐标Float
y选区左上角y坐标Float
width选区宽度Float
height选区高度Float

selectStart

进入选中态时触发。常用于业务侧弹出菜单或开始记录选区位置。

selectChange

选区位置或大小发生变化时触发,例如游标拖动、容器内滚动导致的选区位置刷新。

selectEnd

游标拖动等交互结束、选区稳定时触发。常用于显示弹出菜单。

selectCancel

退出选中态时触发,无参数。常见触发原因:用户点击空白处、容器尺寸变化、调用clearSelection()等。

方法

createSelection

在指定坐标处创建选区。常配合longPress等手势使用,由业务自定义触发时机。

createSelection方法

参数描述类型
x触发点x坐标(相对于容器左上角,dp)Float
y触发点y坐标(相对于容器左上角,dp)Float
type选区类型,参见SelectionTypeSelectionType

SelectionType枚举:

枚举值说明
CHARACTER选中触发点处的单个字符
WORD选中触发点所在的词
PARAGRAPH选中触发点所在的段落
SENTENCE仅iOS选中触发点所在的句子。Android、鸿蒙端会回退为PARAGRAPH

createSelectionAll

全选容器内所有可选文本。

getSelection

异步获取当前选中的文本内容。回调参数SelectionResult字段如下:

SelectionResult

参数描述类型
content选区内的文本数组,按阅读顺序(先y后x)排列。SelectionResult同时实现了List<String>接口,可直接当作List<String>使用List<String>
preContent选区起点之前的若干段文本(含选区起点所在Text的前半段)List<String>
postContent选区终点之后的若干段文本(含选区终点所在Text的后半段)List<String>

preContent / postContent 使用约定

  • 首个content元素与最后一个preContent元素属于同一Text节点;末尾content与首个postContent同理。
  • 选区刚好覆盖整个Text节点时,对应的preContent末尾元素或postContent首元素为""
  • 选区前/后剩余Text节点不足时,会填入全部剩余节点。

clearSelection

清除当前选区,同时触发selectCancel事件。

完整示例

@Page("TextSelectionExamplePage")
internal class TextSelectionExamplePage : BasePager() {

    private var selectedText by observable("")
    private var selectableContainer: ViewRef<DivView>? = null

    override fun body(): ViewBuilder {
        val ctx = this
        return {
            attr { flexDirectionColumn() }

            View {
                attr { padding(top = 12f, bottom = 12f, left = 16f, right = 16f) }
                event {
                    click {
                        ctx.selectableContainer?.view?.getSelection { result ->
                            ctx.selectedText = result.joinToString(" | ")
                        }
                    }
                }
                Text { attr { text("获取选中内容: ${ctx.selectedText}") } }
            }

            View {
                ref { ctx.selectableContainer = it }
                attr {
                    padding(all = 16f)
                    selectable(SelectableOption.ENABLE)
                    selectionColor(Color(0xFF2196F3))
                }
                event {
                    longPress {
                        if (it.state == "start") {
                            ctx.selectableContainer?.view
                                ?.createSelection(it.x, it.y, SelectionType.WORD)
                        }
                    }
                    selectEnd { frame ->
                        KLog.i("TextSelection", "selectEnd: $frame")
                    }
                }

                Text {
                    attr {
                        fontSize(15f)
                        text("Kuikly是一个跨平台的UI框架,支持iOS、Android、鸿蒙等多端。")
                    }
                }
                Text {
                    attr {
                        fontSize(15f)
                        text("文本选择功能允许用户跨多个文本组件进行连续选择。")
                    }
                }
            }
        }
    }
}

注意事项

  • 容器内若包含可滚动组件,渲染层会自动监听其滚动并刷新游标位置。
  • 容器frame大小发生变化时(如旋转、键盘弹起),会自动取消当前选区。
  • List等列表内的可选文本,进入选中态后会被临时全局保活(关闭keepAlive),退出选区后自动恢复。
  • 不同平台在UI细节上存在差异:iOS暂未实现放大镜液态玻璃效果;鸿蒙在跨多个高度不一致的Text节点时,选区背景范围可能与系统略有差异。