ViewPager in a NestedScrollView

前端 未结 19 1992
面向向阳花
面向向阳花 2020-11-27 10:08

I need to create an interface like Google Newsstand which is a sort of ViewPager (horizontal scroll) over a collapsing header (vertical scroll). One of my requirements is to

相关标签:
19条回答
  • 2020-11-27 10:22

    I had the same issue, and just fixed it with some changes. ViewPager doesn't work within the NestedScrollView. Simply put your ViewPager as a direct child of your CoordinatorLayout. Then the content for each ViewPager's Fragment should be enclosed in NestedScrollView. That's it.

    0 讨论(0)
  • 2020-11-27 10:24

    I had a layout with an app toolbar with NestedScrollView below it, then inside nested toolbar was a LinearLayout, below the LinearLayout was a view pager. Idea was the LinearLayout inside the NestedScrollView was fixed - you could slide left/right between the views of the view pager but this content wouldn't move, horizontally at least. You should still be able to scroll all the content vertically because of the nested scroll view. That was the idea. So I set nested NestedScrollView height to match_parent, fill viewport, then all the child layouts/ViewPager to wrap_content.

    In my head that was right. But it didn't work - ViewPager allowed me to go left/right, but no vertical scrolling, whether the viewpager page content pushed below the bottom of the current screen or not. Turns out it was basically because the ViewPager doesn't respect wrap_content across its various pages.

    I got round this by subclassing the ViewPager to make it change height depending on the current selected item, sort of forcing it to behave like layout_height="wrap_content":

    public class ContentWrappingViewPager extends ViewPager {
    
        public ContentWrappingViewPager(Context context) {
            super(context);
        }
    
        public ContentWrappingViewPager(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    
            int height = 0;
            if (getChildCount() > getCurrentItem()) {
                View child = getChildAt(getCurrentItem());
                child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
                int h = child.getMeasuredHeight();
                if(h > height) height = h;
            }
    
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
    
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }
    

    Solution was inspired by this answer. Worked for me!

    0 讨论(0)
  • 2020-11-27 10:24

    I know one working solution: You use Activity, with CoordinatorLayout and use FrameLayout, container. Then. use fragment manager to put fragment in container. For example my code:

    <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="match_parent"
    android:orientation="vertical">
    
    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:elevation="0dp">
    
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            app:layout_scrollFlags="scroll|enterAlways"
            android:layout_height="@dimen/toolbar_height"
            android:background="?attr/colorPrimary"
            android:gravity="center">
    
        </android.support.v7.widget.Toolbar>
    
    
    </android.support.design.widget.AppBarLayout>
    
    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">
    
    </FrameLayout>
    

    And Fragment:

    <LinearLayout 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"
    android:orientation="vertical"
    tools:context="com.improvemdia.inmyroom.MainFragment">
    
    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    

    Then use FragmentManager

    getSupportFragmentManager().beginTransaction()
                .replace(R.id.container, new MainFragment())
                .commit();
    
    0 讨论(0)
  • 2020-11-27 10:25

    Okay, I made a small demo with the ViewPager and NestedScrollView. The problem I faced was with the height of ViewPager and the ListView. So I did a little modification on ListView and ViewPager's height measuring.

    If anyone would like to look into the code, Here is the link: https://github.com/TheLittleNaruto/SupportDesignExample/

    Output:

    0 讨论(0)
  • 2020-11-27 10:26

    Instead of placing ViewPager inside the NestedScrollView, do it the other way around.

    Place the NestedScrollView in the child Views inside the ViewPager which in essence is the Fragment's layout. It's also very likely that you won't even need to use NestedScrollView if your Fragment's list layout is very simple.

    Example Layouts

    Activity's Layout:

    <?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"
        android:fitsSystemWindows="true">
    
        <android.support.design.widget.AppBarLayout
            android:id="@+id/app_bar"
            android:layout_width="match_parent"
            android:layout_height="@dimen/app_bar_height"
            android:fitsSystemWindows="true"
            android:theme="@style/AppTheme.AppBarOverlay">
    
            <android.support.design.widget.CollapsingToolbarLayout
                android:id="@+id/toolbar_layout"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fitsSystemWindows="true"
                app:contentScrim="?attr/colorPrimary"
                app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
    
                <ImageView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:minHeight="@dimen/app_bar_height"
                    android:scaleType="centerCrop"
                    android:src="@drawable/my_bg"
                    app:layout_collapseMode="parallax"
                    app:layout_collapseParallaxMultiplier="0.8"
                    app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed" />
    
                <android.support.v7.widget.Toolbar
                    android:id="@+id/toolbar"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    app:layout_collapseMode="pin"
                    app:popupTheme="@style/AppTheme.PopupOverlay" />
    
            </android.support.design.widget.CollapsingToolbarLayout>
    
        </android.support.design.widget.AppBarLayout>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">
    
            <android.support.design.widget.TabLayout
                android:id="@+id/content_tabs"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
    
            <android.support.v4.view.ViewPager
                android:id="@+id/viewPager"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1" />
        </LinearLayout>
    
    </android.support.design.widget.CoordinatorLayout>
    

    If you don't need the TabLayout, you can ditch the LinearLayout and make ViewPager standalone. But be sure to use app:layout_behavior="@string/appbar_scrolling_view_behavior" in ViewPager attributes.

    Simple Fragment's Layout:

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    

    Complex Fragment's Layout:

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v4.widget.NestedScrollView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:fillViewport="true"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <android.support.v7.widget.RecyclerView
                android:id="@+id/recycler_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Hello World"/>
        </RelativeLayout>
    </android.support.v4.widget.NestedScrollView>
    

    Example App: CollapsingToolbarPoc

    0 讨论(0)
  • 2020-11-27 10:26

    just put this line in NestedScrollView

    android:fillViewport="true"
    
    0 讨论(0)
提交回复
热议问题