I woke up this morning wanting to write this article, but watching my beloved Cavaliers playing and thinking about lebron James’ 2-0… Thinking raptors first place in the East, today is really a “hazy” Raptors… Raptors fans will not hit me!! Ha ha

Yesterday, a friend asked me to talk about the use of Behavior. I don’t know much about it, but can I learn if I don’t know much about it?! In fact, as programmers, we will be exposed to a lot of new things in daily development, not every one of us to understand, we will not have so much energy. But why do some people know so much? In fact, SOMETIMES I always think about this question, and then I found an interesting thing that they don’t always know everything, but their past experience makes them know how to get to know a new thing, how to learn it quickly. In fact, we should cultivate the ability to solve problems, not everything can… Well, enough of the gossip! So let’s start today. I actually like King James! Haha…

This article focuses on the following aspects:

  • What is Behavior?
  • What are the existing behaviors?
    • The use of BottomSheetBehavior
    • The use of SwipeDismissBehavior
  • Behavior description of the callback
  • Several common Behavior cases:

1. What’s the Behavior

The description of Behavior looks like this

Interaction behavior plugin for child views of CoordinatorLayout. A Behavior implements one or more interactions that a user can take on a child view. These interactions may include drags, swipes, flings, or any other gestures.

CoordinatorLayout the interaction of a View, you can implement one or more interactions ina subclass of CoordinatorLayout, which can be dragging, sliding, flashing, or any other gesture. In fact, it is to realize the interaction of the internal control of CoordinatorLayout, you can achieve the corresponding interaction ina non-invasive way! What can he do? See the back will know!! Haha…

2. What are the existing behaviors?

I went to Google to find out about it, and here’s a picture that says it all:

But in fact, commonly used in development is BottomSheetBehavior, SwipeDismissBehavior and the rest is custom.

2.1 use of BottomSheetBehavior

BottomSheetBehavior is basically a Behavior that implements content popping from the bottom. In fact this contains a lot of content, like BottomSheet, BottomSheetDialog, BottomSheetDialogFragment a a note here:

2.1.1 Use of BottomSheet

This is usually used in the corresponding layout! Why? Because it can be used directly in layout. Introduce the more important concept inside first, otherwise I am afraid you frighten what yao do not know what yao what (forgive my one northeast words)!

  • App :layout_behavior=”@string/bottom_sheet_behavior”
  • App :behavior_peekHeight=”0dp” Visibility of the behavior_peekHeight=”0dp”. (I found that if you don’t set this, the bottom content of the behavior_peekHeight is always on top, so if you don’t want to see it, set it to 0 otherwise.)
  • App: Behavior_hideable =”true” Behavior_hideable =”true” Behavior_hideable =”true
  • Static BottomSheetBehavior from(V view) Gets the corresponding BottomSheetBehavior object
  • SetBottomSheetCallback (BottomSheetCallback) corresponding listener
    • OnStateChanged (@nonNULL View bottomSheet, int newState) callback for state change
    • OnSlide (@nonNULL View bottomSheet, float slideOffset) is called when sliding
  • GetState () gets the corresponding state
  • SetState (final @state int State) Sets the corresponding State
    • STATE_COLLAPSED: indicates the default collapsed state
    • STATE_DRAGGING: Transition state
    • State_demystified: The short amount of time a view can go from sliding away from your fingers to finally settling
    • STATE_EXPANDED: The bottom sheet is in the fully expanded state
    • STATE_HIDDEN: This state is disabled by default. (You can enable this state through app: Behavior_hideable.) After this state is enabled, users can swipe down to hide it completely

The root layout is CoordinatorLayout, this is the key!!

Here are a few points to note:

  • When you get the BottomSheetBehavior object, you use a set ofapp:layout_behavior="@string/bottom_sheet_behavior"The layout of the
  • App :behavior_peekHeight=”0dp” Must be set otherwise you’ll see the behavior_peekHeight on the interface all the time and it won’t respond to your gestures

Code in XML

<? 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:layout_height="match_parent"
    tools:context="com.jinlong.newmaterialdesign.behavior.BehaviorActivity">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="bottomSheet"
        android:text="Show bottomSheet" />

    <LinearLayout
        android:id="@+id/ll_bottom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:behavior_peekHeight="50dp"
        app:layout_behavior="@string/bottom_sheet_behavior">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="#f25b41"
            android:gravity="center"
            android:text="There's something at the bottom!!" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="# 009988"
            android:gravity="center"
            android:text="TAB 1" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="# 002288"
            android:gravity="center"
            android:text="Label 2" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="# 009922"
            android:gravity="center"
            android:text="Label 3" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="#00aa88"
            android:gravity="center"
            android:text="TAB 4" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="# 999988"
            android:gravity="center"
            android:text="Tag 5" />
    </LinearLayout>
