【问题标题】:How to properly scroll ScrollView with a SeekBar如何使用 SeekBar 正确滚动 ScrollView
【发布时间】:2019-06-10 15:20:15
【问题描述】:

我正在尝试创建一个自定义的垂直SeekBar,用于在ScrollView 中滚动文本。这是SeekBar

class CustomSeekBar : SeekBar {

constructor(context: Context) : super(context) {}

constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {}

constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}

override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
    super.onSizeChanged(h, w, oldh, oldw)
}

@Synchronized
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    super.onMeasure(heightMeasureSpec, widthMeasureSpec)
    setMeasuredDimension(measuredHeight, measuredWidth)
}

override fun onDraw(c: Canvas) {

    c.rotate(90f)
    c.translate(0f, -width.toFloat())

    super.onDraw(c)
}

override fun onTouchEvent(event: MotionEvent): Boolean {

    super.onTouchEvent(event)
    if (!isEnabled) {
        return false
    }

    when (event.action) {
        MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE, MotionEvent.ACTION_UP -> {

            val i = (max - (max * event.y / height)).toInt()
            progress = 100 - i
            onSizeChanged(width, height, 0, 0)
        }

        MotionEvent.ACTION_CANCEL -> {
        }
    }
    return true
}
}

这是我的代码,它试图将ScrollView 附加到我的片段的onStart 中的SeekBar

       override fun onStart() {
    super.onStart()

    val helpScrollView = view!!.findViewById<ScrollView>(R.id.helpScrollView)

    val helpSeekBar = view!!.findViewById<CustomSeekBar>(R.id.helpSeekBar)

   helpScrollView.viewTreeObserver.addOnGlobalLayoutListener {

       val scroll: Int = getScrollRange(helpScrollView)

       helpSeekBar.max = scroll
   }

    val seekBarListener = object : SeekBar.OnSeekBarChangeListener {

        override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {

            val min = 0
            if(progress < min) {
                seekBar?.progress = min;}

            helpScrollView.scrollTo(0, progress)

        }
        override fun onStartTrackingTouch(seekBar: SeekBar?) {
        }
        override fun onStopTrackingTouch(seekBar: SeekBar?) {

        }
    }

    helpSeekBar.setOnSeekBarChangeListener(seekBarListener)

}

private fun getScrollRange(scrollView: ScrollView): Int {

    var scrollRange = 0
    if (scrollView.childCount > 0) {
        val child = scrollView.getChildAt(0)
        scrollRange =
            Math.max(0, child.height - (scrollView.height - scrollView.paddingBottom - scrollView.paddingTop))
    }

    return scrollRange
}

SeekBar on 似乎只对其下半部分的触摸做出反应,拇指阴影仍然水平滚动离开屏幕。 ScrollView 轻微移动,但仅在滚动开始时向一个方向移动。我做错了什么?

【问题讨论】:

  • 这有什么需要?您可以更改滚动视图的拇指。
  • 我改变了拇指,我的问题是滚动。我想用 SeekBar 滚动文本。
  • 有什么理由说 text 不包含在可以...提供自己的搜索栏滚动的多行 TextView 中? (我很好奇)
  • 客户想要一个离散的 SeekBar。它只是在设计中。这将嵌入机器中,不会以传统方式滚动。

标签: android android-seekbar


【解决方案1】:

查看底部的更新答案以获取解决方案


我们是谁来判断你需要做什么,客户几乎总是对的!

无论如何,如果您仍然想这样做,(它可能会或可能不会起作用)我认为架构应该看起来像这样:

  1. SeekBar 很愚蠢,不应该知道它在做什么。你给它一个 min (0?) 和一个 MAX (n)。您订阅其监听器并接收“进度”更新。 (哈,这很容易)
  2. ScrollView 包含文本,除了它的基础之外也非常不智能,它可以被告知滚动到一个位置(我猜这会涉及一些工作,但我相信这并不难)。
  3. 计算 MAX 值将决定第 2 步的难度。如果您将滚动内容中的每个“步骤”用作“文本行”,那么这很好,但您需要考虑可能会改变文本大小的布局更改和重新测量。不应该“疯狂”,但请记住这一点,否则一旦用户旋转手机,您就会收到第一份错误报告:)
  4. 如果文本是动态的(可以实时更改),您的第 3 步函数应该尽可能高效,您希望“尽快”获得这些数字。
  5. 响应搜索栏的进度变化并让您的可滚动内容滚动将非常容易(您找到了一种非常容易做到的方法)或者如果您无法使 ScrollView 表现得如您所愿,则非常复杂。

替代方法

如果您的文本真的很长,我敢打赌,如果您将文本分成几行并使用 recyclerview 显示它,您将会获得更好的性能,这将使滚动“稍微容易一些”,因为您可以移动您的 recyclerview到一个位置(线!)。

更新

好的,出于好奇,我尝试了这个。我启动了 AS,创建了一个带有“Empty Activity”的新项目,并添加了一个 ScrollView,里面有一个 TextView,底部有一个 SeekBar(水平)。

这是所有相关位的要点:

https://gist.github.com/Gryzor/5a68e4d247f4db1e0d1d77c40576af33

解决方案的核心开箱即用

scrollView.scrollTo(0, progress) progress 由 seekBar 的 onProgressChanged() 中的框架回调返回给您。

现在的关键是为搜索栏设置正确的“Max”。

这是通过躲避 ScrollView 中的私有方法获得的:

(信用在哪里到期,我从here得到这个想法)

    private fun getScrollRange(scrollView: ScrollView): Int {

        var scrollRange = 0
        if (scrollView.childCount > 0) {
            val child = scrollView.getChildAt(0)
            scrollRange =
                Math.max(0, child.height - (scrollView.height - scrollView.paddingBottom - scrollView.paddingTop))
        }

        return scrollRange
    }

这很好用,假设您等待 seekBar 测量/布局(因此我必须在 treeObserver 中执行此操作)。

【讨论】:

  • 感谢您的回复。我们对建筑有着相似的想法。我将 SeekBar 的最大值设置为 ScrollView 的 maxScrollAmount。不过,我什至还没有达到我什至可以看到这是否有效的地步,因为我不相信 SeekBar 甚至还没有被正确绘制。值得一提的是,这个应用程序被嵌入到一台具有单一屏幕尺寸且没有配置更改的机器上
  • 你用什么来“滚动”?一个ScrollView 里面有一个TextView
  • 是的,在其他地方推荐了滚动视图中的文本视图。
  • 出于好奇,“scrollview”报告为“maxScrollAmount”的值是多少?您确定这是要使用的正确值吗? (我知道你还没到那里)
  • 我将此答案标记为正确,因为我现在意识到我的代码有多个缺陷,而您肯定解决了其中一个缺陷。非常感谢。如果你想留下来,我已经上传了一个关于展示 SeekBar 的其他不良行为的视频 (youtube.com/watch?v=1XGPXF28ONg&feature=youtu.be)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-14
  • 1970-01-01
  • 2012-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-20
相关资源
最近更新 更多