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

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()}
}
}

Related

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.

How to send and get argument in composable in jetpack compose?

I'm new in jetpack compose. I developed an app by XML and Kotlin and want to move it to jetpack compose. The problem is that I have one activity and one fragment that there are several CardViews in the activity and when clicking on them they send a specific key to the fragment and the fragment shows specific information related to that CardView (I just have used one fragment), now in jetpack compose I don't know how to implement it. Could anyone help me, please? I have no problem with navigation I want to know how to change an Image and some Texts. I wonder that how can I use
when (key) {"key" -> text = ... imageResource = ...} in compose or not?
this is my code for XML
class BaseFragment : Fragment() {
internal lateinit var view: View
private lateinit var imgMain : ImageView
private lateinit var txtIngredients : TextView
private lateinit var txtMaking : TextView
private lateinit var txtBeCareful : TextView
#Suppress("UNREACHABLE_CODE")
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
view = inflater.inflate(R.layout.base_fragment, container,
false)
setupViews()
return view
}
private fun setupViews() {
imgMain = view.findViewById(R.id.img_BaseFragment_mainImg)
txtIngredients =
view.findViewById(R.id.txt_BaseFragment_ingredients)
txtMaking = view.findViewById(R.id.txt_BaseFragment_making)
txtBeCareful =
view.findViewById(R.id.txt_BaseFragment_beCareFullText)
this.arguments?.let {
when (it.getString(key: "itemTitle", defaultVlue :"")) {
"mas1" -> {
makeContent(R.drawable.mas1,
R.string.mas1,
R.string.mas1_making,
R.string.mas1_text)
}
"mas2" -> {
makeContent(R.drawable.mas2,
R.string.mas2,
R.string.mas2_making,
R.string.mas2_text)
}
"mas3" -> {
makeContent(R.drawable.mas3,
R.string.mas3,
R.string.mas3_making,
R.string.mas3_text)
}
}
private fun makeContent(imgCont : Int, txtIngredientsCont : Int,
txtMakingCont : Int, txtBeCarCont : Int ){
imgMain.setImageResource(imgCont)
txtIngredients.setText(txtIngredientsCont)
txtMaking.setText(txtMakingCont)
txtBeCareful.setText(txtBeCarCont)
}
}
and this is my code in jetpack compose but it doesn't work
#SuppressLint("UnusedMaterialScaffoldPaddingParameter")
#Composable
fun FinalShowScreen(itemTitle: String? = null, navController:
NavController) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(3.dp)
.verticalScroll(rememberScrollState())
) {
var imageId: Int
var textIngredientsId: Int
var textMakingId: Int
var textBeCarefulId: Int
when (maskArg) {
"mas1" -> {
imageId = R.drawable.mas1
textIngredientsId = R.string.mas1
textMakingId = R.string.mas1making
textBeCarefulId = R.string.mas1_text
}
"mas2" -> {
imageId = R.drawable.mas2
textIngredientsId = R.string.mas2
textMakingId = R.string.mas2making
textBeCarefulId = R.string.mas2_text
}
"mas3" -> {
imageId = R.drawable.mas3
textIngredientsId = R.string.mas3
textMakingId = R.string.mas3making
textBeCarefulId = R.string.mas3_text
}
Image(
painter = painterResource(id =
imageId),
contentDescription = "",
modifier = Modifier
.padding(bottom = 8.dp)
.height(200.dp)
.fillMaxSize()
)
Text(
text = stringResource(id = textIngredientsId),
style = typography.h1,
color = MaterialTheme.colors.primary,
textAlign = TextAlign.Center,
modifier = Modifier
.padding(8.dp)
)
Text(
text = stringResource(id =
textMakingId),
style = typography.h2,
color = MaterialTheme.colors.primaryVariant,
textAlign = TextAlign.Start,
modifier = Modifier
.padding(start = 8.dp, end = 8.dp, bottom = 15.dp,
top = 8.dp)
)
Text(
text = stringResource(id =
textBeCarefulId),
style = typography.h2,
color = MaterialTheme.colors.primaryVariant,
textAlign = TextAlign.Start,
modifier = Modifier
.padding(8.dp)
)
}
}
Finally, my problem was solved when, I changed the variables to
#DrawableRes imageId: Int,
#StringRes textIngredientsId: Int,
#StringRes textMakingId: Int,
#StringRes textBeCarefulId: Int
and I changed the navigation method in the Navgragh to this
class MainActions(navController: NavController) {
val gotoFinalShow: (String) -> Unit = { maskArg ->
navController.navigate("${Screens.FinalShow.route}/$maskArg"){
launchSingleTop = true
restoreState = true
}
}
}

Jetpack compose scrollable table

I need to have a component that scrolls vertically and horizontally.
Here is what I did so far:
#Composable
fun Screen() {
val scope = rememberCoroutineScope()
val scrollOffset = remember {
mutableStateOf(value = 0F)
}
LazyColumn(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(space = 16.dp)
) {
items(10) {
SimpleRow(
onScrollOffsetChange = {
scrollOffset.value = it
}
)
}
}
}
#Composable
private fun SimpleRow(
onScrollOffsetChange: (Float) -> Unit,
) {
val lazyRowState = rememberLazyListState()
LazyRow(
modifier = Modifier.fillMaxWidth(),
state = lazyRowState
) {
item {
Text(
text = "firstText"
)
}
for (i in 1..30) {
item {
Text(text = "qwerty")
}
}
}
}
When anyone of these SimpleRow is scrolled I want to scroll all of the SimpleRows together.
And I do not know how many SimpleRows I have because they came from our server.
Is there any kind of composable or trick that can do it for me?
You can use multiple rows inside a column that scrolls horizontally and vertically, like this:
#Composable
fun MainContent() {
val scrollStateHorizontal = rememberScrollState()
val scrollStateVertical = rememberScrollState()
Column(
modifier = Modifier
.fillMaxSize()
.verticalScroll(state = scrollStateVertical)
.horizontalScroll(state = scrollStateHorizontal)
) {
repeat(40){ c ->
Row {
repeat(40){ r ->
Item("col: $c | row: $r")
}
}
}
}
}
#Composable
fun Item(text: String) {
Text(
modifier = Modifier
.padding(5.dp)
.background(Color.Gray),
text = text,
color = Color.White
)
}

Create vertical slider with label in Jetpack Compose

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)
//...