Create vertical slider with label in Jetpack Compose - kotlin

I made a vertical slider based on this answer, and now I need to add title and value for each sliders.
If I set a fixed width value in modifier like this modifier.width(180.dp), it looks fine like this
However I would like to let the slider height be responsive to the device screen size, so I set the width to modifier.fillMaxWidth(), the bottom text will disappear
Here is my vertical slider compose looks like, and I try to set the height in modifier here.
#Composable
fun VerticalSlider(value: MutableState<Float>, min: Int, max: Int, onFinished:(Int)->Unit) {
Slider(
modifier = Modifier
.graphicsLayer {
rotationZ = 270f
transformOrigin = TransformOrigin(0f, 0f)
}
.layout { measurable, constraints ->
val placeable = measurable.measure(
Constraints(
minWidth = constraints.minHeight,
maxWidth = constraints.maxHeight,
minHeight = constraints.minWidth,
maxHeight = constraints.maxWidth,
)
)
layout(placeable.height, placeable.width) {
placeable.place(-placeable.width, 0)
}
}
// .fillMaxWidth()
.width(180.dp)
.height(50.dp)
,
value = value.value,
valueRange = min.toFloat()..max.toFloat(),
onValueChange = {
value.value = it.toInt().toFloat()
},
onValueChangeFinished = {
onFinished(value.value.toInt())
},
)
}
Vertical slider with text.
#Composable
fun VerticalSliderWithText(sliderValue: MutableState<Float>, min: Int, max: Int, onFinished:(Int)->Unit) {
var sliderValue = remember { mutableStateOf(0f) }
Column(
modifier = Modifier
.fillMaxSize(),
verticalArrangement = Arrangement.SpaceAround,
horizontalAlignment = Alignment.CenterHorizontally
){
Text("slider title")
VerticalSlider(value = sliderValue, min = -6, max = 6,
) {
//println(" finish value: $it")
}
Text(modifier = Modifier.background(Green),
text="slider value")
}
}