</android.support.design.widget.CoordinatorLayout>
Copy the code

Main page logic

        BottomSheetBehavior<LinearLayout> bottomSheetBehavior = BottomSheetBehavior.from(mLlBottomSheet);
        if(bottomSheetBehavior. GetState () = = bottomSheetBehavior. STATE_EXPANDED) {/ / a state, Hidden bottomSheetBehavior. SetState (bottomSheetBehavior. STATE_COLLAPSED); }else{/ / other state bottomSheetBehavior. SetState (bottomSheetBehavior. STATE_EXPANDED); }Copy the code

2.1.2 Use of BottomSheetDialog

In fact, the use of this thing is basically the same as the use of the dialog box. You setContentView() to go into a layout and then call show() to show it, but there is a special concern here, if you set the layout in the dialog to be larger than the entire screen (this does not mean you set match to the full screen, it is valid content). The content will not fill the screen, but there will be a small space at the top, which is similar to peek. Other use and dialog box use, here directly paste the main code!!

    BottomSheetDialog sheetDialog = new BottomSheetDialog(this);        sheetDialog.setContentView(R.layout.sheet_dialog);
    sheetDialog.show();
Copy the code

The use of 2.1.3 BottomSheetDialogFragment

In fact, this is the same as writing a Fragment, but it has the same problem as the above pop-up dialog box, which is when you have too much space.

Here are two main points:

  • Use this to get the corresponding BottomSheetBehaviorBottomSheetBehavior.from((View) view.getParent());
  • useshow(getSupportFragmentManager(), "dialog");Display.

2.2 use of SwipeDismissBehavior

This is slide disappear and slide close, in many cases with the new 5.0 Snackbar. A similar thing to Toast is not the focus of this article, so I won’t expand on Snackbar! In fact, except Snackbar, there is almost no APP that wants to cross out its own page!! In fact, the usage is still very simple, mainly create an object, set some parameters like a can! Directly on the code:

