Reputation: 303
My app consists of the home screen and on this screen, there is a button when users click on it they navigate to the login bottom sheet.
I am going to use this login bottom sheet elsewhere in the app so I prefer to make it a separate screen and navigate from home to login.
It is desirable to show the home screen as the background for the login screen. I mean the login bottom sheet's main content should be empty and transparent in order to see the home screen as the background. But instead of the home screen for background, the white background shows up.
Here are my codes:
LoginScreen:
@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)) {
}
}
}
HomeScreen:
@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")
}
}
}
I use navigation like this:
fun interface NavigationDestination {
fun route(): String
val arguments: List<NamedNavArgument>
get() = emptyList()
val deepLinks: List<NavDeepLink>
get() = emptyList()
}
and then Login destination overrides it:
object LoginDestination : NavigationDestination {
override fun route(): String = "login"
}
and here is the implementation of the navigator:
@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
}
and the navigator event is:
sealed class NavigatorEvent {
object NavigateUp : NavigatorEvent()
object PopBackStack : NavigatorEvent()
class Directions(
val destination: String,
val builder: NavOptionsBuilder.() -> Unit
) : NavigatorEvent()
}
Upvotes: 3
Views: 8046
Reputation: 975
this way you can create transparent bottomsheet in compose, extend below 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()
}
}
}
}
}
Upvotes: 1
Reputation: 303
helpinghand You are right about handling the device back button. But now when the user presses the back button only the Login screen's sheet content collapse and the main content of the login screen which is the main content of the home screen remains. In order to it works I don't need the composable callback screen as a parameter for the login screen function and instead, I replace it with another callback like (callback: () -> Unit) and whenever want to get rid of login screen just invoke it in the login screen (for example when clicking outside the bottom sheet or collapsing it) and then in the home screen create a boolean mutable state for detecting when it needs to show the login screen and so in the trailing lambda make the state false.
Upvotes: 0
Reputation: 221
the way you are trying to show the LoginScreen won't work as you expected because when you navigate to LoginScreen it's like opening a new Screen, HomeScreen is then added to the backstack and not shown behind your LoginScreen. To make it work, try like this:
@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")
}
}
}
And change the LoginScreen parameters that you can give it a 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
}
}
And then use it somehow like this:
LoginScreen( /*YourLoginViewModel*/) {
HomeScreen(Modifier, /*YourHomeScreenModel*/){
}
}
Now your bottom sheet is shown all the time, to hide it you need to work with the BottomSheetState collapsed/expanded and the sheetPeekHeight = 400.dp,
which you need to set to 0 that the sheet is hidden completely at first
In the end you need to implement that the BottomSheetState changes on the ButtonClick where you navigated to the Screen in your first attempt
Edit:
Also don't use backgroundColor
. To change the bottomSheets Background you need to use sheetBackgroundColor = Color.Transparent
Upvotes: 2