天天看點

Jetpack Composes 學習【10】Text

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,
    onTextLayout: (TextLayoutResult) -> Unit = {},
    style: TextStyle = LocalTextStyle.current
)      

​Text​

​​ 是 ​

​Compose​

​ 中最基本的布局元件,它可以顯示文字

@Composable
fun TextDemo() {
    Text("Hello World")
}      

從 ​

​res​

​ 中加載文字

@Composable
fun TextDemo() {
    Text(stringResource(id = R.string.content))
}

<resources>
    <string name="app_name">composestudy</string>
    <string name="content">秋刀魚不會過期</string>
</resources>      

1. style 參數

​style​

​ 參數可以幫助我們配置文本的行高,顔色,粗體等設定

package com.example.composestudy


import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview


class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {

                TextDemo()

        }
    }
}



   @Composable
fun TextDemo() {
       Column{
           Text(
               text = "這是一個标題",
               style = MaterialTheme.typography.h6
           )
           Text(
               text ="我是内容",
               style = MaterialTheme.typography.body2
           )
       }
}


@Preview(name = "Light Mode")

@Composable
fun PreviewMessageCard() {


        TextDemo()

}      
Jetpack Composes 學習【10】Text

文字間距

package com.example.composestudy


import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.sp


class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {

                TextDemo()

        }
    }
}


