0

I have a layout whereby I need the an upper section of toolbar and some content and then a lower section of ViewPager which needs to be hidden based on a boolean value.

The skeleton of the XML looks like:

 <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <androidx.appcompat.widget.Toolbar
            android:layout_width="match_parent"
            android:layout_height="?actionBarSize"/>

        <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.CollapsingToolbarLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    app:expandedTitleGravity="bottom|center_horizontal"
                    app:layout_scrollFlags="scroll">

                    <androidx.constraintlayout.widget.ConstraintLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        app:layout_collapseMode="none">

                        <TextView
                            style="@style/Medium.ExtraLarge"
                            android:layout_width="0dp"
                            android:layout_height="wrap_content"
                            tools:text="Title Something" />

                       <!--Other top section content --> 

                    </androidx.constraintlayout.widget.ConstraintLayout>

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

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


            <androidx.viewpager.widget.ViewPager
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:visibility="@{(viewModel.isInBusinessManagement &amp;&amp; (viewModel.hasActivePremium || viewModel.hasSuspendedPlan)) ? View.VISIBLE : View.GONE}"
                app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
                app:layout_collapseMode="pin"
                tools:visibility="gone">

                <com.google.android.material.tabs.TabLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="@drawable/tab_background_2dp"
                    android:visibility="@{(viewModel.isInBusinessManagement &amp;&amp; (viewModel.hasActivePremium || viewModel.hasSuspendedPlan)) ? View.VISIBLE : View.GONE}"
                    app:layout_collapseMode="pin"
                    app:layout_scrollFlags="scroll|exitUntilCollapsed"
                    app:tabGravity="fill"
                    app:tabMode="fixed"
                    app:tabSelectedTextColor="@color/colorPrimary"
                    app:tabTextAppearance="@style/tab_text"
                    app:tabTextColor="@color/txtColorGrey" />


            </androidx.viewpager.widget.ViewPager>


        </androidx.coordinatorlayout.widget.CoordinatorLayout>
    </LinearLayout>


As you can see I have to control the visibility of the ViewPager and TabLayout based on boolean values, I am using databinding for that.

The layout is all good and I get the expected behavior when it needs to be shown but the issue is that when the conditions mentioned ie. viewModel.isInBusinessManagement &amp;&amp; (viewModel.hasActivePremium || viewModel.hasSuspendedPlan) is false, the Viewpager and TabLayout is invisible but takes up as much space as it did when it was visible.

Now I know that View.INVISIBLE has that behavior but I am clearly using View.GONE for false case.

Also when I put different colors on the root Linearlayout, AppbarLayout and CoordinatorLayout, the extra space on the bottom seems to be coming from CoordinatorLayout.

Could you please help me with this?

ravi
  • 899
  • 8
  • 31
  • can you try to put the `ViewPager` inside a `FrameLayout`, and transfer the `app:layout_behavior` from the pager to this layout .. not sure if that would help to post it as an answer – Zain Dec 27 '20 at 18:33
  • @Zain I did, no luck. The extra space is still there – ravi Dec 28 '20 at 05:07
  • one more point in mind: when you hide these views, can you programmatically remove `app:layout_behavior` from the `ViewPager`, and when you show up them again, add the behavior again .. I think this space is due to the `CoordinatorLayout` Behavior.. let me know if you need some help in that – Zain Dec 28 '20 at 21:41
  • @Zain Yes I do suspect that the extra space is due to `CoordinatorLayout` behavior. It would have been worthwhile to try and remove `app:layout_behavior` from `viewpager` on view `GONE` and again attach the same on view `VISIBLE`, programmatically but I could not find any way to do that. Please do help me if u can. – ravi Dec 29 '20 at 06:29
  • To remove it: `ViewPager viewpager = findViewById(R.id.viewpager); CoordinatorLayout.LayoutParams coordinatorParams = (CoordinatorLayout.LayoutParams) viewpager.getLayoutParams(); coordinatorParams.setBehavior(null);` – Zain Dec 29 '20 at 06:34
  • @Zain Unfortunately that did not work. I cannot help but think, this is some weird CoordinatorLayout bug – ravi Dec 29 '20 at 15:34
  • If possible can you create a demo project so that we attempt it.. I guess answers would not be 100% sure unless testing it – Zain Jan 02 '21 at 15:05
  • What do you expect to happen? Is there some view below the _ViewPager_ that you expect to shift up? Maybe you expect the _CoordinatorLayout_ to shrink? It's unclear. – Cheticamp Jan 03 '21 at 22:13
  • Hi @Cheticamp , as I have mentioned in my question, I want the viewpager `GONE`, which is happening but theres whitespace there when its gone. So what I want is no whitespace there when its gone. Layout Inspector shows the whitespace as part of the CoordinatorLayout – ravi Jan 04 '21 at 07:42
  • @Cheticamp No there is no view below the `ViewPager` that I want to shift up. But yeah, shrink the CoordinatorLayout might be something that I would wanna do. – ravi Jan 04 '21 at 07:44
  • I think it's not issued with `CoordinatorLayout`. try to change colour of top `LinearLayout` and make `CoordinatorLayout` height wrap_content. your `viewpager` will gone – Priyanka Jan 04 '21 at 09:48
  • Hey @Priyankagb I put `wrap_content` on `CoordinatorLayout` and changed `LinearLayout` color to red and CoordinatorLayout color to green, the extra space is green color. But that was already clear when I did a Layout inspection – ravi Jan 05 '21 at 07:46
  • hey why didn't you add output image also. – UD.. Jan 07 '21 at 02:51
  • No need of android:visibility="@{(viewModel.isInBusinessManagement && (viewModel.hasActivePremium || viewModel.hasSuspendedPlan)) ? View.VISIBLE : View.GONE}" in TabLayout. And add output image to understand better – Pankaj Kumar Jan 07 '21 at 03:43
  • @PankajKumar Cant put the output image here. Sorry – ravi Jan 08 '21 at 10:01
  • @ravi Cant help. Sorry – guneetgstar Jan 08 '21 at 14:32

