What I found in most of the tutorial on the internet is:
#Composable
fun addButton() {
Button(text = "I'm a Compose Button")
}
But android studio give me an error: type mismatch Required: () -> Unit, Found: String.
I don't know how to fix this.
According to the docs, To create a Button you have to specify the text inside the RowScope:
Button(onClick = {/* To execute when button is clicked */}) {
Text("I'm a Compose Button")
}
The text is then set by Text() function defined in androidx.ui.foundation package.
You can find more about them in the material-ui docs: https://developer.android.com/reference/kotlin/androidx/ui/material/package-summary
This is how you can add Button in Jetpack compose.
Button(onClick = {/*Handle click action */}, modifier = Modifier.padding(16.dp)) {
Text(
text = "Jetpack Compose Button"
)
}
References:
[1] https://developer.android.com/reference/kotlin/androidx/compose/material/package-summary#button
Use blow code
Button(onClick {/* your onClick listener */}){
Text("I'm a Compose Button")
}
I know it does not seems good but u have to do it like this
Button(onClick = {handle Click Action })
{
Text(text = "Your Button Text")
}
those who are new in compose can use button simple button like this
#Composable
fun MyButton() {
Column(
modifier = Modifier.fillMaxWidth().fillMaxHeight(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Button(
onClick = {},
modifier = Modifier.padding(all = Dp(10f)),
enabled = true,
border = BorderStroke(width = 1.dp, brush = SolidColor(Color.Blue))
) {
Text(text = "I am a compose button", color = Color.White)
}
}
}
You are not using the syntax,
you the this code:
Button(onClick = {/*Handle click action */} ){
Text(
text = "Write the button text here"
)
}
if you want to use modifiers then refer to this,
Button(onClick = {/*Handle click action */}, modifier = Modifier.padding(16.dp)) {
Text(
text = "Write the button text here"
)
}
Related
I have AppBarNavGraph and RootNavGraph.
I'd like to know two methods, Full Screen Dialog and also Navigating to a new Screen.
What I am trying to is..
Column(
modifier = Modifier
.width(97.dp)
.clickable {
Dialog(onDismissResult = { /*TODO*/ }) {
}
}
,
horizontalAlignment = Alignment.CenterHorizontally
But in clickable, composable function is not callable.
So, What I tried is using this,
val isClicked = remember { mutableStateOf(false) }
Column(
modifier = Modifier
.width(97.dp)
.clickable {
isClicked.value = !isClicked.value
},
horizontalAlignment = Alignment.CenterHorizontally
)
if(isClicked.value){
// show full screen dialog or navigate to some screen.
}
Here are two problems.
I tried with Dialog function.
Dialog(
onDismissResult: () -> Unit,
properties: DialogProperties = DialogProperties(),
content: #Composable () -> Unit
)
but, this doesn't show full screen but just next item. (it's in GridLayout and when I click an item, the dialog needs to shows up to add the item.)
For navigation, I tried, varies ways, but I haven't found any clear solutions...
Could you please help me out? or any advices?
This should do the trick for a simple full screen popup
var showPopup by remember { mutableStateOf(false) }
Box(Modifier
.background(Color.Blue)
.fillMaxSize()) {
Button(onClick = { showPopup = true }) {
Text("Show popup")
}
}
if (showPopup) {
Popup(
onDismissRequest = { showPopup = false }
) {
Box(Modifier
.background(Color.Red)
.fillMaxSize()) {
Button(onClick = { showPopup = false },
modifier = Modifier.align(Alignment.Center)) {
Text("Hide popup")
}
}
}
}
Though if you want proper navigation you should probably use this
The Code A displays a dialog box based AlertDialog, and I get Image A when I run Code A.
I find the space between title = { Text(text = dialogTitle) } and text = {...} is too closer in Image A.
So I set Modifier.padding(top = 100.dp) to wish to increase the space between the two controls, but I only get Image B, it seems that Modifier.padding(top = 100.dp) doesn't work as expected, how can I fix it?
Code A
#Composable
fun EditTextDialog(
isShow: Boolean,
onDismiss: () -> Unit,
onConfirm: (String) -> Unit,
saveTitle: String = stringResource(R.string.dialog_save_title),
cancelTitle:String = stringResource(R.string.dialog_cancel_title),
dialogTitle:String ="Edit",
editFieldContent:String ="",
) {
var mText by remember(editFieldContent){ mutableStateOf(editFieldContent) }
val cleanAndDismiss = {
mText = editFieldContent
onDismiss()
}
if (isShow) {
AlertDialog(
title = { Text(text = dialogTitle) },
text = {
Column(
Modifier.padding(top = 20.dp)
//Modifier.padding(top = 100.dp)
//Modifier.height(100.dp), //The same result as Image A
//verticalArrangement = Arrangement.Center
) {
TextField(
value = mText,
onValueChange = { mText = it }
)
}
},
confirmButton = {
TextButton(onClick = { onConfirm(mText) }) {
Text(text = saveTitle)
}
},
dismissButton = {
TextButton(onClick = cleanAndDismiss) {
Text(text = cancelTitle)
}
},
onDismissRequest = cleanAndDismiss
)
}
}
Image A
Image B
With M3 AlertDialog (androidx.compose.material3.AlertDialog) it works.
With M2 AlertDialog, one solution is to remove the title attribute and use the text attribute for the whole layout.
AlertDialog(
onDismissRequest = {},
text = {
Column(){
Text(text = "Title")
Spacer(Modifier.height(30.dp))
TextField(
value = "mText",
onValueChange = { },
)
}
},
//buttons..
)
I don't understand what you're trying to do. If you want more space between the TextField and the dialog buttons, then you don't want a top padding. You want padding below the TextField, so it would be bottom padding on the column.
Also, there's a chance that it won't work properly inside a Column, and you might have to switch it out for Box. And if that doesn't work for some reason, just add a spacer below the TextField:
Spacer(Modifier.height(20.dp).fillMaxWidth())
I assume you are using Material AlertDialog? If yes try using the Material3 variant. It should work then.
Just implement following library:
implementation "androidx.compose.material3:material3:1.0.0-beta02"
And make sure to use the Material3 AlertDialog Composable which is imported with the library.
This question already has answers here:
Why don't Indication work for Button or Icons?
(2 answers)
Closed 6 months ago.
I have seen that we can disable the ripple effect of a view with the clickable(interactionSource, indication) inside for example a row or column but my question is that if we can disable it from a Button or FloatingActionButton
I see that FloatingActionButton has an interactionSource attribute and I have tried this
FloatingActionButton(
modifier = Modifier
.size(40.dp),
onClick = {
buttonState = when (buttonState) {
ButtonState.PRESSED -> ButtonState.UNPRESSED
ButtonState.UNPRESSED -> ButtonState.PRESSED
}
},
interactionSource = remember {
MutableInteractionSource()
})
this is not working to disable the ripple effect.
Then I have tried with the indication modifier like this
FloatingActionButton(
modifier = Modifier
.size(40.dp)
.indication(
interactionSource = remember {
MutableInteractionSource()
},
indication = null
),
onClick = {
buttonState = when (buttonState) {
ButtonState.PRESSED -> ButtonState.UNPRESSED
ButtonState.UNPRESSED -> ButtonState.PRESSED
}
})
also is not working, and then last thing I tried is adding the .clickable(...) in the modifier of the Fab button but I think that is pointless since the button has its own onClick event.
All the cases above yields to this
Is there anyway from any Button to disable its ripple effect without adding a Column or Box with a clickable attribute into its modifier ?
You can change ripple o by providing RippleTheme
private class CustomRippleTheme : RippleTheme {
#Composable
override fun defaultColor(): Color = Color.Unspecified
#Composable
override fun rippleAlpha(): RippleAlpha = RippleAlpha(
draggedAlpha = 0f,
focusedAlpha = 0f,
hoveredAlpha = 0f,
pressedAlpha = 0f,
)
}
Demo
#Composable
private fun RippleDemo() {
Column(
modifier = Modifier
.fillMaxSize()
.padding(50.dp)
) {
Button(onClick = { /*TODO*/ }) {
Text("Button with ripple", fontSize = 20.sp)
}
Spacer(Modifier.height(20.dp))
FloatingActionButton(onClick = { /*TODO*/ }) {
Icon(imageVector = Icons.Filled.Add, contentDescription = null)
}
Spacer(Modifier.height(20.dp))
CompositionLocalProvider(LocalRippleTheme provides CustomRippleTheme()) {
Button(onClick = { /*TODO*/ }) {
Text("Button with No ripple", fontSize = 20.sp)
}
Spacer(Modifier.height(20.dp))
FloatingActionButton(onClick = { /*TODO*/ }) {
Icon(imageVector = Icons.Filled.Add, contentDescription = null)
}
}
}
}
Result
A Button, internally, is just a surface with modifications applied to it to make it clickable. It has a default indication set within the implementation, hence cannot be "turned off" at the calling site.
Just pull up the source code and remove the indication, storing the resultant inside a new Composable.
Just do a quick Ctrl+Left Click on the text "Button" in Studio, and it'll take you there.
I'm trying to make an on screen keyboard from buttons and trying to do this using a button function is kind of annoying as I can't set weights like this:
#Composable
fun MyKeyboardButton(text: String){
Button(onClick = { /*TODO*/ }, modifier = Modifier.weight(1F)) {
Text(text = text, textAlign = TextAlign.Center)
}
}
and then insert that into a row for each letter on a keyboard.. instead I'm stuck doing this:
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(4.dp)) {
Button(onClick = { /*TODO*/ }, Modifier.weight(1F)) {
Text(text = "Q")
}
Button(onClick = { /*TODO*/ }, Modifier.weight(1F)) {
Text(text = "W")
to get even spacing, which for each minor change in the code needs to then be implemented for 28 buttons.
Is there a way to add the buttons via a function? or do I need to set a button width for each for like so:
#Composable
fun MyKeyboardButton(text: String, width: Int){
Button(onClick = { /*TODO*/ }, modifier = Modifier.width(width.dp) {
Text(text = text, textAlign = TextAlign.Center)
}
}
I would also massively appreciate examples of on screen keyboards like this if there are any..
Modifier.weight is available inside Row because it's declared on RowScope. You can declare your composable on the same scope, so you can use weight:
#Composable
fun RowScope.MyKeyboardButton(text: String) {
Note that then you won't be able to call it outside of Row.
I have a composable function that i need to call after clicking a button but it keeps showing an error that composables cannot be executed from button clicks , can anyone please guide me to solve this issue Thank you
This is my code
Box(contentAlignment = Alignment.Center) {
Button(onClick = {
// This is a composable function that i need to call
SignUpNewUser(email,fullName,country,password)
}
,modifier = Modifier
.width(200.dp)
.background(color = Color.DarkGray)) {
Text(text = "Sign Up",style = TextStyle(color = Color.White,fontWeight = FontWeight.Bold))
}
}
You can only add a #Composable view to another #Composable view.
onClick is not marked #Composable, so you get this warning. You can only change the state with onClick.
For example, you can create a flag and display the UI depending on that flag:
var signUp by remember { mutableStateOf(false) }
if (signUp) {
SignUpNewUser(email, fullName, country, password)
} else {
Box(contentAlignment = Alignment.Center) {
Button(onClick = {
signUp = true
}, modifier = Modifier
.width(200.dp)
.background(color = Color.DarkGray)) {
Text(text = "Sign Up", style = TextStyle(color = Color.White, fontWeight = FontWeight.Bold))
}
}
}
I suggest you start with this youtube video which explains the basic principles of when you need to use state in compose. You can continue deepening your knowledge with state in Compose documentation.
Another option would be to use Compose Navigation.