Scrollview+Viewpager+fragment sliding conflict, height problem fix

When I came across this combination, I checked a lot of related information. Everyone encountered different situations. Many of them could not be implemented or did not meet the needs: record them here and used them to solve my problem: Complex layout nesting in Android development ( ScrollView+TabLayout+ViewPager+RecyclerView) causes conflict resolution - Huang Qingqing's World - CSDN Blog

Organize what I use: easy to view

General layout:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".MainActivity">

    <com.hq.testscrollview.InterceptScrollView
        android:id="@+id/interceptScrollView"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:id="@+id/container_normal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:descendantFocusability="beforeDescendants"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:orientation="vertical">

            <RelativeLayout
                android:id="@+id/top_info"
                android:layout_width="match_parent"
                android:layout_height="60dp">

                <TextView
                    android:id="@+id/tv"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true"
                    android:text="顶部内容模块添加"
                    android:textSize="18sp" />
            </RelativeLayout>

            <android.support.design.widget.TabLayout
                android:id="@+id/tabLayout"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:background="@android:color/white"
                app:tabMode ="fixed"
                app:tabSelectedTextColor="@android:color/black" />
            <!-- The placeholder layout is in the gone state by default. When the TabLayout is removed, its state is changed to visible, reaching "placeholder" Effect -->
            <View
                android:id="@+id/view_place"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:visibility="gone" />

            <com.hq.testscrollview.AutofitViewPager
                android:id="@+id/viewPager"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

        </LinearLayout>
    </com.hq.testscrollview.InterceptScrollView>

    <!-- Top empty layout suspended above the screen-->
    <LinearLayout
        android:id="@+id/container_top"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:orientation="vertical">

    </LinearLayout>
</RelativeLayout>
Two custom control codes:

public class InterceptScrollView extends ScrollView {

    private int lastInterceptX;
    private int lastInterceptY;

    private ScrollChangedListener onScrollChangedListener;
    
    public InterceptScrollView(Context context) {
        super(context);
    }

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

    public InterceptScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean intercept = false;
        int x = (int) ev.getX();
        int y = (int) ev.getY();
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                intercept = false;
                break;
            case MotionEvent.ACTION_MOVE:
                int deltaX = x - lastInterceptX;
                int deltaY = y - lastInterceptY;
                //如果是垂直滑动,则拦截
                if (Math.abs(deltaX) - Math.abs(deltaY) < 0) {
                    intercept = true;
                } else {
                    intercept = false;
                }

                break;
            case MotionEvent.ACTION_UP:
                intercept = false;
                break;
        }
        lastInterceptX = x;
        lastInterceptY = y;
        super.onInterceptTouchEvent(ev);//This sentence must not be missed, otherwise the event cannot be intercepted
        return intercept;
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if(onScrollChangedListener!=null){
            onScrollChangedListener.onScrollChanged(l,t,oldl,oldt);
        }
    }

    public void setScrollChangedListener(ScrollChangedListener listener){
        onScrollChangedListener = listener;
    }

    public interface ScrollChangedListener{
        void onScrollChanged(int scrollX, int scrollY, int oldScrollX, int oldScrollY);
    }
}

Using fillViewportattributes does not work, then we will rewrite ViewPagerthe onmeasuremethod to solve the problem that the height is displayed as 0. Rewritten ViewPager, the code is as follows:

public class AutofitViewPager extends ViewPager {

    public AutofitViewPager(@NonNull Context context) {
        this(context,null);
    }

    public AutofitViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        addOnPageChangeListener(new OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            }

            @Override
            public void onPageSelected(int position) {                 requestLayout(); // Ensure that each time the current page is selected, the height is calculated to achieve height adaptive effect             }

            @Override
            public void onPageScrollStateChanged(int state) {
            }
        });
    }

    //Rewrite onMeasure to solve the problem that the height is displayed as 0, and the height is dynamically displayed as the height of the current child
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {         int height = 0;         for (int i = 0; i < getChildCount (); i++) {             View child = getChildAt(i);             child.measure(widthMeasureSpec,                     MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));             int h = child.getMeasuredHeight();             if(i==getCurrentItem()) {                 height=h;             }         }         heightMeasureSpec = MeasureSpec. makeMeasureSpec(height,                 MeasureSpec. EXACTLY);












        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

}
This is a common solution.

Let’s take a look at the introduction below CoordinatorLayout, so I won’t spend a lot of space explaining it. Those who are interested in this layout can learn more about it. Of course, before using this layout, remember to add the support:designdependent libraries. Put the layout code directly below:

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/coordinatorLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:elevation="0dp"
        android:background="@android:color/white">

        <RelativeLayout
            android:id="@+id/title_layout"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            app:layout_scrollFlags="scroll">

            <TextView
                android:id="@+id/tv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:text="顶部内容模块"
                android:textSize="18sp" />
        </RelativeLayout>

        <android.support.design.widget.TabLayout
            android:id="@+id/tabLayout"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="@android:color/white"
            app:tabMode="fixed"
            app:tabSelectedTextColor="@android:color/black" />

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

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

</android.support.design.widget.CoordinatorLayout>
This layout can solve many complex viewpager+fragment problems such as various heights and sliding conflicts.

Guess you like

Origin blog.csdn.net/qq_25462179/article/details/121116720