-
-
Notifications
You must be signed in to change notification settings - Fork 28
Open
Labels
bugSomething isn't workingSomething isn't working
Description
macOS Version(s) Used to Build
macOS 13 Ventura
Xcode Version(s)
Xcode 14
Description
The key handles tap with delay if the Кeyboard is in a ScrollView. See the modified KeyboardDemo example below.
The bug only occurs on iOS.
On macOS, the Keyboard in a ScrollView works correctly.
Crash Logs, Screenshots or Other Attachments (if applicable)
Modified ContentView.swift from KeyboardDemo to demonstrate the bug:
import Keyboard
import SwiftUI
import Tonic
let evenSpacingInitialSpacerRatio: [Letter: CGFloat] = [
.C: 0.0,
.D: 2.0 / 12.0,
.E: 4.0 / 12.0,
.F: 0.0 / 12.0,
.G: 1.0 / 12.0,
.A: 3.0 / 12.0,
.B: 5.0 / 12.0
]
let evenSpacingSpacerRatio: [Letter: CGFloat] = [
.C: 7.0 / 12.0,
.D: 7.0 / 12.0,
.E: 7.0 / 12.0,
.F: 7.0 / 12.0,
.G: 7.0 / 12.0,
.A: 7.0 / 12.0,
.B: 7.0 / 12.0
]
let evenSpacingRelativeBlackKeyWidth: CGFloat = 7.0 / 12.0
struct PitchRange: Identifiable {
let range: ClosedRange<Int>
let id: Int
var lowerBound: Int { range.lowerBound }
var upperBound: Int { range.upperBound }
}
struct ContentView: View {
@State private var currentKeyboardId = 2
internal let ranges = [36...47, 48...59, 60...71, 72...83, 84...95, 96...107].enumerated().map {
PitchRange(range: $0.element, id: $0.offset)
}
func noteOn(pitch: Pitch, point: CGPoint) {
print("note on \(pitch)”)
}
func noteOff(pitch: Pitch) {
print("note off \(pitch)”)
}
func noteOnWithVerticalVelocity(pitch: Pitch, point: CGPoint) {
print("note on \(pitch), midiVelocity: \(Int(point.y * 127))”)
}
func noteOnWithReversedVerticalVelocity(pitch: Pitch, point: CGPoint) {
print("note on \(pitch), midiVelocity: \(Int((1.0 - point.y) * 127))”)
}
var randomColors: [Color] = (0 ... 12).map { _ in
Color(red: Double.random(in: 0 ... 1),
green: Double.random(in: 0 ... 1),
blue: Double.random(in: 0 ... 1), opacity: 1)
}
@State var lowNote = 24
@State var highNote = 48
@State var scaleIndex = Scale.allCases.firstIndex(of: .chromatic) ?? 0 {
didSet {
if scaleIndex >= Scale.allCases.count { scaleIndex = 0 }
if scaleIndex < 0 { scaleIndex = Scale.allCases.count - 1 }
scale = Scale.allCases[scaleIndex]
}
}
@State var scale: Scale = .chromatic
@State var root: NoteClass = .C
@State var rootIndex = 0
@Environment(\.colorScheme) var colorScheme
var body: some View {
HStack {
Keyboard(layout: .verticalIsomorphic(pitchRange: Pitch(48) ... Pitch(77))).frame(width: 100)
VStack {
HStack {
Stepper("Lowest Note: \(Pitch(intValue: lowNote).note(in: .C).description)”,
onIncrement: {
if lowNote < 126, highNote > lowNote + 12 {
lowNote += 1
}
},
onDecrement: {
if lowNote > 0 {
lowNote -= 1
}
})
Stepper("Highest Note: \(Pitch(intValue: highNote).note(in: .C).description)”,
onIncrement: {
if highNote < 126 {
highNote += 1
}
},
onDecrement: {
if highNote > 1, highNote > lowNote + 12 {
highNote -= 1
}
})
}
/// BUG DEMO BEGIN
GeometryReader { geoProxy in
ScrollViewReader { scrollProxy in
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 0) {
ForEach(ranges) { range in
Keyboard(layout: .piano(pitchRange: Pitch(intValue: range.lowerBound) ... Pitch(intValue: range.upperBound)),
noteOn: noteOnWithVerticalVelocity(pitch:point:), noteOff: noteOff)
.frame(minWidth: geoProxy.size.width * 0.5)
.id(range.id)
}
}
.frame(height: 200)
.frame(maxWidth: .infinity)
}
.background(.black)
.onChange(of: currentKeyboardId) { newValue in
withAnimation {
scrollProxy.scrollTo(newValue)
}
}
.onAppear {
scrollProxy.scrollTo(currentKeyboardId)
}
}
}
/// BUG DEMO END
HStack {
Stepper("Root: \(root.description)”,
onIncrement: {
let allSharpNotes = (0...11).map { Note(pitch: Pitch(intValue: $0)).noteClass }
var index = allSharpNotes.firstIndex(of: root.canonicalNote.noteClass) ?? 0
index += 1
if index > 11 { index = 0}
if index < 0 { index = 1}
rootIndex = index
root = allSharpNotes[index]
},
onDecrement: {
let allSharpNotes = (0...11).map { Note(pitch: Pitch(intValue: $0)).noteClass }
var index = allSharpNotes.firstIndex(of: root.canonicalNote.noteClass) ?? 0
index -= 1
if index > 11 { index = 0}
if index < 0 { index = 1}
rootIndex = index
root = allSharpNotes[index]
})
Stepper("Scale: \(scale.description)”,
onIncrement: { scaleIndex += 1 },
onDecrement: { scaleIndex -= 1 })
}
Keyboard(layout: .isomorphic(pitchRange:
Pitch(intValue: 12 + rootIndex) ... Pitch(intValue: 84 + rootIndex),
root: root,
scale: scale),
noteOn: noteOnWithReversedVerticalVelocity(pitch:point:), noteOff: noteOff)
.frame(minWidth: 100, minHeight: 100)
Keyboard(layout: .guitar(),
noteOn: noteOn, noteOff: noteOff) { pitch, isActivated in
KeyboardKey(pitch: pitch,
isActivated: isActivated,
text: pitch.note(in: .F).description,
pressedColor: Color(PitchColor.newtonian[Int(pitch.pitchClass)]),
alignment: .center)
}
.frame(minWidth: 100, minHeight: 100)
Keyboard(layout: .isomorphic(pitchRange: Pitch(48) ... Pitch(65))) { pitch, isActivated in
KeyboardKey(pitch: pitch,
isActivated: isActivated,
text: pitch.note(in: .F).description,
pressedColor: Color(PitchColor.newtonian[Int(pitch.pitchClass)]))
}
.frame(minWidth: 100, minHeight: 100)
Keyboard(latching: true, noteOn: noteOn, noteOff: noteOff) { pitch, isActivated in
if isActivated {
ZStack {
Rectangle().foregroundColor(.black)
VStack {
Spacer()
Text(pitch.note(in: .C).description).font(.largeTitle)
}.padding()
}
} else {
Rectangle().foregroundColor(randomColors[Int(pitch.intValue) % 12])
}
}
.frame(minWidth: 100, minHeight: 100)
}
Keyboard(
layout: .verticalPiano(pitchRange: Pitch(48) ... Pitch(77),
initialSpacerRatio: evenSpacingInitialSpacerRatio,
spacerRatio: evenSpacingSpacerRatio,
relativeBlackKeyWidth: evenSpacingRelativeBlackKeyWidth)
).frame(width: 100)
}
.background(colorScheme == .dark ?
Color.clear : Color(red: 0.9, green: 0.9, blue: 0.9))
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working
