【问题标题】:Android support v4 SwipeRefreshLayout empty view issueAndroid 支持 v4 SwipeRefreshLayout 空视图问题
【发布时间】:2014-04-09 10:01:44
【问题描述】:

SwipeRefresh 在为列表视图设置空视图后不起作用,该列表视图是 SwipeRefresh 布局的唯一子项。如何解决这个问题?

【问题讨论】:

  • 我找到了解决方案。我们需要为空视图设置 android:clickable(true) 然后它才能正常工作。
  • 您可以发布您的布局的 XML 吗?我遇到了同样的问题,似乎无法与您的解决方案一起使用。
  • 我已经添加了空视图,但是我不能向下滑动这个空视图来刷新。我能得到这个解决方案吗..提前谢谢。
  • @Dinesh,您应该发布您的解决方案作为答案并接受它 - 这是一种常见的 SO 做法。理想情况下,使用 xml 示例。
  • 请查看我的解决方案 (stackoverflow.com/a/40466223/6608860),它也应该适用于这种情况。

标签: android android-layout swiperefreshlayout


【解决方案1】:

解决方法如下: 您可以简单地使用此视图层次结构:

    <FrameLayout ...>

        <android.support.v4.widget.SwipeRefreshLayout ...>

            <ListView
                android:id="@android:id/list" ... />
        </android.support.v4.widget.SwipeRefreshLayout>

        <TextView
            android:id="@android:id/empty" ...
            android:text="@string/empty_list"/>
    </FrameLayout>

然后,在代码中,您只需调用:

_listView.setEmptyView(findViewById(android.R.id.empty));

就是这样。

【讨论】:

  • 不错,点赞。但是我还面临另一个问题,那就是我无法向下滑动这个空视图来刷新。不是吗..我可以得到解决方案吗..提前谢谢。 @nitesh
  • 您需要覆盖 SwipeRefreshLayout 类中的 canChildScrollUp() 方法。在这里查看我的答案:stackoverflow.com/questions/23236650/… 用于滚动视图,但您可以为自己的视图添加一些逻辑
  • 如果您要采纳别人的答案并将其用作您的答案,至少要给他们点赞:stackoverflow.com/a/23424655/893130
  • @niteshgoel 请也回答这个问题:stackoverflow.com/questions/36434071/…
  • @nitesh goel:我也遇到了 Ashok 在使用此解决方案时遇到的同样问题。
【解决方案2】:

我也遇到了这个问题,在活动中没有任何额外代码通过使用下面的布局解决了它。

如果您使用的是ListActivityListFragment,它会为您处理显示/隐藏空视图,刷新也适用于空列表以及此布局结构。

无需破解,一切都在SwipeRefreshLayout 中,应该是这样。

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/Refresher"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <ListView
            android:id="@android:id/list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:divider="@null" />
        <ScrollView
            android:id="@android:id/empty"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <TextView
                android:text="Geen formulieren gevonden"
                style="@style/text.EmptyView" />
        </ScrollView>
    </LinearLayout>
</android.support.v4.widget.SwipeRefreshLayout>

希望这对您有所帮助。如果是这样,别忘了接受答案。

注意:这是my answer to this question 的重复,但这个问题几乎是这个问题的重复... :)

更新
如果 SwipeRefreshLayout 被过早激活,你可以实现 ListView.OnScroll :

_refresher.Enabled = e.FirstVisibleItem == 0;

这会禁用刷新,直到您滚动到顶部。这仅在使用 ListView 时才需要,新的 RecyclerView 可以按预期工作。

【讨论】:

  • 对我来说它会导致滚动问题
  • 究竟有什么问题?你实现了viewholder模式吗?
  • 是的,我做到了。问题是,当向下滚动列表时,滑动刷新被激活得太早了。下面描述的 CustomSwipeRefreshLayout 可以正常工作。
【解决方案3】:

