如何在ListView中显示空视图,进度视图和数据?

时间:2013-09-30 15:06:34

标签: android listview

这主要是一个概念性问题。我在我的Activity中使用了ListFragment。其列表必须显示以下信息之一:

  • 项目列表
  • 如果没有项目,则为空视图
  • 从数据库加载数据的“加载”视图

空视图由框架自动管理,因为onCreateView上的ListFragment正在创建这样的自定义视图:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance){
    if(Globals.DEBUG_LIFECYCLE)
        Log.d("Fragment", "ONCREATEVIEW");

    return inflater.inflate(R.layout.kanji_list, null);
}

kanji_list的布局就是这个:

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

<ListView android:id="@id/android:list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:listSelector="@android:color/transparent" />

    <ch.shibastudio.kanjinotepad.list.KanjiListEmptyView android:id="@id/android:empty"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:text="@string/no_kanji"
        android:visibility="gone"/>

数据存储在嵌入我的应用程序的SQLite数据库中。当应用程序想要更新到ListView时,使用自定义Loader查询数据库并将Cursor返回到ListFragment。我使用自定义Loader而不是CursorLoader,因为我不想创建ContentProvider。

所以,我想做的事情是:当应用程序从数据库开始查询数据时,将显示“加载”视图,显示进度图和一个文字说“获取数据”。然后,当Loader完成其工作时,我想在ListView中显示查询的数据,或者如果没有数据则显示“空”视图。

出于某些原因,我不想使用ProgressDialog。所以我的问题是:如何提供“加载”视图?以下是我的第一个粗略的想法:

  1. 在加载数据期间通过自定义视图替换ListView,并在Loader完成其作业时显示List
    1. 使用一个适配器显示数据
    2. 使用另一个仅包含一个“加载”视图项目的适配器
    3. 在正确的时间设置正确的适配器(当Loader启动其作业时:myList.setAdapter(mLoadingAdapter),当Loader完成其作业时:myList.setAdapter(mDataAdapter))
    4. 还有其他想法吗?为了达到这个目的,你有什么“好的做法”暗示给我?


      我找到了解决方案,谢谢Kasra Rahjerdi和Harikris! 我是这样做的:

      首先,为ListView,空视图和“加载”视图创建一个布局文件:

      <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      android:orientation="vertical" >
      
          <LinearLayout android:id="@+id/listcontainer"
              android:orientation="vertical"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              >
      
              <ListView android:id="@id/android:list"
                  android:layout_width="fill_parent"
                  android:layout_height="fill_parent"
                  android:listSelector="@android:color/transparent"
                  />
      
              <ch.shibastudio.kanjinotepad.list.KanjiListEmptyView android:id="@id/android:empty"
                  android:layout_width="fill_parent"
                  android:layout_height="fill_parent"
                  android:text="@string/no_kanji"
                  android:visibility="gone"/>
          </LinearLayout>
      
          <ch.shibastudio.kanjinotepad.customviews.LoadingView android:id="@+id/loading"
          android:layout_height="match_parent"
          android:layout_width="match_parent"
          android:visibility="gone"
          />
      </LinearLayout>
      

      为ListView 创建一个容器(此处为 listContainer )非常重要。我尝试将ListView的可见性设置为GONE,并自动将空视图的可见性设置为Visible。看起来有一些内部代码为ListView执行此操作,因此解决方案是将它们放在容器中并完全显示/隐藏它。

      基本上,这个想法是:当数据加载时,我想显示加载视图,为此,我通过将其Visibility置于GONE来隐藏ListView容器(如果我将Visibility置于INVISIBLE,它保持视图中列表的大小,使用GONE就像完全删除它一样,因此,“加载”视图可以占用所有屏幕)并通过将其可见性置于可见状态来显示“加载”视图。

      在我的ListFragment中,我得到了这些视图的引用:

      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance){
          View v = inflater.inflate(R.layout.kanji_list, null);
          mLoadingView = (LoadingView)v.findViewById(R.id.loading);
          mListContainer = (LinearLayout)v.findViewById(R.id.listcontainer);
          return v;
      }
      

      我通过调用此方法显示/隐藏“加载”视图:

      private void setLoadingViewVisible(boolean visible){
          if(null != mLoadingView && null != mListContainer){
              mListContainer.setVisibility(visible ? View.GONE : View.VISIBLE);
              mLoadingView.setVisibility(visible ? View.VISIBLE : View.GONE);
          }
      }
      

4 个答案:

答案 0 :(得分:1)

这是一个与您的应用程序工作相关的非常具体的问题。话虽如此,我认为在您的案例中最好的做法是在fragment布局文件中包含3个视图。 ListView在查询完成且项目计数为非零时显示项目列表。查询正在进行时要使用的另一个ProgressBar视图。通过设置进度编号(默认为0到100),您可以控制此ProgressBar的可见性,或者如果您使用的是indeterminate样式的ProgressBar,则可以控制它{{1}通过使用View的可见性。最后,当要显示的项目为零时,将使用visibilityLabel来控制此视图的可见性。 TextViewListView在您的情况下是互斥的,这意味着TextView显示时,隐藏ListView。 HTH

答案 1 :(得分:1)

查看支持库附带的ListFragment,副本of its source code is here

此类与常规ListFragment不同,差异在onCreateView函数中可见。如果你看一下,它就能提供你正在描述的内容。

  1. 在数据绑定到它之前,它提供了一个动画加载微调器。
  2. 它显示您要在适配器中显示的任何数据,就像常规ListFragment
  3. 一样
  4. 它有一个可选的空字段,您可以通过调用setEmptyText()
  5. 来设置

    所以我建议您使用支持库的ListFragment副本而不是正常副本,否则请使用我上面链接的源代码作为制作您自己版本的垫脚石该课程。

答案 2 :(得分:0)

听起来您希望列表包含加载消息而不会阻止用户。我认为你已经想出了一些在数据提取完成后异步更新列表的方法。

无论如何,我想到了几种方法。

最简单的可能是在线性布局中有三个视图并隐藏其中两个视图,只显示有一些要显示的视图。例如,在加载时你会隐藏id / android:list并显示“loading ...”的视图。加载完成后,您将隐藏“加载...”并取消隐藏列表或“空”视图。

另一种方法是使用三种列表项。看看Adapter。子类适配器(或您正在使用的任何变体)并定义getViewTypeCount以返回3.然后定义getItemViewType以返回三个值中的一个,具体取决于您要显示的内容。最后,增强getView(你必须已经有这个函数的一个版本)来返回三种类型的视图。

答案 3 :(得分:0)

我建议您在 onCreateView 中创建包含ListView的空视图。
然后在 onStart 中显示您的ProgressBar。现在启动一个线程,否则您的ProgressBar可能不会显示,因为以下代码在主线程上运行。在此主题中,您将加载数据,显示它并关闭ProgressBar。

public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.list_view, container, false);

        return view;
}

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

    // ProgressBar
    new ProgressDialog(getActivity());
    final ProgressDialog dialog = ProgressDialog.show(getActivity(),
            getString(R.string.loading_title),
            getString(R.string.loading_msg), true, false);

    // get ListView
    final ListView myListView = (ListView) getView().findViewById(
                R.id.listView1);

    Thread thread = new Thread() {
        @Override
        public void run() {
            //load your data here (fill Adapter)!
            loadData();

            getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    // fill ListView, dismiss Dialog
                    myListView.setAdapter(yourAdapterWithData);
                    dialog.dismiss();
                    }
                });
            }
        };

    thread.start();
}

这只是示例代码,它无法正常工作......