@Composable
fun TextDemo() {
    Column(
        modifier = Modifier.fillMaxWidth(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(
            text = "大前端之旅",
            style = TextStyle(
                fontWeight = FontWeight.W900, //設定字型粗細
                fontSize = 20.sp,
                letterSpacing = 7.sp
            )
        )
    }
}


@Preview(name = "Light Mode")

@Composable
fun PreviewMessageCard() {


        TextDemo()

}      
Jetpack Composes 學習【10】Text

2. maxLines 參數

使用 ​

​maxLines​

​​ 參數可以幫助我們将文本限制在指定的行數之間,如果文本足夠短則不會生效,如果文本超過 ​

​maxLines​

​ 所規定的行數,則會進行截斷

@Composable
fun TextDemo() {

    Column{
        Text(
            text = "男人最好的狀态是,25歲的時候能帶着30歲的成熟去經營愛情,30歲的時候還帶着18歲的不怕,去勇敢愛????",
            style = MaterialTheme.typography.h6,
            maxLines = 1,
        )
        Text(
            text ="大前端之旅",
            style = MaterialTheme.typography.body2
        )
    }

}      

overflow 處理溢出

使用 ​

​overflow​

​ 參數可以幫助我們處理溢出的視覺效果

@Composable
fun TextDemo() {

    Column{
        Text(
            text = "男人最好的狀态是,25歲的時候能帶着30歲的成熟去經營愛情,30歲的時候還帶着18歲的不怕,去勇敢愛????",
            style = MaterialTheme.typography.h6,
            maxLines = 1,
            overflow = TextOverflow.Ellipsis
        )
        Text(
         text ="大前端之旅",
            style = MaterialTheme.typography.body2
        )
    }

}      
Jetpack Composes 學習【10】Text

3. textAlign 參數

當我們在 ​

​Text​

​​ 中設定了 ​

​fillMaxWidth()​

​​ 之後,我們可以指定 ​

​Text​

​ 的對齊方式

@Composable
fun TextDemo() {
    Column {
        Text(
            text = "每天摸魚",
            modifier = Modifier.fillMaxWidth(),
            textAlign = TextAlign.Left
        )
        Text(
            text = "這好嗎",
            modifier = Modifier.fillMaxWidth(),
            textAlign = TextAlign.Center
        )
        Text(
            text = "這非常的好",
            modifier = Modifier.fillMaxWidth(),
            textAlign = TextAlign.Right
        )
    }
}      
Jetpack Composes 學習【10】Text
注意

需要注意區分的是,​

​TextAlign​

​ 設定的是文本的對齊方式,而不是位置方向

Jetpack Composes 學習【10】Text

如果需要實作 Text 元件居中,或者水準位置中其他方向,請參考這裡

4. lineHeight 參數

使用 lineHeight 參數可以讓我們指定 ​

​Text​

​ 中每行的行高間距

Column {
    Text(
        text = "大前端之旅".repeat(15),
    )
    Spacer(Modifier.padding(vertical = 15.dp))
    Text(
        text = "大前端之旅".repeat(15),
        lineHeight = 30.sp
    )
}      
Jetpack Composes 學習【10】Text

5. fontFamily 參數

使用 ​

​fontFamily​

​ 參數可以讓我們自定義字型,它的調用方法是這樣的:

Column {
    Text("Hello World", fontFamily = FontFamily.Serif)
    Text("Hello World", fontFamily = FontFamily.SansSerif)
}      

你也可以加載 ​

​res/font​

​ 下的字型。

建立一個 ​

​font​

​​ 檔案夾可以右鍵 ​

​res​

​​ 檔案夾,選擇 ​

​Android Resource Directory​

​​ -> 選擇 ​

​font​

Jetpack Composes 學習【10】Text
Text(
    text = "男人最好的狀态是,25歲的時候能帶着30歲的成熟去經營愛情,30歲的時候還帶着18歲的不怕,去勇敢愛????",
    fontFamily = FontFamily(
        Font(R.font.pingfang, FontWeight.W700)
    )
)      

6. 可點選的 Text

有的時候也許您需要将文本當作按鈕,那麼隻需要添加 ​

​Modifier.clickable​

​ 即可

代碼如下:

@Composable
fun TextDemo() {
    Text(
        text = "确認編輯",
        modifier = Modifier.clickable(
            onClick = {
                  // TODO
            },
        )
    )
}      

取消點選波紋

但是我們會發現,​

​clickable​

​ 有自帶的波紋效果,如果我們想要取消的話,隻需要添加兩個參數即可:

@Composable
fun TextDemo() {

    // 擷取 context
    val context = LocalContext.current

    Text(
        text = "确認編輯",
        modifier = Modifier.clickable(
            onClick = {
                // 通知事件
                Toast.makeText(context, "你點選了此文本", Toast.LENGTH_LONG).show()
            },
            indication = null,
            interactionSource = MutableInteractionSource()
        )
    )

}      

效果如下:

Jetpack Composes 學習【10】Text

7. 特定的文字顯示

如果我們想讓一個 ​

​Text​

​ 語句中使用不同的樣式,比如粗體提醒,特殊顔色

則我們需要使用到 ​

​AnnotatedString​

​AnnotatedString​

​ 是一個資料類,其中包含了:

  • 一個​

    ​Text​

    ​ 的值
  • 一個​

    ​SpanStyleRange​

    ​​ 的​

    ​List​

    ​,等同于位置範圍在文字值内的内嵌樣式
  • 一個​

    ​ParagraphStyleRange​

    ​​ 的​

    ​List​

    ​,用于指定文字對齊、文字方向、行高和文字縮進樣式
inline fun <R : Any> AnnotatedString.Builder.withStyle(
    style: SpanStyle,
    block: AnnotatedString.Builder.() -> crossinline R
): R      

一個簡單的代碼示範:

@Composable
fun TextDemo() {
    Column(
        modifier = Modifier.fillMaxWidth(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(
            buildAnnotatedString {
                append("你現在觀看的章節是 ")
                withStyle(style = SpanStyle(fontWeight = FontWeight.W900)) {
                    append("Text")
                }
            }
        )
    }
}      

效果如下:

8. 文字超連結?(ClickableText)

在第 6部分我們已經介紹了可以通過 ​

​AnnotatedString​

​​ 來完成在一個 ​

​Text​

​ 中給不同的文字應用不同的樣式

在第 5部分我們已經介紹了可以通過 ​

​Modifier.Clickable()​

​​ 來完成檢測 ​

​Text​

​ 的點選

但是 ​

​Modifier.Clickable()​

​​ 無法檢測 ​

​Text​

​​ 中的部分點選,那如果我們需要檢測一個 ​

​Text​

​ 中的部分點選事件該怎麼辦呢?就像我們經常在 App 底下看到的使用者協定等

其實很簡單,​

​Compose​

​​ 也給我們準備了 ​

​ClickableText​

​,來看看如何使用吧!

package com.example.composestudy


import android.content.ContentValues.TAG
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
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.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp


class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {

                TextDemo()

        }
    }
}


