Compose筆記(四十)--ClickableText

? ? ? ? ?這一節主要了解一下Compose中的ClickableText,在Jetpack Compose中,ClickableText是用于創建可點擊文本的組件,其核心功能是通過聲明式語法將文本設置為交互式元素,用戶點擊時可觸發特定操作。簡單總結如下:

API含義
text:要顯示的文本內容(AnnotatedString類型,支持富文本樣式)。
onClick:點擊事件的回調函數,接收點擊位置的偏移量作為參數,用于定位具體點擊的字符。
style:文本樣式(如顏色、字體大小),可通過TextStyle自定義。
modifier:可選修飾符,用于添加額外交互或布局屬性。
富文本支持:通過AnnotatedString可為文本添加元數據(如鏈接、樣式標簽),結合ClickableText實現復雜交互。

場景
1 基礎交互
創建可點擊的按鈕或鏈接(如“登錄”“注冊”)。
實現文本展開/折疊功能(點擊“顯示更多”展開隱藏內容)。
2 富文本交互
在文章中嵌入可點擊的關鍵詞或參考文獻鏈接。
開發聊天應用時,將用戶名或話題標簽設置為可點擊(如@用戶或#話題)。
3 導航與跳轉
結合路由庫(如Compose Navigation)實現頁面跳轉。

栗子:

import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.ClickableText
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp@Composable
fun TestLinkTextExample(modifier: Modifier = Modifier) {val uriHandler = LocalUriHandler.currentval annotatedText = buildAnnotatedString {append("請閱讀我們的 ")val termsStart = lengthappend("用戶協議")val termsEnd = lengthaddStringAnnotation(tag = "URL", annotation = "https://example.com/terms", // 換成具體業務鏈接start = termsStart,end = termsEnd)addStyle(style = SpanStyle(color = Color(0xFF2196F3),textDecoration = TextDecoration.Underline),start = termsStart,end = termsEnd)append(" 和 ")val privacyStart = lengthappend("隱私政策")val privacyEnd = lengthaddStringAnnotation(tag = "URL",annotation = "https://examplexxx.com/privacy",//換成具體業務鏈接start = privacyStart,end = privacyEnd)addStyle(style = SpanStyle(color = Color(0xFF2196F3),textDecoration = TextDecoration.Underline),start = privacyStart,end = privacyEnd)}ClickableText(text = annotatedText,style = TextStyle(fontSize = 16.sp,color = Color.Black),modifier = modifier.padding(16.dp),onClick = { offset ->annotatedText.getStringAnnotations(tag = "URL", start = offset, end = offset).firstOrNull()?.let { annotation ->uriHandler.openUri(annotation.item)}})
}
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp@Composable
fun TestTextExample(modifier: Modifier = Modifier) {var showDialog by remember { mutableStateOf(false) }var dialogMessage by remember { mutableStateOf("") }// 構建帶@提及和#話題的文本val annotatedText = buildAnnotatedString {val userStart = lengthappend("@JetpackCompose")val userEnd = lengthaddStringAnnotation(tag = "MENTION",annotation = "JetpackCompose", start = userStart,end = userEnd)addStyle(style = SpanStyle(color = Color(0xFF9C27B0)), start = userStart,end = userEnd)append(" 發布了關于 ")val topicStart = lengthappend("#Compose開發")val topicEnd = lengthaddStringAnnotation(tag = "TOPIC", annotation = "Compose開發", start = topicStart,end = topicEnd)addStyle(style = SpanStyle(color = Color(0xFFF44336)), start = topicStart,end = topicEnd)append(" 的新內容,快去看看吧!")}fun handleClick(offset: Int) {annotatedText.getStringAnnotations(tag = "MENTION", start = offset, end = offset).firstOrNull()?.let {dialogMessage = "查看用戶: ${it.item}"showDialog = truereturn}annotatedText.getStringAnnotations(tag = "TOPIC", start = offset, end = offset).firstOrNull()?.let {dialogMessage = "查看話題: ${it.item}"showDialog = truereturn}}if (showDialog) {AlertDialog(onDismissRequest = { showDialog = false },title = { Text("操作提示") },text = { Text(dialogMessage) },confirmButton = {Text(text = "確定",modifier = Modifier.clickable { showDialog = false })})}ClickableText(text = annotatedText,style = TextStyle(fontSize = 16.sp,color = Color.Black),modifier = modifier.padding(16.dp),onClick = ::handleClick)
}

注意
1 點擊區域定位:onClick回調返回的是字符偏移量,需通過AnnotatedString的元數據定位具體點擊的文本片段。若文本包含多語言或復雜排版,需額外處理偏移量計算。
2 性能優化:避免在onClick中執行耗時操作,否則可能導致界面卡頓。
3 無障礙支持:為可點擊文本添加semantic描述,提升無障礙體驗。

簡單看一下其源碼:

@Composable
@Deprecated("Use Text or BasicText and pass an AnnotatedString that contains a LinkAnnotation")
fun ClickableText(text: AnnotatedString,modifier: Modifier = Modifier,style: TextStyle = TextStyle.Default,softWrap: Boolean = true,overflow: TextOverflow = TextOverflow.Clip,maxLines: Int = Int.MAX_VALUE,onTextLayout: (TextLayoutResult) -> Unit = {},onClick: (Int) -> Unit
) {// 1val layoutResult = remember { mutableStateOf<TextLayoutResult?>(null) }// 2 val pressIndicator = Modifier.pointerInput(onClick) {detectTapGestures { pos ->layoutResult.value?.let { layoutResult ->onClick(layoutResult.getOffsetForPosition(pos))}}}// 3BasicText(text = text,modifier = modifier.then(pressIndicator),style = style,softWrap = softWrap,overflow = overflow,maxLines = maxLines,onTextLayout = {layoutResult.value = itonTextLayout(it)})
}

分析:
1.狀態定義:緩存文本布局結果
layoutResult用于mutableStateOf存儲TextLayoutResult對象,用于記錄文本的布局信息(如字符位置、行高、寬高等)。
remember 確保重組時不會重復初始化,僅在依賴變化時更新。
2.點擊事件處理:pointerInput檢測點擊并計算索引
pointerInput:Compose中處理低級觸摸事件的入口,傳入onClick作為鍵(當onClick變化時,重新創建觸摸事件處理器)。
detectTapGestures:手勢檢測器,監聽點擊事件,pos參數是點擊位置相對于組件左上角的坐標(Offset類型,包含x和y偏移)。
索引計算:當點擊發生時,通過layoutResult.getOffsetForPosition(pos)將點擊坐標轉換為字符索引(核心邏輯與新版一致),再通過onClick回調暴露該索引。
3.文本渲染:BasicText與布局結果同步
BasicText:Compose中最基礎的文本渲染組件,負責將AnnotatedString渲染到屏幕上。
修飾符組合:通過modifier.then(pressIndicator)將點擊事件修飾符(pressIndicator)與外部傳入的modifier組合,確保點擊事件能被正確監聽。
布局結果同步:onTextLayout回調在文本布局完成后觸發,將最新的TextLayoutResult存入layoutResult緩存,為點擊索引計算提供數據支持

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/94388.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/94388.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/94388.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

面試必刷的數組三連:原地刪除與合并

堅持用 清晰易懂的圖解 多語言代碼&#xff0c;讓每道題變得簡單&#xff01; 呆頭個人主頁詳情 呆頭個人Gitee代碼倉庫 呆頭詳細專欄系列 座右銘&#xff1a; “不患無位&#xff0c;患所以立。” 面試必刷的數組三連&#xff1a;原地刪除與合并前言目錄1.移除元素2.刪除有序…

力扣經典算法篇-41-旋轉圖像(輔助數組法,原地旋轉法)

1、題干 給定一個 n n 的二維矩陣 matrix 表示一個圖像。請你將圖像順時針旋轉 90 度。 你必須在 原地 旋轉圖像&#xff0c;這意味著你需要直接修改輸入的二維矩陣。請不要 使用另一個矩陣來旋轉圖像。 示例 1&#xff1a;輸入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]]…

譯|用戶增長策略如何使用因果機器學習的案例

來自上傳文件中的文章《[Causal Machine Learning for Growth: Loyalty Programs, LTV, and What to Do When You Can’t Experiment | by Torty Sivill | Towards AI]》 本文探討了當 A/B 測試不可行時&#xff0c;如何利用因果推斷從歷史數據中獲取洞察。技術亮點在于通過構建…

java~final關鍵字

final關鍵字final基本介紹final的使用細節final基本介紹 final是最終的意思&#xff0c;可以修飾類&#xff0c;屬性&#xff0c;方法&#xff0c;局部變量什么時候會要使用到final呢&#xff1f; 1.想要類不被繼承時 2.不希望類的某個屬性的值被改變時 3.不想父類的某個方法被…

Node.js(四)之數據庫與身份認證

數據庫與身份認證 目錄 數據庫與身份認證 十三、數據庫的基本概念 13.1 什么是數據庫 13.2 常見的數據庫及分類 13.3 傳統型數據庫的數據組織結構 1. Excel 的數據組織結構 2. 傳統型數據庫的數據組織結構 3. 實際開發中庫、表、行、字段的關系 十四、安裝并配置MySQ…

SpringBoot+SpringMVC常用注解

文章目錄發展歷程項目創建項目結構入門案例配置文件的兩種方式&#xff1a;只能使用一種創建項目二入門案例常用知識及注解Controller:類上面加&#xff0c;SpringMVC的注解GetMapping:方法上面加Spring框架的兩項核心功能Component:組件。控制反轉&#xff0c;加在業務類上面&…

標準GS相位恢復算法

標準GS相位恢復算法詳解與MATLAB實現 Gerchberg-Saxton (GS) 算法是一種經典的相位恢復方法&#xff0c;廣泛應用于光學成像、衍射成像和全息技術等領域。該算法通過迭代過程從未知相位的強度測量中恢復相位信息。 算法原理 GS算法的核心思想是利用傅里葉變換關系在空間域和頻率…

【Linux網絡編程基礎--socket地址API】

一、主機字節序和網絡字節序主機字節序&#xff08;Host Byte Order&#xff09;&#xff1a;你當前電腦的內存字節順序&#xff08;比如 x86 是小端&#xff09;網絡字節序&#xff08;Network Byte Order&#xff09;&#xff1a;統一規定為大端序&#xff08;高位字節在高位…

Linux路徑MTU發現(Path MTU Discovery, PMTU)

Linux路徑MTU發現&#xff08;Path MTU Discovery, PMTU&#xff09;機制是TCP/IP協議棧中確保數據包高效傳輸的核心技術。其核心目標是動態探測源主機到目的主機路徑上的最小MTU&#xff08;Maximum Transmission Unit&#xff09;&#xff0c;從而避免IP分片&#xff0c;提升…

【MySQL進階】------MySQL程序

MySQL程序簡介 MySQL安裝完成通常會包含如下程序&#xff1a; Linux系統程序?般在 /usr/bin?錄下&#xff0c;可以通過命令查看&#xff1a; windows系統?錄&#xff1a;你的安裝路徑\MySQL Server 8.0\bin&#xff0c;可以通過命令查看&#xff1a; 每個 MySQL 程序都有許…

Linux大頁內存導致服務內存不足

Linux大頁內存導致服務內存不足的解決方法 大頁內存&#xff08;Huge Pages&#xff09;是Linux內核提供的一種機制&#xff0c;用于減少TLB&#xff08;轉換后備緩沖區&#xff09;的壓力&#xff0c;提高內存訪問性能。然而&#xff0c;如果配置不當&#xff0c;大頁內存可能…

超寬帶測距+測角+無線通信一體化模組:智能門鎖、智能遙控器、AR頭戴、智能穿戴

超寬帶測距測角無線通信一體化模組&#xff1a;智能門鎖、智能遙控器、AR頭戴、智能穿戴UWB測距測角技術&#xff0c;因其高精度、低延遲、抗干擾能力&#xff0c;正廣泛應用于“人-物-設備”的空間感知場景&#xff0c;成為構建智能空間和精準互動的重要底層技術。代表廠商與產…

基于單片機空氣質量檢測/氣體檢測系統

傳送門 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品題目速選一覽表 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品題目功能速覽 概述 隨著環境污染問題日益嚴重&#xff0c;空氣質量監測成為社會關注的焦點。基于單片機的空氣質量檢…

網絡安全 | 從 0 到 1 了解 WAF:Web 應用防火墻到底是什么?

&#x1f914; 寫在前面 2020年 我參加公司的安全技能大賽&#xff0c;隊友在實操環節啟用了 WAF 防火墻&#xff0c;這是我第一次接觸到 Web 應用防火墻。作為一個 Web 開發老鳥&#xff0c;真是羞愧呀&#x1f602;。 &#x1f510; Web應用防火墻 WAF 全稱是 Web Applica…

服務器突然之間特別卡,什么原因?

原因總結&#xff1a;1.一般是本地網速的問題&#xff0c;服務器網速的問題&#xff0c;服務器CPU被占滿的問題今天發現另一個會導致特別卡的問題&#xff0c;是主存占滿也會導致卡頓。解釋如下&#xff1a;當服務器的主存&#xff08;物理內存&#xff09;被完全占滿時&#x…

AI應用標準詳解:A2A MCP AG-UI

"OpenAI接入MCP&#xff0c;Google推出A2A&#xff0c;微軟與OpenAI緊密綁定"標志著云計算競爭焦點已從"算力"和"模型參數"轉向?Agent標準協議控制權?。在AI快速演進的今天&#xff0c;我們不再僅關注單個AI的智能水平&#xff0c;而是探索多個…

Web安全學習步驟

以下是Web安全專項學習步驟&#xff0c;聚焦實戰能力培養&#xff0c;分為4個階段資源清單**&#xff0c;適合從入門到進階。重點培養漏洞挖掘能力與防御方案設計雙重視角&#xff1a;---階段1&#xff1a;Web技術筑基&#xff08;1-2個月&#xff09; | 領域 | 關鍵…

Android工程命令行打包并自動生成簽名Apk

1.進入工程目錄查看所有gradle任務 2.打包debug與release 打包前先生成jks簽名文件test.jks 在工程的build.gradle中添加簽名配置 signingConfigs {release {storeFile file("/home/dev/test.jks")storePassword "111111"keyAlias "key0"keyPas…

分布式微服務--Nacos作為配置中心(一)

1.Nacos配置遠程配置中心注意總結&#xff1a;本地配置文件必須使用 bootstrap.yml 或 bootstrap.properties遠程配置的加載優先于 application.yml&#xff0c;因此必須寫在 bootstrap 配置文件中。本地配置文件中 file-extension 的取值僅支持兩種&#xff1a;properties 或 …

Linux安裝MySQL及鏈接第三方工具詳細教程,帶圖帶錯誤分析

本教程所有代碼均為root用戶權限下操作&#xff0c;如果不是root用戶&#xff0c;在代碼前加上&#xff08;sudo &#xff09;即可 一、安裝MySQL服務 準備工作&#xff1a; 有時&#xff0c;系統無法解析 部分域名&#xff0c;導致無法獲取鏡像列表&#xff0c;從而無法安裝…