Android開發 Jetpack_Compose_7 文字

前言

  此篇博客主要講解Compose裏的文字相關的UI功能。文本處理相關的內容與細節較多,此篇博客儘量涵蓋完整,所以博客較長需要耐心看完。

  官網文檔:https://developer.android.google.cn/jetpack/compose/text?hl=zh-cn

Text 文本

全部參數

這裏列出全部參數,下面會一個一個舉例(簡單的就不舉例了)

@Composable
fun Text(
    text: String,                               //文本內容
    modifier: Modifier = Modifier,              //修飾
    color: Color = Color.Unspecified,           //文字顏色
    fontSize: TextUnit = TextUnit.Unspecified,  //文字大小
    fontStyle: FontStyle? = null,               //字體斜體
    fontWeight: FontWeight? = null,             //字體粗細
    fontFamily: FontFamily? = null,             //字體
    letterSpacing: TextUnit = TextUnit.Unspecified,//字體間距
    textDecoration: TextDecoration? = null,     //字體下劃線、中劃線
    textAlign: TextAlign? = null,               //字體對齊方向
    lineHeight: TextUnit = TextUnit.Unspecified,//行間距
    overflow: TextOverflow = TextOverflow.Clip, //字體超出範圍處理
    softWrap: Boolean = true,                   //是否自動換行
    maxLines: Int = Int.MAX_VALUE,              //最大行數
    minLines: Int = 1,                          //最小行數
    onTextLayout: (TextLayoutResult) -> Unit = {},//文本變化回調
    style: TextStyle = LocalTextStyle.current   //字體風格
){}

顯示資源裏的文字

Text(text = stringResource(id = R.string.hello))

文字的大小單位

有兩種單位分別是sp與em。

sp是與屏幕密度有關換算後的數值單位,特點是不會跟隨屏幕分辨率大小的改變而改變,能保持文字大小的一致性。一般情況下是常用這個單位。

em是相對字體大小的數值單位,1.em等於100%, 2.em則是200%相對大小,這時候在需要適配大小屏設備的應用上使用。這樣在大屏上也能跟隨改變文字的相對大小。

代碼

@Composable
fun FontSizeDemo() {
    Box(modifier = Modifier.fillMaxSize()) {
        Column(modifier = Modifier.align(Alignment.Center)) {
            Text(text = "以sp爲單位的文字", fontSize = 20.sp)
            Text(text = "以em爲單位的文字", fontSize = 2.em)
        }
    }
}

效果圖

斜體

代碼

Column(modifier = Modifier.align(Alignment.Center)){
    Text(text = "斜體", fontSize = 30.sp, fontStyle = FontStyle.Italic)
    Text(text = "正常", fontSize = 30.sp, fontStyle = FontStyle.Normal)
}

效果圖

字體粗細

這可能要分辨率高的設備才能明顯看出每階字體粗細的區別

代碼

Column(modifier = Modifier.align(Alignment.Center)){
    Text(text = "細", fontSize = 30.sp, fontWeight = FontWeight.Thin)
    Text(text = "較細", fontSize = 30.sp, fontWeight = FontWeight.ExtraLight)
    Text(text = "輕微細", fontSize = 30.sp, fontWeight = FontWeight.Light)
    Text(text = "正常", fontSize = 30.sp, fontWeight = FontWeight.Normal)
    Text(text = "中", fontSize = 30.sp, fontWeight = FontWeight.Medium)
    Text(text = "半粗", fontSize = 30.sp, fontWeight = FontWeight.SemiBold)
    Text(text = "粗", fontSize = 30.sp, fontWeight = FontWeight.Bold)
    Text(text = "大號粗體", fontSize = 30.sp, fontWeight = FontWeight.ExtraBold)
    Text(text = "黑體", fontSize = 30.sp, fontWeight = FontWeight.Black)
}

效果圖

設置字體

首先需要搞個字體,這裏推薦百度搜索阿里矢量圖,在裏面找到字體庫(全是免費開源),選擇一個下載,如下圖:

在Android studio創建字體目錄

選擇font文件夾,然後ok創建