2 Answers2

1

I tried to solve this locally, and the following code worked for me. You can also try this:

  1. Make a binding adapter that will contain the logic for visibility.

@BindingAdapter(value = ["hasActivePremium", "isInBusinessManagement", "hasSuspendedPlan"], requireAll = true)
   fun controlVPVisibility(view: ViewPager, hasActivePremium: Boolean, isInBusinessManagement:Boolean, hasSuspendedPlan:Boolean) {
        view.visibility = if(isInBusinessManagement && (hasActivePremium || hasSuspendedPlan))  View.VISIBLE else View.GONE````<br/>
    }
  1. All the 3 view model variables are mutable live data of type boolean.
    var isInBusinessManagement = MutableLiveData<Boolean>()
    var hasActivePremium = MutableLiveData<Boolean>()
    var hasSuspendedPlan = MutableLiveData<Boolean>()
  1. Since tab layout is in view pager and both have the same visibility logic, so in XML I am only controlling the visibility of the view pager.
    <androidx.viewpager.widget.ViewPager
                android:id="@+id/vpager"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@color/teal_700"
                isInBusinessManagement="@{viewModel.isInBusinessManagement()}"
                hasActivePremium="@{viewModel.hasActivePremium}"
                hasSuspendedPlan="@{viewModel.hasSuspendedPlan}"          
                app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
                app:layout_collapseMode="pin">

  1. Make sure you have attached a lifecycle owner while using a view model with data binding.
    binding.viewModel = viewModel
    binding.lifecycleOwner = this

  1. And make the height of CoordinatorLayout to wrap_parent

I think only from the 5th step change, you can achieve the result in your existing code. The above 4 steps are to make better use of data binding by writing logic in the binding adapter.

  • Although this answer has been rewarded the bounty, the answer does not solve the issue – ravi May 03 '21 at 05:56
0

maybe this work for you to stop scrolling toolbar when viewpager visibility is gone

noScroll flag in layout_scrollFlags will stop scrolling CollapsingToolbarLayout

<com.google.android.material.appbar.CollapsingToolbarLayout
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     app:expandedTitleGravity="bottom|center_horizontal"
     app:layout_scrollFlags="@{(viewModel.isInBusinessManagement &amp;&amp; (viewModel.hasActivePremium || viewModel.hasSuspendedPlan)) ? scroll : noScroll}">
Priyanka
  • 3,369
  • 1
  • 10
  • 33
  • Cant import `ScrollFlags` to use `scroll` and `noScroll` as can be done with `View`, `View.GONE` and `View.VISIBLE` – ravi Jan 05 '21 at 18:35
  • Doing a `val params = layoutViewPager.collapsing.layoutParams as AppBarLayout.LayoutParams; params.scrollFlags = 0; layoutViewPager.collapsing.layoutParams = params` does not do the trick either – ravi May 03 '21 at 05:54
  • may b this helps you : https://stackoverflow.com/questions/31179435/no-resource-id-found-for-applayout-scrollflags-from-collapsingtoolbarlayout – Priyanka May 04 '21 at 06:16