How can I make a dotted list in jetpack compose in the simplest way possible?
an example of what I meant:
You can use something like:
val itemsList = (0..5).toList() //just an example
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
itemsList.forEach() {
Row(
verticalAlignment = Alignment.CenterVertically,
) {
Box(
modifier = Modifier
.padding(start = 16.dp, end = 8.dp)
.size(8.dp)
.background(Color.Black, shape = CircleShape),
)
Text("Text Text $it")
}
}
}
Related
Hi I am using Jetpack Compose to create a Heterogenous list. I was successful in implementing it. My requirement is when I try to click an Item in the list, I need to recompose the list. The app crashes when tried to refresh the list with below exception:
java.lang.IllegalStateException: Vertically scrollable component was measured with an infinity maximum height constraints, which is disallowed. One of the common reasons is nesting layouts like LazyColumn and Column(Modifier.verticalScroll()). If you want to add a header before the list of items please add a header as a separate item() before the main items() inside the LazyColumn scope. There are could be other reasons for this to happen: your ComposeView was added into a LinearLayout with some weight, you applied Modifier.wrapContentSize(unbounded = true) or wrote a custom layout. Please try to remove the source of infinite constraints in the hierarchy above the scrolling container
My code is below:
#Composable fun PrepareOverViewScreen(overViewList: List<OverViewListItem>) {
Scaffold(topBar = { TopBar("OverView") },
content = { DisplayOverViewScreen(overViewList = overViewList) },
backgroundColor = Color(0xFFf2f2f2)
)
}
#Composable fun DisplayOverViewScreen(
modifier: Modifier = Modifier, overViewList: List<OverViewListItem>
) {
LazyColumn(modifier = modifier) {
items(overViewList) { data ->
when (data) {
is OverViewHeaderItem -> {
HeaderItem(data,overViewList)
}
}
}
}
}
HeaderItem Composable Function is below :
#Composable fun HeaderItem(overViewHeaderItem: OverViewHeaderItem,overViewList: List<OverViewListItem>) { <br>
var angle by remember {
mutableStateOf(0f)
}
var canDisplayChild by remember {
mutableStateOf(false)
}
**if(canDisplayChild){
HandleHistoryTodayChild(canDisplayChild = true,overViewList)
}**
when (overViewHeaderItem.listType) {
ItemType.IN_PROGRESS_HEADER -> {
Column(
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.background(color = Color(0xffdc8633)),
verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.Start
) {
Text(
text = "In Progress", color = Color.White,
modifier = Modifier.padding(start = 16.dp)
)
}
}
ItemType.HISTORY_TODAY_HEADER -> {
Column(
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.background(color = Color(0xffd7d7d7)),
verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.Start
) {
Text(
text = stringResource(R.string.history_label), color = Color.Black,
modifier = Modifier.padding(start = 16.dp)
)
}
}
else -> {
Row(modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.background(color = Color(0xffd7d7d7)),
horizontalArrangement = Arrangement.Start, verticalAlignment = Alignment.CenterVertically) {
Text(
text = stringResource(R.string.history_yesterday), color = Color.Black,
modifier = Modifier.padding(start = 16.dp)
)
Spacer(Modifier.weight(1f))
**Image(
painter = painterResource(id = R.drawable.ic_expand_more),
modifier = Modifier
.padding(end = 5.dp)
.rotate(angle)
.clickable {
angle = (angle + 180) % 360f
canDisplayChild = !canDisplayChild
},
contentDescription = "Expandable Image"
)**
}
}
}
}
Handle History info where recomposition is called
#Composable
fun HandleHistoryTodayChild(canDisplayChild:Boolean,overViewList: List<OverViewListItem>) {
if(canDisplayChild){
**PrepareOverViewScreen(overViewList = overViewList)**
}
}
Your problem should be:
Spacer(Modifier.weight(1f))
Try to specify a fixed height and work your solution from there.
I am trying to overlap two different compose elements. I want to show a toast kind of message at the top whenever there is an error message. I don't want to use a third party lib for such an easy use case. I plan to use the toast in every other composable screen for displaying error message. Below is the layout which i want to achieve
So I want to achieve the toast message saying "Invalid PIN, please try again".
#Composable
fun MyToast(title: String) {
Card(
modifier = Modifier
.absoluteOffset(x = 0.dp, y = 40.dp)
.background(
color = MaterialTheme.colors.primaryVariant,
shape = RoundedCornerShape(10.dp)
), elevation = 20.dp
) {
Row(
modifier = Modifier
.background(color = MaterialTheme.colors.primaryVariant)
.padding(12.dp),
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = painterResource(id = R.drawable.error_circle),
contentDescription = title
)
Text(
text = title,
fontFamily = FontFamily(Font(R.font.inter_medium)),
fontSize = 12.sp,
color = MaterialTheme.colors.primary,
modifier = Modifier.padding(horizontal = 10.dp)
)
}
}
}
and my screen composable is as follows
#Composable
fun Registration(navController: NavController, registrationViewModel: RegistrationViewModel) {
Scaffold() {
Box(){
MyToast(
title = "Invalid pin, please try again"
)
Column() {
//my other screen components
}
}
}
I will add the AnimatedVisibility modifier later to MyToast composable. First I need to overlap MyToast over all the other elements and somehow MyToast is just not visible
If you want the child of a Box to overlay/overlap its siblings behind, you should put it at the last part in the code
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Box(
modifier = Modifier.background(Color.Red).size(150.dp)
)
// your Toast
Box(
modifier = Modifier.background(Color.Green).size(80.dp)
)
}
So if I put the green box before the bigger red box like this
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
// your Toast
Box(
modifier = Modifier.background(Color.Green).size(80.dp)
)
Box(
modifier = Modifier.background(Color.Red).size(150.dp)
)
}
the green box will hide behind the red one
You have to solutions, you can either put the Toast in the bottom of your code because order matters in compose:
#Composable
fun Registration(navController: NavController, registrationViewModel: RegistrationViewModel) {
Scaffold() {
Box() {
Column() {
//my other screen components
}
MyToast(
title = "Invalid pin, please try again"
)
}
}
}
Or you can keep it as it is, but add zIndex to the Toast:
#Composable
fun MyToast(title: String) {
Card(
modifier = Modifier
.absoluteOffset(x = 0.dp, y = 40.dp)
.zIndex(10f) // add z index here
.background(
color = MaterialTheme.colors.primaryVariant,
shape = RoundedCornerShape(10.dp)
), elevation = 20.dp
) {
Row(
modifier = Modifier
.background(color = MaterialTheme.colors.primaryVariant)
.padding(12.dp),
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = painterResource(id = R.drawable.error_circle),
contentDescription = title
)
Text(
text = title,
fontFamily = FontFamily(Font(R.font.inter_medium)),
fontSize = 12.sp,
color = MaterialTheme.colors.primary,
modifier = Modifier.padding(horizontal = 10.dp)
)
}
}
}
Note: elevation in Card composable is not the same as elevation in XML so it's not going to make the composable in the top, it will just add a shadow but if you want to give the composable a higher z order use Modifier.zIndex(10f)
I've recently migrated from XML to Jetpack Compose and decided to create a note app with Jetpack Compose to learn more about it. an item of my notes in this program includes the title, description, and the level of priority, which is displayed in the direction of its start and in different colors.
According to what I wanted, the priority section should extend to the size of the item's content, but
When I set the height of the priority section to fillMaxHeight(), the note item extends to the size of the screen.
I also tried wrapContentHeight(), but this time the priority section disappeared entirely.
My code:
#Composable
fun SingleItem(modifier: Modifier = Modifier, title: String = "", description: String = "") {
Card(
shape = MaterialTheme.shapes.medium,
modifier = Modifier.padding(horizontal = 24.dp, vertical = 16.dp).wrapContentHeight()
) {
Row() {
Box(modifier = Modifier.fillMaxHeight().width(15.dp).background(Color.Red))
Column() {
Text(text = title, modifier = Modifier.padding(start = 16.dp, top = 16.dp))
Spacer(modifier = Modifier.height(16.dp))
Text(text = description, modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp))
}
}
}
}
what happened when using fillMaxHeight() :
what I wanted to do :
something like this
Card(
shape = MaterialTheme.shapes.medium,
modifier = Modifier.padding(horizontal = 24.dp, vertical = 16.dp)
) {
Row(modifier = Modifier.background(Color.Red)) {
Box(modifier = Modifier.width(15.dp)) {
}
Column(modifier = Modifier.background(Color.Black)) {
Text(
text = "title",
modifier = Modifier
.padding(start = 16.dp, top = 16.dp)
)
Spacer(modifier = Modifier
.height(16.dp)
)
Text(
text = "null",
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 16.dp)
)
}
}
}
You have to use Intrinsic Measurements in your Row. Also, remember to pass your incoming Modifier to the Card.
#Composable
fun SingleItem(modifier: Modifier = Modifier, title: String = "", description: String = "") {
Card(
shape = MaterialTheme.shapes.medium,
modifier = modifier.padding(horizontal = 24.dp, vertical = 16.dp).wrapContentHeight()
) {
Row(
modifier = Modifier.height(IntrinsicSize.Min)
) {
Box(modifier = Modifier.fillMaxHeight().width(15.dp).background(Color.Red))
Column() {
Text(text = title, modifier = Modifier.padding(start = 16.dp, top = 16.dp))
Spacer(modifier = Modifier.height(16.dp))
Text(text = description, modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp))
}
}
}
}
How to add a lazy column inside another lazy column in jetpack compose like below screenshot.(The inner list size maybe vary)
#Composable
fun SingleItem() {
LazyColumn(modifier = Modifier
.fillMaxWidth()
),
) {
item {
Row(
modifier = Modifier
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = painterResource(id = R.drawable.ic_school),
contentScale = ContentScale.Crop,
contentDescription = null
)
Text(
text = "School",
modifier = Modifier
.fillMaxWidth()
.weight(1f)
)
Icon(
painter = painterResource(id = R.drawable.ic_down_arrow),
modifier = Modifier
.size(dimensionResource(id = R.dimen.margin_large))
.clip(CircleShape)
.clickable { isExpand = !isExpand },
contentDescription = stringResource(id = R.string.expand_list)
)
}
}
if (isExpand) {
item {
Divider(
modifier = Modifier
.padding(vertical = dimensionResource(id = R.dimen.margin_large))
.background(DividerColor.copy(alpha = 0.5F))
.fillMaxWidth(), thickness = 0.5.dp
)
}
items(3) {
Row(modifier = Modifier
.padding(horizontal = dimensionResource(id = R.dimen.margin_large))
.fillMaxWidth()) {
Text("School",
modifier = Modifier
.fillMaxWidth()
.weight(1f),
)
Text(text = "3 KM",
textAlign = TextAlign.End
)
}
}
}
}
}
//For Full list
#Composable
fun MainList()
{
LazyColumn() {
items(10) {
SingleItem()
}
}
}
But using this code it shows following error.
Vertically scrollable component was measured with an infinity maximum height constraints, which is disallowed. One of the common reasons is nesting layouts like LazyColumn and Column(Modifier.verticalScroll()). If you want to add a header before the list of items please add a header as a separate item() before the main items() inside the LazyColumn scope. There are could be other reasons for this to happen: your ComposeView was added into a LinearLayout with some weight, you applied Modifier.wrapContentSize(unbounded = true) or wrote a custom layout. Please try to remove the source of infinite constraints in the hierarchy above the scrolling container.
It is recommended to avoid Nested Scrolling in the same direction. One possible hack if you already know the size of the component you can use that in modifier.
or try wrapping all of your composables inside one parent LazyColumn and using its DSL to pass in different types of content.
In your example
#Composable
fun MainList()
{
LazyColumn() {
items(10) { item ->
ListComposable(item)
}
}
}
#Composable
private fun ListComposable(item: List<String>){
//...
}
This item can also be a multiple list item.
Reference: https://developer.android.com/jetpack/compose/lists#avoid-nesting-scrollable
I have comment box and need to put icon on specific position ( bottom right ). I need to make something like position absolute where my icon button need to be bottom right inside comment box. Here is image what I am trying to achieve. Any help or idea?
You can do it by using Modifier.offset{} and putting your Icon inside a Box with Modifier.align(Alignment.BottomEnd)
#Composable
private fun Test() {
Column(modifier = Modifier.padding(10.dp)) {
Box(
modifier = Modifier
.width(200.dp)
.background(Color.LightGray.copy(alpha = .5f), RoundedCornerShape(8.dp))
.padding(4.dp)
) {
Column(
modifier = Modifier.fillMaxWidth()
) {
Text("Title", fontSize = 20.sp)
Text("Comment")
}
val offsetInPx = with(LocalDensity.current) {
16.dp.roundToPx()
}
Icon(
imageVector = Icons.Default.Settings,
contentDescription = null,
modifier = Modifier
.offset {
IntOffset(-offsetInPx, offsetInPx)
}
.shadow(2.dp, RoundedCornerShape(40))
.background(Color.White)
.padding(horizontal = 10.dp, vertical = 4.dp)
.size(30.dp)
.align(Alignment.BottomEnd),
tint = Color.LightGray
)
}
Spacer(modifier = Modifier.height(4.dp))
Text("Reply", color = Color.Blue)
}
}