將下載完成的字體且後綴名是.ttf的文件放到font文件夾中

代碼

系統會自帶一些字體,我們可以直接使用,但是隻支持英文

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
        Box(modifier = Modifier.fillMaxSize()) {
            Column(modifier = Modifier.align(Alignment.Center)) {
                Text(
                    text = "默認字體效果Default",
                    fontSize = 30.sp,
                    fontFamily = FontFamily.Default
                )
                //無襯線
                Text(
                    text = "無襯線SansSerif",
                    fontSize = 30.sp,
                    fontFamily = FontFamily.SansSerif
                )
                //襯線體,這個字體不支持中文,想看效果需要英文
                Text(text = "襯線體Serif", fontSize = 30.sp, fontFamily = FontFamily.Serif)
                //等寬字體,這個字體不支持中文,想看效果需要英文
                Text(
                    text = "等寬字體Monospace",
                    fontSize = 30.sp,
                    fontFamily = FontFamily.Monospace
                )
                //手寫體Cursive,這個字體不支持中文,想看效果需要英文
                Text(text = "手寫體Cursive", fontSize = 30.sp, fontFamily = FontFamily.Cursive)
                //添加我們下載的阿里的字體,此外這裏的weight與style屬性是用來設置字體粗細與斜體的,這個可能需要字體庫本身支持這些設置
                Text(
                    text = "阿里方圓體字體效果",
                    fontSize = 30.sp,
                    fontFamily = FontFamily(
                        Font(
                            R.font.alimama_fang_yuan_tivf_thin,
                            weight = FontWeight.Normal,
                            style = FontStyle.Normal
                        )
                    )
                )
            }
        }
    }
}

效果圖

字體間距

代碼

Column(modifier = Modifier.align(Alignment.Center)) {
    Text(
        text = "文字間距測試1",
        fontSize = 30.sp,
        letterSpacing = 5.sp
    )
    Text(
        text = "文字間距測試2",
        fontSize = 30.sp,
        letterSpacing = 20.sp
    )
}

效果圖

 

下劃線與中劃線

代碼

Column(modifier = Modifier.align(Alignment.Center)) {
    Text(
        text = "下劃線效果",
        fontSize = 30.sp,
        textDecoration = TextDecoration.Underline
    )
    Text(
        text = "中劃線效果",
        fontSize = 30.sp,
        textDecoration = TextDecoration.LineThrough                    )
}

效果圖

字體對齊方向

代碼

Column(modifier = Modifier.align(Alignment.Center)) {
    Text(
        text = "左",
        color = Color.White,
        fontSize = 14.sp,
        textAlign = TextAlign.Start,
        //這裏設置一個背景,讓文字對齊方向有參照物
        modifier = Modifier.padding(top = 20.dp).size(100.dp).background(color = Color.DarkGray)
    )
    Text(
        text = "中",
        color = Color.White,
        fontSize = 14.sp,
        textAlign = TextAlign.Center,
        modifier = Modifier.padding(top = 20.dp).size(100.dp).background(color = Color.DarkGray)
    )
    Text(
        text = "右",
        color = Color.White,
        fontSize = 14.sp,
        textAlign = TextAlign.End,
        modifier = Modifier.padding(top = 20.dp).size(100.dp).background(color = Color.DarkGray)
    )
    //什麼都沒設置的效果,作爲下面TextAlign.Justify左右對齊效果的參照物。
    Text(
        text = "Stretch lines of text that end with a soft line break to fill the width of the container.Lines that end with hard line breaks are aligned towards the Start edge.",
        color = Color.White,
        fontSize = 14.sp,
        modifier = Modifier.padding(top = 20.dp).size(160.dp).background(color = Color.DarkGray)
    )
    //設置後TextAlign.Justify 左右對齊後的效果。注意!這個屬性對英文有有意義所以下面使用英文來演示,對中文沒什麼意義,因爲中文文字寬度都一樣,沒有英文單詞有長度上的變化。
    Text(
        text = "Stretch lines of text that end with a soft line break to fill the width of the container.Lines that end with hard line breaks are aligned towards the Start edge.",
        color = Color.White,
        fontSize = 14.sp,
        textAlign = TextAlign.Justify,
        modifier = Modifier.padding(top = 20.dp).size(160.dp).background(color = Color.DarkGray)
    )
}

