Setting app:layout_behavior programmatically
Asked Answered
D

3

41

I have a coordinator layout with a recyclerview which I would like to add programmatically. The reason why it's added programatically is because different fragments which inflate the coordinator layout, may use different types of recyclerviews.

Typically for a recyclerview, in order to set this behaviour I would add it in the xml:

app:layout_behavior="@string/appbar_scrolling_view_behavior"

That works fine. However, I'm at a complete loss as to how to add this behavior when I create the recyclerviews programmatically and then add them to the framelayout:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.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:id="@+id/coordLayout"
    android:layout_height="match_parent" android:fitsSystemWindows="true"
    tools:context=".MainActivity">

    <android.support.design.widget.AppBarLayout android:id="@+id/app_bar"
        android:fitsSystemWindows="true" android:layout_height="@dimen/app_bar_height"
        android:layout_width="match_parent" android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/toolbar_layout"
            android:fitsSystemWindows="true" android:layout_width="match_parent"
            android:layout_height="match_parent" app:layout_scrollFlags="scroll|exitUntilCollapsed"
            app:contentScrim="?attr/colorPrimary">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_height="?attr/actionBarSize"
                android:layout_width="match_parent"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/AppTheme.PopupOverlay" />

        </android.support.design.widget.CollapsingToolbarLayout>

    </android.support.design.widget.AppBarLayout>
    <FrameLayout
        android:id="@+id/frameLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    </FrameLayout>

</android.support.design.widget.CoordinatorLayout>
Defloration answered 14/11, 2015 at 10:17 Comment(0)
B
108

Explanation

Behavior is a parameter of the CoordinatorLayout.LayoutParams. You can set the behavior on an instance of CoordinatorLayout.LayoutParams with setBehavior method.

To get a proper Behavior object that represents the same thing as @string/appbar_scrolling_view_behavior you should create an instance of AppBarLayout.ScrollingViewBehavior.


Example

(this is a cleaned up version of my previous edits to the original answer)

First you will have to get an instance of a child View of your CoordinatorLayout. Let me get this clear: it is NOT the CoordinatorLayout itself. childView is CoordinatorLayout's child.

//e.g. like this:
val childView: View = findViewById(R.id.child_view)

Assuming the childView is already attached to the CoordinatorLayout (so it already has LayoutParams), you can do:

val params: CoordinatorLayout.LayoutParams = yourView.layoutParams as CoordinatorLayout.LayoutParams
params.behavior = AppBarLayout.ScrollingViewBehavior()
yourView.requestLayout()
Barbiturism answered 14/11, 2015 at 10:35 Comment(12)
Do you have an example where this is done programmatically?Defloration
setBehavior is causing an xml parse error when loading my fragment .. it is not working. In the case of fragments with their own class and xml, how do we do it? I notice in the docs there is an undocumented public AppBarLayout.ScrollingViewBehavior (Context context, AttributeSet attrs)Pearlinepearlman
That same behavior can be applied to LinearLayouts but I haven't been able to add it programmatically to yet. Do you happen to know how? I asked a question about it here: #38530696Maidstone
@BartekLipinski Can yourView be a ListView instead of RecyclerView?Mendive
@Mendive I didn't say anything about RecyclerView but I assume you're asking if ListView can also work with CollapsingToolbarLayout. The answer is no. CollapsingToolbarLayout expects you to use a View that is implementing NestedScrollingChild interface. You could implement it yourself (for the ListView) but it seems like a pain in the butt in comparison to reimplementing your screen with RecyclerView instead.Barbiturism
what if I use GridView inside some other ViewGroup? I mean the scrolling view is not directly the child of CoordinatorLayout, and they are all created programatically. Is there any way to set the layout behaviou? to which?Frymire
@Frymire You can only set behavior for direct children of CoordinatorLayout.Barbiturism
@BartekLipinski that is too bad. Is there any way that I can use AppBarLayout in my situation? In fact what I need is just move the title bar out of screenFrymire
@Frymire it's not like some nasty feature of CoordinatorLayout. That's how whole Android SDK works. You can only set layout-specific parameters for direct children of a particular layout. I'd suggest you rethink your layout.Barbiturism
@BartekLipinski yes I agree that. The problem is the current layout. The existing layout is working for long time and is not intent to be changed in near periodFrymire
I want to set the behavior for a view that I'm adding to the Coordinator Layout dynamically. So I'm calling mCoordinatorLayout.addView(customView) and I want to set the behavior of the custom view. However, the custom view doesn't seem to think that its layout params are CoordinatorLayout.ParamsLobectomy
@Lobectomy paste that as a question, not as a comment to this answerBarbiturism
G
10

To enable and disable layout_behavior programatically with kotlin use this code :

fun enableLayoutBehaviour() {
    val param: CoordinatorLayout.LayoutParams = swipeRefreshView.layoutParams as CoordinatorLayout.LayoutParams
    param.behavior = AppBarLayout.ScrollingViewBehavior()
}

fun disableLayoutBehaviour() {
    val param: CoordinatorLayout.LayoutParams = swipeRefreshView.layoutParams as CoordinatorLayout.LayoutParams
    param.behavior = null
}

Note: replace swipeRefreshView with your view

Gravitate answered 8/2, 2019 at 12:6 Comment(1)
As soon as we disable layout behaviour, will the hidden bottom navigation view appear back automatically ?Galoot
Z
5

Accepted answer is correct but the provided code is not compilable. So here is a complete example

CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) 
view.getLayoutParams();

params.setBehavior(new AppBarLayout.ScrollingViewBehavior(view.getContext(), null));

2nd param is AttributeSet and it is fine to have it as null although it is not marked as Nullable in support lib.

Zlatoust answered 29/11, 2017 at 17:1 Comment(1)
why the code from my answer is not compilable? It seems to be compiling just fine for me?Barbiturism

© 2022 - 2024 — McMap. All rights reserved.