【问题标题】:Android TextView inside ListView does not measure the correct height until manually scrollingListView 中的 Android TextView 在手动滚动之前不会测量正确的高度
【发布时间】:2021-02-23 19:51:51
【问题描述】:

我有一个充满多行 TextView 的 listView。每个 TextView 都有不同数量的文本。按下按钮后,用户将被带到另一个 Activity,他们可以在其中更改字体和字体大小。在重新进入 Fragment 时,如果这些设置发生了变化,则 listView 将被重置,TextView 的测量值也会发生变化。

在这些设置更改后,我需要知道视图中第一个 TextView 的测量高度。由于某种原因,测量的高度在测量后最初是不同的。一旦我手动滚动列表,就会记录实际的高度测量值。

日志输出:

测量后:电视高度 = 2036

测量后:电视高度 = 2036

滚动后:电视高度 = 7950

最小代码:

class FragmentRead : Fragment() {
    private var firstVisiblePos = 0
    lateinit var adapterRead: AdapterRead
    lateinit var lvTextList: ListView

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        lvTextList = view.findViewById(R.id.read_listview)
        setListView(lvTextList)


        lvTextList.setOnScrollListener(object : AbsListView.OnScrollListener {
            var offset = 0
            override fun onScrollStateChanged(view: AbsListView, scrollState: Int) {
                if(scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
                    offset = if(lvTextList.getChildAt(0) == null) 0 else lvTextList.getChildAt(0).top - lvTextList.paddingTop
                    println("After scroll: tv height = ${lvTextList[0].height}")
                }
            }

            override fun onScroll(view: AbsListView, firstVisibleItem: Int, visibleItemCount: Int, totalItemCount: Int) {
                firstVisiblePos = firstVisibleItem
            }
        })
    }
    /*=======================================================================================================*/

    fun setListView(lv: ListView) {
        adapterRead = AdapterRead(Data.getTextList(), context!!)
        lv.apply {this.adapter = adapterRead}
    }
    /*=======================================================================================================*/

    inline fun <T : View> T.afterMeasured(crossinline f: T.() -> Unit) {
        viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                if(measuredWidth > 0 && measuredHeight > 0) {
                    println("After measured: tv height = ${lvTextList[0].height}")
                    viewTreeObserver.removeOnGlobalLayoutListener(this)
                    f()
                }
            }
        })
    }
    /*=======================================================================================================*/
    override fun onStart() {
    if(Settings.settingsChanged) {
        setListView(lvTextList)
        lvTextList.afterMeasured {
                println("After measured: tv height = ${lvTextList[0].height}")
            }
        }
    }
}

我尝试过的:

我尝试使用文本和 layoutParams 设置 TextView 并按照此处 (Getting height of text view before rendering to layout) 的说明读取高度,但结果是相同的。测得的高度比我滚动列表后要小很多。

我还尝试使用 lvTextList.scrollBy(0,1) 以编程方式滚动列表,以触发滚动侦听器或在读取正确高度时触发其他任何内容。

编辑:回到片段后我延迟了:

Handler().postDelayed({
println("tv height after delay = ${lvScriptureList[0].height}")}, 1000)

这会报告正确的高度。所以我的猜测是 OnGlobalLayoutListener 被提前调用。有什么办法解决这个问题?

【问题讨论】:

    标签: android listview scroll textview ongloballayoutlistener


    【解决方案1】:

    这是我的解决方案。我需要知道 TextView 高度的原因是因为在用户更改设置(例如字体、字体大小、行距)后 TextView 的大小会发生变化。为了返回 TextView 之前所在的位置,我需要知道新测量的 TextView 的高度。然后我可以根据之前的位置到同一个位置(或非常接近),并根据新的高度重新计算它。

    所以在更改设置并重新加载 Fragment 后:

    override fun onStart(){
        if(Settings.settingsChanged) {
            setListView(lvTextList)
            lvTextList.afterMeasured {
                lvTextList.post { lvTextList.setSelectionFromTop(readPos, 0) }
                Handler().postDelayed({
                    val newOffset = getNewOffset() // Recalculates the new offset based on the last offset and the new TextView height
                    lvTextList.post { lvTextList.setSelectionFromTop(readPos, newOffset) }
                }, 500)
            }
        }
    }
    

    由于某种原因,我必须在安排延迟之前先滚动到某个位置,所以我只是滚动到 TextView 的开头。

    500 毫秒是愚蠢的,只是一个估计值,但它确实有效。它实际上适用于我的手机上的 100 毫秒值,但我想确保跨设备成功的机会更大。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-26
      • 1970-01-01
      • 2016-09-12
      • 2011-09-11
      • 1970-01-01
      • 1970-01-01
      • 2017-03-16
      • 1970-01-01
      相关资源
      最近更新 更多