gpt4 book ai didi

android - 仅使用栏而不是 subview 本身滚动

转载 作者:行者123 更新时间:2023-12-04 23:57:38 24 4
gpt4 key购买 nike

在我的应用程序中,我有一个自定义 View ,如下图所示,

Audio Visualizer

这是一个音频可视化工具,在放大时会在 X 轴上增长。因此我需要在 ScrollView 中使用它来滚动音频图。目前的布局如下所示,

<HorizontalScrollView
android:id="@+id/fileWaveViewScroll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fillViewport="true"
style="@style/CustomScrollbar">

<com.bluehub.fastmixer.common.views.FileWaveView
android:id="@+id/fileWaveView"
android:layout_width="wrap_content"
android:layout_height="120dp"
app:audioFileUiState="@{audioFileUiState}"
app:samplesReader="@{eventListener.readSamplesCallbackWithIndex(audioFileUiState.path)}"
app:fileWaveViewStore="@{fileWaveViewStore}"
tools:layout_height="120dp"/>
</HorizontalScrollView>

自定义 View FileWaveView 是从 LinearLayout 扩展而来的。

现在我想要一个滚动行为,这样当我在自定义 View (音频可视化图表)中滚动时, ScrollView 不应滚动。但是当我通过触摸条本身滚动时,滚动条将滚动它的内容。

我想要这种行为,因为我希望将滚动手势用于可视化图表内的某些其他操作(以调整段选择器宽度,我将在稍后集成)。

请建议我如何制作此滚动条滚动模式,而 View 将仅在滚动条中滚动。我是否应该避免使用 Horizo​​ntalScrollBar 并在自定义 View 本身内创建自己的滚动行为?

最佳答案

在 SlothCoding 的帮助下,我能够解决这个问题。我创建了一个自定义滚动条并用它来控制 Horizo​​ntalScrollView。相关代码如下,

自定义 ScrollView

import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.widget.HorizontalScrollView

class LockedHorizontalScrollView(
context: Context,
attrs: AttributeSet? = null) : HorizontalScrollView(context, attrs) {

init {
isVerticalScrollBarEnabled = false
isHorizontalScrollBarEnabled = false
}

override fun onTouchEvent(ev: MotionEvent?): Boolean {
return false
}

override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
return false
}
}

滚动条

package com.bluehub.fastmixer.common.views

import android.content.Context
import android.util.AttributeSet
import android.view.*
import android.widget.HorizontalScrollView
import androidx.constraintlayout.widget.ConstraintLayout
import com.bluehub.fastmixer.databinding.CustomScrollBarBinding

class CustomHorizontalScrollBar(context: Context, attributeSet: AttributeSet?)
: ConstraintLayout(context, attributeSet) {

private val binding: CustomScrollBarBinding
private lateinit var mHorizontalScrollView: HorizontalScrollView
private lateinit var mView: View

private val mScrollBar: CustomHorizontalScrollBar
private val mScrollTrack: View
private val mScrollThumb: View

private val gestureListener = object: GestureDetector.SimpleOnGestureListener() {
override fun onScroll(
e1: MotionEvent?,
e2: MotionEvent?,
distanceX: Float,
distanceY: Float
): Boolean {

handleScrollOfThumb(e2, distanceX)
return true
}

override fun onDown(e: MotionEvent?): Boolean {
return true
}
}

private val gestureDetector: GestureDetector

init {
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
binding = CustomScrollBarBinding.inflate(inflater, this, true)

mScrollBar = this

mScrollTrack = binding.scrollTrack
mScrollThumb = binding.scrollThumb

gestureDetector = GestureDetector(context, gestureListener)
}

override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
return gestureDetector.onTouchEvent(ev)
}

override fun onTouchEvent(event: MotionEvent?): Boolean {
return gestureDetector.onTouchEvent(event)
}

fun setHorizontalScrollView(horizontalScrollView: HorizontalScrollView) {
this.mHorizontalScrollView = horizontalScrollView
}

fun setControlledView(view: View) {
this.mView = view
setViewWidthListener()
}

