I'm developing an Android app that follows the single activity pattern. In one of my fragments I have a RecyclerView and in the case where the user scrolls down I want to hide my BottomNavigationView.
I have already seen other posts about this matter but none of them seems to help my with my issue. So far I've tried making the bottom nav view and my host fragment childs of CoordinatorLayout as well as adding the app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior" property on my BottomNavigationView. I have also tried to implement this behaviour manually in code but that is not working either.
Here is my activity.xml which contains my BottomNavigationView and my host fragment.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.MainActivity">
<fragment
android:id="#+id/fragmentMaster"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="#id/bottomNav"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="#navigation/nav_graph" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="#menu/menu_bottom_nav">
</com.google.android.material.bottomnavigation.BottomNavigationView>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
And this is the fragment with the RecyclerView
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/topAppBar"
style="#style/Widget.MaterialComponents.Toolbar.Primary"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll"
app:title="#string/app_name" />
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFFFFF"
android:scrollbars="none"
app:layout_scrollFlags="scroll">
<com.google.android.material.chip.ChipGroup
android:id="#+id/filterChips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp"
app:singleLine="true">
<com.google.android.material.chip.Chip
android:id="#+id/breakfastChip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checkable="true"
android:text="#string/breakfast" />
<com.google.android.material.chip.Chip
android:id="#+id/mealChip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checkable="true"
android:text="#string/meal" />
<com.google.android.material.chip.Chip
android:id="#+id/dinnerChip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checkable="true"
android:text="#string/dinner" />
<com.google.android.material.chip.Chip
android:id="#+id/veganChip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checkable="true"
android:text="#string/vegan" />
<com.google.android.material.chip.Chip
android:id="#+id/vegetarianChip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checkable="true"
android:text="#string/vegetarian" />
<com.google.android.material.chip.Chip
android:id="#+id/regularChip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checkable="true"
android:text="#string/regular" />
</com.google.android.material.chip.ChipGroup>
</HorizontalScrollView>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recipeList"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:listitem="#layout/item_recipe_list">
</androidx.recyclerview.widget.RecyclerView>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/newRecipeBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:contentDescription="#string/add_recipe"
android:src="#drawable/ic_baseline_add_24">
</com.google.android.material.floatingactionbutton.FloatingActionButton>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>
Edit: The issue was that the inner CoordinatorLayout was consuming the scroll event and so the AppBarLayout worked as expected, but the outer CoordinatorLayout that manages the BottomNavView never received the scroll notification. The solution is to overwrite the CoordinatorLayout implementation so that it propagates to the parent CoordinatorLayout.
Preview
Create kotlin class NavigationViewBehavior.kt
import android.view.View
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.ViewCompat
import androidx.core.view.ViewCompat.NestedScrollType
import com.google.android.material.bottomnavigation.BottomNavigationView
class NavigationViewBehavior : CoordinatorLayout.Behavior<BottomNavigationView>() {
private var height = 0
override fun onLayoutChild(parent: CoordinatorLayout, child: BottomNavigationView, layoutDirection: Int): Boolean {
height = child.height
return super.onLayoutChild(parent, child, layoutDirection)
}
override fun onStartNestedScroll(coordinatorLayout: CoordinatorLayout,
child: BottomNavigationView, directTargetChild: View, target: View,
axes: Int, type: Int): Boolean {
return axes == ViewCompat.SCROLL_AXIS_VERTICAL
}
override fun onNestedScroll(coordinatorLayout: CoordinatorLayout, child: BottomNavigationView,
target: View, dxConsumed: Int, dyConsumed: Int,
dxUnconsumed: Int, dyUnconsumed: Int,
#NestedScrollType type: Int) {
if (dyConsumed > 0) {
slideDown(child)
} else if (dyConsumed < 0) {
slideUp(child)
}
}
private fun slideUp(child: BottomNavigationView) {
child.clearAnimation()
child.animate().translationY(0f).duration = 200
}
private fun slideDown(child: BottomNavigationView) {
child.clearAnimation()
child.animate().translationY(height.toFloat()).duration = 200
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/business_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hardwareAccelerated="true">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="#+id/coordinator_business_layout"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<FrameLayout
android:id="#+id/frame_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="?actionBarSize"
android:orientation="vertical">
<fragment
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/mobile_navigation"
tools:ignore="FragmentTagUsage" />
</FrameLayout>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/nav_view"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_gravity="bottom"
android:background="#color/colorWhite"
app:itemBackground="#drawable/border_bottom_ver"
app:itemIconTint="#drawable/tab_color"
app:itemTextColor="#drawable/tab_color"
app:menu="#menu/bottom_nav_menu" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
call in MainActivity.kt
val navController = Navigation.findNavController(this,
R.id.nav_host_fragment)
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration!!)
NavigationUI.setupWithNavController(navView!!, navController)
val layoutParams = navView!!.getLayoutParams() as CoordinatorLayout.LayoutParams
layoutParams.behavior = NavigationViewBehavior()
val params = frameLayout.layoutParams as ViewGroup.MarginLayoutParams
//hide bottom navigation no need while sun activities are being used
navController.addOnDestinationChangedListener { controller: NavController?,
destination: NavDestination, arguments: Bundle? ->
if (destination.id == R.id.navigation_fragments ) {
params.setMargins(0, 0, 0, 0)
frameLayout.layoutParams = params
navView!!.setVisibility(View.GONE)
} else {
params.setMargins(0, 0, 0, 160)
frameLayout.layoutParams = params
navView!!.setVisibility(View.VISIBLE)
}
}
home_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rvServices"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
android:visibility="visible" />
<TextView
android:id="#+id/no_values_assigned_message"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:text="#string/no_values_assigned"
android:textSize="#dimen/fontSizeReg"
android:textStyle="bold"
android:visibility="gone" />
</androidx.constraintlayout.widget.ConstraintLayout>
this is the setting my RecyclerView
private fun RecyclerSetting(view: View) {
no_value = view.findViewById(R.id.no_values_assigned_message)
rvItem = view.findViewById(R.id.rvServices)
rvItem!!.setHasFixedSize(true)
//Very IMP This Line
val manager = GridLayoutManager(activity, 2,
GridLayoutManager.VERTICAL,
false)
data
rvItem!!.setLayoutManager(manager)
}
while you scroll recycler view auto-hide and also you can hide bottom navigation from specific Fragment code included
Related
I have a HomeActivity which initiates the ActionBarDrawerToggle as follows:
private fun initDrawer() {
val toolbar = binding.fragmentHomeContainerView.findViewById<MaterialToolbar>(R.id.toolbar)
setSupportActionBar(toolbar)
drawerToggle = ActionBarDrawerToggle(
this,
binding.drawer,
toolbar,
R.string.open_drawer,
R.string.close_drawer
)
binding.drawer.addDrawerListener(drawerToggle)
drawerToggle.syncState()
supportActionBar?.setDisplayHomeAsUpEnabled(true)
binding.navigationView.setNavigationItemSelectedListener {
handleNavigationItemSelected(it)
true
}
}
The toolbar in question is inside a Fragment. Everything's normal and working until here, the toolbar is like Gmail's search with the hamburguer icon. But when I navigate to another fragment (that doesn't have this toolbar, but instead has an arrow back button), and then navigate back again to the first fragment (the one that has the toolbar) the icon doesn't work anymore. What's the best/correct solution for this? I've tried moving the initDrawer() function within the fragment but the application frozes when creating the ActionBarDrawerToggle I assume because of the activity passed to the ActionBarDrawerToggle
drawerToggle = ActionBarDrawerToggle(
activity = (requireActivity() as HomeActivity),
...
)
Moving the toolbar from the Fragment to the Activity isn't a solution neither, not because it doesn't fix the problem (which I'm not sure) but because I need the toolbar inside the fragment.
Minimal reproducible code:
MainActivity.kt:
class MainActivity : AppCompatActivity() {
private val binding: ActivityMainBinding by lazy {
ActivityMainBinding.inflate(layoutInflater)
}
private lateinit var drawerToggle: ActionBarDrawerToggle
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
}
override fun onStart() {
super.onStart()
initDrawer()
}
private fun initDrawer() {
val toolbar = binding.fragmentContainerView.findViewById<MaterialToolbar>(R.id.toolbar)
setSupportActionBar(toolbar)
drawerToggle = ActionBarDrawerToggle(
this,
binding.drawer,
toolbar,
R.string.app_name,
R.string.app_name
)
binding.drawer.addDrawerListener(drawerToggle)
drawerToggle.syncState()
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/fragmentContainerView"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="#navigation/nav_home" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.navigation.NavigationView
android:id="#+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:clipToPadding="false"
android:visibility="visible" />
</androidx.drawerlayout.widget.DrawerLayout>
Fragment1.kt:
class Fragment1 : Fragment(R.layout.fragment_1) {
private val binding: Fragment1Binding by lazy {
Fragment1Binding.bind(requireView())
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.button.setOnClickListener {
navigateToFragment2()
}
}
private fun navigateToFragment2() {
val action = R.id.navigateToFragment2
Navigation.findNavController(requireView()).navigate(action)
}
}
fragment_1.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/entity_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Fragment1">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:background="#android:color/transparent"
android:elevation="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_scrollFlags="scroll|enterAlways|snap"
app:liftOnScroll="true">
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_gravity="center"
android:layout_margin="6dp"
android:background="#drawable/rounded_toolbar"
android:elevation="6dp"
android:minHeight="?attr/actionBarSize"
app:contentInsetStart="0dp"
app:contentInsetStartWithNavigation="0dp"
app:navigationIcon="#drawable/ic_baseline_menu_24"
app:titleTextColor="#android:color/white">
<EditText
android:id="#+id/entities_search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autofillHints="Search for client"
android:background="#android:color/transparent"
android:hint="search"
android:inputType="textPersonName"
android:minHeight="48dp"
android:textColorHint="#color/black" />
</com.google.android.material.appbar.MaterialToolbar>
</com.google.android.material.appbar.AppBarLayout>
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Navigate to fragment 2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/appBarLayout" />
</androidx.constraintlayout.widget.ConstraintLayout>
Fragment2.kt:
class Fragment2 : Fragment(R.layout.fragment_2) {
private val binding: Fragment2Binding by lazy {
Fragment2Binding.bind(requireView())
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setActionBarAction()
}
private fun setActionBarAction() {
val action = R.id.navigateToFragment1
binding.toolbar.setOnClickListener {
Navigation.findNavController(it).navigate(action)
}
}
}
fragment_2.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Fragment2">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginStart="4dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="#android:color/transparent"
android:elevation="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_scrollFlags="scroll|enterAlways|snap"
app:liftOnScroll="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/toolbar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center|start"
android:clickable="true"
android:focusable="true"
android:minHeight="?attr/actionBarSize"
app:contentInsetStartWithNavigation="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navigationIcon="#drawable/ic_baseline_chevron_left_32"
app:titleTextColor="#android:color/white">
</com.google.android.material.appbar.MaterialToolbar>
<com.google.android.material.textview.MaterialTextView
android:id="#+id/app_bar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="34sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.appbar.AppBarLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Navigate back with the arrow button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
nav_home.xml:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/nav_home"
app:startDestination="#id/fragment1">
<fragment
android:id="#+id/fragment1"
android:name="com.example.myapplication.Fragment1"
android:label="fragment_1"
tools:layout="#layout/fragment_1" >
<action
android:id="#+id/navigateToFragment2"
app:destination="#id/fragment2" />
</fragment>
<fragment
android:id="#+id/fragment2"
android:name="com.example.myapplication.Fragment2"
android:label="fragment_2"
tools:layout="#layout/fragment_2" >
<action
android:id="#+id/navigateToFragment1"
app:destination="#id/fragment1" />
</fragment>
</navigation>
In my past project from the beggining of the year I have set the content of my drawerHeader in the mainActivity code. I am rewriting it and now it seems impossible to access the header through binding in MainActivity.
I have a usual drawer layout in the activity -> navigation view -> drawer header.
I used to access it through simple binding.layoutDrawer.userDataHeader but it doesn't find userDataHeader no matter what I do. What am I doing wrong?
main activity layout
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="mainActivity"
type="com.kerubyte.engagecommerce.presentation.ui.activity.MainActivity" />
</data>
<androidx.drawerlayout.widget.DrawerLayout
android:id="#+id/layout_drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".presentation.ui.activity.MainActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/layout_activity_main_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".presentation.ui.activity.MainActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/layout_actionbar_root"
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
android:background="#color/primaryColor"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="#+id/image_open_drawer_action"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="10dp"
android:onClick="#{() -> mainActivity.openDrawerMenu()}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/ic_hamburger" />
<ImageView
android:id="#+id/image_open_profile_action"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginEnd="24dp"
android:onClick="#{() -> mainActivity.onProfileClick()}"
app:layout_constraintBottom_toBottomOf="#+id/image_open_cart_action"
app:layout_constraintEnd_toStartOf="#+id/image_open_cart_action"
app:layout_constraintTop_toTopOf="#+id/image_open_cart_action"
app:srcCompat="#drawable/ic_person" />
<ImageView
android:id="#+id/image_open_cart_action"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginEnd="12dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/ic_cart" />
<TextView
android:id="#+id/text_user_cart_items_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:text="0"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="#+id/image_open_cart_action"
app:layout_constraintEnd_toEndOf="#+id/image_open_cart_action"
app:layout_constraintHorizontal_bias="0.55"
app:layout_constraintStart_toStartOf="#+id/image_open_cart_action"
app:layout_constraintTop_toTopOf="#+id/image_open_cart_action" />
</androidx.constraintlayout.widget.ConstraintLayout>
<fragment
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/layout_actionbar_root"
app:layout_constraintVertical_bias="1.0"
app:navGraph="#navigation/navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.navigation.NavigationView
android:id="#+id/layout_navigation_menu"
app:headerLayout="#layout/drawer_header"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:maxWidth="300dp"
app:menu="#menu/drawer_menu" />
</androidx.drawerlayout.widget.DrawerLayout>
</layout>
drawer header layout
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/user_data_header"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.makeramen.roundedimageview.RoundedImageView
android:id="#+id/image_user_avatar"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginTop="16dp"
android:scaleType="centerCrop"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:riv_oval="true"/>
<View
android:id="#+id/view_avatar_support"
android:layout_width="1dp"
android:layout_height="1dp"
app:layout_constraintBottom_toBottomOf="#+id/image_user_avatar"
app:layout_constraintEnd_toEndOf="#+id/image_user_avatar"
app:layout_constraintStart_toStartOf="#+id/image_user_avatar"
app:layout_constraintTop_toTopOf="#+id/image_user_avatar" />
<TextView
android:id="#+id/text_user_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginBottom="8dp"
android:text="TextView"
app:layout_constraintBottom_toTopOf="#+id/text_user_email"
app:layout_constraintStart_toEndOf="#+id/image_user_avatar" />
<TextView
android:id="#+id/text_user_email"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginBottom="8dp"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="#+id/image_user_avatar"
app:layout_constraintStart_toEndOf="#+id/image_user_avatar" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Main Activity
#AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private val mainViewModel: ActivityMainViewModel by viewModels()
lateinit var binding: ActivityMainBinding
private lateinit var navigationView: NavigationView
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil
.setContentView(
this,
R.layout.activity_main
)
navigationView = binding.layoutNavigationMenu
navController = Navigation.findNavController(
this,
R.id.nav_host_fragment
)
NavigationUI.setupWithNavController(navigationView, navController)
setBindings()
setupObserver()
}
private fun updateDrawerHeader(user: User) {
binding.layoutDrawer.userDataHeader.text_first_name_value_header.text = user.firstName
binding.layoutDrawer.userDataHeader.text_last_name_value_header.text = user.lastName
binding.layoutDrawer.userDataHeader.text_email_value_header.text = user.email
}
}
And Im trying to update the header with
private fun updateDrawerHeader(user: User) {
binding.layoutDrawer.userDataHeader.text_first_name_value_header.text = user.firstName
binding.layoutDrawer.userDataHeader.text_last_name_value_header.text = user.lastName
binding.layoutDrawer.userDataHeader.text_email_value_header.text = user.email
}
userDataHeader I cannot find.
I am trying to implement collapsing toolbar behaviour in my app with a tab layout. I want to hide the toolbar when in collapse mode and just show the tab layout in collapse mode and in normal mode until collapsed I want to show the toolbar with the title of the app. Currently, it works as I want in collapsed mode I just want to add a toolbar that hides in collapsed mode.
My code
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
</data>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="#+id/htab_maincontent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/htab_appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:fitsSystemWindows="true"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="#+id/htab_collapse_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:titleEnabled="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:background="#color/greyprofile"
android:padding="16dp">
<!-- android:background="#drawable/circularbordersolid"-->
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/profilepic"
android:layout_width="150dp"
android:layout_height="150dp"
android:scaleType="centerCrop"
android:src="#drawable/hey" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:fontFamily="#font/proximanovaregular"
android:gravity="center"
android:text="Name User"
android:textColor="#424242"
android:textSize="21sp"
android:textStyle="bold" />
</RelativeLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/proximanovaregular"
android:text="Username"
android:textColor="#424242"
android:gravity="center"
android:textSize="14sp" />
</LinearLayout>
<Button
android:id="#+id/editProfileBtn"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:paddingBottom="10dp"
style="#style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#757575"
android:text="Edit Profile"
android:gravity="center"
android:textAllCaps="false"
android:textSize="16sp" />
</LinearLayout>
<!-- <androidx.appcompat.widget.Toolbar-->
<!-- android:id="#+id/htab_toolbar"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="?attr/actionBarSize"-->
<!-- android:layout_gravity="top"-->
<!-- app:layout_collapseMode="pin"-->
<!-- app:popupTheme="#style/ThemeOverlay.AppCompat.Light"/>-->
<!-- android:layout_marginBottom="48dp"-->
</com.google.android.material.appbar.CollapsingToolbarLayout>
<com.google.android.material.tabs.TabLayout
android:id="#+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"/>
<!-- android:background="#drawable/circularbordersolid"-->
<!-- app:tabIndicatorColor="#android:color/white"-->
<!-- app:tabSelectedTextColor="#android:color/white"-->
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager2.widget.ViewPager2
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/pager"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>
You should remove exitUntilCollapsed from your app:layout_scrollFlags
So, do it like that app:layout_scrollFlags="scroll|snap"
Here's a complete code in Kotlin to hide AppBarLayout for a specific fragment. You can also disable scrolling for collapsing toolbar layout:
mNavController.addOnDestinationChangedListener { _, destination, _ ->
when (destination.id) {
R.id.nav_welcome -> {
appBarLayout.setExpanded(false, false)
canScrollBehaviour.canScroll = false
collapsingToolbarLayout.updateLayoutParams<AppBarLayout.LayoutParams> {
scrollFlags =
AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL or AppBarLayout.LayoutParams.SCROLL_FLAG_SNAP
}
}
else -> {
canScrollBehaviour.canScroll = true
isAppearanceLightStatusBars(true)
appBarLayout.setExpanded(true, false)
collapsingToolbarLayout.updateLayoutParams<AppBarLayout.LayoutParams> {
scrollFlags =
AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL or AppBarLayout.LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED
}
}
}
}
For disabling/enabling scrolling:
class BlockableScrollBehaviour(context: Context, attrs: AttributeSet) : AppBarLayout.Behavior(context, attrs) {
var canScroll = true
override fun onStartNestedScroll(
parent: CoordinatorLayout,
child: AppBarLayout,
directTargetChild: View,
target: View,
nestedScrollAxes: Int,
type: Int
): Boolean = canScroll
override fun onTouchEvent(
parent: CoordinatorLayout,
child: AppBarLayout,
ev: MotionEvent
): Boolean = super.onTouchEvent(parent, child, ev) && canScroll
}
Using this code you can control scrolling:
val canScrollBehaviour =
(appBarLayout.layoutParams as CoordinatorLayout.LayoutParams).behavior as BlockableScrollBehaviour
I have recyclerview to show my order items but it has design issue and after 3 days changing it I have no other solution for it!
screenshot
Issues
Recyclerview is not covering page full height
Items have space same as recyclerview height (it shows 1 item per page!)
Code
fragment_order.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/orderItem"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".main.OrdersFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/orders_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
order_items.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:id="#+id/cardView2"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_marginBottom="5dp"
app:cardElevation="2dp"
android:layout_margin="5dp">
<FrameLayout
android:background="#color/orders"
android:layout_width="4dp"
android:layout_height="match_parent"/>
<TextView
android:id="#+id/order_Iid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:gravity="start|top"
android:text="#string/order_ID"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:id="#+id/order_status_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|start"
android:layout_marginStart="10dp"
android:layout_marginTop="35dp"
android:text="#string/order_status"
android:textColor="#5CDCBD"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="#+id/order_price_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|end"
android:layout_marginEnd="10dp"
android:text="#string/price"
android:textSize="12sp"
android:textStyle="bold" />
</androidx.cardview.widget.CardView>
</LinearLayout>
OrdersFragment.kt
class OrdersFragment : Fragment() {
lateinit var sesssion: SessionManager
lateinit var laundriesRecycler: RecyclerView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val root = inflater.inflate(R.layout.fragment_orders, container, false)
sesssion = SessionManager(context)
laundriesRecycler = root.findViewById(R.id.orders_list)
getOrders()
return root
}
private fun getOrders() {
var session = SessionManager(context)
session.checkLogin()
var user = session.getUserDetails()
var token: String? = user.get(SessionManager.KEY_ACCESS_TOKEN)
val tokenFull = "Bearer $token"
val queue = Volley.newRequestQueue(context)
val url = "https://example.com/api/orders"
val stringReq : StringRequest =
object : StringRequest(
Method.GET, url,
Response.Listener { response ->
val list = Gson().fromJson(response, OrderArr::class.java)
laundriesRecycler.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
laundriesRecycler.adapter = OrdersAdapter(context, list)
},
Response.ErrorListener {
Toast.makeText(context, R.string.errorMessage, Toast.LENGTH_LONG)
.show()
}
){
override fun getHeaders(): Map<String, String> {
val headers = HashMap<String, String>()
headers["Content-Type"] = "application/json"
headers["Authorization"] = tokenFull
return headers
}
}
queue.add(stringReq)
}
}
Any idea?
Update
OrdersAdapter.kt
class OrdersAdapter(
val context: Context?,
private var orderList: OrderArr
) : RecyclerView.Adapter<OrdersAdapter.OrderViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OrdersAdapter.OrderViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(
R.layout.orders_items,
parent,
false
)
//fixing width issue
val outMetrics = DisplayMetrics()
val display = parent.display
display?.getRealMetrics(outMetrics)
itemView.layoutParams = RecyclerView.LayoutParams(outMetrics.widthPixels, RecyclerView.LayoutParams.MATCH_PARENT)
return OrdersAdapter.OrderViewHolder(itemView)
}
override fun onBindViewHolder(holder: OrdersAdapter.OrderViewHolder, position: Int) {
val currentItem = orderList.data[position]
holder.orderId.text = "ID: " + currentItem.id
holder.price.text = if(currentItem.amount!= null){"Rp. " + currentItem.amount + " /KG"}else{"Not provided"}
holder.status.text = if(currentItem.lastProgress!= null) {currentItem.lastProgress.progress.name} else{"Unknown"}
holder.itemView.setOnClickListener {
val i: Intent = Intent(context, OrdersActivity::class.java)
i.putExtra("orderIDArgument", currentItem.id.toString())
it.context.startActivity(i);
}
}
override fun getItemCount() = orderList.data.size
class OrderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
val orderId: TextView = itemView.findViewById(R.id.order_Iid)
val status: TextView = itemView.findViewById(R.id.order_status_text)
val price: TextView = itemView.findViewById(R.id.order_price_text)
}
}
Update 2
Activity_main.xml
Every fragment will replace each other inside this activity
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="56dp">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/fragmentFragmentId"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/main_graphs"
tools:context=".MainActivity" />
</ScrollView>
<!--bottom navigation bar with items-->
<com.google.android.material.bottomappbar.BottomAppBar
android:id="#+id/bottomAppBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="#color/colorPrimaryNewTheme"
android:backgroundTint="#color/colorPrimaryNewTheme"
app:backgroundTint="#android:color/white"
app:fabAlignmentMode="end"
app:fabCradleMargin="10dp"
app:fabCradleRoundedCornerRadius="20dp"
app:fabCradleVerticalOffset="14dp"
app:hideOnScroll="true"
app:menu="#menu/bottom_menu"
tools:ignore="BottomAppBar,MissingConstraints" />
<!--Floating action button which is anchored to the bottom navigation button-->
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="#color/colorPrimaryNewTheme"
android:contentDescription="#string/app_name"
android:src="#drawable/order"
app:backgroundTint="#color/colorPrimaryNewTheme"
app:layout_anchor="#id/bottomAppBar"
app:layout_dodgeInsetEdges="bottom"
tools:ignore="MissingConstraints" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Update 3
fragment_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".main.MainFragment">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/header_imageP"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="#string/himage"
android:scaleType="centerCrop"
android:src="#drawable/main_header"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginStart="42dp"
android:layout_marginTop="31dp"
android:textColor="#FFFFFF"
android:text="#string/nameHint" />
<TextView
android:id="#+id/useremail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/username"
android:layout_alignParentStart="true"
android:layout_marginStart="42dp"
android:layout_marginTop="8dp"
android:textColor="#FFFFFF"
android:text="#string/emailHint" />
<ImageView
android:id="#+id/logo"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_below="#+id/useremail"
android:layout_alignParentStart="true"
android:layout_marginStart="41dp"
android:layout_marginTop="13dp"
android:contentDescription="#string/himage"
android:src="#drawable/logo" />
<TextView
android:id="#+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginStart="21dp"
android:layout_marginTop="118dp"
android:layout_toEndOf="#+id/logo"
android:text="#string/app_name"
android:textColor="#FFFFFF"
android:textSize="18sp"
android:textStyle="bold" />
<RelativeLayout
android:id="#+id/t1"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_below="#+id/header_imageP"
android:layout_marginTop="4dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginStart="6dp"
android:text="HIIII" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/t2"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_below="#+id/t1"
android:layout_marginTop="4dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginStart="6dp"
android:text="BYEEEE" />
</RelativeLayout>
</RelativeLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
First remove code for customizing width and height of recycler item view inside Adapter.
Like:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OrdersAdapter.OrderViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(
R.layout.order_item,
parent,
false
)
//fixing width issue
/*val outMetrics = DisplayMetrics()
val display = parent.display
display?.getRealMetrics(outMetrics)
itemView.layoutParams = RecyclerView.LayoutParams(outMetrics.widthPixels, RecyclerView.LayoutParams.MATCH_PARENT)*/
return OrdersAdapter.OrderViewHolder(itemView)
}
Second, you are not putting any constraint to FragmentContainerView thats why it goes to (0,0) position by default and you have set it's height to wrap_content, so your recycler view looks like the posted image. And it is not recommended to use recycler view inside scroll view. Try with customizing Activity_main.xml as below:
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.bottomappbar.BottomAppBar
android:id="#+id/bottomAppBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:fabAlignmentMode="end"
app:fabCradleMargin="10dp"
app:fabCradleRoundedCornerRadius="20dp"
app:fabCradleVerticalOffset="14dp"
app:hideOnScroll="true"
app:menu="#menu/bottom_menu"
tools:ignore="BottomAppBar,MissingConstraints"
app:layout_constraintBottom_toBottomOf="parent"/>
<fragment
android:id="#+id/nav_view"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="#+id/bottomAppBar"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="#navigation/main_graphs" />
<!-- put FAB here -->
</androidx.constraintlayout.widget.ConstraintLayout>
I need to show the text "Peek" at the collapsed state, but it shows the whole height.
How to hide the blank area above "Peek"?
It must show the "Peek" area at the first, then show "Content" after expand.
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/bottom_sheet"
app:layout_behavior="#string/bottom_sheet_behavior"
app:behavior_hideable="true"
android:background="#drawable/rounded_bottom_dialog"
app:behavior_peekHeight="80dp"
android:orientation="vertical"
>
<TextView
android:id="#+id/textView"
android:layout_width="match_parent"
android:layout_height="80dp"
android:gravity="center"
android:textColor="#color/white"
android:text="Peek" />
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:gravity="center"
android:textColor="#color/white"
android:text="Content" />
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
You need to apply bottom_sheet_behavior to root view.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/bottomSheet"
android:layout_width="match_parent"
android:layout_height="300dp"
app:behavior_hideable="false"
app:behavior_peekHeight="80dp"
app:layout_behavior="#string/bottom_sheet_behavior">
<FrameLayout
android:id="#+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#121212">
<TextView
android:id="#+id/peekView"
android:layout_width="match_parent"
android:layout_height="80dp"
android:gravity="center"
android:text="Peek"
android:textColor="#color/white" />
<TextView
android:id="#+id/contentView"
android:layout_width="match_parent"
android:layout_height="200dp"
android:gravity="center"
android:text="Content"
android:textColor="#color/white" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
You can change the alpha properties of both content and peek views by slideOffset in BottomSheetCallback
class MainActivity : AppCompatActivity() {
private lateinit var bottomSheetBehavior: BottomSheetBehavior<ConstraintLayout>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet)
contentView.alpha = 0f
peekView.alpha = 1f
bottomSheetBehavior.addBottomSheetCallback(object :
BottomSheetBehavior.BottomSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float) {
contentView.alpha = slideOffset
peekView.alpha = 1 - slideOffset
}
override fun onStateChanged(bottomSheet: View, newState: Int) {
}
})
}
}
Result