Как сократить время композиции [закрыто]Android

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Как сократить время композиции [закрыто]

Сообщение Anonymous »

import android.annotation.SuppressLint
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextMeasurer
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.rememberTextMeasurer
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.mobeetest.worker.R
import com.mobeetest.worker.ui.screens.main_activity.network.SharedExpansionController
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch

fun measureColumnWidths(
columnCount: Int,
headers: List,
data: List,
fontFamily: FontFamily,
fontSize: Int,
headerFontSize: Int,
textMeasurer: TextMeasurer,
density: Density
): List {
val space = '\u0020'

val headerWidths = List(columnCount) { col ->
val text = headers.getOrNull(col).orEmpty()
val width = textMeasurer.measure(
text = AnnotatedString("$space$space$space$text$space$space$space"),
style = TextStyle(fontFamily = fontFamily, fontSize = headerFontSize.sp)
).size.width.toFloat()
with(density) { (width + 32).toDp() } // increased padding for headers
}

val dataWidths = List(columnCount) { col ->
val maxWidth = data.maxOfOrNull { row ->
val text = row.getOrNull(col).orEmpty()
textMeasurer.measure(
text = AnnotatedString("$space$space$space$text$space$space$space"),
style = TextStyle(fontFamily = fontFamily, fontSize = fontSize.sp)
).size.width.toFloat()
} ?: 0f
with(density) { (maxWidth + 32).toDp() }
}

return List(columnCount) { col ->
maxOf(headerWidths[col], dataWidths[col])
}
}

