Android - 使用空textview的SwipeRefreshLayout

Nie*_*els 31 android android-listview

我已经实现SwipeRefreshLayout了我的应用程序,但它只能容纳一个应该是listview的直接子项.我试图找出如何将空文本视图添加到以下工作XML文件:

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

    <ListView
        android:id="@+id/listViewConversation"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:dividerHeight="1dp" />

</android.support.v4.widget.SwipeRefreshLayout>
Run Code Online (Sandbox Code Playgroud)

将其包装在线性/相对布局中会使其失灵,因为当您想要向下滑动列表视图时,列表视图将始终更新.我能想到的一种方法是以编程方式进行此操作,但我想这不是最好的选择.

您可以使用本教程学习如何实现它:滑动以刷新GUIDE

所以基本上它一切正常,但我想添加一个空视图,当listview为空时显示一条消息.

Dan*_*ato 52

我不喜欢对一个孩子的限制.此外,SwipeRefreshLayout的当前实现具有ScrollView,ListView和GridView的硬编码"魔术"处理,仅当视图是您自己视图的直接子视图时才触发.

这说好消息是它是开源的,所以你可以复制代码并适应你的需求,或者你可以做我做的事情:

使用两个不同的SwipeRefreshLayout,一个用于Empty视图,另一个用于ListView.

<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"
    tools:context="com.tobrun.example.swipetorefresh.MainActivity">

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

        <ListView
            android:id="@+id/listView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

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

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

        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fillViewport="true">

            <TextView
                android:id="@+id/emptyView"
                android:text="@string/empty"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:gravity="center" />

        </ScrollView>

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


</FrameLayout>
Run Code Online (Sandbox Code Playgroud)

然后告诉列表视图空列表视图是空视图的滑动刷新布局.

现在,当您有数据时,列表视图将自动隐藏空刷新布局,并在列表为空时显示.

列表的滑动刷新布局不应接收触摸事件,因为列表是隐藏的.

祝好运.

  • 以下是一些示例代码:https://github.com/AndroidExamples/SwipeRefreshLayout-ListViewExample (5认同)

and*_*per 31

无需任何解决方法.

您只需使用此视图层次结构:

    <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>
Run Code Online (Sandbox Code Playgroud)

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

_listView.setEmptyView(findViewById(android.R.id.empty));
Run Code Online (Sandbox Code Playgroud)

而已.


编辑:如果您希望即使显示空视图也能够刷到刷新,您将不得不以某种方式避免隐藏ListView,因此您可以使用具有此功能的自定义ListView:

@Override
  public void setVisibility(final int visibility)
    {
    if(visibility!=View.GONE||getCount()!=0)
      super.setVisibility(visibility);
    }
Run Code Online (Sandbox Code Playgroud)

与我编写的解决方案一起,无论您显示多少项目,都会显示刷卡到刷新.

当然,如果你真的想隐藏ListView,你应该改变代码.也许添加"setVisibilityForReal(...)":)

  • 如果你想能够刷新空视图,你必须将`FrameLayout`(包括`ListView`和`EmptyView`)放在`SwipeRefreshLayout`中.另外,在`FrameLayout`中设置`android:clickable ="true"` (7认同)
  • @androiddeveloper在适当尊重的情况下,由于没有互联网或者服务器停机而无法加载数据时,它确实有意义.因此可以刷新空视图.非常感谢提及@antoinem解决方案.以前我尝试过相同但是`android:clickable = true`是关键并且确实有效.这仍然不适用于标准的`SwipeRefreshLayout`!必须使用https://github.com/googlesamples/android-SwipeRefreshMultipleViews (2认同)

viz*_*izZ 11

实际上,你唯一想到的就是把空TextView包裹着一个可滚动的容器 - 例如ScrollView.有关详细信息,请查看SwipeRefreshLayout.canChildScrollUp()方法及其用法.

无论如何,回到原点.这是一个成功的实施:

activity_some.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/swipe_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:measureAllChildren="true">

        <WebView
            android:id="@+id/webview"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

        <include layout="@layout/empty" />

    </FrameLayout>

</android.support.v4.widget.SwipeRefreshLayout>
Run Code Online (Sandbox Code Playgroud)

empty.xml的基本上是你希望包装的东西ScrollView.

empty.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/empty"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true">

    <TextView
        android:text="Nothing here..."
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</ScrollView>
Run Code Online (Sandbox Code Playgroud)

现在,为了摆脱着名SwipeRefreshLayout的只刷新时的问题,SwipeRefreshLayout在必要时切换(特定于片段):

private ViewTreeObserver.OnScrollChangedListener mOnScrollChangedListener;

@Override
public void onStart() {
    super.onStart();

    mOnScrollChangedListener = new ViewTreeObserver.OnScrollChangedListener() {
        @Override
        public void onScrollChanged() {
            int scrollY = mWebView.getScrollY();
            if (scrollY == 0)
                swipeLayout.setEnabled(true);
            else
                swipeLayout.setEnabled(false);

        }
    };
    swipeLayout.getViewTreeObserver().addOnScrollChangedListener(mOnScrollChangedListener);
}

