Android Jetpack Compose:如何滚动到包含新插入的 Room 数据库条目的 LazyColumn 行?

问题描述 投票:0回答:3

我有一个 LazyColumn 连接到 Room 数据库查询。我正在扩展“看得见风景的房间”示例(https://developer.android.com/codelabs/android-room-with-a-view-kotlin#0),但我使用的是 LazyColumn RecyclerView 的用于显示表条目列表。

插入条目(Word)后,我希望 LazyColumn 自动滚动到包含新插入条目的行(或至少使其可见)。请注意,列表查询是按字母顺序排序的,新行不会出现在列表末尾。

// table:
@Entity(tableName = "word_table")
class Word(
    @PrimaryKey @ColumnInfo(name = "word") val text: String
)

// DAO:
@Query("SELECT * FROM word_table ORDER BY word COLLATE NOCASE ASC")
fun getAlphabetizedWords(): Flow<List<Word>>

@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(word: Word)

// repository:
val allWords: Flow<List<Word>> = wordDao.getAlphabetizedWords()

suspend fun insert(word: Word) {
    wordDao.insert(word)
}

// viewModel:
val allWords: LiveData<List<Word>> = repository.allWords.asLiveData()

fun insert(word: Word) = viewModelScope.launch {
    repository.insert(word)
}

// simplified composable:
@Composable
fun WordList() {
   val list by mWordViewModel.allWords.observeAsState(listOf())

   LazyColumn() {
      items(list) { word ->
         Row() {
            Text(word.text)
         }
      }
   }
}

否则一切工作正常,存储库和视图模型是按照一般准则实现的。有什么想法吗?

android android-room items
3个回答
1
投票
val listState = rememberLazyListState(initialFirstVisibleItemIndex = (list.size - 1))

LazyColumn(state = listState){
    items(list){
        ...
    }
}

您可以使用 ListState 来操纵滚动位置,有点像您使用 LayoutManager 那样。


0
投票

我将使用的工作流程:

  1. 您可以将旧列表与新列表进行比较,如下所示:

    firstList.filter { it.name !in secondList.map { item -> item.name } }
    
  2. 然后使用for循环进行计数,直到在列表中找到单词

  3. 根据位置根据编号滚动到位置


0
投票

这是我自己的看法。插入时,行 ID 存储在变量中。当布局重组时,通过列表搜索找到最后插入行的索引,并将 LazyColumn 滚动到该索引。

编辑:我修改了答案中的代码,使其更加通用并符合 Kotlin 习惯用法。

// table:
@Entity(tableName = "word_table")
class Word(
    val text: String,
    // primary key is autogenerated, also variable 
    // because it has to be modified:
    @PrimaryKey(autoGenerate = true) var id: Long = 0L
)

// DAO: 
@Query("SELECT * FROM word_table ORDER BY text COLLATE LOCALIZED ASC")
fun getAlphabetizedWords(): Flow<List<Word>>

@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insertBase(word: Word) : Long

suspend fun insert(word: Word)
{
    // explicitly store inserted row id in entity object,
    // it will not happen automatically:
    word.id = insertBase(word)
}

// repository:
val mAllWords: Flow<List<Word>> = wordDao.getAlphabetizedWords()

suspend fun insert(word: Word) 
{
    wordDao.insert(word)
}

// viewModel:
val mAllWords: LiveData<List<Word>> = repository.mAllWords.asLiveData()
var mInsertedId: Long = -1L; // the id of the last inserted row

fun insert(word: Word) = viewModelScope.launch 
{
    repository.insert(word)
    mInsertedId = word.id // store id
}

fun getInsertedId() : Long
{
    val id = mInsertedId
    mInsertedId = -1L // clear stored value
    return id
}

// helper used by the "Add" button composable (not shown here):
fun addWordToDb(text: String)
{
    if(!text.isBlank())
        mWordViewModel.insert(Word(text))
}

// simplified composable:
@Composable
fun WordList(viewModel: WordViewModel) 
{
   val list by viewModel.allWords.observeAsState(listOf())
   val listState = rememberLazyListState()

    // scroll to inserted item:
    LaunchedEffect(list)
    {
        val insertedId = viewModel.getInsertedId()

        if(insertedId != -1L){
            // find index of last inserted item in list:
            val index = list.indexOfFirst{ it.id == insertedId }

            if(index != -1)
                listState.animateScrollToItem(index)
        }
    }

   // display list:
   LazyColumn(state = listState) 
   {
      items(list) { word ->
         Row() {
            Text(word.text)
         }
      }
   }
}

感谢 F.Mysir 和 eimmer 的投入。顺便说一句,我尝试从 SQLite/Room 获取索引,如下所示:

@Query("SELECT COUNT(*) FROM word_table WHERE LOWER(text) < LOWER(:searchString)")
suspend fun getWordIndex(searchString: String): Int

...并且它(几乎)适用于 ASCII,但对于包含非 ASCII 字符的字符串则失败,即使数据库区域设置设置为具有不同字母表的语言也是如此。

© www.soinside.com 2019 - 2024. All rights reserved.