TextView tvTitle = findViewById(R.id.tv_title); SwipeDismissBehavior<View> mSwipe = new SwipeDismissBehavior(); /* * SWIPE_DIRECTION_START_TO_END can only be swiped from left to right * * SWIPE_DIRECTION_END_TO_START can only be swiped from right to left */ mSwipe.setSwipeDirection(SwipeDismissBehavior.SWIPE_DIRECTION_ANY); mSwipe.setListener(new SwipeDismissBehavior.OnDismissListener() {@override public void onconsequence (View View) {@override public void onDragStateChanged(int state) {/* * STATE_IDLE * STATE_DRAGGING Sliding * STATE_SETTLING disappear */}});Copy the code

Note has been very detailed, here a point ah, if set the function of sliding delete, this page will exist the function of sliding delete, is the page exists this function, most of the door controls can exist sliding delete function, but I tried, AppBarLayout and other corresponding controls can not, It is estimated that the control with behavior set cannot be deleted by sliding, other controls can be deleted, but this is just my guess, no verification!!

3. Behavior:

The nested scroll of behavior is based on a corresponding reference, so in the process of customization, we must distinguish which View is based on and which View is observed. Only by distinguishing these can we better understand the following content. All children in the following are observed views. That’s the View that defines behavior in XML.

  • LayoutDependsOn (CoordinatorLayout parent, View Child, View Dependency) indicates whether the View with Behavior is assigned a dependent layout

    • Parameter 1: the CoordinatorLayout object
    • Parameter 2: Child View to be observed
    • Parameter 3: Variable dependent View (View being observed)
  • OnDependentViewChanged (CoordinatorLayout parent, View child, View Dependency) Method of hi dependency when the dependent View changes

  • onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View directTargetChild, @nonnull View Target, int axes, int type) do you want to handle the action when the user finger presses. Return true when you are sure you want to handle this operation; If false is returned, subsequent callback events will not be responded to. You can skate all you want. I won’t handle it. Axes axes axes axes axes axes axes axes

    • Parameter 3: Direct target, equivalent to a sliding control
    • Parameter 4: View for observation
    • Parameter 5: This can be simply interpreted as the direction of the roll
      • ViewCompat#SCROLL_AXIS_HORIZONTAL Indicates the horizontal direction
      • ViewCompat#SCROLL_AXIS_VERTICAL Specifies the vertical direction
    • Parameter 6: This parameter comes later. If you enter a type other than TYPE_TOUCH, it will not scroll accordingly
  • onNestedScrollAccepted(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child, @NonNull View directTargetChild, @nonnull View Target, @scrolineint axes, @nestedScrollType int type) When onStartNestedScroll is ready to handle this slide (return true) Call back this method. You can do some response preparation in this method!

  • onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, int dx, Int dy, @nonnull int[] consumed, @nestedScrollType int type) Calls this method when scrolling starts.

    • Parameter 4/ Parameter 5: the user’s x/y scroll distance.
    • Parameter 6: the parameter that handles the scrolling distance, internally maintains the output distance, so if the user slides 100px and the child moves 90px, you need to change the consumed [1] value to 90 so that the coordinatorLayout knows to handle only the remaining 10px of scrolling. Consumed [0] represents x axis, and consumed[1] represents Y axis. Maybe you don’t understand this question, but to use a better analogy, let’s say you develop a feature, but you only know 90% of it. So what do you do? You can’t just leave it alone. Ok, so you find your colleague or boss and ask him to do the other 10%. So the problem is solved perfectly, it is a concept!
  • onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, int dxConsumed, Int dyConsumed, int dxUnconsumed, int dyUnconsumed, int Type) When the method above ends, the coordinatorLayout handles the remaining distance, for example, 10px left. But coordinatorLayout realized it was over by the time it rolled 2px. So you finish scrolling, you call that method, and you pass in the remaining pixels of the coordinatorLayout processing as an argument (dxUnconsumed, dyUnconsumed), which is 8px. The parameter also has the number of pixels (dxConsumed, dyConsumed) that the coordinatorLayout handles. The boss is taking care of the rest of the distance! This method mainly deals with some out-of-bounds scrolling. Still don’t get it, do you? Take your boss as an analogy: for example, there is still 10% of the work left, and then the boss deals with 2% and finds it is ready to go online, so the boss ends the work and records the remaining content (dxUnconsumed and dyUnconsumed) and tells you. What the boss has done (dxConsumed, dyConsumed) has also told you.

    • Parameter 4/ Parameter 5: the distance of the x/y axis to scroll without scrolling to the top or bottom
    • Parameter 6/ Parameter 7: the distance of the x/y axis when scrolling to the top or bottom
if (dyConsumed > 0 && dyUnconsumed == 0) {
    System.out.println("Slide up...");
}
if (dyConsumed == 0 && dyUnconsumed > 0) {
    System.out.println("Skidding up the border...");
}
if (dyConsumed < 0 && dyUnconsumed == 0) {
    System.out.println("In decline...");
}
if (dyConsumed == 0 && dyUnconsumed < 0) {
    System.out.println("We're at the boundary, and we're sliding...");
}
Copy the code
  • onNestedPreFling(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, Float velocityX, float velocityY) is called when the finger is released before an inertial action occurs, and this gives you the speed of the response, and you can use that speed to determine if you need to do something like fold, and so on, and if you want to make sure that you respond to this method, return true.

    • Parameter 4/ Parameter 5: represents the corresponding speed
  • onStopNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, Int type) method to call back when scrolling stops. This method is called back when you are not responding to Fling. We could do some cleaning up here. Or something else…

  • OnLayoutChild (CoordinatorLayout parent, View Child, int layoutDirection) to determine the location of the child View, This method can redefine the position of the child View (specifically the View that sets the behavior), as shown in the following example

    • ViewCompat#LAYOUT_DIRECTION_LTR views are oriented from left to right
    • ViewCompat#LAYOUT_DIRECTION_RTL View direction from superior to left

Basically, there are only so many APIS you can use, but there are a lot of things in here, so let’s have a good understanding. I actually don’t understand.

4. Several common Behavior cases:

There are two types of custom behaviors: one is dependent on the corresponding View changes and the other is dependent on scrolling changes.

4.1 Behavior changes depending on the change of a View

The most classic case is the bottom bar to follow the AppBarLayout move to move, in fact, the code is very simple, as long as calculate the AppBarLayout move distance, dynamic Settings to the corresponding dependent controls can be. A wave of code walking!! Let’s start with a rendering.

