When I use a LazyColumn nested in Column that can scroll, sometimes I fast scroll the inner LazyColumn, the columns will bounce to the opposite direction.
Like the attached picture, when LazyColumn scroll to top, the outer Column and the inner LazyColumn will bounce to bottom.
How can I remove this effect?
Thank you in advance!
Note: the compose version is 1.2.1
code is like this:
#Composable
fun NestedScrollSample() {
val dataList1 = mutableListOf<Int>()
for (i in 0..6) {
dataList1.add(i)
}
Column(
content = {
Box(
modifier = Modifier
.background(Color.Blue)
.height(360.dp)
.fillMaxWidth()
)
Text(text = "List", textAlign = TextAlign.Center, modifier = Modifier.fillMaxWidth())
LazyColumn(
content = {
itemsIndexed(dataList1) { index, item ->
Text(
text = "$index $item",
textAlign = TextAlign.Center,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp)
)
Divider(thickness = 1.dp, color = Color(0XFFE5E5E5))
}
}, modifier = Modifier
.background(Color(0xFFF5F7FA))
.height(180.dp)
.padding(horizontal = 4.dp)
)
Box(
modifier = Modifier
.background(Color.Green)
.height(360.dp)
.fillMaxWidth()
)
}, modifier = Modifier
.fillMaxSize()
.verticalScroll(state = rememberScrollState())
)
}
Related
I am trying to create a similar-to-scrollview behavior with Jetpack Compose, which should be simple but I find it not working (I can't scroll the Column). I have been following the example from here:
https://github.com/vinaygaba/Learn-Jetpack-Compose-By-Example/blob/master/app/src/main/java/com/example/jetpackcompose/scrollers/VerticalScrollableActivity.kt#L104
And this is my code:
#Composable
fun MainScreen() {
val scrollState = rememberScrollState()
Column(
modifier = Modifier
.fillMaxSize()
.scrollable(
state = scrollState,
orientation = Orientation.Vertical
)
) {
Text(
text = "This is my first Compose App",
fontSize = 24.sp,
fontWeight = FontWeight.Light,
lineHeight = 40.sp,
color = Color.Black,
modifier = Modifier.padding(top = 32.dp, start = 24.dp)
)
Row(
modifier = Modifier
.fillMaxWidth()
.background(Color(0xFF6A0DAD))
.height(2200.dp))
{}
}
}
as mentioned #bylazy using Modifier.verticalScroll(scrollState) solves it
I am working on this design where I have a column that has text and image on top and I have this card view but I want to remove this white space. The card is white I just added the blue to show the white space showing. How can I remove the white space. I want the R.color.purple_700 to fill that space.
Here is my code
Column(
modifier = modifier
.fillMaxSize()
) {
Column(
modifier = modifier
.fillMaxWidth()
.background(colorResource(id = R.color.purple_700))
.weight(2.0f),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
// Do I add the box here?
Image(
painter = painterResource(id = R.drawable.ic_launcher_background),
contentDescription = "Logo"
)
Text(
text = "Sign in to Continue",
color = (colorResource(id = R.color.white)),
fontSize = 28.sp,
modifier = Modifier.padding(8.dp)
)
}
Card(
shape = RoundedCornerShape(topStart = 32.dp, topEnd = 32.dp),
modifier = modifier
.fillMaxWidth()
.weight(5.0f), elevation = 8.dp
) {
Column(
modifier = modifier
.fillMaxSize()
.padding(horizontal = 16.dp)
.scrollable(scrollState, Orientation.Vertical),
horizontalAlignment = Alignment.CenterHorizontally
) {
// then some outlinedText
}
Just add the background modifier to the Card.
Card(
modifier = Modifier.background(colorResource(id = R.color.purple_700))
//....
)
How can I fit a text, inside a specific Box / Container (i.e of Size 100.dp)
Is there a way to Fit a string inside a Box, in Compose?
Here is what I tried:
#Composable
fun playText() {
Box(
modifier = Modifier
.fillMaxSize()
.background(Color(0xFF242E38)),
contentAlignment = Alignment.Center
) {
Row(modifier = Modifier
.background(Color(0xFFEEEEEE))
.width(100.dp)
.height(100.dp)
) {
Text(
text = "FIT ME",
modifier = Modifier
.fillMaxSize()
.wrapContentSize(
Alignment.Center,
unbounded = true
)
.requiredSize(100.dp),
color = Color(0xFF242E38),
fontSize = 50.sp,
style = TextStyle.Default.copy(
background = Color(0xFFEAC43D)
)
)
}
}
}
#Preview(showBackground = true)
#Composable
fun show() {
playText()
}
Here is the current result:
Here is the expected result (which I achieved by decreasing the font size, just to demonstrate what is expected):
Is it possible to do weights in Jetpack Compose with lazy column?
I'd like to set it menu item is weighted as 1/n (n = number of menus) of a layout, and the other takes up the remaining 1/n, also.
I want to list it at the same height as the number of menus.
MenuList
#Composable
fun MenuList(
loading: Boolean,
menus: List<Menu>,
onNavigateToMenuDetailScreen: (String) -> Unit
) {
Box(modifier = Modifier
.background(color = MaterialTheme.colors.surface)
.fillMaxSize()) {
Column(modifier = Modifier.fillMaxSize()) {
if (loading && menus.isEmpty()) {
LoadingShimmer(imageHeight = 800.dp)
}
else if (menus.isEmpty()) {
NothingHere()
}
else {
LazyColumn(
modifier = Modifier
.fillMaxSize()
.weight(1F)
) {
itemsIndexed(
items = menus
) { index, menu ->
MenuCard(
menu = menu,
onClick = {
}
)
}
}
}
}
}
}
MenuCard
#Composable
fun MenuCard(
menu: Menu,
modifier: Modifier = Modifier,
onClick: () -> Unit,
) {
Card(
shape = MaterialTheme.shapes.small,
modifier = Modifier
.padding(
bottom = 6.dp,
top = 6.dp
)
.fillMaxWidth()
.clickable(onClick = onClick),
elevation = 8.dp
) {
Column {
Text(
text = menu.name,
fontSize = 30.sp,
modifier = Modifier
.fillMaxWidth()
.wrapContentWidth(Alignment.CenterHorizontally)
.wrapContentHeight(Alignment.CenterVertically),
style = MaterialTheme.typography.h3
)
}
}
}
In summary, MenuCards are created as many as the number of menu on the MenuList screen, and I hope the height of each MenuCard will be 1/n.
(n = number of menu)
Like, when number of menu is 8,
Just same height to each menu.
Replace your LazyColumn code with BoxWithConstraints and regular Column.
BoxWithConstraints for getting the minHeight or in this case you can say screen height.
Change to something like the below.
BoxWithConstraints(modifier = Modifier.fillMaxSize()) {
val height = minHeight/menus.size
Column(
modifier = Modifier
.fillMaxSize()
) {
menus.forEachIndexed { index, menu ->
MenuCard(
modifier = Modifier.height(height),
menu = menu,
onClick = {
}
)
}
}
}
MenuCard
#Composable
fun MenuCard(
menu: Menu,
modifier: Modifier = Modifier,
onClick: () -> Unit,
) {
Card(
shape = MaterialTheme.shapes.small,
modifier = modifier
.padding(
bottom = 6.dp,
top = 6.dp
)
.fillMaxWidth()
.clickable(onClick = onClick),
elevation = 8.dp
) {
Column(
modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = menu.name,
fontSize = 30.sp,
style = MaterialTheme.typography.h3
)
}
}
}
You will get this
3 items and 6 items
If all you want is a way to divide the screen height in equal proportions to all the n items, you can simply go for a column.
val items = ... //I assume you have access to this
val screenHeight = LocalConfiguration.current.screenHeightDp
Column{
items.forEach{
MenuCard(modifier = Modifier.height(1f / items.size * screenHeight))
}
}
Column and LazyColumn are fundamentally different. LazyColumn's sole purpose is to deal with large datasets by loading and caching only a small window off that set. Now, if there is nothing to be scrolled, LazyColumn is useless, in fact, it is worse.
EDIT:
You could use BoxWithConstraints to get the screen dimensions as well, but it, in this context, would be more of a workaround than a solution. It adds an extra Composable and decreases the readability of the code too, so for getting the screen dimensions, always use the API that was specifically built for the job.
I've got a some dynamic content that can vary in size and below that is a circular image. The problem is that when the content becomes too big, the image overflows the content.
The ideal thing would be that if dynamic sized content is too big, the image should be hidden instead. Is it possible to hide the image (the box) if it will not fit?
Example code:
#Composable
fun ImageTest(modifier: Modifier = Modifier,
outlineColor: Color = Color.White,
outlineSize: Dp = 16.dp,
image: Int) {
Column(
horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier
.fillMaxSize()
) {
Text("Content that can be of different sizes", style = MaterialTheme.typography.h2, modifier = Modifier.height(550.dp).background(Color.Red))
// Circular image - HIDE THE BOX IF IT DOESN'T FIT
Box(
modifier = modifier
.background(color = outlineColor, shape = CircleShape)
.padding(outlineSize)
.aspectRatio(ratio = 1f)
) {
Image(
painter = painterResource(id = image),
contentDescription = null,
contentScale = ContentScale.Fit,
modifier = Modifier.fillMaxSize()
)
}
}
}
Replace image container Box with BoxWithConstraints. Then, inside BoxWithConstraintsScope you can check how much space is available for your view, and if you don't have enough - don't display it.
BoxWithConstraints(
modifier = modifier
.background(color = outlineColor, shape = CircleShape)
.padding(outlineSize)
.aspectRatio(ratio = 1f)
) {
if (maxHeight > 200.dp) {
Image(
painter = painterResource(id = image),
contentDescription = null,
contentScale = ContentScale.Fit,
modifier = Modifier.fillMaxSize()
)
}
}
If you wanna hide box background too, move it inside if.
If you want add an animation, replace if (maxHeight > 200.dp) { with AnimatedVisibility(visible = maxHeight > 200.dp) {