Skip to content

Commit

Permalink
Fixed issues with new SwiftUI layout. The LSlider and Trackpad had im…
Browse files Browse the repository at this point in the history
…proper positioning after updated to the latest Xcode Beta. I manually set the position of the thumb to be centered in the containing rectangle at 0 offset.
  • Loading branch information
Kieran Brown committed Jul 23, 2020
1 parent cccc82d commit ebf93bd
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 59 deletions.
84 changes: 49 additions & 35 deletions Sources/Sliders/LSlider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -171,28 +171,38 @@ public struct LSlider: View {
public var range: ClosedRange<Double> = 0...1
public var angle: Angle = .zero
public var isDisabled: Bool = false

public init(_ value: Binding<Double>, range: ClosedRange<Double>, angle: Angle, isDisabled: Bool = false) {
self._value = value
self.range = range
self.angle = angle
self.isDisabled = isDisabled
}


public init(_ value: Binding<Double>, range: ClosedRange<Double>, isDisabled: Bool = false) {
self._value = value
self.range = range
self.isDisabled = isDisabled
}

public init(_ value: Binding<Double>, angle: Angle, isDisabled: Bool = false) {
self._value = value
self.angle = angle
self.isDisabled = isDisabled
}

public init(_ value: Binding<Double>) {
self._value = value

}



// MARK: Calculations
// uses an arbitrarily large number to gesture a line segment that is guarenteed to intersect with the
// bounding box, then finds those points of intersection to be used as the start and end points of the slider
private func calculateEndPoints(_ proxy: GeometryProxy) -> (start: CGPoint, end: CGPoint) {
let w = proxy.size.width
let h = proxy.size.height
let big: CGFloat = 50000000

let x1 = w/2 + big*CGFloat(cos(self.angle.radians))
let y1 = h/2 + big*CGFloat(sin(self.angle.radians))
let x2 = w/2 - big*CGFloat(cos(self.angle.radians))
Expand All @@ -201,7 +211,7 @@ public struct LSlider: View {
if points.count < 2 {
return (.zero, .zero)
}

return (points[0], points[1])
}
private func thumbOffset(_ proxy: GeometryProxy) -> CGSize {
Expand All @@ -211,7 +221,7 @@ public struct LSlider: View {
let y = (1-value)*Double(ends.start.y) + value*Double(ends.end.y) - Double(proxy.size.height/2)
return CGSize(width: x, height: y)
}

private var configuration: LSliderConfiguration {
.init(isDisabled: isDisabled,
isActive: isActive,
Expand All @@ -221,7 +231,7 @@ public struct LSlider: View {
min: range.lowerBound,
max: range.upperBound)
}

// MARK: Haptics
private func impactOccured() {
#if os(macOS)
Expand All @@ -230,6 +240,7 @@ public struct LSlider: View {
generator.impactOccurred()
#endif
}

private func impactHandler(_ parameterAtLimit: Bool) {
if parameterAtLimit {
if !atLimit {
Expand All @@ -240,36 +251,39 @@ public struct LSlider: View {
atLimit = false
}
}

// MARK: - Gesture
private func makeGesture(_ proxy: GeometryProxy) -> some Gesture {
DragGesture(minimumDistance: 10, coordinateSpace: .named(self.space))
.onChanged({ drag in
let ends = self.calculateEndPoints(proxy)
let parameter = Double(calculateParameter(ends.start, ends.end, drag.location))
self.impactHandler(parameter == 1 || parameter == 0)
self.value = (self.range.upperBound-self.range.lowerBound)*parameter + self.range.lowerBound
self.isActive = true
})
.onEnded({ (drag) in
let ends = self.calculateEndPoints(proxy)
let parameter = Double(calculateParameter(ends.start, ends.end, drag.location))
self.impactHandler(parameter == 1 || parameter == 0)
self.value = (self.range.upperBound-self.range.lowerBound)*parameter + self.range.lowerBound
self.isActive = false
})
}

// MARK: View
public var body: some View {
ZStack {
style.makeTrack(configuration: configuration)
.overlay(
GeometryReader { proxy in
ZStack {
self.style.makeThumb(configuration: self.configuration)
.offset(self.thumbOffset(proxy))
.gesture(DragGesture(minimumDistance: 10, coordinateSpace: .named(self.space))
.onChanged({ drag in
let ends = self.calculateEndPoints(proxy)
let parameter = Double(calculateParameter(ends.start, ends.end, drag.location))
self.impactHandler(parameter == 1 || parameter == 0)
self.value = (self.range.upperBound-self.range.lowerBound)*parameter + self.range.lowerBound
self.isActive = true
})
.onEnded({ (drag) in
let ends = self.calculateEndPoints(proxy)
let parameter = Double(calculateParameter(ends.start, ends.end, drag.location))
self.impactHandler(parameter == 1 || parameter == 0)
self.value = (self.range.upperBound-self.range.lowerBound)*parameter + self.range.lowerBound
self.isActive = false
})
).allowsHitTesting(!self.isDisabled)
}
}
)
}.frame(idealWidth: 200, idealHeight: 50)
.coordinateSpace(name: space)
GeometryReader { proxy in
self.style.makeThumb(configuration: self.configuration)
.position(x: proxy.size.width/2, y: proxy.size.height/2)
.offset(self.thumbOffset(proxy))
.gesture(self.makeGesture(proxy)).allowsHitTesting(!self.isDisabled)
}
}
.coordinateSpace(name: space)
}
}


45 changes: 21 additions & 24 deletions Sources/Sliders/TrackPad.swift
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ public struct TrackPad: View {
self.rangeY = rangeY
self.isDisabled = isDisabled
}

public init(_ value: Binding<CGPoint>){
self._value = value
}
Expand All @@ -185,8 +185,8 @@ public struct TrackPad: View {
self.rangeX = range
self.rangeY = range
}


private var configuration: TrackPadConfiguration {
.init(isDisabled: isDisabled,
isActive: isActive,
Expand All @@ -199,7 +199,7 @@ public struct TrackPad: View {
minY: Double(rangeY.lowerBound),
maxY: Double(rangeY.upperBound))
}

// MARK: Calculations
// Limits the value of the drag gesture to be within the frame of the trackpad
// If the gesture hits an edge of the trackpad a haptic impact is played, an state
Expand All @@ -220,7 +220,7 @@ public struct TrackPad: View {
} else {
self.atXLimit = false
}
// vertical haptix handling
// vertical haptic handling
if pctY == 1 || pctY == 0 {
if !self.atYLimit {
self.impactOccured()
Expand All @@ -241,7 +241,7 @@ public struct TrackPad: View {
let pctY = (value.y - rangeY.lowerBound)/(rangeY.upperBound - rangeY.lowerBound)
return CGSize(width: w*(pctX-0.5), height: h*(pctY-0.5))
}

// MARK: Haptics
private func impactOccured() {
#if os(macOS)
Expand All @@ -254,24 +254,21 @@ public struct TrackPad: View {
public var body: some View {
ZStack {
style.makeTrack(configuration: configuration)
.overlay(GeometryReader { proxy in
ZStack {
self.style.makeThumb(configuration: self.configuration)
.offset(self.thumbOffset(proxy))
.gesture(
DragGesture(minimumDistance: 0, coordinateSpace: .named(self.space))
.onChanged({
self.constrainValue(proxy, $0.location)
self.isActive = true
})
.onEnded({
self.constrainValue(proxy, $0.location)
self.isActive = false
}))
}
})
GeometryReader { proxy in
self.style.makeThumb(configuration: self.configuration)
.position(x: proxy.size.width/2, y: proxy.size.height/2)
.offset(self.thumbOffset(proxy))
.gesture(
DragGesture(minimumDistance: 0, coordinateSpace: .named(self.space))
.onChanged({
self.constrainValue(proxy, $0.location)
self.isActive = true
})
.onEnded({
self.constrainValue(proxy, $0.location)
self.isActive = false
}))
}
}.coordinateSpace(name: space)

}
}

0 comments on commit ebf93bd

Please sign in to comment.