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 Stack feature not working as per plan.
And now with progress bar overlaying: struct ContentView: View { let barHeight: CGFloat = 30 let barColor = Color.gray let duration: Double = 10 let icon = "globe" @State private var progress: CGFloat = 0 var body: some View { ZStack(alignment: .leading) { // VStack { // Background bar RoundedRectangle(cornerRadius: 10) // .fill(Color.gray.opacity(0.3)) // .frame(height: barHeight) // Set height to the specified barHeight // Progress bar // GeometryReader { geometry in RoundedRectangle(cornerRadius: 10) .fill(barColor.opacity(0.5)) // To see through .frame(width: CGFloat(progress) * UIScreen.main.bounds.width, height: barHeight) // .frame(width: CGFloat(progress) * geometry.size.width, height: barHeight) .animation(.linear(duration: 10), value: progress) // } // .cornerRadius(10) // That's redundant // Icon and label HStack { Rectangle() // to avoid frame moving when animation starts) .fill(.clear) .frame(width: UIScreen.main.bounds.width * 0.05, height: barHeight) Image(systemName: icon) .foregroundColor(.black) .font(.system(size: 28)) // Increased size .padding(.leading, 8) .onTapGesture { progress = 1 // Added to see progress } Spacer() Text(String/*timeString*/(format: "%.1f", /*from: */duration * Double(progress))) .foregroundColor(.black) .bold() .font(.system(size: 24)) // Increased size .padding(.trailing, 8) } .frame(width: UIScreen.main.bounds.width/* * 0.9*/, height: barHeight) // Changed to avoid frame moving when animation starts .zIndex(1) // Ensure the HStack is on top Spacer() // ADDED THIS } .padding(.horizontal) } } We get this during progress: May be we could use overlay, but did not try.
Topic: Programming Languages SubTopic: Swift Tags:
Aug ’24
Reply to Stack feature not working as per plan.
What is ProgressiveBar ? Is it RoundedRectangle(cornerRadius: 10) What do you mean by above or on top. Please show what you get and what you want. Why do you need geometry reader and not just set the zIndex of the progress bar ? I edited your code to guess and complete missing parts: struct ContentView: View { let barHeight: CGFloat = 30 let barColor = Color.gray let duration: Double = 10 let icon = "globe" @State private var progress = 0 var body: some View { ZStack(alignment: .leading) { // Background bar RoundedRectangle(cornerRadius: 10) // .fill(Color.gray.opacity(0.3)) // .frame(height: barHeight) // Set height to the specified barHeight // Progress bar GeometryReader { geometry in RoundedRectangle(cornerRadius: 10) .fill(barColor) .frame(width: CGFloat(progress) * geometry.size.width, height: barHeight) .animation(.linear(duration: 10), value: progress) } .cornerRadius(10) // Icon and label HStack { Image(systemName: icon) .foregroundColor(.black) .font(.system(size: 28)) // Increased size .padding(.leading, 8) .onTapGesture { progress = 10 // Added to see progress } Spacer() Text(String/*timeString*/(format: "%.1f", /*from: */duration * Double(progress))) .foregroundColor(.black) .bold() .font(.system(size: 24)) // Increased size .padding(.trailing, 8) } .frame(width: UIScreen.main.bounds.width * 0.9, height: barHeight) .zIndex(1) // Ensure the HStack is on top } .padding(.horizontal) } } The progressBar is above: I changed ZStack to VStack and removing geometryReader and get this: struct ContentView: View { let barHeight: CGFloat = 30 let barColor = Color.gray let duration: Double = 10 let icon = "globe" @State private var progress = 0 var body: some View { // ZStack(alignment: .leading) { VStack { // Set height to the specified barHeight // Progress bar // GeometryReader { geometry in // REMOVED RoundedRectangle(cornerRadius: 10) .fill(barColor) .frame(width: CGFloat(progress) * UIScreen.main.bounds.width, height: barHeight) // WE CAN get screen width directly // .frame(width: CGFloat(progress) * geometry.size.width, height: barHeight) .animation(.linear(duration: 10), value: progress) // } .cornerRadius(10) // Icon and label HStack { Image(systemName: icon) .foregroundColor(.black) .font(.system(size: 28)) // Increased size .padding(.leading, 8) .onTapGesture { progress = 10 // Added to see progress } Spacer() Text(String/*timeString*/(format: "%.1f", /*from: */duration * Double(progress))) .foregroundColor(.black) .bold() .font(.system(size: 24)) // Increased size .padding(.trailing, 8) } .frame(width: UIScreen.main.bounds.width * 0.9, height: barHeight) // .zIndex(1) // Ensure the HStack is on top Spacer() // ADDED THIS } .padding(.horizontal) } } Is it what you are looking for ? If so, don't forget to close the thread by marking the answer as correct.
Topic: Programming Languages SubTopic: Swift Tags:
Aug ’24