Instead of Modifier.fillMaxWidth, you need to use Modifier.weight, which is available inside a Column. To do so you need to add a modifier parameter:
#Composable
fun VerticalSlider(value: MutableState<Float>, min: Int, max: Int, onFinished:(Int)->Unit, modifier: Modifier) {
Slider(
modifier = modifier
//...
So you can pass Modifier.weight like this:
Column(
modifier = Modifier
.fillMaxSize(),
verticalArrangement = Arrangement.SpaceAround,
horizontalAlignment = Alignment.CenterHorizontally
){
Text("slider title")
VerticalSlider(
value = sliderValue,
min = -6,
max = 6,
onFinished = {
//println(" finish value: $it")
},
modifier = Modifier.weight(1f)
)
Alternatively, you can declare VerticalSlider on ColumnScope, so Modifier.weight can be used directly from the function:
#Composable
fun ColumnScope.VerticalSlider(value: MutableState<Float>, min: Int, max: Int, onFinished:(Int)->Unit) {
Slider(
modifier = Modifier
.weight(1f)
//...

Related

How to bring fun DatePicker's date value to fun TaskContent

I just start to make and edit some android apps after taking some Udemy online courses. I'm beginner at programming myself, so please understand my questions will be basic level for most software engineers. I am editing the code using Jetpack compose. I'm making a todoapp. I used MVVM structure, it's got repository, viewmodel etc... It's first time to ask questions in stackoverflow.
Here is my question. If you need more info to help me, let me know in comment.
I added the date in the TaskContent Function. I can't bring the date data that I chose from DatePicker Function.
How can I modify the code to bring the date information I selected from fun datePicker to fun TaskContent?
#Composable
fun TaskContent(
title: String,
onTitleChange: (String) -> Unit,
description: String,
onDescriptionChange: (String) -> Unit,
priority: Priority,
onPrioritySelected: (Priority) -> Unit,
date: String,
onDateChange: (String) -> Unit
) {
Column(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colors.background)
.padding(all = LARGE_PADDING)
) {
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
value = title,
onValueChange = { onTitleChange(it) },
label = { Text(text = stringResource(id = R.string.title)) },
textStyle = MaterialTheme.typography.body1,
singleLine = true
)
Divider(
modifier = Modifier.height(MEDIUM_PADDING),
color = MaterialTheme.colors.background
)
PriorityDropDown(
priority = priority,
onPrioritySelected = onPrioritySelected
)
Divider(
modifier = Modifier.height(MEDIUM_PADDING),
color = MaterialTheme.colors.background
)
DatePicker(date = date, onDateChange = onDateChange)
OutlinedTextField(
modifier = Modifier.fillMaxSize(),
value = description,
onValueChange = { onDescriptionChange(it) },
label = { Text(text = stringResource(id = R.string.description)) },
textStyle = MaterialTheme.typography.body1
)
}
}
I want to choose the date from fun DatePicker and send the data all the way to viewmodel... other things like title, description, priority are connected all the way to viewmodel.
If I start the app, I can choose the date from calendar using fun DatePicker. However, I can't send the data to fun TaskContent..
#Composable
fun DatePicker(
date: String,
onDateChange: (String) -> Unit
){
val mContext = LocalContext.current
val mYear: Int
val mMonth: Int
val mDay: Int
val mCalendar = Calendar.getInstance()
mYear = mCalendar.get(Calendar.YEAR)
mMonth = mCalendar.get(Calendar.MONTH)
mDay = mCalendar.get(Calendar.DAY_OF_MONTH)
mCalendar.time = Date()
val mDate = remember { mutableStateOf("") }
val mDatePickerDialog = DatePickerDialog(
mContext,
{ _: DatePicker, mYear, mMonth, mDayOfMonth ->
mDate.value = "${mYear}year ${mMonth+1}month ${mDayOfMonth}day"
}, mYear, mMonth, mDay
)
Row(
modifier = Modifier
.fillMaxWidth()
.height(PRIORITY_DROP_DOWN_HEIGHT)
.clickable { mDatePickerDialog.show() }
.border(
width = 1.dp,
color = MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled),
shape = MaterialTheme.shapes.small
).padding(12.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "date: ${mDate.value}", style = MaterialTheme.typography.subtitle2)
}
}

How do I make lazyVerticalGrid's scroll and column's verticalScroll, scroll together as one

I practicing jetpack compose, where I have a LazyVerticalGrid, a Text and a lazyColumn composeables, which I put in inside another composable which I called HomeContentScreen and gave it a scroll function, and as you know, the LasyVerticalGrid already has a built-in scroll function, which I tried to disable but it affected the scrolling function.
To Summarize; the three composeables scroll differently, depending on which part of the screen I touch.
So my question is how do I make them all follow the same scroll function (vertically)
Here's the codes.
|
Text Composeable;
#Composable
fun HomeQuote() {
Text(
text = stringResource(R.string.Lorem_ipsum),
style = MaterialTheme.typography.h2,
modifier = Modifier
.paddingFromBaseline(top = 24.dp, bottom = 18.dp)
.padding(horizontal = 18.dp)
.heightIn(min = 56.dp)
)
}
|
LazyVerticalGrid Composable;
#Composable
fun SecondBodyGrid(
modifier: Modifier = Modifier,
onHomeCardClick: (Int) -> Unit = {},
) {
LazyVerticalGrid(
columns = GridCells.Fixed(1),
contentPadding = PaddingValues(horizontal = 16.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = modifier
.height(1450.dp)
//.disabledVerticalPointerInputScroll()
.....
|
LazyRow Composable
#Composable
fun FirstBodyRow(
onHomeCardClick: (Int) -> Unit = {},
) {
LazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp),
contentPadding = PaddingValues(horizontal = 16.dp),
modifier = Modifier
) {
.....
|
And Finally the Composable I arranged everything, HomeContentScreen;
#Composable
fun HomeContentScreen(
modifier: Modifier = Modifier,
onHomeCardClick: () -> Unit
) {
Column(
modifier
.verticalScroll(rememberScrollState())
.padding(vertical = 16.dp)) {
HomeQuote()
HomeTitleSection(title = R.string.favorite_collections) {
SecondBodyGrid {onHomeCardClick()}
}
HomeTitleSection(title = R.string.align_your_body) {
FirstBodyRow {onHomeCardClick()}
}
}

How to implement Compose Navigation Arguments

I'm practicing Jetpack compose navigation, currently I'm stuck at passing arguments, so the correct information can be displayed when clicked.
I'm trying to navigate from this Destination, MenuScreen;
#Composable
fun HomeScreen(onHomeCardClick: () -> Unit) {
HomeContentScreen(onHomeCardClick = onHomeCardClick)
}
#Composable
fun HomeContentScreen(
modifier: Modifier = Modifier,
onHomeCardClick: () -> Unit
) {
Column(
modifier
.verticalScroll(rememberScrollState())
.padding(vertical = 16.dp)) {
HomeQuote()
....
}
}
To this destination, MenuInfoScreen;
#Composable
fun HomeInfoScreen(){
WelcomeText()
HomeInfoDetails()
}
#Composable
fun WelcomeText() {
Text(
text = "Welcome, to Home Information",
style = MaterialTheme.typography.h3,
modifier = Modifier.padding(horizontal = 12.dp, vertical = 18.dp)
)
}
#Composable
fun HomeInfoDetails(
homeInfo: HomeInfo
) {
Card(
modifier = Modifier
.padding(10.dp)
.clip(CircleShape),
elevation = 10.dp,
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(10.dp)
) {
Image(
painter = painterResource(id = homeInfo.homeInfoImageId),
contentDescription = null,
modifier = Modifier
.fillMaxWidth()
.clip(shape = RoundedCornerShape(topEnd = 4.dp, bottomEnd = 4.dp)),
contentScale = ContentScale.Fit
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = homeInfo.title,
style = MaterialTheme.typography.h3
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = homeInfo.description,
style = MaterialTheme.typography.h5
)
}
}
}
Here's the model I'm trying to follow, HomeInfoModel;
object HomeInfoModel {
val homeInfoModelList = listOf(
HomeInfo(
id = 1,
title = "Monty",
sex = "Male",
age = 14,
description = "Monty enjoys chicken treats and cuddling while watching Seinfeld.",
homeInfoImageId = R.drawable.ab1_inversions
),
.....
)
}
Here's the my NavHost;
NavHost(
navController = navController,
startDestination = Home.route,
modifier = modifier
) {
// builder parameter will be defined here as the graph
composable(route = Home.route) {
HomeScreen(
onHomeCardClick = {}
)
}
....
composable(route = HomeInfoDestination.route) {
HomeInfoScreen()
}
}
}
And my Destinations file;
object Home : KetoDestination {
override val route = "home"
}
....
object HomeInfoDestination : KetoDestination{
override val route = "homeInfo"
}
I know this is a lot and I'm a bit off, but please I've been stuck here for more than a week now. Any little information willl surely come handy.
And Of Course very much appreciated.
Thanks for your help in advance.
You should extract the arguments from the NavBackStackEntry that is available in the lambda of the composable() function.
You can read more in the official android docs https://developer.android.com/jetpack/compose/navigation#nav-with-args

Every element from loop should fill all the free space that is available in the Row

I have elements that I loop through and clicked element changes background to green. I want every element to fill all the free space that is available in the Row. But if I provide weight(1f) it shows only one element that takes all the space, but there should be three elements or whatever count of elements I have passed from outside.
#Composable
fun BottomMenu(
items: List<BottomMenuContent>,
modifier: Modifier = Modifier,
activeHighlightColor: Color = Green,
activeTextColor: Color = Color.White,
inactiveTextColor: Color = Color.Black,
initialSelectedItemIndex: Int = 0
) {
var selectedItemIndex by remember {
mutableStateOf(initialSelectedItemIndex)
}
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = modifier
.fillMaxWidth()
.background(Gray)
.padding(4.dp)
) {
items.forEachIndexed { index, item ->
BottomMenuItem(
item = item,
isSelected = index == selectedItemIndex,
activeHighlightColor = activeHighlightColor,
activeTextColor = activeTextColor,
inactiveTextColor = inactiveTextColor
) {
selectedItemIndex = index
}
}
}
}
#Composable
fun BottomMenuItem(
modifier: Modifier = Modifier,
item: BottomMenuContent,
isSelected: Boolean = false,
activeHighlightColor: Color = Green,
activeTextColor: Color = Color.White,
inactiveTextColor: Color = Color.Black,
onItemClick: () -> Unit
) {
Row( ) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.clickable {
onItemClick()
}
.background(if (isSelected) activeHighlightColor else Color.Transparent)
.weight(1f)
.padding(top = 14.dp, bottom = 14.dp,)
) {
Text(
text = item.title,
color = if(isSelected) activeTextColor else inactiveTextColor
)
}
}}
Remove the weight from the box and instead put it in its parent Row, I modified your code and please look where the weight is placed.
Your BottomMenu
#Composable
fun BottomMenu() {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.background(Color.LightGray)
.fillMaxWidth()
) {
(0..7).forEach {
BottomMenuItem()
}
}
}
Your BottomMenuItem
#Composable
fun RowScope.BottomMenuItem() {
Row(
modifier = Modifier.weight(1f) // remove the weight from the box inside and put it over here instead
) {
Box(
modifier = Modifier
.background(Color.Green)
// remove the weigth(1f) from here
) {
Text(
modifier = Modifier.fillMaxWidth(),
text = "Test",
color = Color.DarkGray
)
}
}
}
Your BottomMenuItem is an extension of a RowScope, so its top level composable can be configured with Row properties such as weight
Output of the code above.

