![](/img/trans.png)
[英]How to navigate from ViewModel to a Fragment in Android Kotlin
[英]Android Kotlin: Setting fragment TextView background on start from ViewModel
我对我的代码中的某些不一致感到困惑,其中只有部分数据正在加载。 我正在尝试在我的片段中设置一个 TextViews 网格,该网格从该片段的 ViewModel 上名为board的列表变量中读取。 TextView 文本被设置为来自视图模型的board[n].text ,其中 n 是它在列表中的索引,这加载得很好。 我还尝试将 TextView 背景设置为三个背景资源之一,这些资源在视图模型上保存为 int board[n].marking 。
这不起作用。 似乎它正在尝试在视图模型中完全初始化board之前为每个 TextView 加载背景,但它似乎并没有尝试为 TextView 文本做同样的事情。 这是我的代码的相关部分。 一、XML布局:
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".screens.game.GameFragment">
<data>
<import type="android.view.View"/>
<variable
name="gameViewModel"
type="com.example.mygametitle.screens.game.GameViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
(...)
<TextView
android:id="@+id/field13"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="@dimen/board_vertical_margin"
android:background="@{gameViewModel.board[2].marking}"
android:onClick="@{ () -> gameViewModel.openGameDialog(2, field13)}"
android:text="@{gameViewModel.board[2].text}"
(...)
有 25 个这样的字段。 所有文本都正确加载,但没有任何背景图像加载。 相反,如果我硬编码我想要的背景,它会正确加载: android:background="@drawable/board_fieldbackground_checked"
。 不过,这对我不起作用,因为我需要在启动时阅读每个条目的背景——它们并没有全部开始检查。
在视图模型上, board是通过从 Room 数据库读取一组 25 个条目来制作的,每个条目包括(除其他信息外)一个文本字符串和一个标记int。 这些都正确更新——如果我使用调试功能打印出我的板的内容,它们在关闭和重新打开片段时都有正确的文本和标记。 当片段打开时,所有文本都是正确的,但背景不是。 关于为什么我的背景没有以与文本相同的方式加载的任何想法?
这是一些相关的视图模型代码:
class GameViewModel(
val database: BoardDatabaseDao,
application: Application,
val boardTitle: String) : AndroidViewModel(application) {
val BG_UNMARKED = R.drawable.board_fieldbackground_bordered
val BG_CHECKED = R.drawable.board_fieldbackground_checked
val BG_MISSED = R.drawable.board_fieldbackground_missed
private val thisBoardEntries = MutableLiveData<List<BoardField>?>()
private val _board = MutableLiveData<List<BoardField>>()
val board: LiveData<List<BoardField>>
get() = _board
private suspend fun getEntries() : List<BoardField>? {
Log.i("GameViewModel", "Running database.getFromParent(boardTitle), function getEntries().")
val entries = database.getFromParent(boardTitle)
return entries
}
init {
viewModelScope.launch {
Log.i("GameViewModel", "Start viewModelScope.launch on init block.")
thisBoardEntries.value = getEntries()
if (thisBoardEntries.value?.isEmpty()!!) {
Log.i(
"GameViewModel",
"allEntries.value is EMPTY, seemingly: ${thisBoardEntries.value}, should be empty"
)
} else {
Log.i(
"GameViewModel",
"allEntries.value is NOT empty, seemingly: ${thisBoardEntries.value}, should be size 25"
)
_board.value = thisBoardEntries.value
}
}
}
fun markFieldMissed(index: Int, view: TextView) {
Log.i("GameViewModel", "My Textview looks like this: $view")
_board.value!![index].marking = BG_MISSED
view.setBackgroundResource(BG_MISSED)
Log.i("GameViewModel", "Set background to $BG_MISSED")
val color = getColor(getApplication(), R.color.white_text_color)
view.setTextColor(color)
viewModelScope.launch {
val markedField = getEntryAtIndex(boardTitle, convertIndexToLocation(index))
Log.i("GameViewModel", "I think markedField is $markedField")
if (markedField != null) {
markedField.marking = BG_MISSED
update(markedField)
Log.i("GameViewModel", "Updated field with $BG_MISSED marking on DB: $markedField")
}
}
}
fun markFieldChecked(index: Int, view: TextView) {
_board.value!![index].marking = BG_CHECKED
view.setBackgroundResource(BG_CHECKED)
Log.i("GameViewModel", "Set background to $BG_CHECKED")
val color = getColor(getApplication(), R.color.white_text_color)
view.setTextColor(color)
viewModelScope.launch {
val markedField = getEntryAtIndex(boardTitle, convertIndexToLocation(index))
Log.i("GameViewModel", "I think markedField is $markedField")
if (markedField != null) {
markedField.marking = BG_CHECKED
update(markedField)
Log.i("GameViewModel", "Updated field with $BG_CHECKED marking on DB: $markedField")
}
}
}
fun debugPrintEntries() {
Log.i("GameViewModel", "DebugPrintEntries function: ${_board.value}")
}
(2020-11-05) 编辑 1:问题的一部分确实是没有被这样阅读的资源。 我在我的布局 XML 中做了以下添加/更改,这让我更进一步:
<data>
<import type="androidx.core.content.ContextCompat"/>
(...)
</data>
<TextView
(...)
android:background="@{ContextCompat.getDrawable(context, gameViewModel.BG_CHECKED)}"
(...)
使用 BG_CHECKED 的硬编码资源作为我的背景图像,一切都可以很好地加载和显示。 问题再次是背景不是从board[4].marking
(其中包含 BG_CHECKED 作为其值)读取的,尽管从board[4].text
读取文本没有问题
布局 XML 中的以下替换不起作用,导致异常: Caused by: android.content.res.Resources$NotFoundException: Resource ID #0x0
with the line
android:background="@{ContextCompat.getDrawable(context, gameViewModel.board[4].marking)}"
我没有使用过数据绑定,但我认为这可能是因为你只是提供一个Int
作为背景,它恰好代表一个资源 ID - 但数据绑定不知道这一点,所以它不知道它需要将其解析为资源中的可绘制值吗? 当您手动设置它时,您通过使用@drawable
语法明确告诉它这样做
这是一个博客,其中有人遇到了类似的事情(无论如何都是这种情况,但是有颜色) - 他们的第二个解决方案是将ContextCompat
导入添加到data
块,然后使用它在数据绑定表达式中进行ContextCompat.getColor
查找. 也许你可以做一些类似的事情来获得你需要的 drawable
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.