I am trying to position a composable to remain at the bottom of the screen. In my case a banner ad.
I tried puting it inside a column and giving it a vertical arrangement of bottom, still no difference.
...
Column(
verticalArrangement = Arrangement.Bottom,
modifier = Modifier
.fillMaxWidth()
) {
// calling method to display banner UI
AdvertView()
}
...
For some reason this doesn't show the banner ad.
I even tried using weights (which I'm not familiar with) still no difference.
AdvertView(Modifier.weight(1f))
#Composable
fun HomeText() {
Column(
modifier = Modifier.fillMaxWidth()
) {
Column(
modifier = Modifier
.fillMaxWidth()
//.fillMaxHeight()
) {
Text(
text = stringResource(R.string.home_text),
style = MaterialTheme.typography.h2,
modifier = Modifier
.paddingFromBaseline(top = 24.dp, bottom = 18.dp)
.padding(horizontal = 18.dp)
.heightIn(min = 56.dp)
)
}
AdvertView(Modifier.weight(1f))
}
}
For some reason this actually makes the banner ad come down a little but still not there yet.
I'd like to think I'm the one not including something or doing something wrong. If that's the case please I'd appreciate your correction. Or if not, I'd like to know how to position the banner at the bottom of the screen.
Please remember this is a banner ad so it overlays the content at the bottom, I think. (this is my first time.. I stand corrected)
Thanks for your help in Advance.. I sincerely appreciate it. Thanks.
You have to use a Column and then set the main content's modifier to use weight(1f) and then add the banner after the main content. Using weight will ensure that the content takes all available space after the banner has been measured.
#Preview(widthDp = 420)
#Preview(widthDp = 420, uiMode = UI_MODE_NIGHT_YES)
#Composable
private fun ComposeSandboxPreview() {
Theme {
Surface(color = Theme.colors.background) {
Column(
modifier = Modifier.fillMaxSize(),
) {
Content(
modifier = Modifier
.fillMaxWidth()
.weight(1f),
)
AdvertView(modifier = Modifier.fillMaxWidth())
}
}
}
}
#Composable
fun Content(modifier: Modifier = Modifier) {
Box(
modifier = modifier.background(Color.Red),
contentAlignment = Alignment.Center
) {
Text(
text = "This is the content"
)
}
}
#Composable
fun AdvertView(modifier: Modifier = Modifier) {
Text(
text = "This is the banner",
textAlign = TextAlign.Center,
modifier = modifier.background(Color.Blue),
)
}
Related
my question is different from the suggested question that is similar because I am making the voting bar change in effect from the parameters of the voting percentage. therefore I need the left column to change dynamically in size and the right column to change dynamically in size therefore I find it difficult to implement with a Stroke object.
what is the attribute of the modifier that I need to change to make the corners round? and the width a little smaller of a Row() element
I am trying to make an android app with jetpack compose,
in the process of implementing the Voting bar which is the bar in the middle with the 2 colors of red and blue.
I can't find the correct attribute to modify so the corners of the bar will be rounded and make the width different from .fillMaxWidth() in the modifier so I ended up using it until I will find a solution.
if you have any insights :) thanks in advance ~!
Figma Design
implementation in android
my code
#Composable
fun VotingBar(
modifier: Modifier = Modifier, leftyPercent: Int, rightyPercent: Int
) {
var leftyPercentWeight: Float = (leftyPercent / 10).toFloat()
var rightyPercentWeight: Float = (rightyPercent / 10).toFloat()
Row(
modifier = modifier
.fillMaxWidth()
.height(50.dp)
.background(Color.White)
.border(1.dp, Color.Black, CircleShape)
) {
Column(
// add rounded corners to the left side
modifier = Modifier
.background(Color(0xFFA60321))
.height(50.dp)
.weight(leftyPercentWeight)
.clip(CircleShape),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
}
Column(
modifier = Modifier
.background(Color(0xFF03588C))
.height(50.dp)
.weight(rightyPercentWeight)
.clip(CircleShape),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
// add rounded corners to the right side
) {}
}
Row(
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.background(Color.White),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
) {
Row {
Box(
modifier = Modifier
.size(30.dp)
.clip(CircleShape)
.background(Color(0xFFA60321))
)
Spacer(modifier = Modifier.width(10.dp))
Text(
text = "Right $rightyPercent%", fontSize = 20.sp, fontWeight = FontWeight.Bold
)
}
Row() {
Box(
modifier = Modifier
.size(30.dp)
.clip(CircleShape)
.background(Color(0xFF03588C))
)
Spacer(modifier = Modifier.width(10.dp))
Text(
text = "Left $leftyPercent%", fontSize = 20.sp, fontWeight = FontWeight.Bold
)
}
}
}
I followed the 5 steps tutorial at the leading developer's website but I fill still a beginner.
You can wrap the 2 Row in a Column applying a padding modifier (to avoid the full width) and an horizontalAlignment.
Then in the 1st Row apply a clip modifier to achieve the rounded shape.
Something like:
val shape = RoundedCornerShape(32.dp)
Column(
Modifier.padding(16.dp),
horizontalAlignment= Alignment.CenterHorizontally
) {
Row(
modifier = modifier
.fillMaxWidth()
.height(32.dp)
.background(Color.White)
.clip(shape)
.border(1.dp, Color.Black, shape)
) {
Column(
// add rounded corners to the left side
modifier = Modifier
.background(Color(0xFFA60321))
.weight(leftyPercentWeight)
.clip(CircleShape),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
}
Column(
modifier = Modifier
.background(Color(0xFF03588C))
.weight(rightyPercentWeight)
.clip(CircleShape),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
// add rounded corners to the right side
) {}
}
//2nd Row
}
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()}
}
}
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.
Why the composable Icon does not appear?
The Cardcontent composable is FillMaxWidth
I want the "Cardcontent" composable to do fillMaxWidth inside the "Cardtest" composable taking into account the "Icon" composable
#Preview
#Composable
fun Icon () {
Image(painter = painterResource(id = R.drawable.icon),
contentDescription ="Icon",
modifier = Modifier.
size(width = 40.dp,
height = 40.dp) )
}
#Preview
#Composable
fun Cardcontent (){
Row (horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth())
{
Avatar()
TextDesc()
}
}
#Preview
#Composable
fun CardTest(){
Row(Modifier
.width(310.dp)
.padding(start = 16.dp)
.padding(vertical = 13.dp),
verticalAlignment = Alignment.CenterVertically)
{
Cardcontent()
Icon()
}
}
Agree with ADM opinion, you must pass the modifier as an argument of CardContent() and that's mandatory, because in order to asign a weight(1f) modifier to your CardContent component, the declaration must be within the scope of a Column or Row, because of possible reusability, you CardContent component could be used in a Box or scaffold in the future, and weight doesn't apply for this components, so imagine that having it declared inside of the CardContent as default weight and then placing it inside of those examples would be useless and give you a sintax error, so finally you must do something like this:
fun CardTest(){
Row(
Modifier
.width(310.dp)
.padding(start = 16.dp)
.padding(vertical = 13.dp),
verticalAlignment = Alignment.centerVertically
)
{
Cardcontent(modifier = Modifier.weight(1f))
Icon()
}
}
You should in CardContend insert argument wherein you hand over component Icon
The following Code A is from the official sample project.
I think Code A is wrong, I think there are two Images in the line, the left image is a real image which is displayed when it has been loaded, and the right image is a temp image which is displayed when the real iamge is loading.
So I replace Code A with Code B.
But in fact the UI displays a temp image named ic_crane_logo first, then displays real image as I expected when I run Code A. And the UI keeps to display the temp iamge when I run Code B.
What is the problem with my thinking and code?
Code A
Row(
modifier = modifier
.clickable { onItemClicked(item) }
.padding(top = 12.dp, bottom = 12.dp)
) {
ExploreImageContainer {
Box {
val painter = rememberImagePainter(
data = item.imageUrl,
builder = {
crossfade(true)
}
)
Image(
painter = painter,
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize(),
)
if (painter.state is ImagePainter.State.Loading) {
Image(
painter = painterResource(id = R.drawable.ic_crane_logo),
contentDescription = null,
modifier = Modifier
.size(36.dp)
.align(Alignment.Center),
)
}
}
}
...
}
Code B
Row(
modifier = modifier
.clickable { onItemClicked(item) }
.padding(top = 12.dp, bottom = 12.dp)
) {
ExploreImageContainer {
Box {
val painter = rememberImagePainter(
data = item.imageUrl,
builder = {
crossfade(true)
}
)
if (painter.state is ImagePainter.State.Success){
Image(
painter = painter,
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize(),
)
}else{
Image(
painter = painterResource(id = R.drawable.ic_crane_logo),
contentDescription = null,
modifier = Modifier
.size(36.dp)
.align(Alignment.Center),
)
}
}
}
...
}
rememberImagePainter does not start loading an image.
It only starts when the corresponding Image is added to the view tree and has non-zero dimensions.
As long as it is not loaded, Image is a transparent view, and you get no performance gain by removing it from the view tree, so part Code A is completely correct.