@Composable
fun TextDemo() {
    val text = buildAnnotatedString {
        append("勾選即代表同意")
        withStyle(
            style = SpanStyle(
                color = Color(0xFF0E9FF2),
                fontWeight = FontWeight.Bold
            )
        ) {
            append("使用者協定")
        }
    }

    ClickableText(
        text = text,
        onClick = { offset ->
            Log.d(TAG, "Hi,你按到了第 $offset 位的文字")
        }
    )

}

@Preview(name = "Light Mode")

@Composable
fun PreviewMessageCard() {


        TextDemo()

}      
Jetpack Composes 學習【10】Text

但是...怎麼才能檢測​

​使用者協定​

​這四個字元的點選事件呢?

也不用怕,​

​Compose​

​​ 還在 ​

​buildAnnotatedString​

​​ 和 ​

​ClickableText​

​ 中引入了相應的方法

先來看看代碼吧!

val annotatedText = buildAnnotatedString {
    append("勾選即代表同意")
    pushStringAnnotation(
        tag = "tag",
        annotation = "一個使用者協定啦啦啦,内容内容"
    )
    withStyle(
        style = SpanStyle(
            color = Color(0xFF0E9FF2),
            fontWeight = FontWeight.Bold
        )
    ) {
        append("使用者協定")
    }
    pop()
}

ClickableText(
    text = annotatedText,
    onClick = { offset ->
        annotatedText.getStringAnnotations(
            tag = "tag", start = offset,
            end = offset
        ).firstOrNull()?.let { annotation ->
            Log.d(TAG, "你已經點到 ${annotation.item} 啦")
        }
    }
)      
Jetpack Composes 學習【10】Text

在上面的代碼中

  1. 多了一個​

    ​pushStringAnnotation()​

    ​​ 方法,它會将給定的注釋附加到任何附加的文本上,直到相應的​

    ​pop​

    ​ 被調用
  2. ​getStringAnnotations()​

    ​​ 方法是查詢附加在這個​

    ​AnnotatedString​

    ​​ 上的字元串注釋。注釋是附加在​

    ​AnnotatedString​

    ​​ 上的中繼資料,例如,在我們的代碼中​

    ​"tag"​

    ​​ 是附加在某個範圍上的字元串中繼資料。注釋也與樣式一起存儲在​

    ​Range​

    ​ 中

小試牛刀

那麼,你已經學會了如何自定義 ​

​Text​

​ 中的樣式和點選事件,來嘗試做出一個這樣的效果?

Jetpack Composes 學習【10】Text

實作的代碼可以通過以下的方式來檢視

package com.example.composestudy


import android.content.ContentValues.TAG
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material.AlertDialog
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role.Companion.Button

import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp


class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {

                TextDemo()

        }
    }
}