public class TwoBehavior extends CoordinatorLayout.Behavior<View> { private String TAG = TwoBehavior.class.getSimpleName(); Public TwoBehavior(Context Context, AttributeSet attrs) {super(Context, attrs); } @override public Boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {// AppBarLayout dependentreturndependency instanceof AppBarLayout; } @Override public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View Dependency) {// Calculate how far AppBarLayout movesfloat top = Math.abs(dependency.getTop());
        Log.e(TAG, "How far AppBarLayout moves" + top);
        child.setTranslationY(top);
        return true; }}Copy the code

Then use: app:layout_behavior=” full path “in the code can be realized, because the content of CoordinatorLayout afraid you do not know, so HERE I still paste the corresponding list file, or you should not realize the pot let me back, I do not back this pot…

<? 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:layout_height="match_parent"
    tools:context="com.jinlong.newmaterialdesign.behavior.TwoBehaviorActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.v7.widget.Toolbar
            android:layout_width="match_parent"
            android:layout_height="? attr/actionBarSize"
            android:background="@color/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways"
            app:title="Bottom linkage Behavior"
            app:titleTextColor="@android:color/white" />
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

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

            <TextView
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:background="# 009988"
                android:gravity="center"
                android:text="TAB 1" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:background="# 002288"
                android:gravity="center"
                android:text="Label 2" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:background="# 009922"
                android:gravity="center"
                android:text="Label 3" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:background="#00aa88"
                android:gravity="center"
                android:text="TAB 4" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:background="# 999988"
                android:gravity="center"
                android:text="Tag 5" />
        </LinearLayout>
    </android.support.v4.widget.NestedScrollView>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="? attr/actionBarSize"
        android:layout_gravity="bottom"
        android:background="@color/colorPrimary"
        android:gravity="center"
        android:text="This is a bottom column."
        android:textColor="@android:color/white"
        app:layout_behavior="com.jinlong.newmaterialdesign.behavior.TwoBehavior" />
</android.support.design.widget.CoordinatorLayout>
Copy the code

It is difficult to deal with the change of View inside, anyway I think so, do not understand the students can supplement the corresponding knowledge, what View change, the method of obtaining the corresponding position and so on some content. Online or quite a lot of, rely on the View is basically this implementation. Are the realization of these two methods, play on the good, write more natural familiar.

4.2 Behavior that depends on rolling changes

This one is a little bit more difficult, because it involves scrolling and so on, and you have to do a lot of writing and reading, so let’s do a simple example. The rest depends on everyone to practice a lot!!

4.2.1 The first is to determine the position

@Override public boolean onLayoutChild(CoordinatorLayout parent, View child, Int layoutDirection) {/ / set up the layout of the behaviors CoordinatorLayout LayoutParams params = (CoordinatorLayout. LayoutParams) child.getLayoutParams();if(params! =null && params.height == CoordinatorLayout.LayoutParams.MATCH_PARENT){ Child. Layout (0, 0, the parent getWidth (), the parent. GetHeight ()); child.setTranslationY(getHeaderHeight());return true;
        }

        returnsuper.onLayoutChild(parent, child, layoutDirection); } /** * this is the height of the Header, you can set it to any height you want */ public intgetHeaderHeight(){// When you set the corresponding manifest file, you do this //return Context.getResources().getDimensionPixelOffset(R.dimen.header_height);
        return 500;
    }
Copy the code

This position is determined using a view.settranslationy () method, which IS similar to view.getTop (), which is an offset from the top left corner of the parent control. So it makes a lot of sense, that the View that sets the Behavior is cheaper than the specified position, because there’s a corresponding image height, so this is below the image.

4.2.2 Handling the corresponding scroll event (here’s the hard part. Take a good look here)

  • First, process the corresponding scroll direction, because the scroll direction here is vertical, so the code is like this drop!
    @Override
    public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {// If the movement is vertical, the event can be followed by the responsereturn axes == ViewCompat.SCROLL_AXIS_VERTICAL || super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, axes, type);
    }
Copy the code
  • Process a series of calculations such as rolling distance

First click on your finger to start sliding and the following method will be executed.

    @Override
    public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {
        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type); // In this method, only the upward slide is handledif(dy < 0){
            return; } // Calculate the distance of each movefloat transY =  child.getTranslationY() - dy;
        if(transY > 0){ child.setTranslationY(transY); consumed[1]= dy; }}Copy the code

