How can I use LazyColumn in LazyColumn in jetpack compose? - android

I got this error message, And I don't get it.
java.lang.IllegalState
Exception: 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 infinit
e constraints in the hierarchy above the scrolling container.
Here's example code.
#Composable
fun SupplementSearchScreen(
onSearch: (String) -> List<Vitamin>,
updateRecentAddedSupplementList: List<Vitamin>
) {
LazyColumn(
modifier = Modifier
.fillMaxSize()
) {
item{
SupplementSearchResultCard(someList)
}
}
}
#Composable
fun SupplementSearchScreen(list:List<SomeList>){
ContentCard(
modifier = Modifier.fillMaxWidth()
) {
Text(
text = "Hello World",
fontSize = 16.sp,
color = Color.Black
)
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
) {
items(list){ resultItem ->
SearchResultItem(resultItem)
}
}
}
}
What's wrong here?

Lazy column needs fixed height component as parent to achieve lazy behavior,
if add lazy column inside parent with modifier Modifier.verticalScroll() or another Lazy column it will get infinite height it wont be able to decide when to compose and when to dispose an composable, instead use items{} of block of lazy column
in xml also same issue appears if wrap recyclerview inside nested scroll view but in xml instead of showing error it cause ANR as items increases in Recycler view adapter

You can use:
Modifier.height(LocalConfiguration.current.screenHeightDp.dp)
on the first lazy column to get all screen height.
I don't know if something like this will work for you but just to try it out.

You can't directly use LazyColumn inside LazyColumn. Just use LazyColumn with different types like this:
sealed interface Item {
data class SearchCard(val name: String) : Item
data class SearchText(val name: String): Item
}
#Composable
fun SearchScreen(list: List<Item>) {
LazyColumn {
items(list.size) { index ->
when (list[index]) {
is Item.SearchCard -> TODO()
is Item.SearchText -> TODO()
}
}
}
}

Related

Nested Listing in Jetpack Compose

I'm trying to structure my composables this way:
Column ->
Tab(Child)
HorizontalPager (Child)->
LazyColumn (Child of Horizontal Pager)
I want to have a toolbar with (scroll | enterAlways) attribute, then a tablayout under, then a list below the tablayout.
I tried this structure but I'm getting this error
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.
This is the structure of what I currently have:
Box(
Modifier
.fillMaxSize()
.nestedScroll(nestedScrollConnection)
) {
Column(){
TabRow(
) {
}
HorizontalPager(
) {
LazyColumn {
}
}
}
TopAppBar()
}
Is there any alternative way to achieve a nested Lazycolumn inside a HorizontalPager and the HorizontalPager will have Column as it's parent?
I gave the below code a try in android studio and did not have any crashes.
Box(
Modifier
.fillMaxSize()
.nestedScroll(nestedScrollConnection)
) {
Column(){
TabRow() { }
HorizontalPager() {
LazyColumn (modifier = Modifier.Height(200.dp)) {
}
}
}
TopAppBar()
}

How to collapse/expand widget code region/area in Compose Android Studio like in XML

I have many Composables and I want to collapse Composable code inside like in xml. Is there extension for that?
Your post title is a bit misleading, but I think your'e asking how to collapse/expand "code" not the actual widget/ui.
I'm not sure if this is exactly what you want, but you can expand/collapse a specific area of your code if you wrap them within region/endregion without the need of any plugin or configuration, its almost the same behavior that your'e expecting from the xml editor, and you can do this anywhere not only to a function.
expanded code region
collapsed code region
Sample Inner composable expanded
Sample Inner composable collapsed
If you wish to make your Column collapse or expand without animation you simply need to add a if statement and set true to display false to collapse
var visible by remember {
mutableStateOf(true)
}
Column(modifier = Modifier.fillMaxSize()) {
Text("Click to expand or collapse", modifier = Modifier
.fillMaxWidth()
.clickable {
visible = !visible
}
)
if(visible) {
// Content to be collapsed or displayed
}
}
If you wish to collapse or expand with animation you can check out AnimatedVisbility composable
var visible by remember {
mutableStateOf(true)
}
Column(modifier = Modifier.fillMaxSize()) {
Text("Click to expand or collapse", modifier = Modifier
.fillMaxWidth()
.clickable {
visible = !visible
}
)
AnimatedVisibility(visible = visible) {
Column {
// Content to be collapsed or displayed
}
}
}

Jetpack Compose Lazy Table

