TextField is hidden behind keyboard - Jetpack Compose - android

I was playing around with Jetpack Compose TextField and I found one strange behaviour with Keyboard.
If my TextField is around bottom of the screen and I open keyboard, the TextField is remain hidden behind the keyboard.
I tried some solutions as well.
Modifying android:windowSoftInputMode="adjustPan" and android:windowSoftInputMode="adjustResize"
If I use adjustPan, sometimes TextField is lifted up with the Keyboard but sometimes it does not.
Here is the code and images of what is happening.

Ok I did something that worked for me, I clarify that I have only been learning compose for a few weeks so don't expect much from me, I simply did something that may not be the right way but it is functional for me and may be useful to anyone.
What I did was create a main class that inherits the ComponentActivity() with all the toys.
class Login : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
HealthAtHansClientTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
LoginLayout()
}
}
}
}
}
After that I imported my #Composable function which contained my layout with the LoginLayout, but the important part is this:
val scrollState = rememberScrollState()
Column(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
.padding(bottom = 100.dp, end = 40.dp, start = 40.dp)
.verticalScroll(scrollState),
verticalArrangement = Arrangement.SpaceAround,
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(top = 30.dp)
) {
Text(text = "Hola !", style = TextStyle(fontSize = 40.sp))
}
Row(horizontalArrangement = Arrangement.Center) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
TextField(
maxLines = 1,
modifier = Modifier.fillMaxWidth(),
value = documentNumber,
onValueChange = { documentNumber = it })
Spacer(modifier = Modifier.height(100.dp))
TextField(
maxLines = 1,
modifier = Modifier.fillMaxWidth(),
value = privateCode,
onValueChange = { privateCode = it })
}
}
}
Note that the space between the Textfields is 100 this was just to test that it is functional.
and finally declare the Login class in my main activity in the following way, since the Mainactivity came by default but it was only for this test, the idea is only that they realize the line that I added
And voilà that was all now my TextField is not hidden, I think it would be very feasible if you have extensive forms you create your "activity" in the manifest and add the line android:windowSoftInputMode="adjustResize"
that way the problem is over.
I hope someone with more skill and knowledge can do something more efficient, for now it works for me.
If there is already a more efficient solution for that, the comment is appreciated, if my solution is stupid, I would appreciate feedback to learn.
One other thing that happens is that if you run the emulator with 'DefaultPreview', none of the ways I try to do it work.
If you run the emulation of your application in App, it works without problem.
But I wanted to go further, so I compiled this example in a release apk version where it is supposed to look like it should and it works perfectly as you can see in the image.

Update at October 2022: The following code does the trick:
class SampleActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
WindowCompat.setDecorFitsSystemWindows(window, false)
super.onCreate(savedInstanceState)
setContent {
LazyColumn(
contentPadding = WindowInsets.navigationBars.asPaddingValues()
) {
// items
}
}
}
}
Setting Activity to fit system windows and also using contentPadding is key here.

Related

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.

Compose LazyColumn laggy while scrolling

Jetpack Compose version: '1.1.0' and
Jetpack Compose component used: androidx.compose.* (base components_
Android Studio Build: 2021.2.1
Kotlin version:1.6.10
I have simple code inside activity. When i start App and start scroll with speed, i see scrolling lags :( What is wrong with this code?
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
TestComposeTheme {
val list = (1..300).toList()
LazyColumn(
Modifier.fillMaxSize(),
) {
items(list) { item ->
SomeItem(
text = item.toString(),
clickListener = {}
)
Spacer(modifier = Modifier.height(16.dp))
}
}
}
}
}
#Composable
fun SomeItem(
text: String,
clickListener: (String) -> Unit
) {
Row(
modifier = Modifier
.fillMaxWidth()
.height(64.dp)
.background(Color.LightGray)
.clickable { clickListener.invoke(text) }
) {
Icon(painter = painterResource(id = R.drawable.ic_back), contentDescription = "")
Spacer(modifier = Modifier.height(8.dp))
Text(
modifier = Modifier,
text = text
)
}
}
I also got laggy scroll when using lazycolumn (I'm migrating my Native Android project to Jetpack Compose, so i used "ComposeView in XML". Its not a pure Compose project.)
I don't know why the issue coming(Tried with release build also ), but i solved with below code.
Instead of using "LazyColumn", i used "rememberScrollState() with Column"
Column(
modifier = Modifier
.verticalScroll(rememberScrollState())
.padding(5.dp)
) {
list.forEachIndexed { i, _ ->
ShowItems(i)
}
}
Hope this will help some one.
Please attach if better Answer there, I will also update my project.
**
EDIT :: UPDATE
**
In release Build, somewhat better then DEBUG app.
The above case is only use for less amount of data. If we have large data there is no option we have to use "LazyColumn".

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?

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,
)

What's the different between aspectRatio(1f) and fillMaxSize() for JetpackCompose Modifier attribute

When I set the modifier as below
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Clock(modifier = Modifier
.aspectRatio(1f)
.fillMaxSize()
.padding(16.dp))
}
}
}
I have both fillMaxSize() and aspectRaio(1f) as per I see other people code and have both set. Are they doing the same thing? Or they are needed for different purposes? (I tried removing one of each, and seems to result the same).
P/S: I tried to view the code to understand the different but can't as per How to see JetpackCompose kotlin source in Android Studio (4.2)?
Looks like aspectRatio(1f) will make it square, while fillMaxSize() will make it take up the entire screen.
An example below of either
setContent {
Clock(modifier = Modifier
.fillMaxSize()
.aspectRatio(1.0f)
.padding(64.dp))
}
or
setContent {
Clock(modifier = Modifier
.fillMaxSize()
.padding(64.dp))
}
where the fillMaxSize() takes precedence, the drawRect will be as below
But when we have aspectRation(1.0f), with an example either of the below,
setContent {
Clock(modifier = Modifier
.aspectRatio(1.0f)
.fillMaxSize()
.padding(64.dp))
}
or
setContent {
Clock(modifier = Modifier
.aspectRatio(1.0f)
.padding(64.dp))
}
it shall be

Categories

Resources