繁体   English   中英

Android Kotlin:从 ViewModel 启动时设置片段 TextView 背景

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM