Some time ago I open source on making an Android sliding ConsecutiveScrollerLayout layout, mainly to solve the problem of layout of nested sliding and sliding conflict. Also wrote two articles used in the introduction of the ConsecutiveScrollerLayout implementation principle and use. This article is to explain ConsecutiveScrollerLayout principle, mainly explain ConsecutiveScrollerLayout layout on the top of the absorption principle. Those who have not read my previous two articles can go and have a look.

Android sustainable slide layout: ConsecutiveScrollerLayout

The use of Android continuous sliding ConsecutiveScrollerLayout layout

While I write ConsecutiveScrollerLayout is in order to solve the problem of complex layout of slide, but layout is sliding on the top of the absorption demand is also common in the normal development, now that I’ve implemented a slide layout, so just add on the top of the absorption function to it.

In the past, the most common way to implement the layout sliding function is to nest a hidden top layout in FrameLayout and a ScrollView, and then put a ScrollView that looks exactly like the hidden top layout, and then listen to the ScrollView sliding. If the top layout needs to slide out of the mask in ScrollView, the hidden top layout is displayed. This approach is cumbersome and unelegant to implement. ConsecutiveScrollerLayout by calculating the view on the top of the sliding position and to have to suck set y offset, to have to suck on the top of the layout at the top of the slide out of the screen when suspended in the layout. You can do this by setting a property for the layout.

ConsecutiveScrollerLayout suspended function are the main implementation of suction a top in resetSticky () method. This method is called when the layout slides or changes.

    private void resetSticky(a) {
      // The top function uses the API only supported by Android 5.0, so Android 5.0 can top
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
          / / get to suck on the top of the view, ConsecutiveScrollerLayout support to set up multiple absorption on the top of the view.
            List<View> children = getStickyChildren();
            if(! children.isEmpty()) {int count = children.size();

                // When resetting the top layout, restore all views to their original state
                for (int i = 0; i < count; i++) {
                    View child = children.get(i);
                    child.setTranslationY(0);
                    child.setTranslationZ(0);
                }

                // The View that needs the top
                View stickyView = null;
                // The next View needs to suck the top
                View nextStickyView = null;

                // Find the View that needs the top
                for (int i = count - 1; i >= 0; i--) {
                    View child = children.get(i);
                    if (child.getTop() <= getScrollY()) {
                        stickyView = child;
                        if(i ! = count -1) {
                            nextStickyView = children.get(i + 1);
                        }
                        break; }}if(stickyView ! =null) {
                    int offset = 0;
                    if(nextStickyView ! =null) {
                      // If nextStickyView is not empty, calculate the offset that needs to be set for the layout.
                      // Because the next top view tops the current top view, the current view needs to be ejected from the screen
                        offset = Math.max(0, stickyView.getHeight() - (nextStickyView.getTop() - getScrollY())); } stickyChild(stickyView, offset); }}}}private void stickyChild(View child, int offset) {
      // Set the y offset of the top view so that it floats at the top
        child.setY(getScrollY() - offset);
      // Set translationZ of the top view to 1
        child.setTranslationZ(1);
    }

    /** * return all views (not GONE) */
    private List<View> getStickyChildren(a) {
        List<View> children = new ArrayList<>();
        int count = getChildCount();
        for (int i = 0; i < count; i++) {
            View child = getChildAt(i);
            if (child.getVisibility() != GONE && isStickyChild(child)) {
                children.add(child);
            }
        }
        return children;
    }

		/** * View */
    private boolean isStickyChild(View child) {
        ViewGroup.LayoutParams lp = child.getLayoutParams();
        if (lp instanceof LayoutParams) {
          // Whether to suck the top
            return ((LayoutParams) lp).isSticky;
        }
        return false;
    }
Copy the code

Here use a custom isSticky LayoutParams attribute, this property is used to represent the child view whether need to suck the top, if installed app ConsecutiveScrollerLayout child view: layout_isSticky = “true”, Indicates that the view needs to suck the top.

On the top of the absorption principle is through the ConsecutiveScrollerLayout scrollY find need to suck on the top of the view and the view on the top of the next need to suck, is to find the next view on the top of the absorption, because slide layout to continue upward, The next top view needs to push the current top view out of the screen, so calculate the offset between them. The top view sets the Y-axis offset by setY() to stay at the top. In the end, I set translationZ to 1 for the top view. This is due to the display level of the Android layout. When two views overlap, the one added later will overwrite the one added first. In order to ensure that the top view is not covered by the view behind it, we need to set the z axis for it. The larger the Z axis, the higher the level of the view displayed. The z of view is equal to translationZ+elevation. Except for some special controls, almost all Android views have both values of 0.

The following is the use and effect of the top suction function.

<?xml version="1.0" encoding="utf-8"? >
<com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/scrollerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scrollbars="vertical">

  <! App :layout_isSticky="true" -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/white"
        android:padding="10dp"
        android:text="吸顶View - 1"
        android:textColor="@android:color/black"
        android:textSize="18sp"
        app:layout_isSticky="true" />

    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/white"
        android:orientation="vertical"
        app:layout_isSticky="true">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="10dp"
            android:text="Top view-2 I'm a LinearLayout"
            android:textColor="@android:color/black"
            android:textSize="18sp" />

    </LinearLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/white"
        android:padding="10dp"
        android:text="吸顶View - 3"
        android:textColor="@android:color/black"
        android:textSize="18sp"
        app:layout_isSticky="true" />

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </androidx.core.widget.NestedScrollView>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/white"
        android:padding="10dp"
        android:text="吸顶View - 4"
        android:textColor="@android:color/black"
        android:textSize="18sp"
        app:layout_isSticky="true" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout>
Copy the code

Project address: ConsecutiveScroller