@SuppressLint("UnusedBoxWithConstraintsScope")
@Composable fun DynamicCellTable(
rowData: List,
modifier: Modifier = Modifier,
linkedControllers: List = emptyList(),
onMaximizeToggle: ((Boolean) -> Unit)? = null
)
{

val highlightedRowIndex = remember { mutableStateOf(null) }
val highlightedColumnIndex = remember { mutableStateOf(null) }

val coroutineScope = rememberCoroutineScope()

var userHasToggled by remember { mutableStateOf(false) }
var toggleExpandNext by remember { mutableStateOf(false) } // initially collapse on first click

val allCollapsed by remember {
derivedStateOf {
linkedControllers.all { !it.isExpanded.value }
}
}

// Trigger recomposition after toggle state changes
LaunchedEffect(userHasToggled, toggleExpandNext) {
snapshotFlow { linkedControllers.map { it.isExpanded.value } }
.collect { /* triggers recomposition */ }
}

val iconRes = if (allCollapsed) {
R.drawable.minimize // All collapsed ➝ show minimize (clicking it will expand)
} else {
R.drawable.maximize // At least one expanded ➝ show maximize (clicking it will collapse all)
}

val columnTitles =
listOf("TIME", "TYPE", "LAC/TAC", "CELL ID", "ARFCN", "LEVEL", "QUALITY", "RUN ")
val listState = rememberLazyListState()
val cornerShape = RoundedCornerShape(bottomStart = 8.dp, bottomEnd = 8.dp)

val textMeasurer = rememberTextMeasurer()
val density = LocalDensity.current

val columnWidths = remember(rowData) {
measureColumnWidths(
columnCount = columnTitles.size,
headers = columnTitles,
data = rowData,
fontFamily = fontPoppins,
fontSize = 9,
headerFontSize = 11,
textMeasurer = textMeasurer,
density = density
)
}

val thumbHeightRatio = remember { mutableStateOf(1f) }
val scrollProgress = remember { mutableStateOf(0f) }
val showScrollbar = remember { mutableStateOf(false) }

LaunchedEffect(listState) {
snapshotFlow { listState.layoutInfo }
.map { layoutInfo ->
val totalItems = layoutInfo.totalItemsCount
val viewportHeight = layoutInfo.viewportEndOffset - layoutInfo.viewportStartOffset
val firstIndex = listState.firstVisibleItemIndex
val firstOffset = listState.firstVisibleItemScrollOffset
val estimatedItemHeight = if (layoutInfo.visibleItemsInfo.size >= 2) {
val first = layoutInfo.visibleItemsInfo[0]
val second = layoutInfo.visibleItemsInfo[1]
(second.offset - first.offset).toFloat()
} else 48f
val totalHeight = totalItems * estimatedItemHeight
val currentScrollY = firstIndex * estimatedItemHeight + firstOffset
val ratio = (viewportHeight / totalHeight).coerceIn(0f, 1f)
val progress = (currentScrollY / (totalHeight - viewportHeight)).coerceIn(0f, 1f)
val shouldShow = totalHeight > viewportHeight
Triple(ratio, progress, shouldShow)
}
.distinctUntilChanged()
.collectLatest { (ratio, progress, shouldShow) ->
thumbHeightRatio.value = ratio
scrollProgress.value = progress
showScrollbar.value = shouldShow
}
}

BoxWithConstraints(
modifier = modifier
.clip(cornerShape)
.border(1.dp, borderRed, cornerShape)
.background(lightRed)
) {

val totalContentWidth = columnWidths.reduce { acc, dp -> acc + dp }
val padding = 1.dp * (columnWidths.size + 1)

// ✅ USE maxWidth here directly (BoxWithConstraints scope is being used properly)
val stretchRatio = with(density) {
val availableSpace = maxWidth - padding
val totalContentPx = totalContentWidth.toPx()
if (totalContentPx > 0f) {
(availableSpace.toPx() / totalContentPx).coerceAtMost(1f)
} else 1f
}

val stretchedWidths = columnWidths.mapIndexed { i, col ->
if (i == columnWidths.lastIndex) col else col * stretchRatio
}

// ⬇ The rest remains unchanged
Column(modifier = Modifier.fillMaxSize()) {
// Header
// Header with maximize icon at top right
Box(modifier = Modifier.fillMaxWidth()) {
Row(modifier = Modifier.wrapContentWidth()) {
columnTitles.forEachIndexed { index, title ->
Box(
modifier = Modifier
.border(
width = if (highlightedColumnIndex.value == index) 2.dp else 1.dp,
color = if (highlightedColumnIndex.value == index) Color.Blue else borderRed,
)
.background(
if (highlightedColumnIndex.value == index) Color.Yellow else borderRed,
shape = RoundedCornerShape(4.dp)
)
.width(stretchedWidths[index])
.clickable {
highlightedColumnIndex.value = index
coroutineScope.launch {
delay(20000)
if (highlightedColumnIndex.value == index) {
highlightedColumnIndex.value = null
}
}
}
.padding(vertical = 2.dp),
contentAlignment = Alignment.Center
) {
Text(
text = title,
fontWeight = if (highlightedColumnIndex.value == index) FontWeight.Bold else FontWeight.Bold,
fontSize = 11.sp,
color = if (highlightedColumnIndex.value == index) Color.Blue else titleColor,
maxLines = 1
)
}
}
}

// Maximize icon at top-right
androidx.compose.foundation.Image(
painter = painterResource(id = iconRes),
contentDescription = "Toggle Size",
modifier = Modifier
.size(20.dp)
.align(Alignment.TopEnd)
.padding(4.dp)
.clickable {
val shouldExpand = allCollapsed // all collapsed ➝ user intends to expand
onMaximizeToggle?.invoke(shouldExpand)
toggleExpandNext = shouldExpand
userHasToggled = true
}

)

}

Box(
modifier = Modifier
.fillMaxWidth()
.height(1.dp)
.background(Color(0xFF2BB28E))
)

// Content + Scrollbar
Box(modifier = Modifier.weight(1f)) {
LazyColumn(
state = listState,
modifier = Modifier
.fillMaxSize()
.background(Color.White)
) {
itemsIndexed(rowData) { index, row ->
val isHighlighted = index == highlightedRowIndex.value
val backgroundColor = when {
isHighlighted -> Color.Yellow
index % 2 == 0 -> Color.White
else -> lightRed.copy(alpha = 0.3f)
}
val textColor = when {
isHighlighted -> Color.Blue
highlightedColumnIndex.value != null -> Color.Black
else -> Color.Black
}

Row(
modifier = Modifier
.background(backgroundColor)
.wrapContentWidth()
.clickable {
highlightedRowIndex.value = index
coroutineScope.launch {
delay(6000)
if (highlightedRowIndex.value == index) {
highlightedRowIndex.value = null
}
}
}
) {
for (colIndex in columnTitles.indices) {
val cellText = row.getOrNull(colIndex) ?: ""
Box(
modifier = Modifier
.width(stretchedWidths[colIndex])
.background(
if (highlightedColumnIndex.value == colIndex) Color.Yellow else Color.Transparent
)
.drawWithContent {
drawContent()
val strokeWidth = 1.dp.toPx()
drawLine(
color = borderRed,
start = Offset(0f, size.height - strokeWidth / 2),
end = Offset(size.width, size.height - strokeWidth / 2),
strokeWidth = strokeWidth
)
drawLine(
color = borderRed,
start = Offset(size.width - strokeWidth / 2, 0f),
end = Offset(size.width - strokeWidth / 2, size.height),
strokeWidth = strokeWidth
)
},
contentAlignment = Alignment.Center
) {
val isColumnHighlighted = highlightedColumnIndex.value == colIndex

Text(
text = cellText,
fontFamily = fontPoppins,
fontSize = 9.sp,
color = when {
isHighlighted -> Color.Blue
isColumnHighlighted -> Color.Blue
else -> Color.Black
},
fontWeight = when {
isHighlighted -> FontWeight.Bold
isColumnHighlighted -> FontWeight.Bold
else -> FontWeight.Normal
},
maxLines = 1,
)

}
}
}
}
}

if (showScrollbar.value) {
Canvas(
modifier = Modifier
.align(Alignment.CenterEnd)
.fillMaxHeight()
.width(6.dp)
.padding(end = 2.dp, top = 1.dp, bottom = 4.dp)
) {
val availableHeight = size.height
val thumbHeight = availableHeight * thumbHeightRatio.value
val scrollOffset = scrollProgress.value * (availableHeight - thumbHeight)
drawRoundRect(
color = Color(0xFF4D4B4B).copy(alpha = 0.5f),
topLeft = Offset(0f, scrollOffset),
size = Size(size.width, thumbHeight),
cornerRadius = CornerRadius(3.dp.toPx())
)
}
}
}

Box(
modifier = Modifier
.fillMaxWidth()
.height(1.dp)
.background(Color(0xFF2BB28E))
)

// Footer with export icons
// Footer with export icons (minimal height)
Box(
modifier = Modifier
.fillMaxWidth()
.background(borderRed)
.height(18.dp)
.padding(vertical=2.dp)
) {
Row(
modifier = Modifier.align(Alignment.Center),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
listOf(
R.drawable.ms_word,
R.drawable.ms_excel,
R.drawable.kml,
R.drawable.pdf
).forEach { icon ->
Icon(
painter = painterResource(id = icon),
contentDescription = null,
tint = Color.Unspecified,
modifier = Modifier
.padding(horizontal = 6.dp)
.clickable {
// Handle export click
}
)
}
}
}

}
}
}