Change the color of the background for each card composable in a lazy list - Jetpack Compose, Android

I am making an app that basically allows the user to search through a list of card composables, each with a heading and a body of text. My question is about changing the color of the background for each card to be a different color from a list of colors I have created. I somehow need to iterate through the list of colors and pass a different color each time and I'm not sure how I do that. Here is some code:
LazyColumn(
modifier = Modifier
.fillMaxSize()
.background(color = matte_black)
) {
val list = if (searching) searchResults else allReadings
list.value.let { list ->
items(list.size) { i ->
val reading = list[i]
ReadingItem(reading, **TODO("Add Color")**)
}
}
}
and the composable ReadingItem:
fun ReadingItem(
reading: ReadingData,
**color : Color**
) {
val context = LocalContext.current
val resources = context.resources
val displayMetrics = resources.displayMetrics
val screenWidth = displayMetrics.widthPixels / displayMetrics.density
val spacing = 16.dp
val scroll = rememberScrollState()
Card(
shape = RoundedCornerShape(4.dp),
backgroundColor = color, TODO("This is where i would like the color to iterate through the list")
modifier = Modifier.padding(16.dp)
) {
Column(
modifier = Modifier.width(screenWidth.dp - (spacing * 2)),
verticalArrangement = Arrangement.Top,
horizontalAlignment = Alignment.Start
) {
Text(
text = reading.title,
modifier = Modifier.padding(8.dp),
textAlign = TextAlign.Start,
style = TextStyle(
color = milk_white,
fontSize = 20.sp,
fontWeight = FontWeight.Bold
)
)
//Spacer(modifier = Modifier.padding(4.dp))
Text(
text = reading.reading,
textAlign = TextAlign.Center,
modifier = Modifier
.padding(8.dp)
.height(100.dp)
.verticalScroll(
state = scroll),
style = TextStyle(
color = milk_white,
fontSize = 16.sp
)
)
}
}
}
and finally, the list of colors:
fun getColors() : List<Color> {
return listOf(
flame_red, orange, ucla_gold, green, tropaz, calypso, plum
)
}
If anyone has any advice it would be very appreciated! Thank you
This should give a basic idea.
Code
#Composable
fun ColourCards() {
val colors = listOf(Color.Blue, Color.Green, Color.Magenta, Color.Gray, Color.Cyan)
LazyColumn {
items(40) {
Box(
Modifier
.fillMaxWidth()
.padding(
horizontal = 16.dp,
vertical = 4.dp,
)
.background(colors[it % colors.size])
.height(80.dp),
)
}
}
}