Post

Replies

Boosts

Views

Activity

UIBarButtonItem getting clipped after a push
I'm attempting to use an untappable UIBarButtonItem in a NavBar that would display a glyph and use CALayer to show a background shadow. I have noticed that the item displays correctly at startup, however as soon as I push a new viewController the UIBarButtonItem clips. Do any of you know of a way to prevent the clipping that occurs after a push? thanks, in advance! At app launch After push and pop class ViewController: UIViewController { var showBack: Bool init(showBack: Bool = false) { self.showBack = showBack super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { self.showBack = false super.init(coder: coder) } override func viewDidLoad() { super.viewDidLoad() navigationItem.rightBarButtonItem = barButton if !showBack { navigationItem.leftBarButtonItem = barButton } } var barButton: UIBarButtonItem { let config = UIImage.SymbolConfiguration(pointSize: 30) let view: UIImageView = .init(image: UIImage(systemName: "multiply.circle", withConfiguration: config)) view.layer.shadowColor = UIColor.black.cgColor view.layer.shadowRadius = 10 view.layer.shadowOffset = .zero view.layer.shadowOpacity = 1.0 view.layer.masksToBounds = false return .init(customView: view) } @IBAction func navPush(sender: UIButton) { let storyboard = UIStoryboard(name: "Main", bundle: nil) let vc = storyboard.instantiateViewController(withIdentifier: "vc") as! ViewController vc.showBack = true self.navigationController?.pushViewController(vc, animated: true) } }
0
0
304
Nov ’23
A question about Swift enum syntax
I would have thought the following code would not compile. Spoiler: It compiles, at least in Xcode 14.3. Does this mean using a dot before an enum case name is just for show? enum Stuff { case first case second case third static var allCases: [Stuff] { [.first, .second, third] } }
2
0
450
Sep ’23
did something break VoiceOver traversal with .accessibilityRepresentation in iOS 16.6?
When I run the code below and enable VoiceOver on my iPhone running iOS 16.6, it navigates from "email1" to "email2". When I run it on an iPhone simulator running iOS 16.4 and use the A11y Inspector it navigates from "email1" to the first textField, and then to "email2" when I delete the .accessibilityRepresentation it navigates from "email1" to the first textField, and the to "email2" on both simulator and device. Am I using .accessibilityRepresentation incorrectly? Or did something change between 16.4 and 16.6? Or is there a better question I should be asking? any and all help greatly appreciated struct ContentView: View { @State var input1: String = "" @State var input2: String = "" var body: some View { VStack { TextInput(title: "email1", inputText: $input1) TextInput(title: "email2", inputText: $input2) } } } struct TextInput: View { let title: String @Binding var inputText: String init(title: String, inputText: Binding<String>) { self.title = title self._inputText = inputText } var body: some View { VStack { Text(title) TextField("enter Text", text: $inputText) .accessibilityRepresentation { TextField("enter Text", text: $inputText) } } } }
0
0
425
Sep ’23
Can I enable (at least in VoiceOver) a subcomponent, when the parent container has been disabled?
When my parent container is disabled and I use VoiceOver, it reads out all the components in the container as "Dimmed" or "Disabled" (iOS 16.4 simulator says "Disabled" 16.6 actual device says "Dimmed", but I digress...) I was hoping to be able to enable one of the components in the container, but VO continues to report the item as Disabled/Dimmed. (see code below) Any suggestions on how I might be able to not report Text("Heading") as Dimmed/Disabled in VO? struct ContentView: View { @State var inputText: String = "" var body: some View { VStack { Text("Heading") .disabled(false) TextField("Type some text", text: $inputText) } .disabled(true) } }
0
0
374
Sep ’23
Trying to understand some odd behavior in SwiftUI DragGesture
I'm attempting to implement a star rating view using a drag gesture. (eg user can press on star#1, then 'change their mind' and drag to star 3 and release) The code below will calculate the inferred star rating based on the width of the Stars HStack and the x value of the current drag position. The odd behavior I'm seeing is when I drag off the leading (left) edge of the stars. sometimes the app gets non-responsive, repeatedly calling onChanged. I believe the cause of this behavior is the following: app detects the user drag has moved to a location to the left of the starts (eg -1, 15) app updates rating Int to 0 and redraws the text view containing rating "0" this increases the width of the root HStack, which causes the stars hstack to move slightly to the left This effectively moves the drag position to just inside the start (eg 1, 15) This changes the rating value to 1 which causes the text view value to update to "1" This causes the stars hStack to move slightly to the right This causes the drag position to update to be slightly to the left of the start (eg -1, 15) goto 2 What's not clear to me is why this behavior continues even after the drag is completed. There are many ways I've found to avoid/prevent this behavior including: fixing the width of the Text containing the rating Int. not letting the rating value be change to 0 when dragging to the left of the stars. But these both feel like hacky work arounds. Is there a better way to avoid this metastable ping pong behavior? thanks! struct ContentView: View { @State var rating: Int = 0 var body: some View { HStack { GeometryReader { proxy in HStack { ForEach(0..<5) { index in Image(systemName: symbolName(for: index)) } } .gesture( DragGesture(minimumDistance: 0) .onChanged { gesture in rating = starValue(for: gesture.location.x, width: proxy.size.width) } ) } .frame(width: 145, height: 30) Text("\(rating)") } } func starValue(for xPosition: CGFloat, width: CGFloat) -> Int { guard xPosition > 0 else { return 0 } let fraction = xPosition / width let result = Int(ceil(fraction * 5)) return max(0, min(result, 5)) } func symbolName(for index: Int) -> String { if index < rating { return "star.fill" } return "star" } }
2
0
774
Aug ’23
Problems combining a .popover and a conditional accessibilityRepresentation
Hello friends/colleagues, I want to create a ViewModifier that accepts a conditional accessibilityIdentifier accepting an optional string input struct AccessibilityModifier: ViewModifier { let identifier: String? func body(content: Content) -> some View { if let identifier = identifier { content .accessibilityRepresentation { content .accessibilityIdentifier(identifier) } } else { content } } } it mostly works as expected, but .popover appears to be broken. For example, in the following code, the popover will work. But if I uncomment the .modifier line, the popover does not get presented struct ContentView: View { @State var isPresented: Bool = false var body: some View { VStack { Button("Show Popover") { isPresented = true } } .popover(isPresented: $isPresented) { Text("A Popover") } // .modifier(AccessibilityModifier(identifier: "a11y Modifier")) } } The popover also works when I use: .modifier(AccessibilityModifier(identifier: nil)) Any suggestions on how I can support both popovers and my conditional accessibilityIdentifier? thanks, in advance, Mike
0
0
442
Aug ’23
Can't seem to get .accessibilityRotor(_:, textRanges:) working
When I run the following code: struct ContentView: View { let mdText = LocalizedStringKey("some text [link](https://apple.com) more text") let text = "some text link more text" var body: some View { VStack { Text(mdText) // .accessibilityRotor(.links, textRanges: [String.Index(utf16Offset: 10, in: text)..<String.Index(utf16Offset: 14, in: text)]) // .accessibilityIdentifier("identifier") } } } It works as expected. Specifically in voiceOver I'm able to use the rotor, select "Links" and select the link described in the markdown text. However if I uncomment the .accessibilityIdentifier modifier, "Links" is no longer present in the Rotor. To work around this, I would like to add an accessibilityRotor modifier to restore the Links Rotor item. When I uncomment the rotor modifier in the above code, Links is present in the Rotor, however there are no items in the list (ie swiping down just generates a 'klunk' noise) I think I have two separate questions: Is there any way to restore Links to the VO Rotor for a Text() using text Ranges? Is there some way to add an accessibilityIdentifier that doesn't clobber the Links setting in the VO rotor? thanks in advance :-)
1
0
653
Jun ’23
Looking for suggestions on how to modify the frame of a cropped Image()
I am hoping to be able to 'crop' a SwiftUI Image() and have the resulting (cropped) Image fill the space previously occupied by the Image() (aspectRatio differences not withstanding) In the code below, commenting out the .clipShape modifier displays the original image, spanning the full width available. When I add the .clipShape modifier, the resulting image only occupies its small portion of the original image. I want to stretch it to fill the available space, but don't know how I might do this. Any/all guidance appreciate struct ContentView: View { var body: some View { VStack() { Image("Hana") .resizable() .aspectRatio(contentMode: .fit) .clipShape(CropFrame()) } } } struct CropFrame: Shape { func path(in rect: CGRect) -> Path { return Path(CGRect(x: 17, y: 5, width: 73, height: 80)) } } My preference would have been to operate on a UIImage, however based on limitations outside the scope of this question, my most viable option is to operate on the SwiftUI Image() thx again :-)
0
0
374
Apr ’23
VNDetectFaceCaptureQualityRequest vs VNDetectFaceRectanglesRequest
Hey fellow devs, I just wanted to make sure I understand the differences between these two requests. It appears both these requests return pitch, yaw and roll in the VNFaceObservation's they return. However, VNDetectFaceCaptureQualityRequest's returned VNFaceObservation's include faceCaptureQuality values, while these values are nil in the response from VNDetectFaceRectanglesRequest. So is the response to a VNDetectFaceCaptureQualityRequest a superset of the properties returned by VNDetectFaceRectanglesRequest? And is the expectation that VNDetectFaceCaptureQualityRequest uses more cycles and/or takes longer than VNDetectFaceRectanglesRequest?
0
0
512
Apr ’23
How to structure code to handle mutations from Vision (face detection) requests
Hi Fellow devs, This is only nominally related to the Vision SDK. I want to detect faces and update my UI based on the results. The code below does not compile. The line that begins with let request = throws the following error: Escaping closure captures mutating 'self' parameter I understand the problem with trying to modify a struct from within a closure, but I don't know what I'd need to change to be able to update the UI, based on the results from the face detection request. Any suggestions? thanks, in advance import SwiftUI import Vision struct ContentView: View { @State var uiImage = UIImage(named: "Ollie")! @State var faceCount = 0 init() { let handler = VNImageRequestHandler(cgImage: uiImage.cgImage!, options: [:]) let request = VNDetectFaceRectanglesRequest { _, _ in self.faceCount = 3 } try! handler.perform([request]) } var body: some View { VStack { Image(uiImage: uiImage) .resizable() .aspectRatio(contentMode: .fit) Text("faces: \(faceCount)") } .padding() } }
1
0
695
Apr ’23
SWAttributionView seems to be getting swallowed inside a view with an .onTapGesture modifier
Hey fellow devs, I have a parent SwiftUI view that includes an SWAttributionView. When I add an .onTapGesture{ } modifier to my parent view, the SWAttributionView no longer appears to 'see' taps. They instead go to the parent's tapGesture modifier. I think I'd be more willing to just accept this, if it wasn't possible for its SwiftUI sibling views to be able to 'see' their taps. Here is some sample code: struct ContentView: View {   @State var tapType: String?   var body: some View {     RowView(accessory: {       Button {         tapType = "Globe"       } label: {         Image(systemName: "globe")           .foregroundColor(.accentColor)       }     })     .onTapGesture {       tapType = "Row"     }     .alert(item: $tapType) { tt in       Alert(title: Text("tap type: \(tt)"))     }   } } struct RowView<Accessory: View>: View {   private let accessory: () -> Accessory   init(accessory: @escaping () -> Accessory) {     self.accessory = accessory   }   var body: some View {     HStack {       VStack {         Text("Row Text")         if let highlight = SharedWithYouMonitor.shared.highlights.first {           SwiftUIAttributionView(highlight: highlight)             .frame(maxHeight: 100)         }       }       accessory()     }     .padding()   } } The above code is able to set tapType to 'globe' by tapping the globe button. It is also able to set tapType to 'row' by tapping anywhere else in the RowView. But it is not able to demonstrate the sharedWithYou tap behaviour. When I comment out the tapType = 'row' onTapGesture modifier, the SWAttributeView behaves as expected. Is this a bug/limitation in SWAttributeView that prevents it from working correctly when its parent has an .onTapGesture modifier? Thanks in advance for any assistance :-) here is some other supporting code, that's not specifically germane to my question, but is needed to get things running. import SharedWithYou public class SharedWithYouMonitor: NSObject {   private let highlightCenter: SWHighlightCenter   public static let shared = SharedWithYouMonitor()   public var localizedTitle: String {     return SWHighlightCenter.highlightCollectionTitle   }   public var highlights: [SWHighlight] {     return highlightCenter.highlights   }   override init() {     self.highlightCenter = SWHighlightCenter()     super.init()     highlightCenter.delegate = self   } } extension SharedWithYouMonitor: SWHighlightCenterDelegate {   public func highlightCenterHighlightsDidChange(_ highlightCenter: SWHighlightCenter) {     highlightCenter.highlights.forEach { highlight in       print("Received a new highlight with URL: \(highlight.url)")     }   } } struct SwiftUIAttributionView: UIViewRepresentable {   private let highlight: SWHighlight   init(highlight: SWHighlight) {     self.highlight = highlight   }   func makeUIView(context: Context) -> SWAttributionView {     let result = SWAttributionView()     result.highlight = highlight     result.displayContext = .summary     result.horizontalAlignment = .center     result.preferredMaxLayoutWidth = 300     return result   }  func updateUIView(_ uiView: SWAttributionView, context: Context) {   } } extension String: Identifiable {   public typealias ID = Int   public var id: Int {     return hash   } }
1
1
524
Feb ’23
SwiftUI ReadMore chevron animation guidance appreciated
Hello, I'm attempting to create a basic showMore/showLess control at the bottom of a large block of text. However it is currently animating in a suboptimal way. When I tap to expand my text block: the text block expands right away the text label changes from 'More' to 'Less' right away the chevron animates both the rotationEffect and its change in position The problem is animating the change of position is odd as it is moving 'over' the expanded text block. My fallback position is to remove the rotationEffect and have the Image(systemName:) choose either "chevron.up" or "chevron.down" depending on is expanded. But is there a way to either: animate the rotationEffect, but have the position change instantly -or- have the more/less label and the chevron both animate the position change together? thanks in advance for any help struct ContentView: View {   @State private var isExpanded = false   let text = "That you have wronged me doth appear in this: You have condemned and noted Lucius Pella For taking bribes here of the Sardians, wherein my letters, praying on his side because I knew the man, were slighted off."   var body: some View {     VStack(alignment: .leading) {       Text(text)         .frame(maxWidth: 300)         .lineLimit(isExpanded ? nil : 2)       footer     }     .padding()   }   @ViewBuilder   private var footer: some View {     HStack {       Text(isExpanded ? "Less" : "More")       Button {         isExpanded.toggle()       } label: {         Image(systemName: "chevron.up")           .rotationEffect(isExpanded ? .degrees(180) : .zero)       }     }   } }
1
0
1.7k
Jan ’23
Odd behaviour from RelativeDateTimeFormatter
I should preface my question by saying I love this formatter and the edge cases it handles for us, but I've found a case that seems odd to me. (all times are in the same time zone. let's go with Pacific) current time is 3:05pm, December 21 comparison time formatter output dec 20 @ 3:15pm 23 hours ago (great!) dec 20 @ 2:15pm yesterday (also great!) dec 19 @ 3:15pm yesterday (wait, wut?!) If today is Dec 21, shouldn't yesterday be limited to Dec 20 00:00:00 - 23:59:59? I see three options: I'm using RelativeDateTimeFormatter incorrectly I'm misunderstanding the sematics of 'yesterday' ( is it correct to refer to 47 hours ago as yesterday?) RelativeDateTimeFormatter is misbehaving all thoughts on this are welcome.foun here is some playground code demonstrating this behaviour let relativeDateFormatter: RelativeDateTimeFormatter = {     let formatter = RelativeDateTimeFormatter()     formatter.dateTimeStyle = .named     return formatter }() func startDate(from dateText: String) -&gt; Date {     let formatter = DateFormatter()     formatter.locale = Locale(identifier: "en_US_POSIX")     formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"     formatter.timeZone = .current     return formatter.date(from: dateText)! } let myNow = startDate(from: "2022-12-21T23:05:00Z") let almostTwoDaysAgo = myNow.addingTimeInterval(-(48 * 3600 - 600)) let relText = relativeDateFormatter.localizedString(for: almostTwoDaysAgo, relativeTo: myNow)
3
0
1k
Dec ’22
Having Trouble passing a ButtonStyle as a parameter to a func
I have a SwiftUI View where the body looks like this              VStack {                   VStack(spacing: 4) {                     Text("Outline")                     Button("Tap Me") {                       print("tapped")                     }                     .buttonStyle(.outline)                   }                   VStack(spacing: 4) {                     Text("Simple")                     Button("Tap Me") {                       print("tapped")                     }                     .buttonStyle(.simple)                   }                 } So to remove the duplication, I want to do something like this:      func textButton(title: String, buttonStyle: ButtonStyle) -> some View {       VStack {         Text(title)         Button("hello") {           print("tapped")         }           .buttonStyle(buttonStyle)       }     } The compiler asks me to add 'any' before ButtonStyle. When I do that I get the following: "Type 'any View' cannot conform to 'View'" It works fine if I don't pass in the ButtonStyle. Any suggestions on how to pass a ButtonStyle into a func? thanks, in advance!
2
1
1.9k
Dec ’22