Подтвердить что ты не робот

SwiperefreshLayout в Android

Я использую SwipeRefreshLayout в моем следующем макете:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:background="@color/homePageBackground"
  android:orientation="vertical" >


<android.support.v4.widget.SwipeRefreshLayout
    android:id="@+id/swipeRefreshLayout_listView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >
<fragment
        android:id="@+id/announcementHomefragment"
        android:name="in.test.app.AnnouncementFragment"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/homePageBackground" >

            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="15dp"
                android:background="@color/homePageBackground" >

                <TextView
                    android:id="@+id/newsTitle"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:layout_marginLeft="15dp"
                    android:layout_marginTop="5dp"
                    android:gravity="center"
                    android:text="@string/new_list"
                    android:textAppearance="?android:attr/textAppearanceSmall"
                    android:textColor="@color/white"
                    android:textStyle="bold" />

                <fragment
                    android:id="@+id/newshomefragment"
                    android:name="in.test.app.NewsFragment"
                    android:layout_width="wrap_content"
                    android:layout_height="190dp"
                    android:layout_below="@id/newsTitle"
                    android:layout_marginTop="-15dp" />

                <TextView
                    android:id="@+id/productTitle"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/newshomefragment"
                    android:layout_gravity="center"
                    android:layout_marginLeft="15dp"
                    android:layout_marginTop="5dp"
                    android:gravity="center"
                    android:text="@string/product_in_home"
                    android:textAppearance="?android:attr/textAppearanceSmall"
                    android:textColor="@color/white"
                    android:textStyle="bold" />

                <fragment
                    android:id="@+id/proCategoryhomefragment"
                    android:name="in.test.app.CategoryFragment"
                    android:layout_width="wrap_content"
                    android:layout_height="170dp"
                    android:layout_below="@id/productTitle"
                    android:layout_marginTop="-15dp" />

                <TextView
                    android:id="@+id/trainingTitle"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/proCategoryhomefragment"
                    android:layout_gravity="center"
                    android:layout_marginLeft="15dp"
                    android:layout_marginTop="2dp"
                    android:gravity="center"
                    android:text="@string/trainings_in_home"
                    android:textAppearance="?android:attr/textAppearanceSmall"
                    android:textColor="@color/white"
                    android:textStyle="bold" />

                <fragment
                    android:id="@+id/trainingfragment"
                    android:name="in.test.app.TrainingFragment"
                    android:layout_width="match_parent"
                    android:layout_height="180dp"
                    android:layout_below="@id/trainingTitle"
                    android:layout_marginBottom="10dp"
                    android:layout_marginTop="-15dp" />
            </RelativeLayout>
        </ScrollView>
    </LinearLayout>
</android.support.v4.widget.SwipeRefreshLayout>

Когда я вытаскиваю свой SwipeRefreshLayout, он работает, но, как вы можете видеть в приведенном выше коде, в нем есть прокрутка. Поэтому, когда я спускаю вниз свой вид прокрутки, он опускается, и половина изображений не отображается, потому что это сбилось. Когда я пытаюсь снова подтянуться, мой просмотр прокрутки не поднимается. Вместо этого SwipeRefreshLayout получает вызов. Что я должен делать?

Пожалуйста, помогите мне.

4b9b3361

Ответ 1

Я бы сказал, что лучше иметь расширенный SwipeRefreshLayout со слушателем, чтобы иметь возможность добавлять различные условия из классов, отображающих этот макет.

Что-то вроде следующего: GeneralSwipeRefreshLayout.java

public class GeneralSwipeRefreshLayout extends SwipeRefreshLayout {   
  private OnChildScrollUpListener mScrollListenerNeeded;

  public interface OnChildScrollUpListener {
    boolean canChildScrollUp();
  }

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

 /**
  * Listener that controls if scrolling up is allowed to child views or not
  */
  public void setOnChildScrollUpListener(OnChildScrollUpListener listener) {
    mScrollListenerNeeded = listener;   
  }

  @Override
  public boolean canChildScrollUp() {
    if (mScrollListenerNeeded == null) {
      Log.e(GeneralSwipeRefreshLayout.class.getSimpleName(), "listener is not defined!");
    }
    return mScrollListenerNeeded != null && mScrollListenerNeeded.canChildScrollUp();
  }
}

И затем внутри вашего класса, который отображает SwipeRefreshLayout, содержащий макет ListView или GridView, вы можете сделать что-то вроде этого:

mSwipeLayout.setOnChildScrollUpListener(new OnChildScrollUpListener() {
  @Override
  public boolean canChildScrollUp() {
    return mListView.getFirstVisiblePosition() > 0 || 
           mListView.getChildAt(0) == null || 
           mListView.getChildAt(0).getTop() < 0;
  }
});

Ответ 2

Просто создайте класс, который расширяет SwipeRefreshLayout и переопределяет метод canChildScrollUp(). Верните true, если вам нужно прокрутить вниз для вашего контроля.

Например, для scrollview вы можете попробовать это,

@override.
boolean canChildScrollUp()
{
   //your condition to check scrollview reached at top while scrolling
   if(scrollview.getScrollY() == 0.0)
      return true;
   else
      return false;
}

Ответ 3

