I am trying to scroll down to the position of a specific UI element on clicking a Text.
The code for my Text is:
Text(
"What is autosaving?",
color = colorResource(id = R.color.text_highlight),
fontSize = with(LocalDensity.current) {
dimensionResource(id = R.dimen._11ssp).toSp()
},
fontFamily = FontFamily(
Font(R.font.poppins_regular)
),
modifier = Modifier.constrainAs(whatIsAutosaving) {
top.linkTo(glWhatIsAutoSaving)
start.linkTo(parent.start)
end.linkTo(parent.end)
},
)
On clicking this Text my screen should scroll to the beginning position of another Text. The code for this another Text is:
Text(
stringResource(id = R.string.autosave_info),
color = colorResource(id = R.color.bright_green),
fontSize = with(LocalDensity.current) {
dimensionResource(id = R.dimen._11ssp).toSp()
}, fontFamily = FontFamily(
Font(R.font.poppins_regular)
),
modifier = Modifier.constrainAs(autoSaveInfo) {
top.linkTo(glAutoSaveInfo)
start.linkTo(glLeft)
end.linkTo(glRight)
width = Dimension.fillToConstraints
},
)
How do I achieve this?
EDIT:
The complete code for my screen is:
@Composable
fun Autosave(navController: NavController) {
val query = remember { mutableStateOf("") }
val errorMsg = remember { mutableStateOf(false) }
Box(
modifier = Modifier
.background(color = MaterialTheme.colors.background)
.fillMaxSize()
) {
ConstraintLayout(
modifier = Modifier.verticalScroll(rememberScrollState())
) {
val (logo, illustration, title, triangle, slider, percent, maxLimitTxt,
maxLimitTextField, buttonSave, whatIsAutosaving, autoSaveInfo, progressBar,
detailsRow, iconUp, spacer, error) = createRefs()
val glLogo = createGuidelineFromTop(0.0075f)
val glIllustrationTop = createGuidelineFromTop(0.0235f)
val glIllustrationBottom = createGuidelineFromTop(0.045f)
val glIllustrationLeft = createGuidelineFromStart(0.27f)
val glIllustrationRight = createGuidelineFromEnd(0.27f)
val glTitle = createGuidelineFromTop(0.053f)
val glSlider = createGuidelineFromTop(0.062f)
val glMaxLimitTxt = createGuidelineFromTop(0.086f)
val glMaxLimitTextField = createGuidelineFromTop(0.09f)
val glButtonSaveTop = createGuidelineFromTop(0.11f)
val glButtonSaveBottom = createGuidelineFromTop(0.12f)
val glWhatIsAutoSaving = createGuidelineFromTop(0.125f)
val glAutoSaveInfo = createGuidelineFromTop(0.175f)
val glSpacer = createGuidelineFromTop(0.99f)
val glLeft = createGuidelineFromStart(0.1f)
val glRight = createGuidelineFromEnd(0.1f)
val glRightIcon = createGuidelineFromEnd(0.825f)
val glLeftTextField = createGuidelineFromStart(0.3f)
val glRightTextField = createGuidelineFromEnd(0.3f)
val coroutineScope = rememberCoroutineScope()
val scrollState = rememberScrollState()
var scrollToPosition by remember { mutableStateOf(0F) }
Image(
painter = painterResource(id = R.drawable.effect_app_bg_720),
contentDescription = "effect top",
modifier = Modifier
.fillMaxSize()
.scale(1.325f)
)
Image(
painter = painterResource(id = R.drawable.logo_voodlee),
contentDescription = "logo", modifier = Modifier
.constrainAs(logo) {
top.linkTo(glLogo)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
)
Image(
painter = painterResource(id = R.drawable.img_autosaving),
contentDescription = "autosave image",
modifier = Modifier.constrainAs(illustration) {
top.linkTo(glIllustrationTop)
bottom.linkTo(glIllustrationBottom)
start.linkTo(glIllustrationLeft)
end.linkTo(glIllustrationRight)
width = Dimension.fillToConstraints
height = Dimension.fillToConstraints
}
)
Text(
"Set the percentage for autosaving",
color = colorResource(id = R.color.bright_green),
fontSize = with(LocalDensity.current) {
dimensionResource(id = R.dimen._13ssp).toSp()
}, fontFamily = FontFamily(
Font(R.font.poppins_regular)
),
modifier = Modifier.constrainAs(title) {
top.linkTo(glTitle)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
)
Image(
painter = painterResource(id = R.drawable.ic_triangle_dn),
modifier = Modifier
.height(39.dp)
.width(29.dp)
.constrainAs(triangle) {
top.linkTo(title.bottom)
start.linkTo(parent.start)
end.linkTo(parent.end)
},
contentDescription = "triangle down"
)
Column(modifier = Modifier.constrainAs(slider) {
top.linkTo(glSlider)
start.linkTo(parent.start)
end.linkTo(parent.end)
}) {
val context = LocalContext.current
val customView = remember { com.shawnlin.numberpicker.NumberPicker(context) }
// Adds view to Compose
AndroidView({ customView }) { view ->
// View's been inflated - add logic here if necessary
with(view) {
orientation = HORIZONTAL
//dividerDrawable = ResourcesCompat.getDrawable(resources, R.drawable.bg_blue, null)
textColor =
ResourcesCompat.getColor(resources, R.color.slider_num_color, null)
selectedTextColor =
ResourcesCompat.getColor(resources, R.color.slider_num_color, null)
selectedTextSize = 120f
wheelItemCount = 6
value = 10
minValue = 0
maxValue = 99
layoutParams.width = MATCH_PARENT
setDividerColorResource(R.color.fade_green)
setDividerDistance(180)
setDividerThickness(10)
}
}
Text(
"%",
color = colorResource(id = R.color.bright_green),
fontSize = with(LocalDensity.current) {
dimensionResource(id = R.dimen._18ssp).toSp()
}, fontFamily = FontFamily(
Font(R.font.poppins_regular)
),
modifier = Modifier
.align(CenterHorizontally)
.offset(y = (-5).dp)
)
}
Text(
"Max Limit per autosaving",
color = colorResource(id = R.color.bright_green),
fontSize = with(LocalDensity.current) {
dimensionResource(id = R.dimen._13ssp).toSp()
},
fontFamily = FontFamily(
Font(R.font.poppins_regular)
),
modifier = Modifier.constrainAs(maxLimitTxt) {
top.linkTo(glMaxLimitTxt)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
)
TextField(
value = query.value,
onValueChange = { newValue -> query.value = newValue
if (newValue != "")
errorMsg.value = newValue.toInt() > 1500
},
label = {
Text(" Amount",
color = colorResource(id = R.color.bright_green),
fontSize = with(LocalDensity.current) {
dimensionResource(id = R.dimen._15ssp).toSp()
},
textAlign = TextAlign.Center
)
},
textStyle = TextStyle(
textAlign = TextAlign.Center,
color = colorResource(id = R.color.bright_green),
fontFamily = FontFamily(Font(R.font.poppins_regular)),
fontSize = with(LocalDensity.current) {
dimensionResource(id = R.dimen._15ssp).toSp()
},
),
modifier = Modifier.constrainAs(maxLimitTextField) {
top.linkTo(glMaxLimitTextField)
start.linkTo(glLeftTextField)
end.linkTo(glRightTextField)
width = Dimension.fillToConstraints
},
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.Transparent,
unfocusedIndicatorColor = colorResource(id = R.color.bright_green),
focusedIndicatorColor = colorResource(id = R.color.bright_green)
)
)
Text(
text =
"*Please enter amount less than Rs.1500",
fontSize = with(LocalDensity.current) {
dimensionResource(id = R.dimen._8ssp).toSp()
},
color = colorResource(id = R.color.voodlee_red),
modifier = Modifier
.padding(top = 8.dp)
.alpha(
if (errorMsg.value) {
1f
} else 0f
)
.constrainAs(error) {
top.linkTo(maxLimitTextField.bottom)
start.linkTo(parent.start)
end.linkTo(parent.end)
},
)
Button(
onClick = {
navController.navigate("fourth_screen")
},
modifier = Modifier.constrainAs(buttonSave) {
top.linkTo(glButtonSaveTop)
bottom.linkTo(glButtonSaveBottom)
start.linkTo(glLeft)
end.linkTo(glRight)
width = Dimension.fillToConstraints
height = Dimension.fillToConstraints
},
colors = ButtonDefaults.buttonColors(backgroundColor = colorResource(id = R.color.voodlee_red))
) {
Text(
"Save", color = colorResource(id = R.color.dark_blue),
fontSize = with(LocalDensity.current) {
dimensionResource(id = R.dimen._16ssp).toSp()
},
)
}
Text(
"What is autosaving?",
color = colorResource(id = R.color.text_highlight),
fontSize = with(LocalDensity.current) {
dimensionResource(id = R.dimen._11ssp).toSp()
},
fontFamily = FontFamily(
Font(R.font.poppins_regular)
),
modifier = Modifier
.constrainAs(whatIsAutosaving) {
top.linkTo(glWhatIsAutoSaving)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
.clickable {
coroutineScope.launch {
scrollState.animateScrollTo(scrollToPosition.roundToInt())
}
},
)
Text(
stringResource(id = R.string.autosave_info),
color = colorResource(id = R.color.bright_green),
fontSize = with(LocalDensity.current) {
dimensionResource(id = R.dimen._11ssp).toSp()
}, fontFamily = FontFamily(
Font(R.font.poppins_regular)
),
modifier = Modifier
.constrainAs(autoSaveInfo) {
top.linkTo(glAutoSaveInfo)
start.linkTo(glLeft)
end.linkTo(glRight)
width = Dimension.fillToConstraints
}
.onGloballyPositioned { coordinates ->
scrollToPosition = coordinates.positionInParent().y
},
)
Row(
modifier = Modifier
.padding(top = 40.dp, bottom = 50.dp)
.constrainAs(detailsRow) {
top.linkTo(autoSaveInfo.bottom)
start.linkTo(glLeft)
end.linkTo(glRight)
width = Dimension.fillToConstraints
},
) {
Text(
text = "For more details",
color = colorResource(id = R.color.bright_green),
fontSize = with(LocalDensity.current) {
dimensionResource(id = R.dimen._11ssp).toSp()
}, fontFamily = FontFamily(
Font(R.font.poppins_regular)
),
)
Spacer(modifier = Modifier.padding(5.dp))
Text(
text = "Click here",
color = colorResource(id = R.color.text_highlight),
fontSize = with(LocalDensity.current) {
dimensionResource(id = R.dimen._11ssp).toSp()
},
fontFamily = FontFamily(
Font(R.font.poppins_regular)
),
)
}
Image(
painter = painterResource(id = R.drawable.ic_btn_upward),
modifier = Modifier
.height(32.dp)
.constrainAs(iconUp) {
top.linkTo(detailsRow.bottom)
start.linkTo(glLeft)
end.linkTo(glRightIcon)
width = Dimension.fillToConstraints
},
contentDescription = ""
)
Spacer(modifier = Modifier
.padding(bottom = 50.dp)
.constrainAs(spacer) {
top.linkTo(glSpacer)
start.linkTo(parent.start)
end.linkTo(parent.end)
},)
}
Card(
Modifier
.align(BottomCenter)
.fillMaxWidth()
.alpha(if (query.value == "") 1f else 0f),
backgroundColor = MaterialTheme.colors.secondaryVariant
) {
ProgressBar5UI(
Modifier
.padding(start = 40.dp, end = 40.dp, top = 10.dp)
)
}
Card(
Modifier
.align(BottomCenter)
.fillMaxWidth()
.alpha(if (errorMsg.value) 1f else 0f),
backgroundColor = MaterialTheme.colors.secondaryVariant
) {
ProgressBar6UI(
Modifier
.padding(start = 40.dp, end = 40.dp, top = 10.dp)
)
}
Card(
Modifier
.align(BottomCenter)
.fillMaxWidth()
.alpha(if (query.value != "" && !errorMsg.value) 1f else 0f),
backgroundColor = MaterialTheme.colors.secondaryVariant
) {
ProgressBar7UI(
Modifier
.padding(start = 40.dp, end = 40.dp, top = 10.dp)
)
}
}
}
Is there possibly any special way to scroll on clicking an element while using Constraint Layout?
You can use the onGloballyPositioned
modifier to retrieve the position of a composable and then use the method scrollState.animateScrollTo
to scroll to that position.
Something like:
val coroutineScope = rememberCoroutineScope()
val scrollState = rememberScrollState()
var scrollToPosition by remember { mutableStateOf(0F) }
Column(Modifier.verticalScroll(scrollState)) {
Text(
"Click here to scroll",
modifier = Modifier.clickable {
coroutineScope.launch {
scrollState.animateScrollTo(scrollToPosition.roundToInt())
}
}
)
//...
Text(
"Target",
modifier = Modifier.onGloballyPositioned { coordinates ->
scrollToPosition = coordinates.positionInRoot().y
}
)
}