The title won't minimize dialog in JetPack Compose BottomSheetDialog with rememberNestedScrollInteropConnection - android

I have BottomDialog Fragment which consists only of Composable (Row(title) and LazyColumn).
The first issue I faced was when you scroll your list down and then you try to scroll up list won't scroll and the dialog starts to minimize. This is solved with
modifier = Modifier.nestedScroll(rememberNestedScrollInteropConnection())
But now user can't minimize a dialog when he tries to do it by touching a title. And there is my question, How to solve this?
Minimum reproducible code
During creating this example I found that I can maximize dialog when touching the title, also I can start moving the action going to the top with my finger (to start to expand it) and then move the finger to the bottom of the screen, in this way the dialog will be dismissed, but still can't minimize it in a non-tricky way.
ComposeView(requireContext()).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
Theme {
Column(modifier = Modifier.nestedScroll(rememberNestedScrollInteropConnection())) {
Row {
Text(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth(),
text = "Title"
)
}
LazyColumn(
Modifier
.weight(1f)
.fillMaxWidth()
) {
items(100) {
Text(
text = "Item $it",
modifier = Modifier
.padding(16.dp)
.fillMaxWidth(),
)
}
}
}
}
}
}
Please do not propose BottomSheetScaffold. Because I want to create a standardized bottom dialog. And to use it I will need just pass a list of items and a Compose function for one item.
IMO BottomSheetScaffold shouldn't be released at all, cause it was designed "not well". Just imagine earlier before Jetpack Compose you write your code around the bottom dialog, nice layering. No.

As a temp decision. I just think of LazyColumn works properly so I need to wrap my header to the LazyColumn.
So I created this function. And Just pass here any Composable
#Composable
fun TrickyLazyColumn(content: #Composable () -> Unit) {
LazyColumn {
items(
items = listOf(1),
itemContent = {
content.invoke()
})
}
}

Related

Stop the keyboard pushing the top app bar off the screen in Compose

I have a Compose activity, where there's a top app bar, and some TextFields towards the bottom of the screen. When I focus on one of the TextFields and the keyboard is invoked, I want the text field to appear above the keyboard, so I can see what I'm typing. This works fine, however the whole screen content is pushed upwards making the top app bar disappear or be cut off at the top.
I think ideally, the top app bar would be pinned to the top, and only the contents below would shift. It doesn't matter if the top app bar is part of the scaffold, or above the scaffold in a Column:
Scaffold(
topBar = {
TopAppBar("...")
}
) {
// scrollable contents with TextFields
}
---> OR
Column {
TopAppBar("...")
Scaffold {
// scrollable contents with TextFields
}
}
This is the unwanted behaviour illustrated:
Is there a way to achieve my desired behaviour of pinning the top app bar? Should the top app bar be pushed up by default in Compose?
It looks like you have to specify a weight to one of your composable.
Taking some reference from an answer from this post. Assuming you have set adjustResize in your manifest,
android:windowSoftInputMode="adjustResize"/>
you can consider this as a rough solution
Scaffold(
topBar = {
TopAppBar(title = { Text("Hello World")})
}
) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(it)
) {
Box(
modifier = Modifier
.weight(1f)
.background(Color.Gray)
.fillMaxWidth()
)
Box(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.background(Color(0xFF6f4d8c)),
contentAlignment = Alignment.Center
) {
TextField(
value = "User Name",
onValueChange = {}
)
}
Box(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.background(Color(0xFF6286bd)),
contentAlignment = Alignment.Center
) {
TextField(
value = "Password",
onValueChange = {}
)
}
}
}
I just put some colors to show how the widgets occupy the space in their parent Column.
Try this
class YourActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
window.setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING
);
setContent { /* Composable Content */ }
}
}

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
}
}
}

TabRow/Tab Recomposition Issue in Compose Accompanist Pager