class TableController(initialData: List) {
private val _rows = mutableStateListOf().apply {
initialData.forEach { add(it.toMutableList()) }
}
val rows: List get() = _rows

fun insertRow(row: List) {
if (row.size == 8) _rows.add(row.toMutableList())
}

fun updateRowCell(rowIndex: Int, colIndex: Int, value: String) {
if (rowIndex in _rows.indices && colIndex in 0..7) {
_rows[rowIndex][colIndex] = value
}
}
}

< /code>
Этот код в основном производится из Chatgpt, и я очень рад помочь мне сделать это композицию. < /p>
Как запустить: < /p>
DynamicCellTable(
rowData = generateMockRowsFor5GSA(),
linkedControllers = listOf(),
onMaximizeToggle = { _ -> },
modifier = Modifier.fillMaxWidth().padding(top=2.dp,bottom=2.dp,start=4.dp,end=4.dp)
)

fun generateMockRowsFor5GSA(): List = List(80) { i ->
listOf(
"12:${(10 + i) % 60}:10",
"5G SA",
"31${i % 100}",
"NCI${100000 + i}",
"${620000 + (i % 3000)}",
"-${65 + (i % 15)} dBm",
"-${8 + (i % 10)} dB",
if (i % 6 == 0) "2 sec" else "6 sec"
)
}
< /code>
Проблема состоит в том, что если таблица занимала полную высоту экрана, требуется ~ 6s для составления и ~ 4s для каждого навигающего. DynamicCelltable Composable? src = "https://i.sstatic.net/1k9yq073.jpg"/>

Подробнее здесь: https://stackoverflow.com/questions/797 ... ition-time
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»