Just to clarify: dy<0 means sliding down. Child.gettranslationy () gets the offset from the View setting the Behavior to the top of the CoordinatorLayout. Dy is the distance of each move. So what transY calculates is the distance from the top that should be set to the corresponding View after each move. Here consumed[1]= dy is the distance you’re dealing with (which you’ll use later). Therefore, it is not difficult to understand that every time you slide up, you will calculate the corresponding value and set it to the child, so that it will gradually move up, once you reach the top, you will not change the corresponding vertical. That’s it…

The following method is called each time the above method completes execution

    @Override
    public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type); // Only sliding down is handled in this methodif(dyUnconsumed >0){
            return;
        }

        float transY = child.getTranslationY() - dyUnconsumed;
        Log.i(TAG,"------>transY:"+transY+"****** child.getTranslationY():"+child.getTranslationY()+"--->dyUnconsumed"+dyUnconsumed);
        if(transY > 0 && transY < getHeaderHeight()){ child.setTranslationY(transY); }}Copy the code

Remember the boss’s problem I mentioned above? When you’re consumed [1] = dy, would have passed the corresponding parameter dxUnconsumed/dyUnconsumed representative to deal with the rest of the parameters, but should pay attention to some here. In the example above when you get on a way to return, then the dxUnconsumed/dyUnconsumed can have value! As you slide down, you change the position of the child until it is fully displayed!

4.2.3 The whole content is maroon

public class OneBehavior extends CoordinatorLayout.Behavior {

    private String TAG = OneBehavior.class.getSimpleName();

    public OneBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void onStopNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, int type) {
        super.onStopNestedScroll(coordinatorLayout, child, target, type);
    }

    @Override
    public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {// Respond to the event if the movement is horizontalreturn axes == ViewCompat.SCROLL_AXIS_VERTICAL || super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, axes, type);
    }

    @Override
    public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type); // Only sliding down is handled in this methodif(dyUnconsumed >0){
            return;
        }

        float transY = child.getTranslationY() - dyUnconsumed;
        Log.i(TAG,"------>transY:"+transY+"****** child.getTranslationY():"+child.getTranslationY()+"--->dyUnconsumed"+dyUnconsumed);
        if(transY > 0 && transY < getHeaderHeight()){
            child.setTranslationY(transY);
        }
    }

    @Override
    public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {
        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type); // In this method, only the upward slide is handledif(dy < 0){
            return;
        }

        float transY =  child.getTranslationY() - dy;
        Log.i(TAG,"transY:"+transY+"++++child.getTranslationY():"+child.getTranslationY()+"---->dy:"+dy);
        if(transY > 0){ child.setTranslationY(transY); consumed[1]= dy; } } @Override public boolean onLayoutChild(CoordinatorLayout parent, View child, Int layoutDirection) {/ / set up the layout of the behaviors CoordinatorLayout LayoutParams params = (CoordinatorLayout. LayoutParams) child.getLayoutParams();if(params! =null && params.height == CoordinatorLayout.LayoutParams.MATCH_PARENT){ Child. Layout (0, 0, the parent getWidth (), the parent. GetHeight ()); child.setTranslationY(getHeaderHeight());return true;
        }

        returnsuper.onLayoutChild(parent, child, layoutDirection); } /** * this is the height of the Header, you can set it to any height you want */ public intgetHeaderHeight(){// When you set the corresponding manifest file, you do this //return Context.getResources().getDimensionPixelOffset(R.dimen.header_height);
        return500; }}Copy the code

4.2.3 Layout content

The content of the layout is much simpler. I’m just going to introduce a behavior. There is a problem, because the top is a dead height, so the layout is a dead height. If you want to make a good fit, you can just get it directly from the XML.

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

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="500px"
        android:scaleType="centerCrop"
        android:src="@mipmap/heard_1"/ > <! - this is a picture -- -- > <. Android support. The v4. Widget. NestedScrollView android: id ="@+id/nested_scroll_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/white"
        app:layout_behavior="com.jinlong.newmaterialdesign.behavior.OneBehavior"> <! <TextView Android :layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="@string/large_text" />
    </android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
Copy the code

Basically so much, in fact, I really slag in the algorithm above, very slag a very slag can not describe me. I’ve tried very hard to make this clear to you. If you don’t understand, you can leave a message to me. In fact, custom Behavior is really a practice when you see one, and slowly you can drive! In fact, I also read what others shared after summing up. Have what bad place return to ask a lot of advice! If you are interested in the principle of Behavior, this article by Helen CSLD is also very thorough! I hope this helps you! Let’s call it a day. Bye-bye…

Code on gitHub address interested students can go to see!!