@Composable
fun TextDemo() {

    var content by remember{ mutableStateOf("")}
    val openDialog = remember { mutableStateOf(false)  }
    val annotatedText = buildAnnotatedString {
        append("勾選即代表同意")
        pushStringAnnotation(
            tag = "tag",
            annotation = stringResource(id = R.string.content)
        )
        withStyle(
            style = SpanStyle(
                color = Color(0xFF0E9FF2),
                fontWeight = FontWeight.Bold
            )
        ) {
            append("使用者協定")
        }
        pop()
    }

    Box(
        modifier = Modifier
            .fillMaxSize()
            .padding(bottom = 15.dp),
        contentAlignment = Alignment.BottomCenter
    ){
        ClickableText(
            text = annotatedText,
            onClick = { offset ->
                annotatedText.getStringAnnotations(
                    tag = "tag", start = offset,
                    end = offset
                ).firstOrNull()?.let { annotation ->
                    openDialog.value = true
                    content = annotation.item
                }
            }
        )
    }

    if(openDialog.value){
        AlertDialog(
            onDismissRequest = {
                openDialog.value = false
            },
            title = {
                Box(Modifier.fillMaxWidth(),contentAlignment = Alignment.Center){
                    Text(
                        text = "使用者協定",
                        style = MaterialTheme.typography.h6,
                    )
                }
            },
            text = {
                Text(content)
            },
            confirmButton = {
                Button(
                    onClick = {
                        openDialog.value = false
                    }
                ){
                    Text("确認")
                }
            },
            dismissButton = {
                Button(
                    onClick = {
                        openDialog.value = false
                    }
                ){
                    Text("取消")
                }
            }
        )
    }
}

@Preview(name = "Light Mode")

@Composable
fun PreviewMessageCard() {


        TextDemo()

}      

9. 文字複制

預設情況下 ​

​Text​

​​ 并不能進行複制等操作,我們需要設定 ​

​SelectionContainer​

​​ 來包裝 ​

​Text​

package com.example.composestudy


import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview


class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {

                TextDemo()

        }
    }
}


@Composable
fun TextDemo() {

    SelectionContainer {
        Column{
            Text(
                text = "每天摸魚",
                modifier = Modifier.fillMaxWidth(),
                textAlign = TextAlign.Left
            )
            Text(
                text = "這好嗎",
                modifier = Modifier.fillMaxWidth(),
                textAlign = TextAlign.Center
            )
            Text(
                text = "這非常的好",
                modifier = Modifier.fillMaxWidth(),
                textAlign = TextAlign.Right
            )
        }
    }
}

@Preview(name = "Light Mode")

@Composable
fun PreviewMessageCard() {


        TextDemo()

}      
Jetpack Composes 學習【10】Text

10. 文字強調效果

文字根據不同情況來确定文字的強調程度,以突出重點并展現出視覺上的層次感。

Material Design 建議采用不同的不透明度來傳達這些不同的重要程度,你可以通過 ​

​LocalContentAlpha​

​ 實作此功能。

您可以通過為此 ​

​CompositionLocal​

​ 提供一個值來為層次結構指定内容 Alpha 值。(​

​CompositionLocal​

​ 是一個用于隐式的傳遞參數的元件,後續會提到)

package com.example.composestudy


import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.material.ContentAlpha
import androidx.compose.material.LocalContentAlpha
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.tooling.preview.Preview


class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {

                TextDemo()

        }
    }
}


@Composable
fun TextDemo() {

   Column() {
       // 将内部 Text 元件的 alpha 強調程度設定為高
// 注意: MaterialTheme 已經預設将強調程度設定為 high
       CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.high) {
           Text("這裡是high強調效果")
       }
// 将内部 Text 元件的 alpha 強調程度設定為中
       CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
           Text("這裡是medium強調效果")
       }
// 将内部 Text 元件的 alpha 強調程度設定為禁用
       CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) {
           Text("這裡是禁用後的效果")
       }
   }
}

@Preview(name = "Light Mode")

@Composable
fun PreviewMessageCard() {


        TextDemo()

}      

這是運作效果:

這張圖可以很好的說明這個效果

11. 文字水準位置

一般情況下,Text 不會水準居中,如果你在 ​

​Row​

​​, ​

​Column​

​​, ​

​Box​

​​ 這些 Composable 裡面想要實作居中的效果,你可以在 Text 外圍寫一個 ​

​Box​

​​, ​

​Row​

​​, ​

​Column​

​ 等

像這樣:

Column {
    Text("123")
    Text("456")
    Box(
        modifier = Modifier.fillMaxWidth(),
        contentAlignment = Alignment.Center
    ) {
        Text("789")
    }
}      
Jetpack Composes 學習【10】Text

水準靠左: ​

​Alignment.Start​

水準靠右: ​

​Alignment.End​

12. 更多