【问题标题】:SwiperefreshLayout in AndroidAndroid 中的 SwiperefreshLayout
【发布时间】:2015-08-12 08:57:06
【问题描述】:

我在下面的布局中使用 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 正在接听电话。我该怎么办?

请帮帮我。

【问题讨论】:

    标签: android android-layout android-fragments uiswipegesturerecognizer swiperefreshlayout


    【解决方案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();
      }
    }
    

    然后在显示包含 ListView 或 GridView 布局的 SwipeRefreshLayout 的类中,您可以执行以下操作:

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

    【讨论】:

    • 非常适合我!谢谢!
    • 别忘了把你的xml布局从android.support.v4.widget.SwipeRefreshLayout改成yourpackage.GeneralSwipeRefreshLayout
    • 你会如何为 RecyclerView 改变它?
    【解决方案2】:

    只需创建一个扩展 SwipeRefreshLayout覆盖 方法canChildScrollUp() 的类。当您想要向下滚动控件时返回 true。

    例如对于滚动视图,你可以试试这个,

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

    【讨论】:

    • 感谢您的回复。我已经通过更改一些 XML 来解决它。但无论如何感谢您的支持。
    • +1 很好的答案。它对我有用,但你在说什么样的条件? @User22791
    • 如果我只保留return true,那么刷新对我不起作用
    • @droid_dev 是的。你不能把 true 放在那里。它总是允许您的列表或滚动视图向上滚动。您必须使用某种符合您的条件的条件
    • @rup35h 你的布局有什么变化?也发布您的答案,以便其他人也可以获得帮助。
    【解决方案3】:

    正如其他人已经说过的那样,如果您没有将可滚动视图(即列表视图)作为 SwipeRefreshLayout 的直接子级,则库存 canChildScrollUp 将不起作用。

    与 SwipeRefreshLayout 用于检查子视图滚动能力的简单逻辑有关。

    我在 ActionbarActivity 中使用 ListView,并且希望在我的列表视图为空时包含一个空视图。这会导致问题,因为 SwipeRefreshLayout 类只能有一个子级。请注意,它还会检查此子项的向上滚动能力,以确定下拉项是否会导致子项向上滚动,或者是否会导致子项内容刷新。

    因此,如果您想使用与 SwipeRefreshLayout 相同的逻辑,只需扩展该类,并创建一个方法以允许您将句柄传递给可滚动视图。请注意,股票实现使用 canScrollVertically() 完全符合我们的要求,但仅出现在 SDK >= 14 中。

    在扩展类时不要忘记包含包含参数“AttributeSet”的构造函数,否则在布局文件中使用该类会遇到问题。

    因此,在包含列表视图的 Activity(在我的情况下是 ActionBarActivity)的 onCreate 方法中,只需调用 setMyScrollableView 传入您的 ListView 或您使用的任何滚动视图。

    /*Constructor*/
    public MySwipeRefreshLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }
    
    
     View mMyScrollableView = null;  //The content that get's 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() 方法,正如 this answer 所解释的那样,View 方法描述了它在容器中滚动了多远,而不是描述的方法你的 Scroll 容器滚动了多少。

        如果您使用与其他答案相同的技术(覆盖 canChildScrollUp() 方法),您可以轻松检查 Scrollable 是否处于最高点:

        @Override
        public boolean canChildScrollUp() {
            return !isListAtTop();
        }
        
        private boolean isListAtTop()   {   
            if(mGridView.getChildCount() == 0) return true;
            return mGridView.getChildAt(0).getTop() == 0;
        }
        

        (如您所见,我使用的是GridView,但您也可以使用ListView

        【讨论】:

        • 这样的解决方案包含一个错误:mGridView.getChildAt(0) 将返回第一个可见的孩子,但不是绝对 0 位置的孩子。这就是为什么每次第一个可见视图滚动到 0 时用户都会卡住的原因。
        【解决方案6】:

        更简单的解决方案是使用 onScrollListener 并检查用户是否可以看到 firstElement。

        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 的自定义类并覆盖SwipRefreshLayout 中的canChildScrollUp() 方法

          这是一个例子:

           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;
              }
          
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-06-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多