效果圖

行間距

代碼

Column(modifier = Modifier.align(Alignment.Center)) {
    Text(
        text = "行間距測試一,ABCDEFGHWJKL",
        color = Color.White,
        fontSize = 20.sp,
        lineHeight = 10.sp,
        modifier = Modifier.padding(top = 20.dp).size(200.dp).background(color = Color.DarkGray)
    )
    Text(
        text = "行間距測試二,ABCDEFGHWJKL",
        color = Color.White,
        fontSize = 20.sp,
        lineHeight = 50.sp,
        modifier = Modifier.padding(top = 20.dp).size(200.dp).background(color = Color.DarkGray)
    )
}

效果圖

文本內超出顯示

代碼

Column(modifier = Modifier.align(Alignment.Center)) {
    Text(
        text = "裁剪_Clip the overflowing text to fix its container.",
        color = Color.White,
        fontSize = 20.sp,
        overflow = TextOverflow.Clip,
        modifier = Modifier.padding(top = 20.dp).size(80.dp).background(color = Color.DarkGray)
    )
    Text(
        text = "省略_Use an ellipsis to indicate that the text has overflowed.",
        color = Color.White,
        fontSize = 20.sp,
        overflow = TextOverflow.Ellipsis,
        modifier = Modifier.padding(top = 20.dp).size(80.dp).background(color = Color.DarkGray)
    )
}

效果圖

文本內容、參數、佈局回調

每次文本變化後都會回調

代碼

@Composable
fun TextLayout() {
    val count = remember { mutableStateOf(0) }
    val log = remember { mutableStateOf("") }
    //創建一個計數功能
    LaunchedEffect(true){
        while (isActive){
            count.value++
            delay(1000)
        }
    }
    Box(modifier = Modifier.fillMaxSize()) {
        Column(modifier = Modifier.align(Alignment.Center)) {
            Text(
                text = count.value.toString(),
                color = Color.Black,
                fontSize = 38.sp,
                onTextLayout = {
                    log.value = "文本內容 = ${it.layoutInput.text} \n ${it.toString()}"
                }
            )
            //這裏實現一個Text,用來顯示上面Text的變化日誌
            Text(text = log.value, modifier = Modifier.padding(top = 30.dp))
        }
    }
}

效果圖

文字組合拼接

這裏的text = buildAnnotatedString,是另一個重載函數Text的參數(text: AnnotatedString),用於實現文本的拼接與單獨的風格設置。這裏會涉及到style的內容,這個會在下面講解,這裏只是先演示文字拼接的代碼與效果。

代碼

@Composable
fun BuildAnnotatedStringDemo() {
    Box(modifier = Modifier.fillMaxSize()) {
        Column(modifier = Modifier.align(Alignment.Center)) {
            Text(fontSize = 20.sp, text = buildAnnotatedString {
                append("拼接文字效果:\n")
                withStyle(style = SpanStyle(color = Color.Red, fontSize = 20.sp)) {
                    append("紅")
                }
                withStyle(style = SpanStyle(color = Color.Yellow, fontSize = 30.sp)) {
                    append("黃")
                }
                withStyle(style = SpanStyle(color = Color.Blue, fontSize = 35.sp)) {
                    append("藍")
                }
                append("\n----------分割線----------")
                //還能以下面嵌套的方式,進行文字的拼接組合
                withStyle(style = ParagraphStyle(lineHeight = 80.sp)) {
                    withStyle(style = SpanStyle(fontSize = 45.sp)) {
                        withStyle(style = SpanStyle(color = Color.Cyan)) {
                            append("青\n")
                        }
                        withStyle(style = SpanStyle(color = Color.Gray)) {
                            append("灰\n")
                        }
                        withStyle(style = SpanStyle(color = Color.Black)) {
                            append("黑\n")
                        }
                    }

                }
            })
        }
    }
}

效果圖

文字組合拼接後獨立點擊