Как уже указывали другие, если у вас нет прокручиваемого вида (т.е. listview) в качестве прямого дочернего элемента SwipeRefreshLayout, то файл canChildScrollUp не будет работать.

Имеет дело с простой логикой, используемой SwipeRefreshLayout при проверке возможности прокрутки дочернего вида.

Я использовал ListView внутри ActionbarActivity и хотел включить пустое представление, когда мой список был пуст. Это вызвало проблемы, поскольку класс SwipeRefreshLayout может иметь только один дочерний элемент. Обратите внимание, что он также проверяет эту дочернюю способность scrollUp, чтобы определить, приводит ли pull down к дочернему элементу scrollUp, или если он вызывает обновление содержимого childs.

Итак, если вы хотите использовать ту же логику, что и SwipeRefreshLayout, просто расширьте класс и создайте метод, позволяющий вам передать дескриптор в прокручиваемое представление. Обратите внимание, что в реализации запаса используется canScrollVertically(), который делает именно то, что мы хотим, но появляется только в SDK >= 14.

Также не забудьте включить конструктор, содержащий параметр "AttributeSet", когда вы расширяете класс, иначе у вас будут проблемы с использованием класса в ваших файлах макета.

Итак, в методе onCreate вашей деятельности (в моем случае это ActionBarActivity), который включает в себя представление списка, просто вызовите setMyScrollableView, проходящий в вашем ListView, или любой вид, который вы используете, который прокручивается.

/*Constructor*/
public MySwipeRefreshLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    // TODO Auto-generated constructor stub
}


 View mMyScrollableView = null;  //The content that get pulled down.
 /*Method used to pass in my scrollable view*/
 public void setMyScrollableView(View view){
    mMyScrollableView = view;
 }

/**
 * @return Whether it is possible for the child view of this layout to
 * scroll up.  This was taken for the most part directly from SwipeRefreshLayout
 */
public boolean canChildScrollUp() {
    if(mMyScrollableView == null)
      return false;
    if (android.os.Build.VERSION.SDK_INT < 14) {
        if (mMyScrollableView instanceof AbsListView) {
            final AbsListView absListView = (AbsListView) mMyScrollableView;
            return absListView.getChildCount() > 0
        && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
        .getTop() < absListView.getPaddingTop());
        } else {
            return mMyScrollableView.getScrollY() > 0;
        }
    } else {
        return ViewCompat.canScrollVertically(mMyScrollableView, -1);
    }
}

Ответ 4

Решение из @User22791 прекрасно работает, и на основе этого я создал библиотеку, доступную в github, которую вы можете использовать (и изменять), чтобы упростить использование swipeRefreshLayout для разработчиков. Здесь: https://github.com/dagova/referencedSwipeRefreshLayout

В основном вам просто нужно указать в своем макете представление, которое нужно проверить в методе canChildScrollUp. Надеюсь, это будет полезно.

Ответ 5

Я также нашел, что другие ответы не совсем сработали.

Потребовал немного времени, чтобы понять, что они используют метод getScrollY(), который, как объясняет этот ответ, является методом View, описывающим, как далеко это прокрутка в контейнере, а не метод для описания того, насколько прокручивается ваш прокручиваемый контейнер.

Если вы используете ту же технику, что и в других ответах (переопределяя метод canChildScrollUp()), вы можете легко проверить, находится ли прокручиваемая в ней самая высокая точка:

@Override
public boolean canChildScrollUp() {
    return !isListAtTop();
}

private boolean isListAtTop()   {   
    if(mGridView.getChildCount() == 0) return true;
    return mGridView.getChildAt(0).getTop() == 0;
}

(Как вы можете видеть, я использую GridView, но вы также можете использовать ListView)

Ответ 6

Простое решение - использовать onScrollListener и проверить, может ли пользователь видеть первый элемент.

someView.setOnScrollListener(new AbsListView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(AbsListView absListView, int scrollState) {
        if (scrollState == SCROLL_STATE_IDLE) {
            if (isViewAtTop()) {
                swipeLayout.setEnabled(true);
            } else {
                swipeLayout.setEnabled(false);
            }
        }

    }

    @Override
    public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        if (firstVisibleItem == 0) {
            swipeLayout.setEnabled(true);
        } else {
            swipeLayout.setEnabled(false);
        }
    }
});

Где метод isViewAtTop() - это другой метод, который проверяет, что этот вид прокручивается вверху

Ответ 7

Хорошо, у меня это работает. Если SwipeRefreshLayout является корнем макета, а ScrollView находится глубоко в иерархии (я поставил ScrollView внутри RelativeLayout), а не прямое дочернее устройство SwipeRefreshLayout, он не обнаружит проведите по экрану ScrollView правильно.

Вы должны создать пользовательский класс, который расширяет SwipeRefreshLayout и переопределяет метод canChildScrollUp() в SwipRefreshLayout

Вот пример:

 public class CustomSwipeRefreshLayout extends SwipeRefreshLayout {

    private ScrollView scrollview;

    public CustomSwipeRefreshLayout(Context context) {
        super(context);
    }

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

    public void setView(ScrollView view) {
        this.scrollview = view;
    }

    @Override
    public boolean canChildScrollUp() {
        return scrollview.getScrollY() != 0;
    }

}