Unable to gain focus on any compose component. It use to work in the project but after some gradle changes, only in some screens i can request focus. So i started a new project to test out the behavior in a clean environment. With this setup, onFocusChange gets the values "inactive" before requestFocus (which is correct) then changes to "deactivated", and after requestFocus, nothing. This is a new project with almost no code
#Composable
fun Greeting(name: String) {
val focusRequester = remember { FocusRequester() }
Button(
onClick = {},
modifier = Modifier
.focusRequester(focusRequester = focusRequester)
.onFocusChanged {
it
}
.wrapContentSize()
,
) {
Text(text = "Hello $name!")
}
LaunchedEffect(Unit) {
this.coroutineContext.job.invokeOnCompletion {
focusRequester.requestFocus()
}
}
}
And in my build.gradle, where compose_version = 1.1.1
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1'
implementation 'androidx.activity:activity-compose:1.4.0'
}
You NEED to add the focusable modifier. It should come AFTER the onFocusChanged and focusRequestor Modifiers, and can also be replaced by focusTarget in some cases. See focusRequestor
Related
I am using compose 1.1.1 in my jetpack compose. I cannot update to latest version. I am want something like this solution. I am getting error on my weight modifier. Can someone guide me how can I get my weight modifier in Row?
implementation "androidx.compose.runtime:runtime:$compose_version"
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.foundation:foundation:$compose_version"
implementation "androidx.compose.foundation:foundation-layout:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation "androidx.compose.runtime:runtime-livedata:$compose_version"
implementation "androidx.compose.ui:ui-tooling:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
androidTestImplementation "androidx.compose.ui:ui-test:$compose_version"
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
implementation "androidx.activity:activity-compose:$compose_version"
Row.kt
Column {
Row(
modifier = Modifier.weight(1f, false)
) {
//...
}
}
Error
Expression 'weight' cannot be invoked as a function. The function 'invoke()' is not found
Many Thanks
UPDATE
I am adding my whole code here please have a look...
#Composable
fun Input(optionData: OptionData) {
Column(
modifier = Modifier
.fillMaxSize()
) {
Item(optionData)
}
}
#Composable
fun Item(optionData: OptionData) {
/// more item of compose i.e. Text, Textfield
Submit()
}
#Composable
fun Submit() {
Row(
modifier = Modifier.weight(1f, false)
) {
//...
}
}
UPDATE 2
After trying #Thracian solution it solve the problem of weight but my view is not going to bottom.
#Composable
fun Submit() {
Column {
OnSubmit {
PrimaryMaterialButton(text = stringResource(id = R.string.submit)) {
}
}
}
}
#Composable
fun ColumnScope.OnSubmit(content: #Composable () -> Unit) {
Row(
modifier = Modifier.weight(1f, false)
) {
content()
}
}
#Composable
fun Submit() {
Row(
modifier = Modifier.weight(1f, false)
) {
//...
}
}
For this code to be able to access Modifier.weight() from Column it should have receiver as ColumnScope. Some modifiers are created with scope so they are available only inside that scope such as Modifier.weight for Row or Column or Modifier.matchParentSize for Box.
#Composable
fun ColumnScope.Submit() {
Row(
modifier = Modifier.weight(1f, false)
) {
//...
}
}
// Allowed
Column {
Submit()
}
//Not Allowed
Row() {
Submit()
}
How can I open Keyboard on Button click in Jetpack Compose? I have a button and I want the keyboard to open when I click this button. How can I do this? This is my screen and the keyboard does not open when I click:
#ExperimentalComposeUiApi
#Composable
fun MainScreen(
viewModel: MainScreenViewModel = hiltViewModel(),
) {
val number = viewModel.score.value
val kc = LocalSoftwareKeyboardController.current
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Column(modifier = Modifier.align(Alignment.Center)) {
ScoreBoard(number)
Spacer(modifier = Modifier.height(12.dp))
Button(onClick = { viewModel.increaseScore(1) }) { Text(text = "Increase Number") }
Spacer(modifier = Modifier.height(12.dp))
Button(onClick = {
kc?.show()
viewModel.startGame()
}) { Text(text = "Start the game") }
}
}
}
You can use the LocalSoftwareKeyboardController.current to get the software keyboard controller inside a composable.
Then you can use its show() and hide() functions.
Keep in mind that the soft keyboard can usually only be opened if an input (or something that accepts input) has focus.
Since this is an experimental Compose API, you will have to annotate the parent function with #OptIn(ExperimentalComposeUiApi::class) (or #ExperimentalComposeUiApi)
//#ExperimentalComposeUiApi
#OptIn(ExperimentalComposeUiApi::class)
#Composable
fun OpenKeyboardExample() {
val kc = LocalSoftwareKeyboardController.current
Button(
onClick = { kc?.show() }
) {
// ...
}
}
If you get warnings related to opt-in you can add the compiler argument to your app.gradle
android {
...
kotlinOptions {
freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn"
}
}
From LocalSoftwareKeyboardController.current docs:
Return a SoftwareKeyboardController that can control the current software keyboard.
If it is not provided, the default implementation will delegate to LocalTextInputService.
Returns null if the software keyboard cannot be controlled.
Source: https://developer.android.com/reference/kotlin/androidx/compose/ui/platform/LocalSoftwareKeyboardController
In Jetpack Compose, where is ScrollToTopButton coming from? It is mentioned in Google's documentation. Annoyingly, they neglect to mention the package. I have imports of foundation version 1.2.0-alpha08; also tried with 1.2.0-beta02 as well as ui and material (1.1.1). Not found. (yes did do an internet search on the term, came back empty handed).
implementation "androidx.compose.foundation:foundation:${version}"
implementation "androidx.compose.foundation:foundation-layout:${version}"
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
#Composable
fun MessageList(messages: List<Message>) {
val listState = rememberLazyListState()
// Remember a CoroutineScope to be able to launch
val coroutineScope = rememberCoroutineScope()
LazyColumn(state = listState) {
// ...
}
ScrollToTopButton(
onClick = {
coroutineScope.launch {
// Animate scroll to the first item
listState.animateScrollToItem(index = 0)
}
}
)
}
Google documentation
Edit: If this is NOT a function they offer, but rather a suggestion to create your own, shame on whoever wrote the documentation, it literally suggests being a function offered by Compose.
Edit 2: Turns out it is a custom function (see the answer). What moved the author of the documentation to write it like this? Why not just put Button? Sigh.
It's not clear from the documentation but you actually have to make your own. For example you can use this:
#Composable
fun ScrollToTopButton(onClick: () -> Unit) {
Box(
Modifier
.fillMaxSize()
.padding(bottom = 50.dp), Alignment.BottomCenter
) {
Button(
onClick = { onClick() }, modifier = Modifier
.shadow(10.dp, shape = CircleShape)
.clip(shape = CircleShape)
.size(65.dp),
colors = ButtonDefaults.buttonColors(
backgroundColor = Color.White,
contentColor = Color.Green
)
) {
Icon(Icons.Filled.KeyboardArrowUp, "arrow up")
}
}
}
And then:
val showButton by remember{
derivedStateOf {
listState.firstVisibleItemIndex > 0
}
}
AnimatedVisibility(
visible = showButton,
enter = fadeIn(),
exit = fadeOut(),
) {
ScrollToTopButton(onClick = {
scope.launch {
listState.animateScrollToItem(0)
}
})
}
I have updated my project to Kotlin 1.6.10, Compose 1.1.0 and compose compiler to 1.1.0
Previously I was using Kotlin 1.5.31, Compose 1.0.5 and compose compiler 1.0.5, and it running ok
#Composable
fun Test() {
var value: String? = null
Scaffold(Modifier.fillMaxSize(), backgroundColor = Color.White) {
Column(Modifier.fillMaxSize()) {
val ret = value?.let {
Box(
modifier = Modifier
.size(50.dp)
.background(color = Color.Red)
)
}
ret ?: Spacer(modifier = Modifier.height(50.dp))
Text(text = "ret = $ret")
Text(text = "KotlinVersion = ${KotlinVersion.CURRENT}")
}
}
}
The above Spacer function has never been executed
look this:
Test Preview
At first I thought it was an issue with Kotlin 1.6.10
Kotlin 1.6.10 Doc
Kotlin 1.6.10 Small Test
After check out the official documentation and run small test. I don't think it's a issue with Kotlin 1.6.10
So is this a bug in Compose 1.1.0?
This question already has an answer here:
Why Compose Card not clickable?
(1 answer)
Closed 1 year ago.
I have a composable with an expandable Card view.
#Composable
fun ItemCard() {
var isExpanded by remember { mutableStateOf(false) }
Card(modifier = Modifier.clickable {
isExpanded = !isExpanded
Log.d(TAG, "Expanded set to $isExpanded")
}) {
// regular card segment goes here
AnimatedVisibility (isExpanded) {
// expanded card segment goes here
}
}
}
So, I updated compose to 1.0.0-beta08 and Modifier.clickable stoped working.
Here are the dependencies:
implementation 'androidx.core:core-ktx:1.5.0'
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.3.0'
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation "androidx.compose.ui:ui-tooling:$compose_version"
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
implementation 'androidx.activity:activity-compose:1.3.0-alpha08'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
implementation "androidx.navigation:navigation-compose:2.4.0-alpha01"
implementation "androidx.constraintlayout:constraintlayout-compose:1.0.0-alpha07"
implementation 'androidx.room:room-common:2.3.0'
implementation 'androidx.room:room-ktx:2.3.0'
implementation "androidx.room:room-runtime:2.3.0"
kapt "androidx.room:room-compiler:2.3.0"
implementation "androidx.compose.runtime:runtime-livedata:$compose_version"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.32"
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9"
api "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9"
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.1.5")
All I changed was changing compose from 1.0.0-beta07 to 1.0.0-beta08 and (as required by the compose update) changing classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.32" to classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.10"
Cause:
This is a Behaviour Breaking API change from 1.0.0-beta07 to 1.0.0-beta08 as mentioned in release notes for Jetpack Compose.
Jetpack compose Version 1.0.0-beta08 Behavior Breaking API Change
BEHAVIOUR-BREAKING:
Card now consumes clicks, making clicks added via Card(Modifier.clickable) to be a no-op. Please, use new experimental overload of a Card that accepts onClick. (Ia8744, b/183775620)
Solution:
The solution provided is an overload of Card which allows handling clicks alongside related properties like indication, interactionSource, enabled/disabled.
Added a new Card overload that handles clicks as well as other clickable functionality: indication, interactionSource, enabled/disabled. It wasn't possible to use a regular non-clickable Card with the Modifier.clickable because the Card will not clip the ripple indication in those cases.
Card overload:
Here is the new Card overload which exposes onClick as well as interactionSource and indication.
#Composable
fun Card(
onClick: () -> Unit,
modifier: Modifier = Modifier,
shape: Shape = MaterialTheme.shapes.medium,
backgroundColor: Color = MaterialTheme.colors.surface,
contentColor: Color = contentColorFor(backgroundColor),
border: BorderStroke? = null,
elevation: Dp = 1.dp,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
indication: Indication? = LocalIndication.current,
enabled: Boolean = true,
onClickLabel: String? = null,
role: Role? = null,
content: #Composable () -> Unit
)