CoordinatorLayout achieves TabLayout ceiling effect

Ceiling is a method that many applications in the market will adopt at present, such as Jingdong, Xianyu, meituan, meituan takeout, hungry, chain home, shell house search and other home pages. If you are careful, other mainstream apps can also find the realization of this effect.

I'd like to present a renderings first


Next is an example of hungry:


Take another look at the of idle fish:

Finally, the shell is looking for a house (similar to chain home):

There is no harm without comparison. Is it silky compared with mainstream applications?

Previous company projects also had this demand. I searched online for this effect for a long time. Basically, I customized the RecyclerView and then processed sliding events, but the implementation was not very ideal. Later, I did other projects and used CoordinatorLayout. I accidentally found that ceiling can also be achieved. I had to shout, Google dad is very nice!

Starting with the text below, I always think that the layout nesting of CoordinatorLayout is particularly complex, so I don't want to use it very much, but the effect is... Really fragrant!

Let's first look at the page layout structure:

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:id="@+id/coordinator"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.google.android.material.appbar.AppBarLayout
            android:id="@+id/appbar"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <com.google.android.material.appbar.CollapsingToolbarLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:titleEnabled="false"
                app:layout_scrollFlags="scroll|exitUntilCollapsed">
                ``````````
            </com.google.android.material.appbar.CollapsingToolbarLayout>

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

        <androidx.appcompat.widget.LinearLayoutCompat
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
            ````````
        </androidx.appcompat.widget.LinearLayoutCompat>
        
    </androidx.coordinatorlayout.widget.CoordinatorLayout>

The whole parent layout is CoordinatorLayout, and then it is divided into two sub layouts, AppBarLayout and linearlayoutcompact. The CollapsingToolbarLayout is nested under AppBarLayout, and then I simply put an AppCompatImageView. Under linearlayoutcompact, TabLayout and ViewPage2

The following is the complete layout:

  <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:id="@+id/coordinator"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.google.android.material.appbar.AppBarLayout
            android:id="@+id/appbar"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <com.google.android.material.appbar.CollapsingToolbarLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:titleEnabled="false"
                app:layout_scrollFlags="scroll|exitUntilCollapsed">

                <androidx.appcompat.widget.AppCompatImageView
                    android:id="@+id/iv_image"
                    app:layout_collapseMode="pin"
                    android:scaleType="centerCrop"
                    android:layout_width="match_parent"
                    android:layout_height="@dimen/dp_200"/>

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

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

        <androidx.appcompat.widget.LinearLayoutCompat
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <com.google.android.material.tabs.TabLayout
                android:id="@+id/tab_layout"
                app:tabMode="scrollable"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>

            <androidx.viewpager2.widget.ViewPager2
                android:id="@+id/view_pager2"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>

        </androidx.appcompat.widget.LinearLayoutCompat>

    </androidx.coordinatorlayout.widget.CoordinatorLayout>

The business code is pasted below:

class MultiplexFragment : DataBindingFragment<FragmentMultiplexBinding, MultiplexViewModel>() {
    companion object {
        fun newInstance(): MultiplexFragment {
            return MultiplexFragment()
        }
    }
    private val strArray = arrayOf("follow", "recommend", "video", "live broadcast", "picture", "Piece", "Essence", "Hot")

    override fun initView(view: View, savedInstanceState: Bundle?) {
        mViewData?.apply {
            Glide.with(getThis())
                .load("https://wx2.sinaimg.cn/mw690/002Po4pSly1grt79wku06j61jk0rskjl02.jpg").into(ivImage)
//            In this usage, there will be no memory leakage when fragments are used. Although there are many fragments, RecyclerFragment.newInstance() is used every time
            viewPager2.adapter = object :FragmentStateAdapter(getThis()){
                override fun getItemCount(): Int = strArray.size

                override fun createFragment(position: Int): Fragment {
                    return RecyclerFragment.newInstance()
                }
            }
            TabLayoutMediator(tabLayout,viewPager2){tab,position->
                tab.text = strArray[position]
            }.attach()
        }
    }

    //Configure the content of the current page. All parameters can be blank
    //Br.xxxviewmodel is the xxxviewmodel in the corresponding xml file generated by the kotlin kapt plug-in by default
    override fun getDataBindingConfig(): DataBindingConfig? {
        return DataBindingConfig(layoutId = R.layout.fragment_multiplex,variableId = BR.MultiplexViewModel,
            vmClass = MultiplexViewModel::class.java)
    }
}

The above is all the code to achieve the ceiling effect. The children's shoes in a hurry can be taken directly and handed over. If you are not in a hurry, you can look down. We should know not only what it is, but also why.

At the beginning, I learned about CoordinatorLayout because of its folding effect. Using it as ceiling is just an accident. An important attribute of this transformation is app:layout_collapseMode="pin", which also has another attribute app:layout_collapseMode="parallax" we can see the folding effect by changing the attribute in the demo to parallax:

You can see that the parallax attribute hides the picture with the effect of folding, and the pin attribute hides the picture with the effect of scrolling up.

For more properties of CoordinatorLayout, refer to:
CoordinatorLayout learning

github address of demo:

Android Jetpack best practices! Combined with the rapid development of MVVM, help developers deeply understand Jetpack!

Tags: Android

Posted by lordphate on Wed, 06 Oct 2021 07:05:39 +0530