2

这主要是一个概念问题。我在我的活动中使用 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。我使用自定义加载器而不是 CursorLoader,因为我不想创建 ContentProvider。

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

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

  1. 在加载数据期间将 ListView 替换为自定义视图,并在 Loader 完成其工作时显示 List

或者

  1. 使用一个适配器显示数据
  2. 使用另一个仅包含一个“正在加载”视图的适配器
  3. 在正确的时间设置正确的 Adapter(当 Loader 开始工作时:myList.setAdapter(mLoadingAdapter),当 Loader 完成工作时:myList.setAdapter(mDataAdapter))

还有其他想法吗?为了实现这一目标,你有什么“好的做法”提示给我吗?


我找到了解决方案,谢谢 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 的 Visibility 设置为 GONE,它会自动将空视图的 Visibility 设置为 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

4 回答 4

1

这是一个与您的应用程序工作相关的非常具体的问题。话虽如此,我认为在你的情况下最好的办法是在你的fragment布局文件中有 3 个视图。ListView每当查询完成并且项目计数非零时显示项目列表。ProgressBar查询正在进行时使用的另一个视图。通过设置进度编号(默认为 0 到 100),您可以控制它的可见性,ProgressBar或者如果您使用indeterminateProgressBar 样式,您可以visibility通过使用视图的可见性来控制它。最后,当要显示零个项目时使用Labelor - 控制此视图的可见性。并且在您的情况下是互斥的,这意味着在显示时,TextViewListViewTextViewListViewTextView是隐藏的。高温高压

于 2013-09-30T15:21:39.557 回答
1

看一下ListFragment支持库附带的哪个,它的源代码的副本在这里

这个类与常规类不同ListFragment,不同之处在函数中是可见的onCreateView。如果您查看它,它会提供您所描述的内容。

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

所以我要么建议你使用支持库的副本ListFragment而不是普通的,否则使用我上面链接的源代码作为制作你自己版本的类的垫脚石。

于 2013-09-30T15:28:49.807 回答
0

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

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

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

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

于 2013-09-30T15:17:57.060 回答
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();
}

这只是示例代码,它不会正常工作......

于 2013-09-30T17:50:09.857 回答