【问题标题】:Updating rotary knob in real time with SwiftUI使用 SwiftUI 实时更新旋钮
【发布时间】:2021-08-01 09:50:36
【问题描述】:

我目前正在尝试将滑块转换为旋钮,这一切都很艰难。旋钮在设计中有效,但我很难在旋钮中设置正确的值,因此会实时更改应用程序中的值。

我正在使用 AVAudio 设置一个引擎供人们使用它来录制,它具有混响和延迟等效果。

混响值在音频类中设置如下:

@Published var reverbValue: Float = 0.0

稍后在函数中引用以更改其值

   func changeReverbValue() {
    
    setReverb.wetDryMix = reverbValue
    

}

当我按如下方式使用常规滑块时,更改有效:

Slider(value: $recordingsettings.reverbValue, in: Float(0.0)...recordingsettings.reverbMaxValue, onEditingChanged: { _ in
                
   self.recordingsettings.changeReverbValue()

  }).accentColor(Color.white)

如前所述,旋钮的设计效果很好:

    ZStack {
        
        Knobs(color: .orange)
            .rotationEffect(
                .degrees(max(0, initialCircleState()))
            )
            .gesture(DragGesture(minimumDistance: 0)
            .onEnded({ _ in
                startDragValue = -1.0
            })
            .onChanged { dragValue in
                let touchDifferential =  touchDifference(dragValue)
               
                setInitialDragVal()
                
                let computedTouch = computeTouch(touchDifferential)
                
                print(computedTouch)
                
                baseValue = getBaseVal(computedTouch)
                
                let normalizeVal = baseValue / touchAmt
                
                value = Float(normalizeVal * rngOffset(range: bounds) + bounds.lowerBound)
                print("vaule is: \(value)")

            }
            )
            
        GrayCircle(bounds: bounds)
        OrangeCircle(baseValue: $value, bounds: bounds)
        
    }
    .rotationEffect(bounds.lowerBound < 0 ? .degrees(90) : .degrees(107))

我已经成功地将旋钮连接到混响值,当旋钮移动时滑块也会移动,但是 changeReverbValue 功能不起作用。

成功来自于在旋钮视图中设置值如下:

@Binding var value: AUValue

然后在与滑块相同的主视图结构上引用旋钮:

Knob(value: $recordingsettings.reverbValue, bounds: 0...CGFloat(recordingsettings.reverbMaxValue))
                        .onTapGesture {
                            self.recordingsettings.changeReverbValue()
                        }

点击手势是我认为在转动旋钮时它可能会调用更改混响值函数但无济于事的一种方式。

在旋钮中传递的绑定值还有其他挑战。出于某种原因,当我在没有耳机的情况下播放音频然后转动旋钮时,音频开始断断续续。耳机不会发生这种情况,我觉得这很奇怪。

有谁知道我如何在旋钮内引用混响值并同时调用 changeReverbValue 函数?

我只是想用看起来更好的东西替换滑块。否则我将不得不暂时搁置这一点,并在整个应用程序中实现滑块。

如果我没有在旋钮视图中将旋钮的值设置为@binding,则曲目在播放时不会断断续续,但是我不知道是否可以在没有@binding var的情况下更改混响值.

【问题讨论】:

  • 为什么不把“self.recordingsettings.changeReverbValue()”放在旋钮“.onChanged { ... }”中?
  • @workingdog 我确实尝试过,但没有成功。应该在我最初的帖子中澄清。

标签: xcode swiftui slider avaudiorecorder avaudioengine


【解决方案1】:

我很难从叙述中解析出一个精确的单一问题陈述,所以这可能只是一个偏离基础的评论,而不是一个解决方案。我走开了,以为您的问题是:自定义 UI 组件在交互过程中“跳跃/卡顿”,并在应用状态上产生类似的点状效果。

如果公平的话,我在我的第一个 SwiftUI 应用程序中解决了同样的问题。原因可能是两件事:

  1. 不小心使用了正确的异步队列。
  2. 强制@State@Published 属性更新所有全局状态更改。这意味着您将之前的陈旧状态推回到交互中,可能带有循环反馈循环。

解决方案非常简单。请求和使用带有值 源标记的模型更新。节流并过滤掉自标记,以保持本地状态仅响应一个即时数据流。

我在第一个应用程序(免费,Inclusivity for Mac)中使用了该模式来协调 HSV 色轮和颜色通道自定义滑块组件。滚轮、滑块和其他交互输入/读取共享的组合管道 (CurrentValueSubject&lt;SourcedColorVector,Never&gt;.erasedToAny())。

一些示例手势,它们只是将门控工作放到视图模型中:

HSVWheel 左右拖动或点击手势

    private func touchUpInWheel() -> ExclusiveGesture<_ChangedGesture<DragGesture>, _EndedGesture<DragGesture>> {
        ExclusiveGesture(
            DragGesture(minimumDistance: 10, coordinateSpace: .named(wheel))
                .onChanged { change in
                    let adjusted = CGPoint(x: change.translation.width - targetDiameter + change.startLocation.x / 2,
                                           y: change.translation.height - targetDiameter + change.startLocation.y / 2)
                        vm.setHueSat(drag: adjusted)
                },
            DragGesture(minimumDistance: 0, coordinateSpace: .named(wheel))
                .onEnded { end in
                    let click = CGPoint(x: end.location.x - vm.radius,
                                        y: end.location.y - vm.radius)
                        vm.setHueSat(click: click)
                }
        )
        
    }

典型的滑块手势(这是垂直值滑块)

private func tapAndDrag() -> _EndedGesture<_ChangedGesture<DragGesture>>  {
        DragGesture(minimumDistance: 0,
                    coordinateSpace: .named(valuePickerSpace))
            .onChanged { value in
                let location = value.location.y - .valueSliderGestureOffset
                vm.setValueKnobLocation(raw: location)
            }
            .onEnded { end in
                let location = end.location.y - .valueSliderGestureOffset
                vm.setValueKnobLocation(raw: location)
            }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-12
    • 2020-04-02
    • 2021-01-17
    • 1970-01-01
    • 2019-12-17
    • 1970-01-01
    • 1970-01-01
    • 2021-03-25
    相关资源
    最近更新 更多