Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/179.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
带有RecyclerView的Android ViewPager在底部工作不正常_Android_Android Viewpager_Android Recyclerview_Bottom Sheet - Fatal编程技术网

带有RecyclerView的Android ViewPager在底部工作不正常

带有RecyclerView的Android ViewPager在底部工作不正常,android,android-viewpager,android-recyclerview,bottom-sheet,Android,Android Viewpager,Android Recyclerview,Bottom Sheet,当我尝试滚动列表时,有时这会不正确-BottomSheet截获滚动事件并隐藏 如何重现这一点: 开底板 更改ViewPager的页面 尝试滚动列表 结果:将隐藏底页 以下是示例代码: 编译'com.android.support:design:23.4.0' MainActivity.java package com.nkdroid.bottomsheetsample; import android.os.Bundle; import android.support.design.widget

当我尝试滚动列表时,有时这会不正确-BottomSheet截获滚动事件并隐藏

如何重现这一点:

  • 开底板
  • 更改ViewPager的页面
  • 尝试滚动列表
  • 结果:将隐藏底页

    以下是示例代码:

    编译'com.android.support:design:23.4.0'

    MainActivity.java

    package com.nkdroid.bottomsheetsample;
    
    import android.os.Bundle;
    import android.support.design.widget.BottomSheetBehavior;
    import android.support.design.widget.TabLayout;
    import android.support.v4.view.PagerAdapter;
    import android.support.v4.view.ViewPager;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.LinearLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.Button;
    import android.widget.TextView;
    
    public
    class MainActivity
            extends AppCompatActivity
    {
    
        private BottomSheetBehavior behavior;
    
        @Override
        protected
        void onCreate(final Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            final Button btnView = (Button) findViewById(R.id.btnView);
            btnView.setOnClickListener(new View.OnClickListener()
            {
                @Override
                public
                void onClick(final View v) {
                    behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
                }
            });
    
            final View bottomSheet = findViewById(R.id.bottom_sheet);
            behavior = BottomSheetBehavior.from(bottomSheet);
    
            final ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager);
            viewPager.setAdapter(new MyPagerAdapter());
    
            final TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
            tabLayout.setupWithViewPager(viewPager);
    
    
        }
    
        private
        class MyPagerAdapter
                extends PagerAdapter
        {
            @Override
            public
            int getCount() {
                return 15;
            }
    
            @Override
            public
            Object instantiateItem(final ViewGroup container, final int position) {
                final RecyclerView recyclerView = new RecyclerView(MainActivity.this);
    
                recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
                recyclerView.setAdapter(new ItemAdapter());
    
                container.addView(recyclerView);
                return recyclerView;
            }
    
            @Override
            public
            boolean isViewFromObject(final View view, final Object object) {
                return view.equals(object);
            }
    
            @Override
            public
            void destroyItem(final ViewGroup container, final int position, final Object object) {
                container.removeView((View) object);
            }
    
            @Override
            public
            CharSequence getPageTitle(final int position) {
                return String.valueOf(position);
            }
        }
    
        public
        class ItemAdapter
                extends RecyclerView.Adapter<ItemAdapter.ViewHolder>
        {
    
            @Override
            public
            ViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
                return new ViewHolder(new TextView(MainActivity.this));
            }
    
            @Override
            public
            void onBindViewHolder(final ViewHolder holder, final int position) {
            }
    
            @Override
            public
            int getItemCount() {
                return 100;
            }
    
            public
            class ViewHolder
                    extends RecyclerView.ViewHolder
            {
                public TextView textView;
    
                public
                ViewHolder(final View itemView) {
                    super(itemView);
                    textView = (TextView) itemView;
                }
            }
        }
    }
    
    package com.nkdroid.bottomsheetsample;
    导入android.os.Bundle;
    导入android.support.design.widget.BottomSheetBehavior;
    导入android.support.design.widget.TabLayout;
    导入android.support.v4.view.PagerAdapter;
    导入android.support.v4.view.ViewPager;
    导入android.support.v7.app.AppActivity;
    导入android.support.v7.widget.LinearLayoutManager;
    导入android.support.v7.widget.RecyclerView;
    导入android.view.view;
    导入android.view.ViewGroup;
    导入android.widget.Button;
    导入android.widget.TextView;
    公众的
    班级活动
    扩展AppCompative活动
    {
    私人行为;
    @凌驾
    受保护的
    创建时无效(最终捆绑包保存状态){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    最终按钮btnView=(按钮)findViewById(R.id.btnView);
    btnView.setOnClickListener(新视图.OnClickListener()
    {
    @凌驾
    公众的
    void onClick(最终视图v){
    behavior.setState(behavior.STATE_扩展);
    }
    });
    最终视图底图=findViewById(R.id.底图);
    行为=底部板材行为。从(底部板材);
    final ViewPager ViewPager=(ViewPager)findviewbyd(R.id.ViewPager);
    setAdapter(新的MyPagerAdapter());
    最终TabLayout TabLayout=(TabLayout)findviewbyd(R.id.tabs);
    tabLayout.setupWithViewPager(viewPager);
    }
    私有的
    类MyPagerAdapter
    扩展页雷达
    {
    @凌驾
    公众的
    int getCount(){
    返回15;
    }
    @凌驾
    公众的
    对象实例化项(最终视图组容器,最终int位置){
    最终RecyclerView RecyclerView=新的RecyclerView(MainActivity.this);
    setLayoutManager(新的LinearLayoutManager(MainActivity.this));
    setAdapter(newitemAdapter());
    container.addView(recyclerView);
    返回回收视图;
    }
    @凌驾
    公众的
    布尔值isViewFromObject(最终视图,最终对象){
    返回视图.equals(对象);
    }
    @凌驾
    公众的
    void destroyItem(最终视图组容器、最终int位置、最终对象){
    container.removeView((视图)对象);
    }
    @凌驾
    公众的
    CharSequence getPageTitle(最终整数位置){
    返回字符串.valueOf(位置);
    }
    }
    公众的
    类项适配器
    扩展RecyclerView.Adapter
    {
    @凌驾
    公众的
    ViewHolder onCreateViewHolder(最终视图组父视图,最终int视图类型){
    返回新的ViewHolder(新的TextView(MainActivity.this));
    }
    @凌驾
    公众的
    无效onBindViewHolder(最终ViewHolder,最终int位置){
    }
    @凌驾
    公众的
    int getItemCount(){
    返回100;
    }
    公众的
    类视图持有者
    扩展RecyclerView.ViewHolder
    {
    公共文本视图文本视图;
    公众的
    ViewHolder(最终视图项视图){
    超级(项目视图);
    textView=(textView)项目视图;
    }
    }
    }
    }
    
    活动\u main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.design.widget.CoordinatorLayout android:id = "@+id/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:background = "#a3b1ef"
        android:fitsSystemWindows = "true"
        tools:context = ".ui.MainActivity"
        >
    
        <Button
            android:id = "@+id/btnView"
            android:layout_width = "match_parent"
            android:layout_height = "wrap_content"
            android:text = "Show view"
            app:layout_behavior = "@string/appbar_scrolling_view_behavior"
            />
    
    
        <LinearLayout
            android:id = "@+id/bottom_sheet"
            android:layout_width = "match_parent"
            android:layout_height = "400dp"
            android:background = "#fff"
            android:gravity = "center"
            android:orientation = "vertical"
            app:layout_behavior = "@string/bottom_sheet_behavior"
            >
    
    
            <android.support.design.widget.TabLayout
                android:id = "@+id/tabs"
                android:layout_width = "match_parent"
                android:layout_height = "wrap_content"
                app:tabMode = "scrollable"
                />
    
            <android.support.v4.view.ViewPager
                android:id = "@+id/viewPager"
                android:layout_width = "match_parent"
                android:layout_height = "match_parent"
                />
    
        </LinearLayout>
    </android.support.design.widget.CoordinatorLayout>
    
    
    


    有什么解决办法吗

    我遇到了同样的限制,但能够解决它

    您所描述的效果的原因是
    BottomSheetBehavior
    (从v24.2.0开始)仅支持一个滚动子项,该子项在布局期间以以下方式标识:

    private View findScrollingChild(View view) {
        if (view instanceof NestedScrollingChild) {
            return view;
        }
        if (view instanceof ViewGroup) {
            ViewGroup group = (ViewGroup) view;
            for (int i = 0, count = group.getChildCount(); i < count; i++) {
                View scrollingChild = findScrollingChild(group.getChildAt(i));
                if (scrollingChild != null) {
                    return scrollingChild;
                }
            }
        }
        return null;
    }
    
    将库添加到依赖项:

    dependencies {
        compile "biz.laenger.android:vpbs:0.0.2"
    }
    
    使用
    ViewPagerBottomSheetBehavior
    查看底部图纸视图:

    app:layout_behavior="@string/view_pager_bottom_sheet_behavior"
    
    在底部图纸内设置任何嵌套的ViewPager:

    BottomSheetUtils.setupViewPager(bottomSheetViewPager)
    
    (当ViewPager是底部图纸视图时,这也适用于其他嵌套的ViewPager)

    这篇文章救了我的命:

    在底部工作表内显示我对ViewPager的修复

    package com.google.android.material.bottomsheet
    
    import android.view.View
    import androidx.annotation.VisibleForTesting
    import androidx.viewpager.widget.ViewPager
    import java.lang.ref.WeakReference
    
    
    class BottomSheetBehaviorFix<V : View> : BottomSheetBehavior<V>(), ViewPager.OnPageChangeListener {
    
        override fun onPageScrollStateChanged(state: Int) {}
    
        override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
    
        override fun onPageSelected(position: Int) {
            val container = viewRef?.get() ?: return
            nestedScrollingChildRef = WeakReference(findScrollingChild(container))
        }
    
        @VisibleForTesting
        override fun findScrollingChild(view: View): View? {
            return if (view is ViewPager) {
                view.focusedChild?.let { findScrollingChild(it) }
            } else {
                super.findScrollingChild(view)
            }
        }
    }
    
    package com.google.android.material.bottomsheet
    导入android.view.view
    导入androidx.annotation.VisibleForTesting
    导入androidx.viewpager.widget.viewpager
    导入java.lang.ref.WeakReference
    类BottomSheetBehaviorFix:BottomSheetBehavior(),ViewPager.OnPageChangeListener{
    重写有趣的onPageScrollStateChanged(状态:Int){}
    覆盖已滚动的页面(位置:Int,位置偏移:Float,位置偏移像素:Int){}
    覆盖所选页面(位置:Int){
    val container=viewRef?.get()?:返回
    nestedScrollingChildRef=WeakReference(findScrollingChild(容器))
    }
    @可视性测试
    覆盖有趣的findScrollingChild(视图:视图):视图{
    返回if(视图为ViewPager){
    view.focusedChild?.let{findScrollingChild(it)}
    }否则{
    super.findScrollingChild(视图)
    }
    }
    }
    
    还有一种方法不需要修改BottomSheetBehavior,而是利用BottomSheetBehavior仅识别其找到的第一个NestedScrollingEnabled的NestedScrollView这一事实。因此,与其改变BottomSheetBehavior中的逻辑,不如启用和禁用相应的滚动视图。我在这里发现了这种方法:

    在我的例子中,我的行为是使用带有FragmentPagerAdapter的表格布局,所以我的Fra
    package com.google.android.material.bottomsheet
    
    import android.view.View
    import androidx.annotation.VisibleForTesting
    import androidx.viewpager.widget.ViewPager
    import java.lang.ref.WeakReference
    
    
    class BottomSheetBehaviorFix<V : View> : BottomSheetBehavior<V>(), ViewPager.OnPageChangeListener {
    
        override fun onPageScrollStateChanged(state: Int) {}
    
        override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
    
        override fun onPageSelected(position: Int) {
            val container = viewRef?.get() ?: return
            nestedScrollingChildRef = WeakReference(findScrollingChild(container))
        }
    
        @VisibleForTesting
        override fun findScrollingChild(view: View): View? {
            return if (view is ViewPager) {
                view.focusedChild?.let { findScrollingChild(it) }
            } else {
                super.findScrollingChild(view)
            }
        }
    }
    
    @Override
    public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
    
            super.setPrimaryItem(container, position, object);
    
            Fragment f = ((Fragment)object);
            String activeFragmentTag = f.getTag();
            View view = f.getView();
    
            if (view != null) {
                View nestedView = view.findViewWithTag("nested");               
                if ( nestedView != null && nestedView instanceof NestedScrollView) {
                    ((NestedScrollView)nestedView).setNestedScrollingEnabled(true);
                }
            }
    
            FragmentManager fm = f.getFragmentManager();
    
            for(Fragment frag : fm.getFragments()) {
    
                if (frag.getTag() != activeFragmentTag) {
                    View v = frag.getView();
                    if (v!= null) {
    
                        View nestedView = v.findViewWithTag("nested");
    
                        if (nestedView!= null && nestedView instanceof NestedScrollView) {
                            ((NestedScrollView)nestedView).setNestedScrollingEnabled(false);
                        }
                    }
                }
            }
    
            container.requestLayout();
        }
    
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".ui.MLeftFragment">
    
        <androidx.core.widget.NestedScrollView
            android:id="@+id/nestedScrollView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:tag="nested"
            android:fillViewport="true">
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">
    
                <!-- TODO: Update blank fragment layout -->
                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="@string/hello_mool_left_fragment" />      
    
            </LinearLayout>  
    
        </androidx.core.widget.NestedScrollView>
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    
    package com.google.android.material.bottomsheet
    import android.content.Context
    import android.util.AttributeSet
    import android.view.View
    import androidx.annotation.VisibleForTesting
    import androidx.viewpager.widget.ViewPager
    import java.lang.ref.WeakReference
    class ViewPagerBottomSheetBehavior<V : View>
        : com.google.android.material.bottomsheet.BottomSheetBehavior<V>,
        ViewPager.OnPageChangeListener {
    
        constructor() : super()
        constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
    
        override fun onPageScrollStateChanged(state: Int) {}
        override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
        override fun onPageSelected(position: Int) {
            val container = viewRef?.get() ?: return
            nestedScrollingChildRef = WeakReference(findScrollingChild(container))
        }
    
        @VisibleForTesting
        override fun findScrollingChild(view: View?): View? {
            return if (view is ViewPager) {
                view.focusedChild?.let { findScrollingChild(it) }
            } else {
                super.findScrollingChild(view)
            }
        }
    }
    
    constructor() : super()
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
    
    @VisibleForTesting
    override fun findScrollingChild(view: View?): View? {
        return if (view is ViewPager) {
            view.focusedChild?.let { findScrollingChild(it) }
        } else {
            super.findScrollingChild(view)
        }
    }
    
            <androidx.constraintlayout.widget.ConstraintLayout
              app:layout_behavior="com.google.android.material.bottomsheet.ViewPagerBottomSheetBehavior"
                android:layout_height="match_parent"
                android:layout_width="match_parent">
            <include
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    layout="@layout/you_content_with_a_viewPager_scroll"
            />
        </androidx.constraintlayout.widget.ConstraintLayout>
    
    
    import android.content.Context
    import android.util.AttributeSet
    import android.view.View
    import androidx.viewpager.widget.ViewPager
    import java.lang.reflect.Field
    
    class BottomSheetViewPager(context: Context, attrs: AttributeSet?) : ViewPager(context, attrs) {
        constructor(context: Context) : this(context, null)
        private val positionField: Field =
            ViewPager.LayoutParams::class.java.getDeclaredField("position").also {
                it.isAccessible = true
            }
    
        init {
            addOnPageChangeListener(object : SimpleOnPageChangeListener() {
                override fun onPageSelected(position: Int) {
                    requestLayout()
                }
            })
        }
    
        override fun getChildAt(index: Int): View {
            val stackTrace = Throwable().stackTrace
            val calledFromFindScrollingChild = stackTrace.getOrNull(1)?.let {
                it.className == "com.google.android.material.bottomsheet.BottomSheetBehavior" &&
                        it.methodName == "findScrollingChild"
            }
            if (calledFromFindScrollingChild != true) {
                return super.getChildAt(index)
            }
    
            val currentView = getCurrentView() ?: return super.getChildAt(index)
            return if (index == 0) {
                currentView
            } else {
                var view = super.getChildAt(index)
                if (view == currentView) {
                   view = super.getChildAt(0)
                }
                return view
            }
        }
    
        private fun getCurrentView(): View? {
            for (i in 0 until childCount) {
                val child = super.getChildAt(i)
                val lp = child.layoutParams as? ViewPager.LayoutParams
                if (lp != null) {
                    val position = positionField.getInt(lp)
                    if (!lp.isDecor && currentItem == position) {
                        return child
                    }
                }
            }
            return null
        }
    }