有時候會需求一行文字需要2個點擊效果的情況,例如 <用戶協議>與<隱私政策> 這種情況,點擊用戶協議與隱私政策分別需要2個不一樣的點擊回調。這裏就可以使用文字組合拼接的獨立點擊功能

代碼


@Composable
fun BuildAnnotatedStringDemo() {
    val context = LocalContext.current
    Box(modifier = Modifier.fillMaxSize()) {
        Column(modifier = Modifier.align(Alignment.Center)) {
            val annotatedText = buildAnnotatedString {
                pushStringAnnotation(tag = "userAgreement", annotation = "<用戶協議>")
                withStyle(
                    style = SpanStyle(
                        fontSize = 20.sp,
                        color = Color.Blue,
                        fontWeight = FontWeight.Bold
                    )
                ) {
                    append("<用戶協議>")
                }
                /*
                 * 這裏的pop函數很重要,在每完成一段字符串註解後,都要使用pop進行記錄,防止和下面新增的其他字符串註解混在一起
                 * 如果不設置就會出現下面的點擊一次,就會返回2個字符串註解
                 */
                pop()
                append("與")
                pushStringAnnotation(tag = "privacyPolicy", annotation = "<隱私政策>")
                withStyle(
                    style = SpanStyle(
                        fontSize = 20.sp,
                        color = Color.Blue,
                        fontWeight = FontWeight.Bold
                    )
                ) {
                    append("<隱私政策>")
                }
                pop()
            }
            ClickableText(
                text = annotatedText,
                onClick = { offset ->
                    Log.e("zh", "offset = ${offset}: ")
                    annotatedText.getStringAnnotations(
                        tag = "userAgreement",
                        start = offset,
                        end = offset
                    ).firstOrNull()?.let { annotation ->
                        Toast.makeText(context, "點擊 ${annotation.item}", Toast.LENGTH_SHORT)
                            .show()
                    }
                    annotatedText.getStringAnnotations(
                        tag = "privacyPolicy",
                        start = offset,
                        end = offset
                    ).firstOrNull()?.let { annotation ->
                        Toast.makeText(context, "點擊 ${annotation.item}", Toast.LENGTH_SHORT)
                            .show()
                    }
                }
            )
        }
    }
}

效果圖

style風格_作爲通用文字風格的例子

這是一個相當重要的屬性,它可以組合上面的全部文字配置,下面的例子創建了一個style作爲通用的文字風格,可以添加到任意Text上作爲通用風格,這樣可以大大減少我們配置文字屬性的冗餘重複的代碼。

代碼

@Composable
fun TextStyleDemo() {
    val style = LocalTextStyle.current.merge(
        TextStyle(
            color = Color.Blue,
            fontSize = 30.sp,
            lineHeight = 10.sp,
            fontWeight = FontWeight.Bold,
            fontStyle = FontStyle.Normal,
            textAlign = TextAlign.Center,
            background = Color.Gray,
        )
    )
    Box(modifier = Modifier.fillMaxSize()) {
        Column(modifier = Modifier.align(Alignment.Center)) {
            Text(text = "文本1", style = style)
            Text(text = "文本2", style = style)
        }
    }
}

效果圖

style風格_文字背景

上面的例子展示的都是上面已經說明過的屬性,但是它可以完成更多的文字風格定製,從這裏開始會講解style特定的文字屬性。

style風格的背景設置非常不一樣,它並不是整個Text的背景顏色設置,而是根據文字佔位的背景顏色

代碼