@Override
public void onStop() {
    swipeLayout.getViewTreeObserver().removeOnScrollChangedListener(mOnScrollChangedListener);
    super.onStop();
}
Run Code Online (Sandbox Code Playgroud)

而已!希望能帮助到你!;)

顺便说一句,你为什么会使用SwipeRefreshLayoutFrameLayout这种方式?因为这样您可以执行平滑过渡动画,例如交叉渐变效果,并且您的任何状态视图都可以刷卡(如果您需要统一的提取/刷新/重试机制).


Sta*_*ica 8

这就是我所做的:我禁用刷卡刷新,除非我的listView已启动.

mBookedProductsListView.setOnScrollListener(new AbsListView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(AbsListView absListView, int i) {
        }
        @Override
        public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount,     int totalItemCount) {
            if (firstVisibleItem == 0)
                mSwipeRefreshLayout.setEnabled(true);
            else
                mSwipeRefreshLayout.setEnabled(false);
        }
    });
Run Code Online (Sandbox Code Playgroud)

我的Xml:

<?xml version="1.0" encoding="utf-8"?>

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

<RelativeLayout
        android:id="@+id/productListLL"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >

    <EditText
            android:id="@+id/search"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:layout_alignParentTop="true"
            android:background="#a4aeb8"
            android:drawableRight="@drawable/search_icon"
            android:paddingRight="15dp"
            android:textColor="@android:color/white"
            android:paddingLeft="15dp"
            android:hint="Rechercher"
            android:textColorHint="@android:color/white"
            android:inputType="textCapWords|textNoSuggestions"
            />

    <include android:layout_width="match_parent" android:layout_height="wrap_content" layout="@layout/filter_by_categories_buttons" android:id="@+id/categoriesTree" android:layout_below="@id/search" />

    <ListView
            android:id="@+id/productListLV"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:divider="@drawable/product_listview_divider"
            android:dividerHeight="1dp"
            android:scrollbars="none"
            android:overScrollMode="never"
            android:choiceMode="multipleChoiceModal"
            android:background="#e7eaef"
            android:visibility="gone"
            android:layout_below="@id/categoriesTree"
            />

</RelativeLayout>

</android.support.v4.widget.SwipeRefreshLayout>
Run Code Online (Sandbox Code Playgroud)

奇迹般有效.


huf*_*g03 6

我遇到了同样的问题.令人讨厌的是SwipeRefreshLayout只能有一个AdpaterView子项.

如果为AdpaterView设置了空视图,则在没有可用数据的情况下将其设置为隐藏.但是,SwipeRefreshLayout需要AdpaterView才能工作.因此,我扩展了AdpaterView以使其仍然显示,即使它是空的.

@Override
public void setVisibility(int visibility) {
    if (visibility == View.GONE && getCount() == 0) {
        return;
    }
    super.setVisibility(visibility);
}
Run Code Online (Sandbox Code Playgroud)

也许您需要将适配器视图的背景设置为透明.但在我的情况下,它不是必需的,因为空视图是一个简单的TextView.


Gre*_*nis 5

根据此处的一些答案和 SwipeRefreshLayout 的源代码,我将视图子类化为专门处理 RecyclerView(或 ListView)以及容器内的“空”视图,即子容器。

它需要一个布局,例如

<SwipeRefreshLayoutWithEmpty ...>
  <FrameLayout ...>
    <TextView android:text="List is Empty" ...>
    <RecyclerView ...>
  </FrameLayout>
</SwipeRefreshLayoutWithEmpty>
Run Code Online (Sandbox Code Playgroud)

代码是:

public class SwipeRefreshLayoutWithEmpty extends SwipeRefreshLayout {
    private ViewGroup container;

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

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

    @Override
    public boolean canChildScrollUp() {
        // The swipe refresh layout has 2 children; the circle refresh indicator
        // and the view container. The container is needed here
        ViewGroup container = getContainer();
        if (container == null) {
            return false;
        }

        // The container has 2 children; the empty view and the scrollable view.
        // Use whichever one is visible and test that it can scroll
        View view = container.getChildAt(0);
        if (view.getVisibility() != View.VISIBLE) {
            view = container.getChildAt(1);
        }

        return ViewCompat.canScrollVertically(view, -1);
    }

    private ViewGroup getContainer() {
        // Cache this view
        if (container != null) {
            return container;
        }

        // The container may not be the first view. Need to iterate to find it
        for (int i=0; i<getChildCount(); i++) {
            if (getChildAt(i) instanceof ViewGroup) {
                container = (ViewGroup) getChildAt(i);

                if (container.getChildCount() != 2) {
                    throw new RuntimeException("Container must have an empty view and content view");
                }

                break;
            }
        }

        if (container == null) {
            throw new RuntimeException("Container view not found");
        }

        return container;
    }
}
Run Code Online (Sandbox Code Playgroud)

完整要点:https : //gist.github.com/grennis/16cb2b0c7f798418284dd2d754499b43