يقوم صف الدردشة المرن ، ChatFlexBoxLayout ، بتوضع عناصره بناءً على عدد من خطوط رسالة النص ، وعرض الوالدين ، وعرض حالة الرسالة. تم إنشاء SubcomposeColumn باستخدام SubComposelayout الذي يعيد إعادة أطفالها على أساس أطول أطفال. هذا مفيد لمطابقة رسالة الاقتباس وطول الرسالة بعد حساب الموضع. ينشئ هذان المكونتان معًا صفوف رسائل ديناميكية تضع الأطفال ، وتضع الرسالة وتاريخ الرسالة وحالة الرسالة.
هناك 3 ملفات تنفيذ لتجربة ChatFlexBoxLayout ، و SubcomposeColumn هي DemoFullChat.kt و DemoChatAndWidth.kt و DemoResizableColumn.kt
| دردشة كاملة | عرض الدردشة | قابلة للتوحيد |
|---|---|---|
![]() | ![]() | ![]() |
يقيس هذا التصميم رسالة ومواضع ، وحاوية أخرى تستخدم تاريخ الرسالة أو تاريخ الرسالة + الوضع الوضعية مثل تطبيقات المراسلة.
هناك 4 شروط محتملة لوضع الرسائل والإحصائيات
ChatFlexBoxLayout (
modifier : Modifier = Modifier ,
text : String ,
color : Color = Color . Unspecified ,
fontSize : TextUnit = 16 .sp,
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 ,
messageStat : @Composable () -> Unit ,
onMeasure : (( ChatRowData ) -> Unit ) ? = null
) نظرًا لأن TextLayout مطلوب للحصول على طول النص ، وعرض السطر الأخير والخصائص الأخرى ، فإنه داخلي لهذا القابل للتكنولوجيا ولكن يمكن تعيين خصائص Text القابلة للتكوين مع نفسه كما يتم باستخدام Text .
يقوم onMeasure بإرجاع بيانات التخطيط الداخلي لهذا الصف ، هكذا قمت بتعيين الألوان بشكل مختلف في عينة عرض الدردشة . messageStat قابلة للتكوين يحتوي على نص رسالة أو حالة إذا كنت بحاجة إلى ذلك.
ChatFlexBoxLayout (
modifier = Modifier
.background(color, shape = RoundedCornerShape ( 8 .dp))
.padding(start = 2 .dp, top = 2 .dp, end = 4 .dp, bottom = 2 .dp),
text = text,
messageStat = {
MessageTimeText (
modifier = Modifier .wrapContentSize(),
messageTime = messageTime,
messageStatus = messageStatus
)
},
onMeasure = { chatRowData ->
color = when (chatRowData.measuredType) {
0 -> Color . Yellow
1 -> Color . Red
2 -> Color . Green
else -> Color . Magenta
}
}
) يأخذ الحمل الزائد الآخر من ChatFlexBoxLayout مركبات اثنين كوسائط يمكن استخدامها للرسالة المخصصة التي يمكن استخدامها بدلاً من السلسلة أو المشروح.
@Composable
fun ChatFlexBoxLayout (
modifier : Modifier ,
message : @Composable () -> Unit ,
messageStat : @Composable () -> Unit = {},
chatRowData : ChatRowData ,
onMeasure : (( ChatRowData ) -> Unit ) ? = null
) {
// ...
} استخدم مع remember { ChatRowData() } لتوفير إحصائيات واستدعاء measureText(chatRowData, it) لتعيين خصائص نصية على هذه البيانات
val chatRowData = remember { ChatRowData () }
ChatFlexBoxLayout (
modifier = Modifier .padding(
start = 2 .dp,
top = 2 .dp,
end = 8 .dp,
bottom = 2 .dp
),
message = {
Text (
modifier = Modifier .padding(horizontal = 6 .dp, vertical = 4 .dp),
text = text,
fontSize = 16 .sp,
onTextLayout = {
// ️ THIS IS REQUIRED TO MEASURE Text size and get line count
measureText(chatRowData, it)
}
)
},
messageStat = {
MessageTimeText (
modifier = Modifier .wrapContentSize(),
messageTime = messageTime,
messageStatus = messageStatus
)
},
chatRowData = chatRowData
)
} يستخدم هذا التصميم subcomposelayout للعثور على أطول طفل ثم يعيد تخفيض أطفاله ووضع كل طفل على أقصى عرض. هناك اثنين من الأحمال الزائدة لهذا القابل للتأليف إذا كنت بحاجة فقط إلى استخدام طفلان مباشران يمكنك استخدامه الذي يعيد حجم المكون الرئيسي كـ IntSize
fun SubcomposeColumn (
modifier : Modifier = Modifier ,
mainContent : @Composable () -> Unit = {},
dependentContent : @Composable ( IntSize ) -> Unit
) {
.. .
}هذه الوظيفة المحملة مناسبة للتخطيط مع أي عدد من الأطفال
@Composable
fun SubcomposeColumn (
modifier : Modifier = Modifier ,
content : @Composable () -> Unit = {},
) {
SubcomposeLayout (modifier = modifier) { constraints ->
var recompositionIndex = 0
var placeables : List < Placeable > = subcompose(recompositionIndex ++ , content).map {
it.measure(constraints)
}
val maxSize =
placeables.fold( IntSize . Zero ) { currentMax : IntSize , placeable : Placeable ->
IntSize (
width = maxOf(currentMax.width, placeable.width),
height = currentMax.height + placeable.height
)
}
// Remeasure every element using width of longest item as minWidth of Constraint
if ( ! placeables.isNullOrEmpty() && placeables.size > 1 ) {
placeables = subcompose(recompositionIndex, content).map { measurable : Measurable ->
measurable.measure( Constraints (maxSize.width, constraints.maxWidth))
}
}
layout(maxSize.width, maxSize.height) {
var yPos = 0
placeables.forEach { placeable : Placeable ->
placeable.placeRelative( 0 , yPos)
yPos + = placeable.height
}
}
}
}