Post

Replies

Boosts

Views

Activity

Countdown timer picker with minutes and seconds
I am trying to replicate the timer picker from the Clock app, shown below, using SwiftUI. DatePicker doesn't have a countDownTimer mode like UIDatePicker does, but then that doesn't show seconds even though the countDownDuration property is in seconds. I am currently trying to use a custom UIPickerView with two components (minutes and seconds), all wrapped inside a UIViewRepresentable. This sort of works, but I can't seem to get the min and sec labels to be positioned where they are. Any help on this matter would be much appreciated.
2
0
3.5k
Jul ’21
Custom Font Picker Accessing UIFont Properties Crashes App
I am attempting to create a custom font picker (similar to the one in Pages) using SwiftUI, because the current UIFontPickerViewController isn't sufficient enough for my app. When running the app and presenting FontPickerView in a sheet, the app seems to pause, the sheet doesn't appear, and a lot of dialog continuously pops up in the Xcode console. This is an example of what keeps showing: CoreText note: Client requested name ".SFUI-Regular", it will get TimesNewRomanPSMT rather than the intended font. All system UI font access should be through proper APIs such as CTFontCreateUIFontForLanguage() or +[UIFont systemFontOfSize:]. The .SFUI string changes with different font styles, for example -Bold, -Compressed, -SemiExpandedLight... I believe the problem lies when accessing the UIFont family and font name properties and methods. Is there a reason why this is happening? A possible solution? Help is appreciated. Here is some code you can test (Xcode 13 beta 3): extension Character {     var isUppercase: Bool {         String(self).uppercased() == String(self)     } } extension UIFont { // Will show dialog from here     class func familyName(forFontName fontName: String) -> String {         var familyName = ""         familyNames.forEach { family in             fontNames(forFamilyName: family).forEach { font in                 if font == fontName {                     familyName = family                 }             }         }         return familyName     } } struct FontPickerView: View {     @Environment(\.dismiss) private var dismiss     @ScaledMetric private var linkPaddingLength = 24     @State private var searchText = ""     @State private var linkSelection: String?     @Binding var selectedFontName: String // Will show dialog from here     private var familyNames: [String] {         UIFont.familyNames.filter {             $0.contains(searchText) || searchText.isEmpty         }     } // Will show dialog from here     private var familyPickerBinding: Binding<String> {         Binding {             UIFont.familyName(forFontName: selectedFontName)         } set: {             selectedFontName = UIFont.fontNames(forFamilyName: $0)[0]         }     }     var body: some View {         NavigationView {             List {                 Picker("All Fonts", selection: familyPickerBinding) {                     ForEach(familyNames, id: \.self, content: pickerRow)                 }                 .labelsHidden()                 .pickerStyle(.inline)             }             .listStyle(.insetGrouped)             .searchable(text: $searchText, placement: .navigationBarDrawer)             .navigationTitle("Fonts")             .navigationBarTitleDisplayMode(.inline)             .toolbar {                 Button("Cancel", action: dismiss.callAsFunction)             }         }     }     private func linkPadding(forFamilyName familyName: String) -> CGFloat {         familyPickerBinding.wrappedValue == familyName ? 0 : linkPaddingLength     }     private func familyText(forFamilyName familyName: String) -> some View {         Text(familyName)             .font(.custom(familyName, size: UIFont.labelFontSize))     }     private func familyTextWithStyles(forFamilyName familyName: String) -> some View {         ZStack(alignment: .leading) {             NavigationLink("Style options", tag: familyName, selection: $linkSelection) {                 FontStylesView(selection: $selectedFontName, family: familyName)             }             .hidden()             HStack {                 familyText(forFamilyName: familyName)                 Spacer()                 Button(action: { linkSelection = familyName }) {                     Label("Style options", systemImage: "info.circle")                         .labelStyle(.iconOnly)                         .imageScale(.large)                 }                 .buttonStyle(.borderless)                 .padding(.trailing, linkPadding(forFamilyName: familyName))             }         }     }     private func pickerRow(forFamilyName familyName: String) -> some View {         Group {             if UIFont.fontNames(forFamilyName: familyName).count == 1 {                 familyText(forFamilyName: familyName)             } else {                 familyTextWithStyles(forFamilyName: familyName)             }         }     } } struct FontStylesView: View {     @Binding var selection: String     let family: String     var body: some View {         List {             Picker("Font Styles", selection: $selection) { // Will show dialog from here                 ForEach(UIFont.fontNames(forFamilyName: family), id: \.self) { font in                     Text(fontType(forFontName: font))                         .font(.custom(font, size: UIFont.labelFontSize))                 }             }             .labelsHidden()             .pickerStyle(.inline)         }         .navigationTitle(family)     }     private func fontType(forFontName fontName: String) -> String {         if let index = fontName.lastIndex(of: "-") {             var text = String(fontName.suffix(from: index).dropFirst())             // Add spaces between words.             let indexes = text.enumerated().filter { $0.element.isUppercase }.map { $0.offset }             var count = 0             indexes.forEach { index in                 guard index > 0 else { return }                 text.insert(" ", at: text.index(text.startIndex, offsetBy: index + count))                 count += 1             }             return text         } else {             return "Regular"         }     } } (There are a few bugs that I am going to fix.)
2
0
2.3k
Apr ’22