I was trying to create a sample Tab View in Jetpack compose, so the structure will be like
Inside a Parent TabRow we are iterating the tab title and create Tab composable.
More precise code will be like this.
#OptIn(ExperimentalPagerApi::class)
#Composable
private fun MainApp() {
Scaffold(
topBar = {
TopAppBar(
title = { Text(stringResource(R.string.app_name)) },
backgroundColor = MaterialTheme.colors.surface
)
},
modifier = Modifier.fillMaxSize()
) { padding ->
Column(Modifier.fillMaxSize().padding(padding)) {
val pagerState = rememberPagerState()
val coroutineScope = rememberCoroutineScope()
val tabContents = listOf(
"Home" to Icons.Filled.Home,
"Search" to Icons.Filled.Search,
"Settings" to Icons.Filled.Settings
)
HorizontalPager(
count = tabContents.size,
state = pagerState,
contentPadding = PaddingValues(horizontal = 32.dp),
modifier = Modifier
.weight(1f)
.fillMaxWidth()
) { page ->
PagerSampleItem(
page = page
)
}
TabRow(
selectedTabIndex = pagerState.currentPage,
backgroundColor = MaterialTheme.colors.surface,
contentColor = MaterialTheme.colors.onSurface,
indicator = { tabPositions ->
TabRowDefaults.Indicator(
Modifier
.pagerTabIndicatorOffset(pagerState, tabPositions)
.height(4.dp)
.background(
color = Color.Green,
shape = RectangleShape
)
)
}
) {
tabContents.forEachIndexed { index, pair: Pair<String, ImageVector> ->
Tab(
selected = pagerState.currentPage == index,
selectedContentColor = Color.Green,
unselectedContentColor = Color.Gray,
onClick = {
coroutineScope.launch {
pagerState.animateScrollToPage(index)
}
},
text = { Text(text = pair.first) },
icon = { Icon(imageVector = pair.second, contentDescription = null) }
)
}
}
}
}
}
#Composable
internal fun PagerSampleItem(
page: Int
) {
// Displays the page index
Text(
text = page.toString(),
modifier = Modifier
.padding(16.dp)
.background(MaterialTheme.colors.surface, RoundedCornerShape(4.dp))
.sizeIn(minWidth = 40.dp, minHeight = 40.dp)
.padding(8.dp)
.wrapContentSize(Alignment.Center)
)
}
And coming to my question is whenever we click on the tab item, the inner content get recompose so weirdly. Im not able to understand why it is happens.
Am attaching an image of the recomposition counts below, please take a look that too, it would be good if you guys can help me more for understand this, also for future developers.
There are two question we have to resolve in this stage
Whether it will create any performance issue, when the view getting more complex
How to resolve this recompostion issue
Thanks alot.
… whenever we click on the tab item, the
inner content get recompose so weirdly. Im not able to understand why
it is happens...
It's hard to determine what this "weirdness" is, there could be something inside the composable your'e mentioning here.
You also didn't specify what the API is, so I copied and pasted your code and integrated accompanist view pager, then I was able to run it though not on an Android Studio with a re-composition count feature.
And since your'e only concerned about the Text and the Icon parameter of the API, I think that's something out of your control. I suspect the reason why your'e getting those number of re-composition count is because your'e animating the page switching.
coroutineScope.launch {
pagerState.animateScrollToPage(index)
}
Though 'm not able to try this on another Android Studio version with the re-composition feature, I think (though I'm not sure) scrolling to another page without animation will yield less re-composition count.
coroutineScope.launch {
pagerState.scrollToPage(index)
}
If it still bothers you, the best course of action is to ask them directly, though personally I wouldn't concerned much about this as they are part of an accepted API and its just Text and Icon being re-composed many times by an animation which is also fine IMO.
Now if you have some concerns about your PagerSampleItem stability(which you have a full control), based on the provided code and screenshot, I think your'e fine.
There's actually a feature suggested from this article to check the stability of a composable, I run it and I got this report.
restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun PagerSampleItem(
stable page: Int
)
Everything about this report is within the article I linked.
Also, your Text and Icon are using String and ImageVector which is stable and immutable (marked by #Immutable) respectively.
So TLDR, IMO your code is fine, your PagerSampleItem is not re-composing in the screenshot.

How to use both "ModalDrawer" and "ModalBottomSheetLayout" at the same time

My app needs ModalDrawer & ModalBottomSheetLayout at the same time.
I searched but couldn't find the officially recommended way to accomplish it.
So I just put ModalDrawer inside ModalBottomSheetLayout. Please check the below code.
#Composable
fun MainScreen()
{
ModalBottomSheetLayout(
sheetState = recipeViewModel.bottomSheetState,
sheetContent = { #AnotherComposable },
sheetShape = RoundedCornerShape(topStart = 50.dp, topEnd = 50.dp)
) {
// "Rest-Content Area"
Column(
modifier = Modifier
.padding(10.dp)
.fillMaxWidth()
) {
Buttons()
}
// Drawer
ModalDrawerSample()
}
}
ModalDrawerSample() working fine without any issue.
However, the UIs in the "Rest-Content Area" is not working. For example, button clicking it not working at all.
When we press the button, the color of the button area should be changed (gray like colored) but it's not.
Is there any official document that recommend the best practice or any other solution for it?

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 !

Categories

Resources