My current goal is to achieve view that can represent a table, but this table can contain pretty much elements in its columns and rows. My current idea is to populate LazyColumn with LazyRows.
#Composable
internal fun Table() {
LazyColumn {
items(count = 100) {
LazyRow {
items(10) {
Box(
modifier = Modifier
.size(100.dp)
.border(width = 1.dp, color = Color.Black)
)
}
}
}
}
}
But there is a huge problem: i don't want the rows to be able to scroll by themselves, i want any scrolling to be shared. Unfortunately, i can't figure out gow to achieve that. As far as i know lazy grid can't help me either.
I also tried to use same instance of LazyListState, but it doesn't work.
In a new version appered new layout called "LazyLayout" - it's somewhat of your custom lazy layout builder. This should solve my problem, although i haven't tried it yet

compose LazyColumn crops the content at the bottom

I have empty fragment with composable:
setContent {
Surface(
modifier = Modifier
.fillMaxWidth().fillMaxHeight().padding(bottom = 48.dp, top = 16.dp),
color = colorResource(id = R.color.usaa_white)
) {
val itemsList = (0..50).toList()
val itemsIndexedList = listOf("A", "B", "C")
LazyColumn(
) {
items(itemsList.size) {
Text("Item is $it")
}
item {
Text("Single item")
}
itemsIndexed(itemsIndexedList) { index, item ->
Text("Item at index $index is $item")
}
}
}
}
the problem is: I can only scroll the content until "Single Item" row and the rest of content is hidden. I added some padding to make sure that it wasn't bottomNavBar covering the list but it's still cropped.
Looks like the issue is caused by bottomNavBar. What's interesting is that it happens only with LazyColumn and works fine when I use Column
The fix I found is to add contentPadding to the bottom. (But hope to find better solution)
LazyColumn(contentPadding = PaddingValues(bottom = 70.dp)) { }
Use Scaffold (check documentation).
Scaffold has a generic content trailing lambda slot. The lambda receives an instance of PaddingValues that should be applied to the content root — for example, via Modifier.padding — to offset the top and bottom bars, if they exist.
setContent {
Scaffold { contentPadding ->
Box(
modifier = Modifier.padding(contentPadding)
) {
// Your code
}
}
}
Hope it helps !

TextField IME padding in LazyColumn , Compose

Problem : TextField (inside lazy column) text goes below the keybaord
Explanation :
I have a LazyColumn that contains a list of items displaying text fields , In the manifest the activity has windowSoftInputMode="adjustResize" and I am also setting the flag WindowCompat.setDecorFitsSystemWindows(window,false) in the onCreate Method before setContent and I want to make text appear above the keyboard at all times for smoother editing experience !
Using Accompanist Library providing Window Insets to give padding to the Box like this
Box(modifier = Modifier.weight(1f).navigationBarsWithImePadding()){
LazyColumn() {
items(myItems) { item->
ItemComposable(item)
}
}
}
As you can see , there's navigationBarsWithImePadding on the box , but it does't work since the text goes below the keyboard , I tried setting the modifier on LazyColumn but then it provides padding with the LazyColumn relative to other items outside of the box !
so I tried contentPadding
LazyColumn(contentPadding=insets.ime.toPaddingValues(additionalBottom=insets.navigationBars.bottom.dp)) {
items(editor.blocks) { block ->
RenderBlock(block)
}
}
Again did't work , since the content padding is applied to the last item / or after it , The keyboard goes above the text
Replacing LazyColumn with a simple Column and using a verticalScroll modifier causes the same problem , Because the list can be long vertical scroll becomes a need
Finally I have a solution for it. Just follow these steps below:
Step 1: In your AndroidManifest.xml
<activity
...
android:windowSoftInputMode="adjustResize">
</activity>
Step 2: In your Activity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
setContent {
AppTheme {
ProvideWindowInsets(
windowInsetsAnimationsEnabled = true,
consumeWindowInsets = false,
) {
// your content
}
}
}
Step 3:
LazyColumn(
modifier = Modifier
.navigationBarsWithImePadding()
.verticalScroll(state = rememberScrollState())
.height(LocalConfiguration.current.screenHeightDp.dp)
.fillMaxWidth(),
) {
// your TextField items
}
Step 4:
// init your CoroutineScope
val coroutineScope = rememberCoroutineScope()
// init your BringIntoViewRequester
val bringIntoViewRequester = BringIntoViewRequester()
// use them in your TextField modifier
modifier = Modifier
/* ... your other modifiers*/
.bringIntoViewRequester(bringIntoViewRequester)
.onFocusEvent {
if (it.isFocused || it.hasFocus) {
coroutineScope.launch {
delay(250)
bringIntoViewRequester.bringIntoView()
}
}
}
}
Hope it helps.
If you use Column, you can refer to the following code snippet:
Column(
modifier = Modifier
// other modifiers
.verticalScroll(scrollState, reverseScrolling = true)
.navigationBarsWithImePadding(),
verticalArrangement = Arrangement.Bottom,
)

Categories

Resources