ITmob-Ly
发布于 2022-09-26 / 278 阅读
0

检查和统计 Jetpack Compose 中的文本溢出

项目需要展示标签列表,并且要显示文本溢出效果(统计并显示隐藏的标签个数)。Compose 实现这个效果还是很简单的,Compose 中 Text 的 onTextLayout 参数是 Text 计算布局时的回调,包含段落信息、文本大小、基线和其他详细信息。这个回调可用来向文本添加额外的装饰或功能。例如,围绕文本绘制选择。

onTextLayout 回调的参数是 TextLayoutResult 对象,它包含有很多 Text 的详细信息,这里用到的主要是 hasVisualOverflowgetLineEnd (判断是否发生了文本溢出,获取某行结束的偏移量)。

下图是实现的效果:

Compose Text  Overflow

如下是实现该效果的代码:

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import cn.itmob.catalog.compose.ui.theme.ComposeCatalogTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ComposeCatalogTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier
                        .fillMaxSize()
                        .padding(16.dp),
                    color = MaterialTheme.colorScheme.background
                ) {
                    Column(verticalArrangement = Arrangement.Center) {
                        Greeting(
                            arrayOf(
                                "Android",
                                "IOS",
                                "Java",
                                "Kotlin",
                                "Go",
                                "Dart",
                                "JS",
                                "TypeScript",
                                "C",
                                "CPP",
                                "Lua",
                                "PHP"
                            )
                        )
                    }
                }
            }
        }
    }
}

@Composable
fun Greeting(contacts: Array<String>) {
    var overflowedText by remember { mutableStateOf("") }
    var overflowedTextCount by remember { mutableStateOf(0) }
    var overflowedTagsCount by remember { mutableStateOf(0) }
    val contactsStr = contacts.joinToString(", ")

    Column {
        Row {
            Text(
                text = "Tags: $contactsStr",
                modifier = Modifier
                    .fillMaxWidth()
                    .weight(1f),
                overflow = TextOverflow.Ellipsis,
                maxLines = 1,
                onTextLayout = { layoutResult ->
                    if (layoutResult.hasVisualOverflow) {
                        val lineEnd = layoutResult.getLineEnd(lineIndex = 0, visibleEnd = true)
                        contactsStr.substring(lineEnd).let {
                            overflowedTagsCount = it.split(", ").count()
                            overflowedTextCount = it.length
                            overflowedText = it
                        }
                    }
                }
            )
            if (overflowedTagsCount > 0) {
                Text(
                    modifier = Modifier
                        .clip(RoundedCornerShape(100))
                        .background(Color.LightGray)
                        .alpha(0.5f)
                        .padding(horizontal = 4.dp),
                    text = overflowedTagsCount.toString()
                )
            }
        }
        Spacer(Modifier.height(16.dp))
        Text("Overflowed Count: $overflowedTextCount")
        Spacer(Modifier.height(16.dp))
        Text("Overflowed Text: $overflowedText")
    }
}