对我来说问题是,当空视图可见时,尽管刷新方法有效,但刷新圆圈并未显示。对我来说,这段代码有效,我希望它有所帮助。

  • xml 布局:

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clickable="true">
    
        <ListView
            android:id="@+id/listView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:fadingEdge="none"
            android:footerDividersEnabled="false"
            android:headerDividersEnabled="false"/>
    
        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:gravity="center">
    
            <TextView
                android:id="@+id/empty_view"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:gravity="center"
                android:visibility="gone"/>
        </ScrollView>
    </FrameLayout>
    

  • 自定义 SwipeRefreshLayout:

    package misc;
    
    import android.content.Context;
    import android.support.v4.widget.SwipeRefreshLayout;
    import android.widget.ListView;
    
    public class CustomSwipeRefreshLayout extends SwipeRefreshLayout {
        private ListView mListView;
    
        public CustomSwipeRefreshLayout(Context context) {
            super(context);
        }
    
        public void setListView(ListView listView) {
            mListView = listView;
        }
    
        @Override
        public boolean canChildScrollUp() {
            if (mListView == null) {
                return true;
            }
    
            return mListView.canScrollVertically(-1);
        }
    }
    
  • 在我使用布局的 Fragment 中,我只将滑动设置为以这种方式刷新布局:

    mSwipeRefreshLayout.setListView(mListView);
    
  • ListView的空视图是这样设置的:

    TextView emptyView = (TextView) view.findViewById(R.id.empty_view);
    emptyView.setText("No data");
    mListView.setEmptyView(emptyView);
    

希望对你有帮助。

