Using TabLayout and ViewPager with CollapsingToolbarLayout



Using android TabLayout and new viewpager2 you can make your fragment layout inside tab layout to make them have expand collapse. To make the top layout collapse you have to use CollapsingToolbarLayout with combination of other layouts and properties.

Below is the example where we use TabLayout , ViewPager2 with FragmentStateAdapter to host fragments.


Main Activity Layout which host CollapsingToolbarLayout , TabLayout , ViewPager2 you can have this inside fragment also so viewpager can host other fragments.


activity_tab_layout.xml

<?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"
android:fitsSystemWindows="true"
tools:ignore="MissingPrefix">

<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:toolbarId="@+id/toolbar">

<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:contentScrim="@color/purple_500"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:titleEnabled="false">

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="?attr/actionBarSize"
android:background="@color/white">

<ImageButton
android:id="@+id/ib_add_1"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_alignParentStart="true"
android:clickable="false"
android:src="@drawable/ic_baseline_add_24" />

<ImageButton
android:id="@+id/ib_add_2"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_alignParentEnd="true"
android:clickable="false"
android:src="@drawable/ic_baseline_add_24" />

</RelativeLayout>

<Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_gravity="top"
android:background="@color/purple_500"
app:layout_collapseMode="pin"
tools:ignore="MissingPrefix" />

</com.google.android.material.appbar.CollapsingToolbarLayout>

<com.google.android.material.tabs.TabLayout
android:id="@+id/tl_landing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="@color/white"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />


</com.google.android.material.appbar.AppBarLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="visible"
app:layout_behavior="@string/appbar_scrolling_view_behavior">

<androidx.viewpager2.widget.ViewPager2
android:id="@+id/vp_landing"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white" />
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

as above example you can see we have 2 ImageButton in top section inside CollapsingToolbarLayout which want to be scrollable with our screen content scrolling app:layout_collapseMode="pin" to have toolbar pinned on top once user scroll list.

other important properties are 

we use  app:contentScrim="@color/purple_500" to have content inside have color match with toolbar with app:layout_scrollFlags="scroll|exitUntilCollapsed" to be able to scrollable and get hidden once you scroll all the way.

Activity code to setup view pager and tab layout

val demoCollectionPagerAdapter = SamplePageAdapter(this)
val viewPager = findViewById<ViewPager2>(R.id.vp_landing)
viewPager.adapter = demoCollectionPagerAdapter

val tabLayout = findViewById<TabLayout>(R.id.tl_landing)
TabLayoutMediator(tabLayout, viewPager) { tab, position ->
tab.text = "LABEL ${(position + 1)}"
}.attach()

class SamplePageAdapter(activity: MainActivity) : FragmentStateAdapter(activity) {

override fun getItemCount(): Int = 2

override fun createFragment(position: Int): Fragment {
return if (position == 0) {
SampleFragment1()
} else {
SampleFragment2()
}
}
}

If you are doing setup of tab and viewpager from fragment you will require to pass FragmentManger in place of activity

SampleFragment1 code which host recyclerview to make it scrollable 

layout file for SampleFragment1:

we have to use layout_behavior property appbar_scrolling_view_behavior to able to have recyclerview scrollable with collpasing toolbar

<?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:layout_width="match_parent"
android:layout_height="match_parent">

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_animals"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />

</androidx.constraintlayout.widget.ConstraintLayout>

for fragment code we just setup our recyclerview with sample data and adapter.

For SampleFragment2 we don't want to use recyclerview but Let's see we want to use simple scrollable content. in that case you will need Nested Scrollable with layout behavior property.

below is the sample layout:

<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_height="match_parent">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:layout_behavior="@string/appbar_scrolling_view_behavior">

<TextView

android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Error Message"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>

below is how it looks like with expanded and collapsed state with above layout behaviors :







above example we are using white background for tab and top layout , you can use same color as toolbar to have match color on collapsed state for toolbar.

One issue here you notice in second fragment layout the error message content is center aligned. but when its expanded/ collapse state content doesn't look center aligned when expanded state haven't found proper solution to have message center aligned in both expand/collapse state.



Comments

Popular posts from this blog

Using android BadgeDrawable to show the Badge android

Styling TextInput Layout with material design library