我的应用程序由主屏幕组成,在这个屏幕上,有一个按钮,当用户点击它时,他们会导航到登录底页。
我打算在应用程序的其他地方使用这个登录底页,所以我更喜欢把它做成一个单独的屏幕,然后从主页导航到登录。
希望将主屏幕显示为登录屏幕的背景。我的意思是登录底部表单的主要内容应该是空的和透明的,以便将主屏幕视为背景。但是显示的不是背景的主屏幕,而是白色背景。
这是我的代码:
登录屏幕:
@Composable
fun LoginScreen(
loginViewModel: LoginViewModel = hiltViewModel()
) {
val bottomSheetScaffoldState = rememberBottomSheetScaffoldState(
bottomSheetState = BottomSheetState(BottomSheetValue.Collapsed)
)
val coroutineScope = rememberCoroutineScope()
BottomSheetScaffold(
scaffoldState = bottomSheetScaffoldState,
sheetContent = {
LoginContent()
},
sheetPeekHeight = 400.dp,
sheetShape = RoundedCornerShape(topEnd = 52.dp, topStart = 52.dp),
backgroundColor = Color.Transparent
) {
Box(modifier = Modifier.fillMaxSize().background(color = Color.Transparent)) {
}
}
}
主屏幕:
@Composable
fun HomeScreen(
modifier: Modifier = Modifier,
viewModel: HomeViewModel = hiltViewModel(),
) {
Column(
modifier = Modifier
.fillMaxSize()
.background(color = Color.White)
) {
somecontent
...
...
...
Button(onClick = {
viewModel.navigate(
LoginDestination.route()
)
}) {
Text("Go to the login screen")
}
}
}
我这样使用导航:
fun interface NavigationDestination {
fun route(): String
val arguments: List<NamedNavArgument>
get() = emptyList()
val deepLinks: List<NavDeepLink>
get() = emptyList()
}
然后登录目标覆盖它:
object LoginDestination : NavigationDestination {
override fun route(): String = "login"
}
这里是导航器的实现:
@Singleton
internal class ClientNavigatorImpl @Inject constructor() : ClientNavigator {
private val navigationEvents = Channel<NavigatorEvent>()
override val destinations = navigationEvents.receiveAsFlow()
override fun navigateUp(): Boolean =
navigationEvents.trySend(NavigatorEvent.NavigateUp).isSuccess
override fun popBackStack(): Boolean =
navigationEvents.trySend(NavigatorEvent.PopBackStack).isSuccess
override fun navigate(route: String, builder: NavOptionsBuilder.() -> Unit): Boolean =
navigationEvents.trySend(NavigatorEvent.Directions(route, builder)).isSuccess
}
导航器事件是:
sealed class NavigatorEvent {
object NavigateUp : NavigatorEvent()
object PopBackStack : NavigatorEvent()
class Directions(
val destination: String,
val builder: NavOptionsBuilder.() -> Unit
) : NavigatorEvent()
}
您尝试显示 LoginScreen 的方式不会像您预期的那样工作,因为当您导航到 LoginScreen 时,就像打开一个新屏幕一样,然后将 HomeScreen 添加到后台堆栈,而不是在您的 LoginScreen 后面显示。要让它工作,请像这样尝试:
@Composable
fun HomeScreen(
modifier: Modifier = Modifier,
viewModel: HomeViewModel = hiltViewModel(),
) {
Column(
modifier = Modifier
.fillMaxSize()
.background(color = Color.White)
) {
Button(onClick = {
//TODO: Add functionality
}) {
Text("Go to the login screen")
}
}
}
并更改 LoginScreen 参数,您可以给它一个 Composable:
@Composable
fun LoginScreen(
loginViewModel: LoginViewModel = hiltViewModel(),
screen: @Composable (() -> Unit)
) {
val bottomSheetScaffoldState = rememberBottomSheetScaffoldState(
bottomSheetState = BottomSheetState(BottomSheetValue.Collapsed)
)
val coroutineScope = rememberCoroutineScope()
BottomSheetScaffold(
scaffoldState = bottomSheetScaffoldState,
sheetContent = {
//The Login Content needs to be here
*EDIT*
BackHandler(enabled = true) {
coroutineScope.launch {
bottomSheetScaffoldState.bottomSheetState.collapse()
}
}
*EDIT*
},
sheetPeekHeight = 400.dp,
sheetShape = RoundedCornerShape(topEnd = 52.dp, topStart = 52.dp),
backgroundColor = Color.Transparent
) {
screen() //Adds the content which is shown on the Screen behind bottomsheet
}
}
然后像这样使用它:
LoginScreen( /*YourLoginViewModel*/) {
HomeScreen(Modifier, /*YourHomeScreenModel*/){
}
}
现在你的底部工作表一直显示,要隐藏它你需要使用 BottomSheetState 折叠/展开和你需要设置为 0 的
sheetPeekHeight = 400.dp,
工作表首先完全隐藏
最后,您需要在第一次尝试导航到屏幕的 ButtonClick 上实现 BottomSheetState 更改
编辑: 也不要使用
backgroundColor
。要更改 bottomSheets 背景,您需要使用 sheetBackgroundColor = Color.Transparent
helpinghand 你对处理设备后退按钮是正确的。但是现在,当用户按下后退按钮时,只有登录屏幕的工作表内容会折叠,而登录屏幕的主要内容(主屏幕的主要内容)仍然存在。为了让它工作,我不需要可组合的回调屏幕作为登录屏幕功能的参数,而是将其替换为另一个回调,如 (callback: () -> Unit) 并且每当想要摆脱登录屏幕时只需在登录屏幕中调用它(例如,在底部工作表外部单击或折叠它时),然后在主屏幕中创建一个布尔可变状态,用于检测何时需要显示登录屏幕,因此在尾随的 lambda 中创建状态假的。
这样你就可以在 compose 中创建透明的 bottomsheet, 延伸到 custombottomsheet 下方
abstract class CustomBottomSheeet :
BottomSheetDialogFragment() {
var isDraggable: Boolean = true
abstract fun init()
@Composable
abstract fun BuildContentComposable()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
dialog?.let {
val sheet = it as BottomSheetDialog
sheet.behavior.state = BottomSheetBehavior.STATE_EXPANDED
sheet.behavior.peekHeight =
Resources.getSystem().displayMetrics.heightPixels
sheet.behavior.isDraggable = isDraggable
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState)
dialog.setOnShowListener {
//this line transparent your dialog background
(view?.parent as ViewGroup).background =
ColorDrawable(android.graphics.Color.TRANSPARENT)
}
return dialog
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = ComposeView(requireContext()).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
BottomSheetTop {
BuildContentComposable()
}
}
}
init()
return view
}
@Preview
@Composable
private fun Preview(){
BottomSheetTop(){}
}
@Composable
private fun BottomSheetTop(content: @Composable () -> Unit) {
Box(modifier = Modifier
.fillMaxWidth()
.background(
colorResource(id = R.color.transparent),
shape = RoundedCornerShape(topStart = 14.sdp, topEnd = 14.sdp)
)
.clip(RoundedCornerShape(topStart = 14.sdp, topEnd = 14.sdp))
) {
ConstraintLayout(
modifier = Modifier
.fillMaxWidth()
.background(color = colorResource(id = R.color.transparent))
) {
val (topImage, contentView) = createRefs()
// ImageViewCustomPainterSource(painterResource = R.drawable.bg_transparent,modifier = Modifier.fillMaxSize())
Box(
modifier = Modifier
.width(40.sdp)
.height(3.sdp)
.constrainAs(topImage) {
top.linkTo(parent.top)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
.background(
colorResource(id = R.color.white),
shape = RoundedCornerShape(20.sdp)
)
)
val marginHorizontal = 6.sdp
val marginTop = 4.sdp
val marginBottom = 10.sdp
Box(modifier = Modifier.background(color = colorResource(id = R.color.white),shape = RoundedCornerShape(14.sdp))
.padding(start = 4.sdp, end = 4.sdp, top = 6.sdp, bottom = 10.sdp)
.constrainAs(contentView) {
start.linkTo(parent.start,marginHorizontal)
end.linkTo(parent.end,marginHorizontal)
top.linkTo(topImage.bottom,marginTop)
bottom.linkTo(parent.bottom,marginBottom)
width = Dimension.fillToConstraints
}) {
content()
}
}
}
}
}