SwipeRefreshLayout внутри ViewPager

У меня есть активность, состоящая из панели инструментов и пейджера. Его схема выглядит следующим образом:

<FrameLayout 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"
android:orientation="vertical">

<android.support.v4.view.ViewPager
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="112dp"
    android:layout_gravity="bottom"
    tools:context=".Rhino68PanelActivity" />

<LinearLayout
    android:id="@+id/toolbarContainer"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <include
        android:id="@+id/app_bar"
        layout="@layout/app_bar" />

    <include
        android:id="@+id/tap_strip"
        layout="@layout/tab_strip" />

</LinearLayout>

I then load two fragments into the view pager. Each fragment contains its own SwipeRefreshLayout. I will show one fragments layout:

<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:weightSum="12"
    tools:context=".Rhino68PanelActivity$DummySectionFragment">
    ...        
  <android.support.v7.widget.RecyclerView
    android:id="@+id/recyclerView_panel_status"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clipToPadding="false" />

</LinearLayout>

Now when I run the activity it seems to work. However I have noticed that is I slide horizontally (ie to go to the next tab). It triggers the swipeRefreshLayout OnRefreshListener

     mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                mSwipeRefreshLayout.setRefreshing(true);
                DoUpdate();
            }
        });

Я также испытываю странное визуальное поведение, когда пытаюсь выполнить обновление. Знак загрузки (вращающийся круг) часто не отображается, а иногда отображается, но остается маленьким. Я не уверен, является ли это также причиной конфликта двух взглядов друг с другом.

Есть ли способ исправить эту проблему. Я не уверен, как. Может быть, ограничив SwipeRefreshLayout прослушиванием только вертикальных пролистываний?

Любые предложения будут очень признательны.


person Zapnologica    schedule 24.05.2015    source источник
comment
У меня нет этой проблемы в моем проекте, который также использует аналогичную структуру. Можете ли вы опубликовать пример проекта, который воспроизводит эту проблему?   -  person corsair992    schedule 25.05.2015
comment
Не могли бы вы поделиться своим макетом? Наверняка два макета будут мешать друг другу? Если бы я просто записал на пленку SwipeRefreshLayout, это вызвало бы OnRefresh()   -  person Zapnologica    schedule 25.05.2015
comment
Существует временной интервал, прежде чем любой из этих ViewGroup примет на себя событие касания, и он определяется тем, было ли перетаскивание более вертикальным или горизонтальным. Как только событие касания принимается ViewGroup, он продолжает обрабатывать событие без помех (используя метод requestDisallowInterceptTouchEvent()). Мое приложение и макет довольно сложны, а также конфиденциальны, было бы полезно, если бы вы могли опубликовать минимальный пример проекта с этой проблемой (чтобы я мог его отладить).   -  person corsair992    schedule 25.05.2015
comment


Ответы (2)


У меня тоже была эта глупая проблема. Похоже, это ошибка в SwipeRefreshLayout. В качестве обходного пути мне пришлось удалить все его дочерние представления в методе Fragment.onDestroyView().

public SwipeRefreshLayout mSwipeRefreshLayout;
...

@Override public void onDestroyView() {
    mSwipeRefreshLayout.removeAllViews();
    super.onDestroyView();
}
person sergej shafarenka    schedule 20.10.2015

Это потому, что в SwipeRefreshLayout есть ошибка! Ошибка заключается в том, что «onRefresh не работает должным образом, если onMeasure не вызывается». Вы должны расширить SwipeRefreshLayout следующим образом!

public class SwipeRefreshLoading extends SwipeRefreshLayout {
    public SwipeRefreshLoading(Context context) {
        super(context, null);
    }

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

    private boolean mMeasured = false;
    private boolean mPreMeasureRefreshing = false;

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (!mMeasured) {
            mMeasured = true;
            setRefreshing(mPreMeasureRefreshing);
        }
    }


    @Override
    public void setRefreshing(boolean refreshing) {
        if (mMeasured) {
            super.setRefreshing(refreshing);
        } else {
            mPreMeasureRefreshing = refreshing;
        }
    }
}
person The Finest Artist    schedule 27.06.2015
comment
Благодарю вас! У меня есть RefreshLayout внутри ViewPager и setRefreshing внутри страницы (в моем случае это был фрагмент) по некоторым причинам не работает. Кстати, я использую ваш фрагмент кода, и у меня немного неправильное положение освежающего счетчика. Если вы переместите логику из метода onMeasure в метод onLayout, тогда позиция будет правильной. - person IlyaEremin; 08.07.2015
comment
@IlyaEremin У меня проблема в vievpager с refreshlayout - когда я запускаю onrefresh * setrefresg(false) в первом фрагменте viewpager, анимация пропадает (все в порядке) - но во втором фрагменте анимация все еще воспроизводится, даже если я вызвал setrefreshing(false) - я расширил макет, как указано выше - также перешел в onlayout, но все еще безрезультатно, также попробовал отложить публикацию на макете - может быть, мне следует добавить setrefresh в макет? - person ceph3us; 01.10.2015
comment
@TomaszBest, это глупый вопрос, но я спрошу. Вы вызывали setRefreshing(false) для второго фрагмента SwipeRefreshLayout? - person IlyaEremin; 02.10.2015
comment
@ilyaeremin я вызываю onRefresh (с помощью жеста) и setRefresh (false) во фрагменте (дочернем фрагменте), а не во фрагменте хоста ... 1) первый жест смахивания для запуска onRefresh () -> макет анимируется -> в этом методе вызывается загрузчик для поставить курсор -> загрузчик вызывает метод фрагмента onUpdate(), который вызывает setRefresh(false). он работает для первого фрагмента в адаптере страницы (видимый), но когда я прокручиваю второй фрагмент и запускаю onRefresh с помощью жеста прокрутки, все происходит так же, как и для первого фрагмента, но setRefresh (false) не останавливает анимацию во втором фрагменте (видимый) - person ceph3us; 02.10.2015
comment
- макет является общим для каждого фрагмента в пейджере просмотра - я получаю ссылку на refreshlayout перед каждым вызовом setRefresh -> false (также я проверяю, совпадает ли состояние макета обновления с моим вызовом true/false -> if(isRefreshing != Refresh ) setRefresh (обновить) - person ceph3us; 02.10.2015
comment
@IlyaEremin - хорошо, я нашел проблему - как я уже сказал, я использовал CursorLoaderCallback - который работает в рабочем потоке - поэтому мне нужно опубликовать мой метод, который находится в onLoadFinished (), как запускаемый в потоке пользовательского интерфейса - небольшой совет - если вы что-то делаете, убедитесь, что дважды сделай это в правильном треде :D - person ceph3us; 05.10.2015