Android ViewPager с RecyclerView работает неправильно внутри BottomSheet

когда я пытаюсь прокрутить список, иногда это работает неправильно - BottomSheet перехватывает событие прокрутки и скрывает.

Как воспроизвести этот:

  1. Открыть Нижний Лист
  2. изменить страницу ViewPager
  3. попробуйте прокрутить список

результат: BottomSheet будет скрыт.

вот пример кода:

компиляции Ариа.андроид.поддержка:дизайн: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;
            }
        }
    }
}

activity_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>

Screenshot

есть идеи для обходного пути?

1 ответов


я столкнулся с тем же ограничением, но смог его решить.

причина описанного вами эффекта в том, что 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;
}

вы можете видеть, что он по существу находит первый ребенок прокрутки с помощью DFS.

Я немного улучшил эту реализацию и собрал небольшой библиотека а также пример приложения. Вы можете найти здесь: https://github.com/laenger/ViewPagerBottomSheet

просто добавьте url-адрес репозитория maven в свою сборку.Gradle в:

repositories {
    maven { url "https://raw.github.com/laenger/maven-releases/master/releases" }
}

добавьте библиотеку в зависимости:

dependencies {
    compile "biz.laenger.android:vpbs:0.0.2"
}

использовать ViewPagerBottomSheetBehavior для вашего вида нижнего листа:

app:layout_behavior="@string/view_pager_bottom_sheet_behavior"

настройка любого вложенного ViewPager внутри нижнего листа:

BottomSheetUtils.setupViewPager(bottomSheetViewPager)

(это также работает, когда ViewPager и вид нижнего листа и для дальнейшего вложенного ViewPagers)

sample implementation