Use a UIViewRepresentable to set slider images instead of introspection

The slider was losing the custom images when being opened/closed
sometimes because introspection doesn't get called.
This commit is contained in:
Jackson Harper 2022-09-27 16:21:54 +08:00
parent d77f893e06
commit 8e1ac67d80
2 changed files with 84 additions and 27 deletions

View file

@ -192,11 +192,11 @@ public struct MiniPlayer: View {
if !expanded {
Text(itemAudioProperties.title)
.font(expanded ? .appTitle : .appCallout)
.font(.appCallout)
.lineSpacing(1.25)
.foregroundColor(.appGrayTextContrast)
.fixedSize(horizontal: false, vertical: false)
.frame(maxWidth: .infinity, alignment: expanded ? .center : .leading)
.frame(maxWidth: .infinity, alignment: .leading)
.matchedGeometryEffect(id: "ArticleTitle", in: animation)
playPauseButtonItem
@ -221,31 +221,15 @@ public struct MiniPlayer: View {
.foregroundColor(.appGrayText)
}
Slider(value: $audioController.timeElapsed,
in: 0 ... self.audioController.duration,
onEditingChanged: { scrubStarted in
if scrubStarted {
self.audioController.scrubState = .scrubStarted
} else {
self.audioController.scrubState = .scrubEnded(self.audioController.timeElapsed)
}
})
.accentColor(.appCtaYellow)
.introspectSlider { slider in
// Make the thumb a little smaller than the default and give it the CTA color
// for some reason this doesn't work on my iPad though.
let tintColor = UIColor(Color.appCtaYellow)
let image = UIImage(systemName: "circle.fill",
withConfiguration: UIImage.SymbolConfiguration(scale: .small))?
.withTintColor(tintColor)
.withRenderingMode(.alwaysOriginal)
slider.setThumbImage(image, for: .selected)
slider.setThumbImage(image, for: .normal)
slider.minimumTrackTintColor = tintColor
}
ScrubberView(value: $audioController.timeElapsed,
minValue: 0, maxValue: self.audioController.duration,
onEditingChanged: { scrubStarted in
if scrubStarted {
self.audioController.scrubState = .scrubStarted
} else {
self.audioController.scrubState = .scrubEnded(self.audioController.timeElapsed)
}
})
HStack {
Text(audioController.timeElapsedString ?? "0:00")

View file

@ -0,0 +1,73 @@
//
// ScrubberView.swift
//
//
// Created by Jackson Harper on 9/27/22.
//
import Foundation
import SwiftUI
struct ScrubberView: UIViewRepresentable {
typealias UIViewType = UISlider
@Binding var value: Double
var minValue: Double
var maxValue: Double
var onEditingChanged: (Bool) -> Void
init(value: Binding<Double>, minValue: Double, maxValue: Double, onEditingChanged: @escaping (Bool) -> Void) {
self._value = value
self.minValue = minValue
self.maxValue = maxValue
self.onEditingChanged = onEditingChanged
}
func makeUIView(context: Context) -> UISlider {
let slider = UISlider(frame: .zero)
slider.maximumValue = Float(minValue)
slider.maximumValue = Float(maxValue)
let tintColor = UIColor(Color.appCtaYellow)
let image = UIImage(systemName: "circle.fill",
withConfiguration: UIImage.SymbolConfiguration(scale: .small))?
.withTintColor(tintColor)
.withRenderingMode(.alwaysOriginal)
slider.setThumbImage(image, for: .selected)
slider.setThumbImage(image, for: .normal)
slider.minimumTrackTintColor = tintColor
slider.addTarget(context.coordinator,
action: #selector(Coordinator.valueChanged(_:)),
for: .valueChanged)
return slider
}
func updateUIView(_ uiView: UISlider, context _: Context) {
uiView.value = Float(value)
}
func makeCoordinator() -> Coordinator {
let coordinator = Coordinator(value: $value, onEditingChanged: onEditingChanged)
return coordinator
}
class Coordinator: NSObject {
var value: Binding<Double>
var onEditingChanged: (Bool) -> Void
init(value: Binding<Double>, onEditingChanged: @escaping (Bool) -> Void) {
self.value = value
self.onEditingChanged = onEditingChanged
super.init()
}
@objc func valueChanged(_ sender: UISlider) {
value.wrappedValue = Double(sender.value)
onEditingChanged(sender.isTracking)
}
}
}