2

私はこれが初めてです。ListView をスクロールした後、自動選択される前に選択したアイテムと「同じ位置」にあるアイテム。(同じ位置は、データベースではなく画面内の位置を意味します。)OnItemClickListenerのListViewのインデックスでアイテムを選択していたため、以前にこの問題がありました。しかし、私は正しい方法でやっていますが、この問題に再び直面しています。

ListView でアイテムをクリックすると、一意の ID が取得され、それに基づいて、このアイテム (データベース内のこの行) の SELECTED 値が 0 または 1 に変更されます (クリックされたかどうかによって異なります)。その後、背景色を灰色に切り替えます (または白に戻します)。これは、SELECTED プロパティを区別する CursorAdapter で処理されます。

これが私のコードです。

MainActivity.kt の OnCreate

    val dbHelper = DBHelper(this)

    val db = dbHelper.writableDatabase

    val myCursor = db.rawQuery("SELECT * FROM ${ContractClass.FeedReaderContract.TABLE_NAME}", null)
    val myAdapter = CursorAdapter(this, myCursor)
        myListView.adapter = myAdapter

    myListView.setOnItemClickListener { _, view, _, _ ->
            val text = view.txtName.text
            val select = "${ContractClass.FeedReaderContract.COLUMN_NAME_ENWORD} MATCH ?"
            val selectCursor = db.query(
                ContractClass.FeedReaderContract.TABLE_NAME,   // The table to query
                null,             // The array of columns to return (pass null to get all)
                select,              // The columns for the WHERE clause
                arrayOf("$text"),          // The values for the WHERE clause
                null,                   // don't group the rows
                null,                   // don't filter by row groups
                null               // The sort order
            )
            with(selectCursor) {
                while (moveToNext()) {
                    val itemSel = getInt(getColumnIndexOrThrow(ContractClass.FeedReaderContract.COLUMN_NAME_SELECTED))
                    if (itemSel == 1){
                        val values = ContentValues().apply {
                            put(ContractClass.FeedReaderContract.COLUMN_NAME_SELECTED, 0)
                        }
                        val count = db.update(
                            ContractClass.FeedReaderContract.TABLE_NAME, values, select, arrayOf("$text"))

                    }else{
                        val values = ContentValues().apply {
                            put(ContractClass.FeedReaderContract.COLUMN_NAME_SELECTED, 1)
                        }
                        val count = db.update(
                            ContractClass.FeedReaderContract.TABLE_NAME, values, select, arrayOf("$text"))
                    }
                }
            }
        }

CursorAdapter.kt

class CursorAdapter(context: Context, cursor: Cursor) : CursorAdapter(context, cursor, 0) {

    // The newView method is used to inflate a new view and return it,
    // you don't bind any data to the view at this point.
    override fun newView(context: Context, cursor: Cursor, parent: ViewGroup): View {
        if (cursor.getInt(cursor.getColumnIndexOrThrow(ContractClass.FeedReaderContract.COLUMN_NAME_SELECTED)) == 0){
            return LayoutInflater.from(context).inflate(R.layout.row_list_row, parent, false)
        }else{
            return LayoutInflater.from(context).inflate(R.layout.user_list_row_selected, parent, false)
        }
    }

    // The bindView method is used to bind all data to a given view
    // such as setting the text on a TextView.
    override fun bindView(view: View, context: Context, cursor: Cursor) {
        // Find fields to populate in inflated template
        val tvBody = view.findViewById<View>(R.id.txtName) as TextView
        val tvPriority = view.findViewById<View>(R.id.txtComment) as TextView
        val tvPriority2 = view.findViewById<View>(R.id.txtThird) as TextView
        val tvPriority3 = view.findViewById<View>(R.id.txtThi) as TextView
        // Extract properties from cursor
        val body = cursor.getString(cursor.getColumnIndexOrThrow(ContractClass.FeedReaderContract.COLUMN_NAME_ENWORD))
        val priority = cursor.getString(cursor.getColumnIndexOrThrow(ContractClass.FeedReaderContract.COLUMN_NAME_DEFN))
        val priority2 = cursor.getInt(cursor.getColumnIndexOrThrow(ContractClass.FeedReaderContract._id))
        val priority3 = cursor.getInt(cursor.getColumnIndexOrThrow(ContractClass.FeedReaderContract.COLUMN_NAME_SELECTED))
        // Populate fields with extracted properties
        tvBody.text = body
        tvPriority.text = priority.toString()
        tvPriority2.text = priority2.toString()
        tvPriority3.text = priority3.toString()
    }
}

データベース テーブルの作成

private val SQL_CREATE_ENTRIES =
        "CREATE VIRTUAL TABLE ${ContractClass.FeedReaderContract.TABLE_NAME} USING fts4(" +
                "${ContractClass.FeedReaderContract._id}," +
                "${ContractClass.FeedReaderContract.COLUMN_NAME_ENWORD} TEXT," +
                "${ContractClass.FeedReaderContract.COLUMN_NAME_DEFN} TEXT," +
                "${ContractClass.FeedReaderContract.COLUMN_NAME_SELECTED} INTEGER)"

ここで同様の投稿を見つけました:単純なカーソルアダプターアイテムがチェックされたリストビューは、スクロール中にチェックされ ていませんが、私がすでに行ったことを示唆していると思います。

助けてくれてありがとう。

4

2 に答える 2

0

getItemViewType(position)複数の異なるビュー タイプを使用する場合は、オーバーライドする必要があります。そうしないと、アダプターは、View渡されたインスタンスがconvertView正しいタイプであるかどうかを知る方法がなく、不適切にリサイクルされたビューになってしまいます。

これは些細なことではないようですCursorAdapter(私は経験がありません)。私はそれを行う正しい方法は次のようなものであるべきだと思います:

override fun getItemViewType(position: Int): Int {
    cursor.moveToPosition(position)
    val columnIndex = cursor.getColumnIndexOrThrow(ContractClass.FeedReaderContract.COLUMN_NAME_SELECTED)
    return when (cursor.getInt(columnIndex)) {
        0 -> 0
        else -> 1
    }
}

newView()また、これらのタイプを活用するように変更する必要があると思います。あなたが持っているものを残してもうまくいくはずですが、それは重複したコードになります.

override fun newView(context: Context, cursor: Cursor, parent: ViewGroup): View {
    val layoutId = when (val type = getItemViewType(cursor.position)) {
        0 -> R.layout.row_list_row
        1 -> R.layout.user_list_row_selected
        else -> throw IllegalStateException("unexpected viewType: $type")
    }
    return LayoutInflater.from(context).inflate(layoutId, parent, false)
}
于 2019-09-16T22:01:52.997 に答える