@Composable
fun TextStyleDemo() {
    val style = LocalTextStyle.current.merge(
        TextStyle(
            background = Color.Gray //注意,這裏的背景與下面的Text的背景是不同的
        )
    )
    Box(modifier = Modifier.fillMaxSize()) {
        Column(modifier = Modifier.align(Alignment.Center)) {
            Text(text = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", style = style, modifier = Modifier.size(100.dp).background(color = Color.Cyan))
        }
    }
}

效果圖

 

style風格_設置文字在行距的位置

一共有4種樣式,FirstLineTop、LastLineBottom、Both、None

代碼

@Composable
fun TextStyleDemo() {
    val noneStyle = LocalTextStyle.current.merge(
        TextStyle(
            //這裏增加行距,讓lineHeightStyle的屬性效果更明顯
            lineHeight = 3.em,
            /*
                platformStyle這個屬性,根據官網文檔說是爲了給第一行文字頂部和最後一行文字底部的字體指標添加額外的內邊距。
                這個屬性會影響下面的lineHeightStyle行距調整,所以需要設置爲false關閉。
             */
            platformStyle = PlatformTextStyle(
                includeFontPadding = false
            ),
            lineHeightStyle = LineHeightStyle(
                alignment = LineHeightStyle.Alignment.Center,
                trim = LineHeightStyle.Trim.None
            ),
            //加個背景,可以看的更清楚行距的區別
            background = Color.Gray
        )
    )
    val bothStyle = LocalTextStyle.current.merge(
        TextStyle(lineHeight = 3.em, platformStyle = PlatformTextStyle(includeFontPadding = false),
            lineHeightStyle = LineHeightStyle(alignment = LineHeightStyle.Alignment.Center, trim = LineHeightStyle.Trim.Both),
            background = Color.Gray
        )
    )
    val lastLineBottomStyle = LocalTextStyle.current.merge(
        TextStyle(lineHeight = 3.em, platformStyle = PlatformTextStyle(includeFontPadding = false),
            lineHeightStyle = LineHeightStyle(alignment = LineHeightStyle.Alignment.Center, trim = LineHeightStyle.Trim.LastLineBottom),
            background = Color.Gray
        )
    )
    val firstLineTopStyle = LocalTextStyle.current.merge(
        TextStyle(lineHeight = 3.em, platformStyle = PlatformTextStyle(includeFontPadding = false),
            lineHeightStyle = LineHeightStyle(alignment = LineHeightStyle.Alignment.Center, trim = LineHeightStyle.Trim.FirstLineTop),
            background = Color.Gray
        )
    )
    Box(modifier = Modifier.fillMaxSize()) {
        Column(modifier = Modifier.align(Alignment.Center)) {
            Text(text = "文字在行距中間\nLineHeightStyle.Trim.None\nLineHeightStyle.Trim.None", style = noneStyle)
            Text(text = "第一行在行距上面,最後一行在行距下面,中間行在中間\nLineHeightStyle.Trim.Both\nLineHeightStyle.Trim.Both", style = bothStyle, modifier = Modifier.padding(top = 20.dp))
            Text(text = "文字在行距下面\nLineHeightStyle.Trim.LastLineBottom\nLineHeightStyle.Trim.LastLineBottom", style = lastLineBottomStyle, modifier = Modifier.padding(top = 20.dp))
            Text(text = "第一行在行距上面,其他行在中間\nLineHeightStyle.Trim.FirstLineTop\nLineHeightStyle.Trim.FirstLineTop", style = firstLineTopStyle, modifier = Modifier.padding(top = 20.dp))
        }
    }
}

效果圖

style風格_文字陰影

代碼

@Composable
fun TextStyleDemo() {
    val shadowStyle1 = LocalTextStyle.current.merge(
        TextStyle(
            //offset是陰影的範圍,範圍越大陰影越大
            //blurRadius是陰影的模糊半徑,數值越大陰影越模糊,越小而越清晰
            shadow = Shadow(color = Color.Blue, offset = Offset(2f, 2f), blurRadius = 1f)
        )
    )
    val shadowStyle2 = LocalTextStyle.current.merge(
        TextStyle(
            shadow = Shadow(color = Color.Blue, offset = Offset(5f, 5.0f), blurRadius = 10f)
        )
    )
    Box(modifier = Modifier.fillMaxSize()) {
        Column(modifier = Modifier.align(Alignment.Center)) {
            Text(text = "文字陰影", fontSize = 20.sp, style = shadowStyle1)
            Text(text = "文字陰影", fontSize = 20.sp, style = shadowStyle2)
        }
    }
}

效果圖

選中文字

 

TextField 輸入框

 

 

 

End

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章