在Compose中使用带有Button Sticky的CollapsingToolbar

huangapple go评论66阅读模式
英文:

CollapsingToolbar in Compose with Button Sticky

问题

I'm here to provide translations for the text you provided. Here's the translation:

我正在尝试在Compose中实现CollapsingToolbar,但我在互联网上找到的示例不符合我的需求。
我以前使用xml,相同的布局如下:

- AppBarLayout
  - CollapsingToolbarLayout
    - ConstraintLayout
      - ImageView(视差,centerCrop)
      - Toolbar
- NestedScrollView
- FloatingButton(anchorGravity="bottom|end")
- Button(sticky)

我尝试了很多方法,但困难的部分是要有FloatingButton(可以是任何其他视图,不一定是FAB)。

演示:
在Compose中使用带有Button Sticky的CollapsingToolbar

我实现了视差效果如下:

Box(
   modifier = Modifier.graphicsLayer { 
        translationy = -scroll.value.toFloat() / 2f
        alpha = (-1f / headerHeightPx) * scroll.value + 1
   }
) { Image... }

我还找到了Compose Collapsing Toolbar库,但如果可能的话,我更喜欢不使用任何库。

我注意到Material3中有一个TopAppBar,也许它会起作用。

更新

我还尝试了Material3库,但效果不如预期,因为我的行为不符合预期。

我考虑创建一个Box,或者因为我想要阴影效果,可以创建一个Surface,在其中包含Icon和Image,以及中心的Box。

我创建了一个简单的图像来描述我的想法,也许这是一个好的开始。
在Compose中使用带有Button Sticky的CollapsingToolbar

在这里,我需要将列表的滚动链接到.value,以创建动画或更改Image的Alpha(或视差效果),然后一旦折叠,就向Surface添加阴影。

在第二张图中,中心的框没有以相同的方式对齐,但我不想更改它,这是一个绘制错误。

所以总结一下:

创建这个Composable并“伪造”TopAppBar,以便在高度达到56.dp时停止“折叠”。

滚动时,Image应该执行动画或更改其Alpha(或视差效果),然后将背景转换为白色作为过渡。

然后我看到的问题是,我需要添加一些计算来检测exitUntilCollapsed的行为,比如说我想要在列表的第一个项目可见时“取消折叠”。

英文:

I'm trying to implement the CollapsingToolbar in Compose but the examples I've found through the internet don't accomplish my needs.
I used to use xml and the same layout was :

-AppBarLayout
  -CollapsingToolbarLayout
    -ConstraintLayout
      -ImageView(parallax, centerCrop)
      -Toolbar
-NestedScrollView
-FloatingButton (anchorGravity="bottom|end")
-Button(sticky)

I've tried many things, but the hard thing is to have the FloatingButton (can be any other view not specially a FAB).

Demo :

在Compose中使用带有Button Sticky的CollapsingToolbar

The parallax effect I did it as follows :

Box(
   modifier = Modifier.graphicsLayer { 
        translationy = -scroll.value.toFloat() / 2f
        alpha = (-1f / headerHeightPx) * scroll.value + 1
   }
) { Image... }

I also found the Compose Collapsing Toolbar library but I'd prefer to not use any library if possible.

I've seen that there's a Material3 there's a TopAppBar and perhaps it would work.

Update

I've also tried the Material3 library but is not working as expected since my behaviour is breaking the how it should be.

What I'm thinking is to create a Box or since I want elevation a Surface and on it, contain inside the Icon and the Image and also the center Box.

I've created a simple image to describe what I've thought and perhaps is a good way to start.

在Compose中使用带有Button Sticky的CollapsingToolbar

Here I'd need to link the scroll of the List and with the .value create the animation or change the Alpha of the Image and then once is collapsed add the elevation to the Surface.

In the second image the center box is not aligned the same way, but I don't want to change it, it was a miss paint.

So the recap should be :

Create this Composable and fake the TopAppBar so it should stop collapsing when the height is 56.dp as the min size of the TopAppBar.

When scrolling the Image should animate or change it's alpha (or parallax effect) and then convert the background to white as a transition.

And then the problem I'm seeing is that I'd need to add some calculations to detect the behaviour of exitUntilCollapsed let's say I want to un-collapse once the first item of the list is visible.

答案1

得分: 1

根据您的绘图建议,我尝试了一下:

import androidx.compose.animation.core.animateDpAsState
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Divider
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Alignment.Companion.BottomCenter
import androidx.compose.ui.Alignment.Companion.Center
import androidx.compose.ui.Alignment.Companion.CenterVertically
import androidx.compose.ui.Alignment.Companion.TopStart
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.max
import com.canopas.base.ui.AppTheme
import com.canopas.base.ui.ColorPrimary
import com.canopas.base.ui.White
import com.canopas.ui.R
import kotlin.math.min

