I'm new to jetpack compose. I want to start typing from TextField's centervertically-start
position but I can't put "Example" to center
vertically-start position.
Row(
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.shadow(5.dp)
.background(Color.Yellow),
) {
BasicTextField(
value = text,
onValueChange = {onvalueChange(it)},
modifier = Modifier.weight(10f).background(Color.Blue).fillMaxSize(),
singleLine = true,
textStyle = LocalTextStyle.current.copy(
textAlign = TextAlign.Center
)
)
Image(painter = painterResource(id = R.drawable.ic_baseline_search_24),
contentDescription = "Search",
modifier = Modifier.weight(2f).fillMaxSize()
)
This is my code
And this is what I want to do.
Row has a verticalAlignment for this. Also, if you want your TextField left align like the picture, remove the textAlign (or change it but it default to start)
Row(
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.shadow(5.dp)
.background(Color.Yellow),
verticalAlignment = Alignment.CenterVertically,
) {
BasicTextField(
value = text,
onValueChange = {onvalueChange(it)},
modifier = Modifier.weight(10f).background(Color.Blue).fillMaxSize(),
singleLine = true,
)
Image(painter = painterResource(id = R.drawable.ic_baseline_search_24),
contentDescription = "Search",
modifier = Modifier.weight(2f).fillMaxSize()
)
}
Use background box to control, please try:
Row(
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.shadow(5.dp)
.background(Color.Yellow),
) {
Box(Modifier.weight(10f).background(Color.Blue).fillMaxSize(),contentAlignment = CenterStart){
BasicTextField(
value = text,
onValueChange = { onvalueChange(it) },
modifier = Modifier.wrapContentHeight(
Alignment.CenterVertically),
singleLine = true,
textStyle = LocalTextStyle.current.copy(
textAlign = TextAlign.Start
)
)
}
Image(
Icons.Filled.Search,
contentDescription = "Search",
modifier = Modifier.weight(2f).fillMaxSize()
)
}
Related
I am trying to build the following component.
Following is my code,
#Composable
fun View(modifier: Modifier = Modifier){
Row(modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalArrangement = Arrangement.spacedBy(10.dp),
verticalAlignment = Alignment.CenterVertically) {
IconButton(onClick = { /*TODO*/ },
modifier = Modifier
.background(shape = roundShape, color = Color.Blue)
.size(40.dp)) {
Icon(
painter = painterResource(id = R.drawable.ic_microphone_2),
contentDescription = null,
tint = Color.White
)
}
BasicTextField(
value = "",
onValueChange = { },
modifier=Modifier
.height(40.dp)
.fillMaxWidth()
.border(1.dp,Color.Gray,roundShape)
)
}
The content of the IconButton is no longer centered after switching the LayoutDirection to Rtl.
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
View()
}
this is the result of my code.
#Composable
fun IconView(modifier: Modifier = Modifier) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalArrangement = Arrangement.spacedBy(10.dp),
verticalAlignment = Alignment.CenterVertically
) {
Box(modifier = Modifier
.background(shape = RoundedCornerShape(20.dp), color = Color.Blue)
.size(50.dp).clickable {
}
){
Icon(
modifier = Modifier.align(alignment = Center),
painter = painterResource(id = android.R.drawable.ic_menu_call),
contentDescription = null,
tint = Color.White
)
}
BasicTextField(
value = "",
onValueChange = { },
modifier = Modifier
.height(40.dp)
.fillMaxWidth()
.border(1.dp, Color.Gray, RoundedCornerShape(20.dp))
)
}
}
Don't use iconButton as parent use Box and align child Icon to center. I Hope it will help you. Cheers
How can we achieve this in jetpack compose
I'm doing something like this
Button(
elevation = ButtonDefaults.elevation(
defaultElevation = 0.dp,
pressedElevation = 8.dp,
disabledElevation = 0.dp
),
onClick = { onClick },
shape = RoundedCornerShape(28.dp),
modifier = modifier
.fillMaxWidth()
.shadow(0.dp),
contentPadding = PaddingValues(15.dp),
colors = ButtonDefaults.buttonColors(backgroundColor = Color.White),
border = BorderStroke(1.dp, Color.Grey)
) {
Box(modifier = modifier.fillMaxWidth(),
contentAlignment = Alignment.Center) {
Icon(
imageVector = imageVector,
modifier = Modifier
.size(18.dp),
contentDescription = "drawable icons",
tint = Color.Unspecified
)
Spacer(modifier = Modifier.width(10.dp))
Text(
text = buttonText,
color = Color.Black,
textAlign = TextAlign.Center
)
}
}
So as you can see the Google logo is just left of the text I need it at the start of the box so how can I do this.
You can use align(Alignment.CenterStart) on the Icon's Modifier parameter to center the icon around the start of the Box Composable. This alignment will have priority over the Box's alignment parameter.
You can also delete the Spacer composable because the Box layout children are stacked one on top of the other in the composition order. So the Spacer composable is basically laying below the Text composable in the center.
If you want some space between the Icon and the Text, you could use some padding around the Icon instead.
Try this (It worked for me) :
Box(modifier = modifier.fillMaxWidth(),
contentAlignment = Alignment.Center) {
Icon(
imageVector = imageVector,
modifier = Modifier
.size(18.dp)
.align(Alignment.CenterStart),
contentDescription = "drawable icons",
tint = Color.Unspecified
)
Text(
text = buttonText,
color = Color.Black,
textAlign = TextAlign.Center
)
}
#Composable
fun GoogleButton(
modifier: Modifier = Modifier,
imageVector: ImageVector,
buttonText: String,
onClick: (isEnabled: Boolean) -> Unit = {},
enable: Boolean = true,
backgroundColor: Color,
fontColor: Color,
) {
Button(
onClick = { onClick(enable) },
modifier = modifier
.fillMaxWidth()
.shadow(0.dp)
.noInteractionClickable(enabled = false) { onClick(enable) },
elevation = ButtonDefaults.elevation(
defaultElevation = 0.dp,
pressedElevation = 0.dp,
hoveredElevation = 0.dp,
focusedElevation = 0.dp
),
shape = RoundedCornerShape(28.dp),
contentPadding = PaddingValues(15.dp),
colors = ButtonDefaults.buttonColors(
backgroundColor = backgroundColor,
contentColor = fontColor
),
border = BorderStroke(1.dp, MaterialTheme.colors.getButtonBorderStroke)
) {
Box(
modifier = Modifier
.fillMaxWidth(),
contentAlignment = Alignment.Center
) {
Row(
modifier = Modifier
.fillMaxWidth()
.align(Alignment.CenterStart)
) {
Spacer(modifier = Modifier.width(4.dp))
Icon(
imageVector = imageVector,
modifier = Modifier
.size(18.dp),
contentDescription = "drawable_icons",
tint = Color.Unspecified
)
}
Text(
modifier = Modifier.align(Alignment.Center),
text = buttonText,
color = MaterialTheme.colors.loginButtonTextColor,
textAlign = TextAlign.Center,
fontSize = 16.sp,
fontFamily = FontFamily(
Font(
R.font.roboto_medium
)
)
)
}
}
}
As suggested in other answers you can wrap the content with a Box.
As alternative you can simply use the RowScope of the Button without any container.
Just apply a weight(1f) modifier to the Text and an offset(x=- iconWidth/2).
Something like:
Button(
//....
) {
Icon(
imageVector = imageVector,
modifier = Modifier.size(iconWidth),
contentDescription = "drawable icons",
tint = Color.Unspecified
)
Text(
text = "Button",
color = Color.Black,
textAlign = TextAlign.Center,
modifier = Modifier
.weight(1f)
.offset(x= -iconWidth/2) //default icon width = 24.dp
)
}
If you want to use a Box, remove the contentAlignment = Alignment.Center in the Box and use:
Box(modifier = Modifier.fillMaxWidth()) {
Icon( /* ..... */ )
Text(
modifier = Modifier.fillMaxWidth(),
text = "buttonText",
textAlign = TextAlign.Center
)
}
Box doesn't provide bounds, so for longer texts, it causes overlapping. Row works better for me. Also, you can use Spacer here which is not possible for Box. In my case, I have used spacedBy as a replacement for Spacer:
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
painter,
contentDescription = null
)
Box(
modifier = Modifier.weight(1F),
contentAlignment = Alignment.Center
) {
Text(buttonText)
}
}
Box(contentAlignment = Center){
Icon(Modifier.align(CenterStart))
Text()
}
Items seem to have fixed height inside Column.
I'm trying to show multiple rows of dynamic height inside the column, and the items of those rows also having dynamic height.
I have tried wrapping the Column inside the box, but that doesn't work.
Box {
Column(
modifier = Modifier
.fillMaxSize()
) {
Image(
painter = painterResource(id = R.drawable.background_home),
contentDescription = "",
contentScale = ContentScale.FillBounds,
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(0.3f)
)
Spacer(modifier = Modifier.height(10.dp))
List()
Spacer(modifier = Modifier.height(10.dp))
Row(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(10.dp)
) {
Text(
text = "My Days",
style = TextStyle(
fontStyle = FontStyle.Normal,
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Bold
)
)
Text(text = "Red Sun")
}
MyAnotherList(
Modifier
.fillMaxWidth()
.fillMaxHeight(0.6f)
.padding(10.dp)
.horizontalScroll(rememberScrollState())
)
Spacer(modifier = Modifier.height(10.dp))
Row(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(10.dp)
) {
Text(
text = "My Other Days",
style = TextStyle(
fontStyle = FontStyle.Normal,
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Bold
)
)
Text(text = "Blue Sun")
}
MyOtherList()
}
TopBar()
}
Trying to achieve something like this, but all the rows will have dynamic height
Is there a way that I can provide dynamic height to the items inside scrollable columns.
How can I align an Image with a Text's baseline in a Row. Modifier.alignByBaseline() works for the Texts but the Image doesn't participate in the alignment.
#Composable
fun Sample() {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center,
) {
Text(
text = "One",
modifier = Modifier.alignByBaseline(),
fontSize = 40.sp
)
Image(
modifier = Modifier
.padding(horizontal = 8.dp)
.size(24.dp)
.alignBy(FirstBaseline),
painter = painterResource(id = R.drawable.ic_launcher_background),
contentDescription = "",
)
Text(
text = "two",
modifier = Modifier.alignByBaseline(),
fontSize = 40.sp
)
}
}
alignByBaseline aligns item by it's own baseline, not neighbours ones.
You can use paddingFromBaseline for Text and same value for image padding with verticalAlignment = Alignment.Bottom.
And to get actual value of baseline offset to pass it to the padding modifier, you need to wait for TextLayoutResult: it gets called when text layout is calculated depending on text size, font, etc.
Row(
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.Bottom,
modifier = Modifier.fillMaxWidth()
) {
var maxBaseline by remember { mutableStateOf(0f) }
fun updateMaxBaseline(textLayoutResult: TextLayoutResult) {
maxBaseline = max(maxBaseline, textLayoutResult.size.height - textLayoutResult.lastBaseline)
}
val topBaselinePadding = with(LocalDensity.current) { maxBaseline.toDp() }
Text(
text = "One",
modifier = Modifier.paddingFromBaseline(bottom = topBaselinePadding),
fontSize = 20.sp,
onTextLayout = ::updateMaxBaseline
)
Image(
painter = painterResource(id = R.drawable.ic_launcher_background),
contentDescription = "",
modifier = Modifier
.padding(bottom = topBaselinePadding)
.size(24.dp)
)
Text(
text = "two",
modifier = Modifier.paddingFromBaseline(bottom = topBaselinePadding),
fontSize = 40.sp,
onTextLayout = ::updateMaxBaseline
)
}
I'm trying to use BasicTextField with TextAlignment.End for RTL. it's my code:
val textState = remember { mutableStateOf(TextFieldValue("")) }
val shape = RoundedCornerShape(CornerSize(4.dp))
BasicTextField(
value = textState.value,
onValueChange = { newText -> textState.value = newText },
textStyle = LocalTextStyle.current.copy(
color = ColorPrimaryDarkText,
fontWeight = FontWeight.Medium,
textAlign = TextAlign.End,
fontSize = 14.sp,
),
maxLines = 1,
singleLine = true,
modifier = Modifier
.fillMaxWidth()
.padding(32.dp, 0.dp)
.clip(shape)
.background(color = Color.White),
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Done
),
decorationBox = { innerTextField ->
Row(
modifier = Modifier
.fillMaxWidth()
.background(Color.White, shape)
.padding(8.dp),
) {
if (textState.value.text.isEmpty()) {
Text(
text = "hint",
textAlign = TextAlign.End,
fontWeight = FontWeight.Medium,
modifier = Modifier.fillMaxWidth(),
fontSize = 14.sp,
)
} else {
innerTextField()
}
}
}
)
it's OK when it's empty but it's not working well when you try to type anything (it's starting to type from center):
Remove the textAlign = TextAlign.End and use something like:
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl ) {
BasicTextField( /* your code */)
}
Otherwise if you want to use your code add horizontalArrangement = Arrangement.End in Row in the decorationBox parameter:
decorationBox = { innerTextField ->
Row(
modifier = Modifier
.fillMaxWidth()
.background(Color.White, shape)
.padding(8.dp),
horizontalArrangement = Arrangement.End){
//your code
}