private fun handleScrollOfThumb(event: MotionEvent?, distanceX: Float) {
event?: return

if (event.x >= mScrollThumb.left && event.x <= mScrollThumb.left + mScrollThumb.width) {

var newLeft = mScrollThumb.left - distanceX.toInt()
var newRight = mScrollThumb.right - distanceX.toInt()

if (newRight <= mScrollBar.width && newLeft >= 0) {
repositionScrollThumb(newLeft, newRight)
}
// Thumb is not at left nor right, but distanced asked to traverse by move is more
else if (mScrollThumb.left != 0 && mScrollThumb.right < mScrollBar.width - 1) {

// Distance from right end of bar
val distanceToRight = mScrollBar.width - mScrollThumb.right - 1

// Get the closest distance to move the thumb to
val newDist = if (mScrollThumb.left < distanceToRight) {
mScrollThumb.left
} else {
-distanceToRight
}

newLeft = mScrollThumb.left - newDist
newRight = mScrollThumb.right - newDist

repositionScrollThumb(newLeft, newRight)
}
}
}

private fun repositionScrollThumb(newLeft: Int, newRight: Int) {
mScrollThumb.layout(newLeft, mScrollThumb.top, newRight, mScrollThumb.bottom)
performScrollOnScrollView()
}

private fun performScrollOnScrollView() {
val ratio = mView.width.toFloat() / mScrollBar.width.toFloat()
val posToScroll = (ratio * mScrollThumb.left).toInt()
mHorizontalScrollView.post {
mHorizontalScrollView.scrollTo(posToScroll, mHorizontalScrollView.top)
}
}

private fun setViewWidthListener() {
mView.addOnLayoutChangeListener { view: View, _, _, _, _, _, _, _, _ ->

if (mScrollTrack.width == 0) return@addOnLayoutChangeListener

val w = view.width

val ratio = w.toFloat() / mScrollTrack.width.toFloat()

if (ratio == 1.0f) {
mScrollBar.visibility = View.INVISIBLE
} else {
mScrollBar.visibility = View.VISIBLE

val layoutParams = mScrollThumb.layoutParams
val newWidth = (mScrollTrack.width.toFloat() / ratio).toInt()
if (mScrollThumb.width != newWidth) {
mScrollThumb.post {
mScrollThumb.layoutParams = layoutParams
}
}
}
}
}
}

滚动条布局,

<?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">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">

<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="1dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5"/>

<View
android:id="@+id/scrollTrack"
android:layout_width="match_parent"
android:layout_height="@dimen/scrollbar_track_height"
android:background="@drawable/scrollbar_horizontal_track"
app:layout_constraintTop_toTopOf="@id/guideline"
app:layout_constraintBottom_toBottomOf="@+id/guideline"
app:layout_constraintStart_toStartOf="parent" />


<View
android:id="@+id/scrollThumb"
android:layout_width="18dp"
android:layout_height="@dimen/scrollbar_thumb_height"
android:background="@drawable/scrollbar_horizontal_thumb"
app:layout_constraintTop_toTopOf="@id/guideline"
app:layout_constraintBottom_toBottomOf="@+id/guideline"
app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

</layout>

自定义 View 在滚动条内的布局,

<com.bluehub.fastmixer.common.views.LockedHorizontalScrollView
android:id="@+id/fileWaveViewScroll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fillViewport="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">

<com.bluehub.fastmixer.common.views.FileWaveView
android:id="@+id/fileWaveView"
android:layout_width="wrap_content"
android:layout_height="@dimen/audio_file_view_height"
app:audioFileUiState="@{audioFileUiState}"
app:samplesReader="@{eventListener.readSamplesCallbackWithIndex(audioFileUiState.path)}"
app:fileWaveViewStore="@{fileWaveViewStore}"
tools:layout_height="120dp">

<com.bluehub.fastmixer.common.views.AudioWidgetSlider
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

</com.bluehub.fastmixer.common.views.FileWaveView>

</com.bluehub.fastmixer.common.views.LockableHorizontalScrollView>

<com.bluehub.fastmixer.common.views.CustomHorizontalScrollBar
android:id="@+id/fileWaveViewScrollBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/fileWaveViewScroll" />

终于在父 View 中,

binding.apply {
fileWaveViewScrollBar.setHorizontalScrollView(fileWaveViewScroll)
fileWaveViewScrollBar.setControlledView(fileWaveView)
}

我们有一些用于滚动轨道和滚动拇指的绘图。

滚动轨迹,

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >

<gradient
android:angle="0"
android:endColor="#9BA3C5"
android:startColor="#8388A4" />

<corners android:radius="8dp" />

</shape>

滚动拇指,

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<gradient
android:angle="0"
android:endColor="#005A87"
android:startColor="#007AB8" />

<corners android:radius="8dp" />

</shape>

关于android - 仅使用栏而不是 subview 本身滚动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66117792/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com