Column(modifier = Modifier.fillMaxSize()) {
    val items = (1..100).map { "Item $it" }
    val lazyListState = rememberLazyListState()
    val scrollOffset: Float = min(
        1f,
        1 - (lazyListState.firstVisibleItemScrollOffset / 200f + lazyListState.firstVisibleItemIndex)
    )
    val imageSize by animateDpAsState(targetValue = max(0.dp, 300.dp * scrollOffset))
    Box(contentAlignment = Center) {
        Image(
            painterResource(id = R.drawable.ic_intro_screen_image1),
            modifier = Modifier.size(imageSize),
            contentScale = ContentScale.FillWidth,
            contentDescription = "Food Category thumbnail"
        )
        Row(
            Modifier
                .height(56.dp)
                .background(Color.White).align(BottomCenter),
            horizontalArrangement = Arrangement.Center, verticalAlignment = CenterVertically
        ) {
            Text(text = "Title", modifier = Modifier.padding(vertical = 12.dp).fillMaxSize(), textAlign = TextAlign.Center)
        }
        IconButton(onClick = { /*TODO*/ }, modifier = Modifier.align(TopStart)) {
            Icon(imageVector = Icons.Default.ArrowBack, contentDescription = "")
        }
    }

    LazyColumn(
        Modifier
            .fillMaxWidth()
            .weight(1f),
        lazyListState,
    ) {
        items(items) {
            Text(
                text = it,
                Modifier
                    .background(Color.White)
                    .fillMaxWidth()
                    .padding(8.dp)
            )
        }
    }

    Column(
        modifier = Modifier.fillMaxWidth(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Divider(modifier = Modifier.fillMaxWidth(), color = ColorPrimary)
        Spacer(modifier = Modifier.height(10.dp))
        Button(
            onClick = {
            },
            shape = RoundedCornerShape(25.dp),
            colors = ButtonDefaults.buttonColors(
                backgroundColor = ColorPrimary,
            ),
            elevation = ButtonDefaults.elevation(
                defaultElevation = 0.dp,
                pressedElevation = 0.dp,
                disabledElevation = 0.dp,
                hoveredElevation = 0.dp,
                focusedElevation = 0.dp
            ),
            modifier = Modifier
                .wrapContentHeight()
        ) {
            Text(
                text = "Button",
                color = White,
                style = AppTheme.typography.buttonStyle,
                modifier = Modifier.padding(vertical = 6.dp)
            )
        }
        Spacer(modifier = Modifier.height(10.dp))
    }
}

在Compose中使用带有Button Sticky的CollapsingToolbar


[1]: https://i.stack.imgur.com/zpjhC.gif
<details>
<summary>英文:</summary>
Just gave it a try according to your drawing suggestions:

import androidx.compose.animation.core.animateDpAsState
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Divider
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Alignment.Companion.BottomCenter
import androidx.compose.ui.Alignment.Companion.Center
import androidx.compose.ui.Alignment.Companion.CenterVertically
import androidx.compose.ui.Alignment.Companion.TopStart
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.max
import com.canopas.base.ui.AppTheme
import com.canopas.base.ui.ColorPrimary
import com.canopas.base.ui.White
import com.canopas.ui.R
import kotlin.math.min

Column(modifier = Modifier.fillMaxSize()) {
val items = (1..100).map { "Item $it" }
val lazyListState = rememberLazyListState()
val scrollOffset: Float = min(
1f,
1 - (lazyListState.firstVisibleItemScrollOffset / 200f + lazyListState.firstVisibleItemIndex)
)
val imageSize by animateDpAsState(targetValue = max(0.dp, 300.dp * scrollOffset))
Box(contentAlignment = Center) {
Image(
painterResource(id = R.drawable.ic_intro_screen_image1),
modifier = Modifier.size(imageSize),
contentScale = ContentScale.FillWidth,
contentDescription = "Food Category thumbnail"
)
Row(
Modifier
.height(56.dp)
.background(Color.White).align(BottomCenter),
horizontalArrangement = Arrangement.Center, verticalAlignment = CenterVertically
) {
Text(text = "Title", modifier = Modifier.padding(vertical = 12.dp).fillMaxSize(), textAlign = TextAlign.Center)
}
IconButton(onClick = { /TODO/ }, modifier = Modifier.align(TopStart)) {
Icon(imageVector = Icons.Default.ArrowBack, contentDescription = "")
}
}

    LazyColumn(
Modifier
.fillMaxWidth()
.weight(1f),
lazyListState,
) {
items(items) {
Text(
text = it,
Modifier
.background(Color.White)
.fillMaxWidth()
.padding(8.dp)
)
}
}
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Divider(modifier = Modifier.fillMaxWidth(), color = ColorPrimary)
Spacer(modifier = Modifier.height(10.dp))
Button(
onClick = {
},
shape = RoundedCornerShape(25.dp),
colors = ButtonDefaults.buttonColors(
backgroundColor = ColorPrimary,
),
elevation = ButtonDefaults.elevation(
defaultElevation = 0.dp,
pressedElevation = 0.dp,
disabledElevation = 0.dp,
hoveredElevation = 0.dp,
focusedElevation = 0.dp
),
modifier = Modifier
.wrapContentHeight()
) {
Text(
text = &quot;Button&quot;,
color = White,
style = AppTheme.typography.buttonStyle,
modifier = Modifier.padding(vertical = 6.dp)
)
}
Spacer(modifier = Modifier.height(10.dp))
}
}

[![enter image description here][1]][1]
[1]: https://i.stack.imgur.com/zpjhC.gif
</details>

huangapple
  • 本文由 发表于 2023年5月25日 03:13:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76326733.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定