使用基于SQLite DB数据的不同ListView布局

时间:2014-07-30 10:35:38

标签: android sqlite android-layout listview android-listview

我正在开发一个非常简单的列表应用程序,用于将项目保存到SQLite DB,并使用它的内容填充ListView。

这可以使用SimpleCursorAdapter完成,我喜欢这样:

mySQLiteAdapter.openToRead();
cursor = mySQLiteAdapter.queueAll();
String[] from = new String[]{mySQLiteAdapter.getKeyContent()};
int[] to = new int[]{R.id.normal};
cursorAdapter = new SimpleCursorAdapter(this, R.layout.row, cursor, from, to, 0);
listView.setAdapter(cursorAdapter);
mySQLiteAdapter.close();

现在我想实现通过点击或长按来删除行中文本的功能,或者将行更改为不同的布局(也可能会对文本产生影响)

首先,我只需为列表视图设置onClickListener,并更改绘制标记以触发文本。这可以正常工作,直到列表中有足够的项目来滚动视图,或者直到重新加载活动。在后者中,罢工已经消失(因为没有任何东西是持久性的),并且在前者中其他行被打击,而预期的行则没有。然后滚动时会发生变化。有关我自己的类似情况,请参阅Custom ListView adapter, strange ImageView behavior

由此我发现我需要使用自定义适配器来做我想要的。所以我创建了一个CustomCursorAdapter,它扩展了SimpleCursorAdapter并覆盖了一些方法,试图用背景颜色来膨胀单独的布局。我没有太多运气。

这是我到目前为止所做的:

// Creating a new instance of the custom adapter and assigning it to the listview
mySQLiteAdapter.openToRead();
cursor = mySQLiteAdapter.queueAll();
String[] from = new String[]{mySQLiteAdapter.getKeyContent()};
int[] to = new int[]{R.id.normal};
cursorAdapter = new CustomCursorAdapter(this, R.layout.row, cursor, from, to, 0);
listView.setAdapter(cursorAdapter);
mySQLiteAdapter.close();

// CustomCursorAdapter class
private class MyCursorAdapter extends SimpleCursorAdapter {
    private LayoutInflater inflater;

    public MyCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) {
        super(context, layout, c, from, to, flags);
        inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // Get reference to the row
        View view = super.getView(position, convertView, parent);
        //View view;

        if (getItemViewType(position) == 0) {
            view = inflater.inflate(R.layout.row, null);
        }
        else {
            view = inflater.inflate(R.layout.rowstrike, null);
        }
        return view;
    }

    @Override
    public int getItemViewType(int position) {
        int row;
        if (cursor.getInt(cursor.getColumnIndex(mySQLiteAdapter.getKeyStrike())) == 1) {
            Log.d("DEBUG", "Row " + position + " is STRIKED");
            row =  1;
        }
        else  {
            Log.d("DEBUG", "Row " + position + " is normal");
            row =  0;
        }
        return row;
    }
}

CustomCursorAdapter的实现可以正常工作并显示正确的行数。通过查询db来确定行是否应包含striked文本的逻辑是正确的,但返回的膨胀视图是完全空白的。我认为这可能与我的XML文件的排列方式以及我传递给适配器的方式有关,但到目前为止,我所有的测试和修补试图让这个工作都失败了。

以下是布局的XML文件

// activity_main.xml
<RelativeLayout 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"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <EditText
        android:layout_width="fill_parent"
        android:layout_height="35dp"
        android:id="@+id/editText"
        android:hint="Press here to add an item"
        android:maxLines="1"
        android:imeOptions="actionDone"
        android:inputType="textAutoCorrect"/>

    <ListView
        android:layout_width="match_parent"
        android:layout_height="fill_parent"
        android:id="@+id/listView"
        android:layout_below="@id/editText"/>
</RelativeLayout>

// row.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="5dp" >
    <TextView
    android:id="@+id/normal"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textStyle="bold"/>
</RelativeLayout>

//rowstrike.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="5dp" >
    <TextView
    android:id="@+id/striked"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textColor="#F05"/>
</RelativeLayout>

我一直在搜索这些日子和日子,每次都越来越近但似乎什么都没有用,或者解释对于像我这样的人来说并不适合初学者。

我发现的最接近的帖子是我 ListView view recycling with CustomAdapter

但是我认为我需要更多的代码片段,因为我必须在我的应用中的其他地方做错了什么? 提到覆盖getViewTypeCount方法,但我不确定如何做到这一点......

还有 How would I use a different row layout in custom CursorAdapter based on Cursor data? 但是我不太确定从这篇文章到哪里去......

编辑:基于Luksprogs帖子的解决方案。

mySQLiteAdapter.openToRead();
cursor = mySQLiteAdapter.queueAll();

String[] from = new String[]{mySQLiteAdapter.getKeyContent()};
int[] to = new int[]{R.id.normal};

cursorAdapter = new SimpleCursorAdapter(this, R.layout.row, cursor, from, to, 0);
cursorAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {

    @Override
    public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
        if (view.getId() == R.id.normal) {
            TextView tv = (TextView)view.findViewById(R.id.normal);

            if (cursor.getInt(cursor.getColumnIndex(mySQLiteAdapter.getKeyStrike())) == 1) {
                tv.setPaintFlags(tv.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
            }
            else {
                tv.setPaintFlags(tv.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
            }
        }
        return false;
    }

});

listView.setAdapter(cursorAdapter);
mySQLiteAdapter.close();

我有一个OnItemClickListener,如下所示,以打击和取消打击行

private ListView.OnItemClickListener listViewOnItemClickListener
        =new ListView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        final int rowID = cursor.getInt(cursor.getColumnIndex(mySQLiteAdapter.getKeyID()));
        mySQLiteAdapter.openToWrite();

        if (cursor.getInt(cursor.getColumnIndex(mySQLiteAdapter.getKeyStrike())) == 0) {
            mySQLiteAdapter.setKeyStrike(rowID, 1);
        }
        else {
            mySQLiteAdapter.setKeyStrike(rowID, 0);
        }
        cursor = mySQLiteAdapter.queueAll();
        cursorAdapter.swapCursor(cursor);
        mySQLiteAdapter.close();
};

1 个答案:

答案 0 :(得分:0)

  

但是返回的膨胀视图完全是空白的。

作为旁注,您不应该覆盖基于Cursor的适配器的getView()方法,因为这种类型的适配器实现了getView()来分隔构建行布局并使用两个单独的方法绑定数据{ {1}}和newView()。应该重写这两种方法。另外,SimpleCursorAdapter是为基本场景设计的类,如果你需要实现(真的)不同的行类型,那么扩展CursorAdapter将是一种更好的方法。

您获得空白行布局,因为您不会对它们进行任何数据绑定。在getView()方法中,您可以:

bindView()

将返回正确构建的行布局(通过SimpleCursorAdapter类实现),仅丢弃该视图并根据行类型(if-else代码片段)膨胀行布局)。您不会将任何数据绑定到这些视图,因此您只返回膨胀的布局,该布局将为空白。

如果你的两行只是一个删除线文本不同,那么你不应该使用两种行类型(当行的结构不同时,应该使用不同的行类型)。您可以通过ViewBinder实现您想要的内容:

View view = super.getView(position, convertView, parent);

如果你想要

  

我想实现能够删除文本的能力   点击或长按

然后你需要记住某个地方的行状态,以便你可以用它来恢复它。