【讨论】:

    【解决方案4】:

    我是这样做的(可能不是很优雅的解决方案)

    private void createEmptyView() {
        ViewGroup parent = (ViewGroup) listView.getParent();
        emptyView = (TextView) getLayoutInflater(null)
                .inflate(R.layout.view_empty, parent, false);
        parent.addView(emptyView);
        listView.setEmptyView(emptyView);
    }
    
    public class FrameSwipeRefreshLayout extends SwipeRefreshLayout {
    
        private ViewGroup listView;
        public void setListView(ViewGroup list) {
            listView = list;
        }
    
        @Override
        public boolean canChildScrollUp() {
            if (listView != null) {
                View child = listView.getChildAt(0);
                return child != null && child.getTop() != 0;
            }
            return super.canChildScrollUp();
        }
    }
    

    空布局

    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:gravity="center_horizontal"
          android:clickable="true" />
    

    列表布局

        <FrameSwipeRefreshLayout
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                >
            <ListView
                android:id="@android:id/list"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                />
            </FrameLayout>
        </FrameSwipeRefreshLayout>
    

    【讨论】:

    【解决方案5】:

    您可以查看此问题。我发布了一个解决方案。

    Android - SwipeRefreshLayout with empty textview

    【讨论】:

      【解决方案6】:

      我使用两个 SwipeToRefreshLayouts 解决了这个问题。

      • 一个用于包装 ListView
      • 另一个为空视图

      我在GitHub 上发布了我的代码。

      【讨论】:

      • 这有效,但我的 ListView 不再可点击。
      • 我将 emptyView 的 SwipeToRefreshLayout 移到 ListView 的 SwipeToRefreshLayout 上方,现在可以使用了。
      【解决方案7】:

      正如上面写的@Dinesh,我使用了clickable="true",如下面的空RecyclerView

      mRecyclerView.setVisibility(View.VISIBLE);
      mRecyclerView.setClickable(true);
      myText.setVisibility(View.VISIBLE);
      

      xml 布局:

      <RelativeLayout
          android:layout_width="match_parent"
          android:layout_height="match_parent">
      
          <android.support.v4.widget.SwipeRefreshLayout
              android:id="@+id/swipeRefreshKartvizitKisilerim"
              android:layout_width="match_parent"
              android:layout_height="wrap_content">
      
              <android.support.v7.widget.RecyclerView
                  android:id="@+id/recyclerView"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"/>
          </android.support.v4.widget.SwipeRefreshLayout>
      
      
          <TextView
              android:id="@+id/myText"
              android:visibility="gone"
              android:text="@string/noListItem"
              android:textSize="18sp"
              android:layout_centerInParent="true"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content" />
      
      </RelativeLayout>
      

      RecyclerView 的高度为 match_parentSwipeRefresh 的高度为 wrap_content。当列表中有项目时,不要忘记输入文字gone

      【讨论】:

        【解决方案8】:

        我有另一个很好的想法。 继承 ListView 并覆盖 setAdapter()setEmptyView()setEmptyView 应该只存储用于空视图的视图,并且 setAdapter 应该注册一个 DataSetObserver 来隐藏/显示空视图而不改变列表视图的可见性。您可能希望使用一个 FrameLayout 来保存您的 SwipeToRefreshLayout 和一个空视图(作为兄弟姐妹)。然后,您可以使用重力和布局重力很容易地将空视图定位在顶部/中间/底部等。您也可以使用 RelativeLayout 但我没有尝试过。你会想以某种方式取消注册 dataSetObserver,我相信你可能想在 onDetachFromWindow 中这样做,就像我在下面所做的那样。

        public class SwipeToRefreshCompatibleList extends ListView {
        
            private boolean mIsEmpty = false;
            private View mEmptyView;
            private Adapter mAdapter;
        
            private DataSetObserver mLocalObserver = new  DataSetObserver() {
                @Override
                public void onChanged() {
                    boolean isEmpty = mAdapter == null || mAdapter.getCount() == 0;
                    if (mEmptyView != null) {
                        if (isEmpty != mIsEmpty) {
                            mEmptyView.setVisibility(isEmpty ? View.VISIBLE : View.GONE);
                        }
                    }
                    mIsEmpty = isEmpty;
                }
            };
        
            public SwipeToRefreshCompatibleList(Context context) {
                super(context);
            }
        
            public SwipeToRefreshCompatibleList(Context context, AttributeSet attrs) {
                super(context, attrs);
            }
        
            public SwipeToRefreshCompatibleList(Context context, AttributeSet attrs, int defStyleAttr) {
                super(context, attrs, defStyleAttr);
            }
        
            @TargetApi(Build.VERSION_CODES.LOLLIPOP)
            public SwipeToRefreshCompatibleList(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
                super(context, attrs, defStyleAttr, defStyleRes);
            }
        
            @Override
            public void setAdapter(ListAdapter adapter) {
                mAdapter = adapter;
                adapter.registerDataSetObserver(mLocalObserver);
                super.setAdapter(adapter);
            }
        
        
            @Override
            public void setEmptyView(View view) {
                mEmptyView = view;
            }
        
            @Override
            protected void onDetachedFromWindow() {
                super.onDetachedFromWindow();
                if (mAdapter != null) {
                    mAdapter.unregisterDataSetObserver(mLocalObserver);
                }
            }
        
        }
        

        示例布局文件:

            <?xml version="1.0" encoding="utf-8"?>
            <FrameLayout
                xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                >
                <android.support.v4.widget.SwipeRefreshLayout
                    android:id="@+id/swipe_container"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    >
        
                    <com.company.widget.SwipeToRefreshCompatibleList
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:id="@+id/BasicList"
                        android:divider="@null"
                        />
        
        
                </android.support.v4.widget.SwipeRefreshLayout>
        
                <TextView
                    android:padding="20dp"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center_horizontal"
                    android:layout_gravity="center"
                    android:textSize="18sp"
                    android:id="@android:id/empty"
                    />
        
            </FrameLayout>
        

        虽然这需要更多的代码而不是简单地继承 ListView 并更改 setVisibility 以便它不会将列表设置为 GONE/HIDDEN,但我觉得这不是一个 hack 并且仍然允许用户将列表设置为消失/隐藏,如果他们需要的话。

        【讨论】:

          【解决方案9】:

          我尝试过 UI hack,但没有成功,唯一有效的解决方案是设置适配器。 传递空值确保该值不会为空。

          NotificationListAdapter notificationListAdapter;
          notificationListAdapter = new NotificationListAdapter(mContext,notificationResponse);
          reCycleViewNotificationList.setAdapter(notificationListAdapter); // weather ListView or RecyclerView
          

          【讨论】:

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