i'm trying to make a TextField that is a minimum size, and that expands around the text being written inside it, how can i achieve this?
This is my test code
var text by rememberSaveable { mutableStateOf("Prova") }
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(text = "Test")
TextField(
modifier = Modifier
// .widthIn(10.dp, Dp.Infinity)
// .width(IntrinsicSize.Min)
.width(30.dp)
.wrapContentWidth(),
value = text,
onValueChange = {
text = it
},
textStyle = TextStyle.Default.copy(
textAlign = TextAlign.End
)
)
}
This is the result i seek (should expand with more text in width up until it hits the left Text)
Thanks for the help!
Using Spacer with Modifier.weight(1f) in between will make it work.
I would suggest replacing TextField with BasicTextField to get finer control over its look (specifically achieving smaller minimum width than MinWidth default value of 280.dp).
var text by rememberSaveable { mutableStateOf("Prova") }
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(text = "Test")
Spacer(modifier = Modifier.weight(1f))
TextField(
modifier = Modifier
.widthIn(1.dp),
value = text,
onValueChange = {
text = it
},
textStyle = TextStyle.Default.copy(
textAlign = TextAlign.End
)
)
}
Related
I have the below code, however the Preview is rendering the view different to when I run it on a AVD (Android Virtual Device). It looks there are 2 things different:
Firstly, the AVD is rending the view at the top of the screen, but the preview is rending the view in the centre of the screen. I've added contentAlignment = Alignment.Center to my AlertView Box which I believe should render it in the middle of the screen.
Secondly, the AVD is showing a weird shadow compared to the preview.
Images below of the preview and AVD:
//Preview Provider
#Preview(
showSystemUi = true,
device = Devices.PIXEL_4_XL,
uiMode = Configuration.UI_MODE_NIGHT_NO,
showBackground = true,
backgroundColor = 0xFFFFFFFF
)
#Preview(
showSystemUi = true,
device = Devices.PIXEL_4,
uiMode = Configuration.UI_MODE_NIGHT_YES,
showBackground = true,
backgroundColor = 0xFF000000
)
#Composable
fun DefaultPreview() {
AlertView()
}
//AlertViewModel
class AlertViewModel : ViewModel() {
var showAlert: Boolean by mutableStateOf(false)
var alertIcon: ImageVector by mutableStateOf(Icons.Rounded.WifiOff)
var alertTitle: String by mutableStateOf("No internet connection")
var alertMessage: String by mutableStateOf("This is the alert message and it is purposely longer than one line to be displayed on screen")
var alertButtonText: String by mutableStateOf("This is the alert button text")
}
//--------------------------------------------------------------------------------------------------
//.onCreate
class AlertManager : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
AlertView()
}
}
}
//AlertView
#Composable
fun AlertView(alertViewModel: AlertViewModel = viewModel()) {
Box(
contentAlignment = Alignment.Center
) {
Column(
verticalArrangement = Arrangement.spacedBy(10.dp),
modifier = Modifier
.padding(30.dp, 0.dp)
.background(
shape = RoundedCornerShape(15.dp),
color =
if (isSystemInDarkTheme()) {
Color.Black
} else {
Color.White
}
)
.shadow(
elevation = 1.dp,
shape = RoundedCornerShape(15.dp),
ambientColor = if (isSystemInDarkTheme()) {
Color.Black
} else {
Color.White
},
spotColor = if (isSystemInDarkTheme()) {
Color.White
} else {
Color.Gray
},
)
.padding(30.dp, 25.dp),
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(20.dp)
) {
Icon(
imageVector = alertViewModel.alertIcon,
contentDescription = null,
tint = if (isSystemInDarkTheme()) {
Color.White
} else {
Color.Black
},
)
Text(
text = alertViewModel.alertTitle,
style = TextStyle(
fontSize = 20.sp,
fontWeight = FontWeight.SemiBold,
color = if (isSystemInDarkTheme()) {
Color.White
} else {
Color.Black
}
)
)
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(25.dp),
) {
Text(
text = alertViewModel.alertMessage,
color = if (isSystemInDarkTheme()) {
Color.White
} else {
Color.Black
}
)
Button(
onClick = {
alertViewModel.showAlert = false
},
colors = ButtonDefaults.buttonColors(
backgroundColor = if (isSystemInDarkTheme()) {
Color.White
} else {
Color.Black
}
),
shape = RoundedCornerShape(15.dp),
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 10.dp),
contentPadding = PaddingValues(15.dp),
) {
Text(
text = alertViewModel.alertButtonText,
fontWeight = FontWeight.Bold,
color = if (isSystemInDarkTheme()) {
Color.Black
} else {
Color.White
}
)
}
}
}
}
}
My Code :::
#Composable
fun VerticalImageCards(toolsList: List<HealthTool>) {
val domainName = stringResource(id = R.string.media_url)
FlowRow(mainAxisSpacing = 8.dp,
crossAxisSpacing = 16.dp,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 16.dp),
mainAxisSize = SizeMode.Wrap) {
for (i in toolsList) {
val imgUrl = "$domainName${i.url}"
ToolsCardLayout(cardTitle = i.title, imgUrl = imgUrl)
}
}
}
#Composable
fun ToolsCardLayout(
imgUrl: String,
cardTitle: String,
) {
Box(modifier = Modifier.clickable {}) {
AsyncImage(model = imgUrl,
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxWidth())
Box(modifier = Modifier
.size(32.dp)
.align(Alignment.TopEnd)) {
Image(painter = painterResource(id = R.drawable.schedule),
contentDescription = null,
modifier = Modifier
.fillMaxSize()
.padding(top = 8.dp, end = 8.dp),
contentScale = ContentScale.Fit)
}
}
Card(modifier = Modifier
.height(44.dp)
.fillMaxWidth()) {
Text(text = cardTitle,
style = MaterialTheme.typography.h6,
modifier = Modifier
.padding(horizontal = 16.dp, vertical = 8.dp)
.clip(RoundedCornerShape(bottomStart = 8.dp, bottomEnd = 8.dp)))
}
}
Code Explanation:::
I'm getting a list of tools details which is having tool image, title, description from server.
imgURl -> url for image
cardTitle -> tool's name
Problem :::
Card is taking the whole width. Earlier, I used weight(1f) when the data was hardcoded and I don't have to retrieve it from backend. Also, I'm going to use it on the Homescreen, so the grid shouldn't be scrollable.
PLEASE VISIT THIS DRIVE LINK FOR MORE DETAILS, I have added code snippet and images + screen recording for better understanding
You can use official LazyVerticalGrid
#Composable
fun VerticalImageCards(toolsList: List<HealthTool>) {
val domainName = stringResource(id = R.string.media_url) {
LazyVerticalGrid(
columns = GridCells.Fixed(2),
modifier = modifier,
state = rememberLazyGridState()
) {
items(toolsList) {
val imgUrl = "$domainName${it.url}"
ToolsCardLayout(cardTitle = it.title, imgUrl = imageUrl)
}
}
}
I'm using kotlin and jetpack compose. My Alert Dialog has a TextField at bottom, when I press enter too much time on keyboard, the text field gets longer height and it go outside of the dialog. How can I limit it to not enter out of alert layout? I have set maxlines but the layout get white space at top. please see the code below and image
Column(
Modifier
.background(Color.White)
.wrapContentHeight()
.verticalScroll(rememberScrollState())
.pointerInput(Unit) {
detectTapGestures(onTap = {
focusManager.clearFocus()
})
}
)
TextField(
modifier = Modifier
.fillMaxWidth()
.wrapContentSize(),
value = text.value ?: "-",
onValueChange = {
isExceed = it.filter { char -> char == '\n' }.count() > maxLine
text.value = it
onValueChange(it)
},
//maxLines = maxLine,
placeholder = {
Text(text = NfcApp.str(textHint, ResEnum.refrigerant))
},
keyboardActions = KeyboardActions(
onDone = { keyboardController?.hide() }
),
colors = TextFieldDefaults.textFieldColors(
textColor = Color.Black,
backgroundColor = Color.White,
cursorColor = underLine_green,
disabledIndicatorColor = underLine_green,
unfocusedIndicatorColor = underLine_green,
focusedIndicatorColor = underLine_green
)
))
I have 3 composable in Column and I want to align 2nd composable to bottom of 1st composable like this:
But currently i'm getting output like this:
Here is my current code:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ComposePlaygroundTheme {
Column(modifier = Modifier
.fillMaxSize()) {
topControls("Game 1",34,Modifier.weight(1f))
centerControls()
bottomControls()
}
}
}
}
}
#Composable
fun topControls(gamename: String, totalTime: Int, modifier: Modifier) {
Column(modifier = modifier
.background(Color.LightGray)
.padding(start = 24.dp, end = 24.dp, top = 24.dp)) {
Row(modifier = Modifier.padding(end = 32.dp)) {
Image(
painter = painterResource(R.drawable.ic_launcher_foreground),
contentDescription = "",
Modifier
.height(32.dp)
.width(32.dp)
)
Text(
text = gamename,
modifier = Modifier
.weight(1f)
.align(Alignment.CenterVertically),
textAlign = TextAlign.Center
)
}
Text(text = totalTime.toString(),modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Center,fontSize = 53.sp)
Image(
painter = painterResource(R.drawable.ic_launcher_background),
contentDescription = "",
Modifier.fillMaxSize(),
contentScale = ContentScale.FillBounds
)
}
}
#Composable
fun centerControls() {
Box(modifier = Modifier
.fillMaxWidth()) {
Divider(color = Color.Blue, thickness = 1.dp, modifier = Modifier.align(Alignment.Center))
Row(modifier = Modifier.padding(start = 20.dp, end = 20.dp)) {
Button(onClick = { },colors = ButtonDefaults.buttonColors(backgroundColor = Color.Black,contentColor = Color.White), modifier = Modifier
.weight(1f)
.padding(end = 20.dp)
.fillMaxWidth()) {
Text(text = "End Game",modifier = Modifier
.wrapContentWidth()
.wrapContentHeight(), textAlign = TextAlign.Center,fontSize = 20.sp)
}
Image(painter = ColorPainter(Color.Gray), contentDescription = "", modifier = Modifier
.padding(horizontal = 25.dp)
.align(Alignment.CenterVertically)
.height(32.dp)
.width(32.dp))
}
}
}
#Composable
fun bottomControls() {
Spacer(modifier = Modifier.height(170.dp))
}
Is there anyway I can achieve this in jetpack compose without using Constraint layout?
As you need to place one view under an other one, you should use Box.
Using Modifier.align, you can specify position of your centerControls, in this case Alignment.BottomCenter.
Using Modifier.layout you can add offset, equal to half view size.
Column(modifier = Modifier
.fillMaxSize()
) {
Box(Modifier.weight(1f)) {
topControls("Game 1", 34, Modifier.fillMaxHeight())
centerControls(
Modifier
.align(Alignment.BottomCenter)
.layout { measurable, constraints ->
val placeable = measurable.measure(constraints)
layout(placeable.width, placeable.height) {
placeable.place(0, placeable.height / 2)
}
}
)
}
bottomControls()
}
Result:
Something like this should work
ComposePlaygroundTheme {
Column(modifier = Modifier
.fillMaxSize()) {
topControls("Game 1",34)
Box(modifier = Modifier.weight(1f)) { // FrameLayout, weight will occupy rest of the content
centerControls()
bottomControls() // will be stacked up on top of topControls()
}
}
}
//I'm having problems trying to get the title text in the KbfPlayScreen.kt to access the "url" in the list that is in the Data.kt on button click.
**KbfPlayScreen.kt**
#Composable
fun KbfSermonsView(sermons: List<Sermon>) {
Column() {
sermons.forEach {
SermonRow(it.title, it.timestamp)
Divider(thickness = 1.dp, modifier = Modifier.padding(top = 5.dp, bottom = 5.dp))
}
}
}
**Data.kt**
val kbfList = listOf<Kbf>(
Kbf(
title = "The Purpose Of KBF", description = "", imageId = R.drawable.kbf_tony, sermons =
listOf<Sermon>(
Sermon(title= "The Purpose Of KBF", image= "kbf_tony", url=
"https://www.youtube.com/embed/O5xZCZlCqBw", timestamp= "1612674000"),
)),
Kbf(
title = "Goal Setting", description = "", imageId = R.drawable.kbf_mike, sermons =
listOf<Sermon>(
Sermon(title = "Goal Setting", image = "kbf_mike", url =
"https://www.youtube.com/embed/HRDPWpUagxY", timestamp = "1612674000")
))
)