Post

Replies

Boosts

Views

Activity

Reply to Plz help
Try to restart in safe mode: https://support.apple.com/en-gb/guide/mac-help/mh21245/mac#:~:text=Turn%20on%20or%20restart%20your,Boot”%20in%20the%20menu%20bar. Start up your Intel-based Mac in safe mode Turn on or restart your Mac, then immediately press and hold the Shift key until you see the login window. Log in to your Mac. You might be asked to log in again. On either the first or second login window, you should see “Safe Boot” in the menu bar.
Aug ’24
Reply to Attempting to add scrubbing to UISlider
I fear it may be a bit tricky. I see a few options: adapt the mouse speed in beginTracking (see the link https://stackoverflow.com/questions/47254745/change-mac-cursor-speed-programmatically) and restore the original value in touchesEnded. But if speed is already at minimum, it will have no effect in continueTracking, modify the mouse position to adjust to the reduced move ; https://stackoverflow.com/questions/70864549/swift-macos-set-mouse-cursor-position you could try to compute thumb position so that it moves only a fraction on mouse movement in func thumbRect by changing let origin = CGPoint(x: (currentLocation?.x ?? bounds.width / 2) - thumbDiameter / 2, y: (currentLocation?.y ?? thumbDiameter / 2) - thumbDiameter / 2) so that x is not currentLocation (mouse position), but the adjusted value. Problem is that you will not be able to move the thumb on the full range…
Topic: UI Frameworks SubTopic: UIKit Tags:
Aug ’24
Reply to Attempting to add scrubbing to UISlider
OK, so getting thumb out of slider is expected. But I don't understand the logic. At the end, the location during tracking is let location = touch.location(in: self) During update, thumb moves slower, but immediately after the mouse position prevails, which annihilate the effect. You should change the touch position as well depending on speed. Or change the cursor move speed programmatically, to fit with the speed you selected. An implementation here: https://stackoverflow.com/questions/47254745/change-mac-cursor-speed-programmatically
Topic: UI Frameworks SubTopic: UIKit Tags:
Aug ’24
Reply to Attempting to add scrubbing to UISlider
OK, it's better. What is the problem, precisely ? What do you get ? What did you expect ? Please show screenshots. Here are my screenshots showing it is working, but thumb can move out of slider, which is probably not expected: You can force the thumb inside slider by making the following change: override func thumbRect(forBounds bounds: CGRect, trackRect rect: CGRect, value: Float) -> CGRect { let thumbDiameter = CGFloat(defaultDiameter * value) let origin = CGPoint(x: (currentLocation?.x ?? bounds.width / 2) - thumbDiameter / 2, y: 0 /*(currentLocation?.y ?? thumbDiameter / 2) - thumbDiameter / 2*/) // <<-- CHANGED return CGRect(origin: origin, size: CGSize(width: thumbDiameter, height: thumbDiameter)) }
Topic: UI Frameworks SubTopic: UIKit Tags:
Aug ’24
Reply to Attempting to add scrubbing to UISlider
Could you explain what you mean and expect exactly by 'scrubbing' ? This line does not compile (UIColor has no circle attribute) let thumbImage = UIColor.red.circle(CGSize(width: thumbDiameter, height: thumbDiameter)) Is there a line missing ? Or did you define an extension (if so, please provide it). I change the thumbImage to some systemImage. It compiles, but screen remains empty. So I added a background to SizeSlider and I get it on screen. But just a coloured rect, not a slider. Could you show what you get ? I completed code as follows, and now thumb (and slider) increase size. But thumb can get out of slider, is not saved at the end of school… Looks like there are missing parts in your code. extension UIImage { static func from(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) -> UIImage { let format = UIGraphicsImageRendererFormat() format.scale = 1 return UIGraphicsImageRenderer(size: size, format: format).image { context in color.setFill() context.fill(CGRect(origin: .zero, size: size)) } } } class SizeSliderView: UISlider { private var previousLocation: CGPoint? private var currentLocation: CGPoint? private var translation: CGFloat = 0 private var scrubbingSpeed: CGFloat = 1 private var defaultDiameter: Float init(startValue: Float = 0, defaultDiameter: Float = 500) { self.defaultDiameter = defaultDiameter super.init(frame: .zero) value = clamp(value: startValue, min: minimumValue, max: maximumValue) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func draw(_ rect: CGRect) { super.draw(rect) clear() createThumbImageView() addTarget(self, action: #selector(valueChanged(_:)), for: .valueChanged) } // Clear elements private func clear() { tintColor = .clear maximumTrackTintColor = .clear backgroundColor = .clear thumbTintColor = .clear } // Call when value is changed @objc private func valueChanged(_ sender: SizeSliderView) { CATransaction.begin() CATransaction.setDisableActions(true) CATransaction.commit() createThumbImageView() } // Create thumb image with thumb diameter dependent on thumb value private func createThumbImageView() { let thumbDiameter = CGFloat(defaultDiameter * value) // let thumbImage = UIColor.red.circle(CGSize(width: thumbDiameter, height: thumbDiameter)) let thumbImage = UIImage.from(color: .blue, size: CGSize(width: thumbDiameter, height: thumbDiameter)) setThumbImage(thumbImage, for: .normal) setThumbImage(thumbImage, for: .highlighted) setThumbImage(thumbImage, for: .application) setThumbImage(thumbImage, for: .disabled) setThumbImage(thumbImage, for: .focused) setThumbImage(thumbImage, for: .reserved) setThumbImage(thumbImage, for: .selected) } // Return true so touches are tracked override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool { let location = touch.location(in: self) // Ensure that start location is on thumb let thumbDiameter = CGFloat(defaultDiameter * value) print(location, bounds, thumbDiameter) if location.x < bounds.width / 2 - thumbDiameter / 2 || location.x > bounds.width / 2 + thumbDiameter / 2 || location.y < 0 || location.y > thumbDiameter { return false } previousLocation = location super.beginTracking(touch, with: event) return true } // Track based on moving slider override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool { guard isTracking else { return false } guard let previousLocation = previousLocation else { return false } // Reference // location: location of touch relative to device // delta location: change in touch location WITH scrubbing // adjusted location: location of touch to slider bounds (WITH scrubbing) // translation: location of slider relative to device let location = touch.location(in: self) currentLocation = location scrubbingSpeed = getScrubbingSpeed(for: location.y - 50) let deltaLocation = (location.x - previousLocation.x) * scrubbingSpeed var adjustedLocation = deltaLocation + previousLocation.x - translation if adjustedLocation < 0 { translation += adjustedLocation adjustedLocation = deltaLocation + previousLocation.x - translation } else if adjustedLocation > bounds.width { translation += adjustedLocation - bounds.width adjustedLocation = deltaLocation + previousLocation.x - translation } self.previousLocation = CGPoint(x: deltaLocation + previousLocation.x, y: location.y) let newValue = Float(adjustedLocation / bounds.width) * (maximumValue - minimumValue) + minimumValue setValue(newValue, animated: false) sendActions(for: .valueChanged) return true } // Reset start and current location override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { self.currentLocation = nil self.translation = 0 super.touchesEnded(touches, with: event) } // Thumb location follows current location and resets in middle override func thumbRect(forBounds bounds: CGRect, trackRect rect: CGRect, value: Float) -> CGRect { let thumbDiameter = CGFloat(defaultDiameter * value) let origin = CGPoint(x: (currentLocation?.x ?? bounds.width / 2) - thumbDiameter / 2, y: (currentLocation?.y ?? thumbDiameter / 2) - thumbDiameter / 2) return CGRect(origin: origin, size: CGSize(width: thumbDiameter, height: thumbDiameter)) } private func getScrubbingSpeed(for value: CGFloat) -> CGFloat { switch value { case 0: return 1 case 0...50: return 0.5 case 50...100: return 0.25 case 100...: return 0.1 default: return 1 } } private func clamp(value: Float, min: Float, max: Float) -> Float { if value < min { return min } else if value > max { return max } else { return value } } } //UIView representative: struct SizeSlider: UIViewRepresentable { private var startValue: Float private var defaultDiameter: Float init(startValue: Float, defaultDiameter: Float) { self.startValue = startValue self.defaultDiameter = defaultDiameter } func makeUIView(context: Context) -> SizeSliderView { let view = SizeSliderView(startValue: startValue, defaultDiameter: defaultDiameter) view.minimumValue = 0.1 view.maximumValue = 1 return view } func updateUIView(_ uiView: SizeSliderView, context: Context) { } } struct ContentView: View { var body: some View { SizeSlider(startValue: 0.20, defaultDiameter: 100) .frame(width: 400) .background(.red). // Just to see something .opacity(0.1) } }
Topic: UI Frameworks SubTopic: UIKit Tags:
Aug ’24
Reply to Will a Major Update from Flutter to SwiftUI Affect App Store Review Approval?
Will the review process reject the update due to the significant changes in the app? Not at all. Apps do evolve significantly in new releases, either functionally or technically. They don't mind as long that you comply with guidelines. You don't even have to mention the change from Flutter. In fact it would probably be seen as a positive move as more future proof and guaranteed multi platforms.
Aug ’24
Reply to "The city cannot exceed 35 characters."
The best is to contact Apple Support: https://developer.apple.com/contact/topic/select
Replies
Boosts
Views
Activity
Aug ’24
Reply to AppStorage extension for Bool Arrays
I need to handle arrays of boolean values. There is a very simple solution: convert true / false to "T", "F" and handle as String. map() let do it at once. Convert back when you need to use the Bool values. Here again, map() is your friend.
Topic: Programming Languages SubTopic: Swift Tags:
Replies
Boosts
Views
Activity
Aug ’24
Reply to I have rejection issues: Healthkit
You should ask the question of firebase forums.
Replies
Boosts
Views
Activity
Aug ’24
Reply to NSAttributedString draw in rect
An idea: use boundingRect(with:options:context:) to test what is the rect for drawing and adjust size until it fits ? Could you also post the code so that we can make some test.
Topic: UI Frameworks SubTopic: AppKit Tags:
Replies
Boosts
Views
Activity
Aug ’24
Reply to Plz help
Try to restart in safe mode: https://support.apple.com/en-gb/guide/mac-help/mh21245/mac#:~:text=Turn%20on%20or%20restart%20your,Boot”%20in%20the%20menu%20bar. Start up your Intel-based Mac in safe mode Turn on or restart your Mac, then immediately press and hold the Shift key until you see the login window. Log in to your Mac. You might be asked to log in again. On either the first or second login window, you should see “Safe Boot” in the menu bar.
Replies
Boosts
Views
Activity
Aug ’24
Reply to Attempting to add scrubbing to UISlider
I fear it may be a bit tricky. I see a few options: adapt the mouse speed in beginTracking (see the link https://stackoverflow.com/questions/47254745/change-mac-cursor-speed-programmatically) and restore the original value in touchesEnded. But if speed is already at minimum, it will have no effect in continueTracking, modify the mouse position to adjust to the reduced move ; https://stackoverflow.com/questions/70864549/swift-macos-set-mouse-cursor-position you could try to compute thumb position so that it moves only a fraction on mouse movement in func thumbRect by changing let origin = CGPoint(x: (currentLocation?.x ?? bounds.width / 2) - thumbDiameter / 2, y: (currentLocation?.y ?? thumbDiameter / 2) - thumbDiameter / 2) so that x is not currentLocation (mouse position), but the adjusted value. Problem is that you will not be able to move the thumb on the full range…
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
Boosts
Views
Activity
Aug ’24
Reply to Attempting to add scrubbing to UISlider
OK, so getting thumb out of slider is expected. But I don't understand the logic. At the end, the location during tracking is let location = touch.location(in: self) During update, thumb moves slower, but immediately after the mouse position prevails, which annihilate the effect. You should change the touch position as well depending on speed. Or change the cursor move speed programmatically, to fit with the speed you selected. An implementation here: https://stackoverflow.com/questions/47254745/change-mac-cursor-speed-programmatically
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
Boosts
Views
Activity
Aug ’24
Reply to Attempting to add scrubbing to UISlider
OK, it's better. What is the problem, precisely ? What do you get ? What did you expect ? Please show screenshots. Here are my screenshots showing it is working, but thumb can move out of slider, which is probably not expected: You can force the thumb inside slider by making the following change: override func thumbRect(forBounds bounds: CGRect, trackRect rect: CGRect, value: Float) -> CGRect { let thumbDiameter = CGFloat(defaultDiameter * value) let origin = CGPoint(x: (currentLocation?.x ?? bounds.width / 2) - thumbDiameter / 2, y: 0 /*(currentLocation?.y ?? thumbDiameter / 2) - thumbDiameter / 2*/) // <<-- CHANGED return CGRect(origin: origin, size: CGSize(width: thumbDiameter, height: thumbDiameter)) }
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
Boosts
Views
Activity
Aug ’24
Reply to Attempting to add scrubbing to UISlider
Could you explain what you mean and expect exactly by 'scrubbing' ? This line does not compile (UIColor has no circle attribute) let thumbImage = UIColor.red.circle(CGSize(width: thumbDiameter, height: thumbDiameter)) Is there a line missing ? Or did you define an extension (if so, please provide it). I change the thumbImage to some systemImage. It compiles, but screen remains empty. So I added a background to SizeSlider and I get it on screen. But just a coloured rect, not a slider. Could you show what you get ? I completed code as follows, and now thumb (and slider) increase size. But thumb can get out of slider, is not saved at the end of school… Looks like there are missing parts in your code. extension UIImage { static func from(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) -> UIImage { let format = UIGraphicsImageRendererFormat() format.scale = 1 return UIGraphicsImageRenderer(size: size, format: format).image { context in color.setFill() context.fill(CGRect(origin: .zero, size: size)) } } } class SizeSliderView: UISlider { private var previousLocation: CGPoint? private var currentLocation: CGPoint? private var translation: CGFloat = 0 private var scrubbingSpeed: CGFloat = 1 private var defaultDiameter: Float init(startValue: Float = 0, defaultDiameter: Float = 500) { self.defaultDiameter = defaultDiameter super.init(frame: .zero) value = clamp(value: startValue, min: minimumValue, max: maximumValue) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func draw(_ rect: CGRect) { super.draw(rect) clear() createThumbImageView() addTarget(self, action: #selector(valueChanged(_:)), for: .valueChanged) } // Clear elements private func clear() { tintColor = .clear maximumTrackTintColor = .clear backgroundColor = .clear thumbTintColor = .clear } // Call when value is changed @objc private func valueChanged(_ sender: SizeSliderView) { CATransaction.begin() CATransaction.setDisableActions(true) CATransaction.commit() createThumbImageView() } // Create thumb image with thumb diameter dependent on thumb value private func createThumbImageView() { let thumbDiameter = CGFloat(defaultDiameter * value) // let thumbImage = UIColor.red.circle(CGSize(width: thumbDiameter, height: thumbDiameter)) let thumbImage = UIImage.from(color: .blue, size: CGSize(width: thumbDiameter, height: thumbDiameter)) setThumbImage(thumbImage, for: .normal) setThumbImage(thumbImage, for: .highlighted) setThumbImage(thumbImage, for: .application) setThumbImage(thumbImage, for: .disabled) setThumbImage(thumbImage, for: .focused) setThumbImage(thumbImage, for: .reserved) setThumbImage(thumbImage, for: .selected) } // Return true so touches are tracked override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool { let location = touch.location(in: self) // Ensure that start location is on thumb let thumbDiameter = CGFloat(defaultDiameter * value) print(location, bounds, thumbDiameter) if location.x < bounds.width / 2 - thumbDiameter / 2 || location.x > bounds.width / 2 + thumbDiameter / 2 || location.y < 0 || location.y > thumbDiameter { return false } previousLocation = location super.beginTracking(touch, with: event) return true } // Track based on moving slider override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool { guard isTracking else { return false } guard let previousLocation = previousLocation else { return false } // Reference // location: location of touch relative to device // delta location: change in touch location WITH scrubbing // adjusted location: location of touch to slider bounds (WITH scrubbing) // translation: location of slider relative to device let location = touch.location(in: self) currentLocation = location scrubbingSpeed = getScrubbingSpeed(for: location.y - 50) let deltaLocation = (location.x - previousLocation.x) * scrubbingSpeed var adjustedLocation = deltaLocation + previousLocation.x - translation if adjustedLocation < 0 { translation += adjustedLocation adjustedLocation = deltaLocation + previousLocation.x - translation } else if adjustedLocation > bounds.width { translation += adjustedLocation - bounds.width adjustedLocation = deltaLocation + previousLocation.x - translation } self.previousLocation = CGPoint(x: deltaLocation + previousLocation.x, y: location.y) let newValue = Float(adjustedLocation / bounds.width) * (maximumValue - minimumValue) + minimumValue setValue(newValue, animated: false) sendActions(for: .valueChanged) return true } // Reset start and current location override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { self.currentLocation = nil self.translation = 0 super.touchesEnded(touches, with: event) } // Thumb location follows current location and resets in middle override func thumbRect(forBounds bounds: CGRect, trackRect rect: CGRect, value: Float) -> CGRect { let thumbDiameter = CGFloat(defaultDiameter * value) let origin = CGPoint(x: (currentLocation?.x ?? bounds.width / 2) - thumbDiameter / 2, y: (currentLocation?.y ?? thumbDiameter / 2) - thumbDiameter / 2) return CGRect(origin: origin, size: CGSize(width: thumbDiameter, height: thumbDiameter)) } private func getScrubbingSpeed(for value: CGFloat) -> CGFloat { switch value { case 0: return 1 case 0...50: return 0.5 case 50...100: return 0.25 case 100...: return 0.1 default: return 1 } } private func clamp(value: Float, min: Float, max: Float) -> Float { if value < min { return min } else if value > max { return max } else { return value } } } //UIView representative: struct SizeSlider: UIViewRepresentable { private var startValue: Float private var defaultDiameter: Float init(startValue: Float, defaultDiameter: Float) { self.startValue = startValue self.defaultDiameter = defaultDiameter } func makeUIView(context: Context) -> SizeSliderView { let view = SizeSliderView(startValue: startValue, defaultDiameter: defaultDiameter) view.minimumValue = 0.1 view.maximumValue = 1 return view } func updateUIView(_ uiView: SizeSliderView, context: Context) { } } struct ContentView: View { var body: some View { SizeSlider(startValue: 0.20, defaultDiameter: 100) .frame(width: 400) .background(.red). // Just to see something .opacity(0.1) } }
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
Boosts
Views
Activity
Aug ’24
Reply to Swiftui Table statement conditional table columns
You don't show the complete code, so harder to explain… But the way I would do it would be to have the condition in the dataSource through a computed var.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Aug ’24
Reply to SwiftUI List rows loaded all at once
Could you show the code where you build the List ?
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Aug ’24
Reply to Will a Major Update from Flutter to SwiftUI Affect App Store Review Approval?
Will the review process reject the update due to the significant changes in the app? Not at all. Apps do evolve significantly in new releases, either functionally or technically. They don't mind as long that you comply with guidelines. You don't even have to mention the change from Flutter. In fact it would probably be seen as a positive move as more future proof and guaranteed multi platforms.
Replies
Boosts
Views
Activity
Aug ’24
Reply to SwiftUI gets stuck in a view update cycle when I pass down a Binding to a NavigationPath
You set .environmentObject(SomeEnvironmentObject()) in Preview. Do you do the same for the app where you call ContentView() ?
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Aug ’24
Reply to Video PLayer - remove maximizer controller
Sorry not being able to help. But you'd better try to understand why it crashes. There may be a bug somewhere that will reappear sooner or later. You may also file a bug report in Feedback, in case.
Topic: Spatial Computing SubTopic: General Tags:
Replies
Boosts
Views
Activity
Aug ’24
Reply to does simulator accurately reflect translucent UIs?
What simulator are you speaking about ? There is no simulator for Mac apps, it is directly the app running on the Mac. So, do you mean Preview ?
Replies
Boosts
Views
Activity
Aug ’24