- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在我的应用程序中,我有一个自定义 View ,如下图所示,
这是一个音频可视化工具,在放大时会在 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 将仅在滚动条中滚动。我是否应该避免使用 HorizontalScrollBar 并在自定义 View 本身内创建自己的滚动行为?
最佳答案
在 SlothCoding 的帮助下,我能够解决这个问题。我创建了一个自定义滚动条并用它来控制 HorizontalScrollView。相关代码如下,
自定义 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/
我在自定义表格单元格中长按时添加 subview ,但是当我滚动表格时, subview 消失。 p> 我应该怎么做,以便当我向后滚动时,该 subview 仍然显示/出现在该单元格上,或者换句话说,
如何遍历 UIView 的所有 subview ,以及它们的 subview 和它们的 subview ? 最佳答案 使用递归: // UIView+HierarchyLogging.h @inter
如果我有 contentView 和 2 个 subview 。我想根据subviewB居中subviewA subviewA 和 subviewB 有相同的父 View 。 这就是我现在正在做的,将
我想向 self.view 添加一个覆盖整个区域的 subview (如调光 View )。但在它下面,有一些 View 我不希望受到添加的 subview 的影响(我不希望这些 View 具有变暗的
我正在尝试向 UITabBar 添加 subview ,它应该位于其他 UITabBar subview 之后。 我在 UITabBarController 的子类中添加了这样的 subview :
图像描述了我必须将这种 subview 添加到我现有的单元格中,并且在多次单击“添加”图标时还要添加相同的 subview 。 我在添加 subview 时遇到困难。如果有人能为我提供处理此结构的正确
我添加了一个 subview ,如下所示: func showPlayerView2() { self.view.frame = CGRect(x: 0, y: 0, width: view.
我的问题是关于 UIView/CALayer: Transform triggers layoutSubviews in superview 据报道,来自苹果的 TSI 回复: Generally,
我试图为我的主视图创建一个辅助 View 。这个 subview 需要很小的高度,它需要适合另一个带有标签的大 UIView。 问题是当我使用 UIView addSubview 时,第三个 UIVi
我正在尝试淡出整个 View ,但只有一个特定的 subview , 这将强调 subview更清晰的外观。假设 self.view 有 5 textfields和 2 UIView如subviews
我确信我在这里错过了一些愚蠢的东西,但我有 mainView、subviewA 和 subviewB。我试图将 subviewB 添加到 subviewA 并将其锚定在 subviewA 内部,但是它
我有一个包含 3 个 subview 的 View ,分别称为 view A、view B、view C。 当我删除 subview 时,意味着我需要自动设置边距以进行调整。 当我删除 view A
我有两个加载的 subview 。一个是位于 View Controller 内部的选项卡栏,它很早就加载,第二个是按下选项卡栏项目时出现的 View 。 但是,当添加此 subview 时,它会加载
在 iOS 应用中,我在主视图中添加了一个 subview : [self.view addSubview:firstUIImageSubview]; 但是在 subview 类 firstUIIma
我正在制作一个球程序,您可以通过长按手势将球 UIView subview 添加到 super View 。点击 View 会将其从父 View 中移除。 添加所有 View 效果很好,重新添加 Vi
我使用以下代码在单击按钮时将日期选择器 View 添加到我的应用程序主视图。 - (IBAction)CalenderButton_Click:(id)sender { // code to add
我正在努力向 View 添加 subview 。进度变量在其 View Controller 的 viewDidLoad() 中设置。 progressView frame size 设置正确,只是添
这是我的代码 var button = [UIButton?](count:3, repeatedValue: UIButton()) for i in 0...2{
我有一个 UIViewController,里面有几个不同的 UIView subview 。当用户调用某个 Action 时,我手动更改每个的大小、比例和位置。我想更新其中一个 UILabel( s
我的屏幕有一个主视图模型。它由 2 个 subview 模型组成。 其中一个负责注册部分。其中一个处理登录部分。其中一个负责处理菜单部分(如果经过身份验证,可以显示哪些菜单项,以及“欢迎“用户名”类型
我是一名优秀的程序员,十分优秀!