How to stop SwiftUI from changing font sizes automatically - swiftui

I using text like this in SwiftUI
Text("Customize").font(.footnote)
But this is also changing the font size base of device font size settings.
So how I stop SwiftUI to change the default font size automatically?
PS: I don't want to set all Texts font size manually.

Just create a Font extension like this:
import SwiftUI
extension Font {
static var appButton:Font {
get {
return .system(size: 18)
}
}
}
Then use it as:
Text("Observation mode")
.font(.appButton)

Hey! Please Give It A Try!
Text("Customize").font(.system(size: 32))

Related

how to match the font of an existing view

I'm curious, is there a way to make the fonts in a view match those of an existing view in SwiftUI? I don't like the default selections of swiftUI in a certain context, and I'd like some control over the situation.
Here's some code to illustrate:
struct FontMatchView: View {
var body: some View {
Form {
Section {
Text("Some Controls Here")
} header: {
HStack {
Text("Header")
Spacer()
Button("Option") {
}
}
}
}
}
}
This gives this result:
In the Section Header, I'd like the font in the button on the right (with label "OPTION") to match the label to its left ("HEADER"). I'm guessing this will be hard because the font is not known at the time of view definition. But the choices SwiftUI has made here are "clearly wrong" :-), and I need to fix this.
Is there a way we solve this (other than overriding both fonts)? Ideally, I could say "use a font that is 0.8 x the height of whatever font will be used in view X". But I'd settle for "use the same font as will be used in view X".
You can remove "buttonizing" (which includes adjusting the font) by applying .buttonStyle(.plain). This will make it match the other Text in the current context. If you then want to re-accent it, you may:
Button("Option") {}
.buttonStyle(.plain)
.foregroundColor(.accentColor)
That said (and somewhat unrelated), making the button as small as the HEADER text may make it uncomfortably small as a hit area. It may be better to make HEADER larger rather than OPTION smaller.

Setting the font of SwiftUI's .searchable() with the appearance API of UITextField+UISearchBar doesn't work

I'm customizing the appearance of the .searchable() modifier of SwiftUI with the appearance API of UISearchBar.
Almost everything works, except the font of the text field, and I have no idea why (setting the font of the cancel button works, or setting the background color or text color of the text field also work, so the correct reference is there).
Talk is cheap, show me the code!
let textAttributes: [NSAttributedString.Key: Any] = [
.foregroundColor: UIColor.systemBlue, // this works
.font: UIFont.boldSystemFont(ofSize: 15) // this doesnt
]
let placeholder = NSAttributedString(
string: "Search...", // this doesnt
attributes: [
.foregroundColor: UIColor.systemGray, // this works
.font: UIFont.boldSystemFont(ofSize: 15) // this doesnt
])
let textFieldAppearance = UITextField
.appearance(whenContainedInInstancesOf: [UISearchBar.self])
textFieldAppearance.backgroundColor = .red // this works
textFieldAppearance.defaultTextAttributes = textAttributes // color works, font not
textFieldAppearance.attributedPlaceholder = placeholder // color works, font or text not
I guess it's time to file a -radar- feedback?
I haven't found a reliable way of customizing this, with the solution posted below there's a glitch on the search bar that happens when SwiftUI re-renders the view (scrolling or just typing on the search bar), that is very obvious on a real device (not so much on the simulator).
Old answer:
Far from ideal, I found a way to make it work, which is introspecting the view searching for the UITextField and setting the font directly. The easiest way to do this is using a library like SwiftUI-Introspect (https://github.com/siteline/SwiftUI-Introspect).
Then on the View you're using .searchable() from just:
.introspectTextField { textField in
textField.font = UIFont.boldSystemFont(ofSize: 15)
}
Fixed! The perfect solution would be to use the appearance API, but I guess we'll have to wait till iOS 16...
Setting the .font and .foregroundColor modifiers after .searchable will do the desired result, but it still doesn't work with .background modifier (if you want it) as the time of this writing (iOS 16).

Swiftui: multiple lines in a menu item or picker

I've started using SwiftUI and trying to convert an application that I've created with Jetpack Compose to iOS, but I've run into a problem with menus (or picker if that's easier).
What I want to do is to be able to create items that has multi-lines and different font size for the two lines. But I can't make it work, only the first line is visible
I've tried something like:
Picker("Select menu item", selection: $selectedItem) {
ForEach(0..<items.count) {
VStack {
Text("Menu item 1").fontWeight(.bold) // Only this text is shown
Text("Description")
}
}
}
I've also tried with
Menu("Options") {
VStack {
Text("Menu item 1").fontWeight(.bold) // Only this text is shown
Text("Description")
}
}
What I want it to look like is something like:
I've spent many hours trying to find an example of something like this. Is this possible to do in SwiftUI? If not, what control should you suggest to use instead?

Swift UI padding on Navigation "back" button

How do I adjust the padding of a Swift UI "back" navigation button? i.e. the blue "Navigation" text in the image below (Image contributed by someone else on a different question). I want to add more space between the text and the leading edge of the screen.
You can use custom appearance for this purpose configured in the init of view holding NavigationView.
Here is a demo (with big offset for better visibility). Prepared with Xcode 13 / iOS 15.
init() {
let appearance = UINavigationBarAppearance()
appearance.backButtonAppearance.normal.titlePositionAdjustment =
UIOffset(horizontal: 40, vertical: 0)
UINavigationBar.appearance().standardAppearance = appearance
}

SwiftUI TextField freezes when deleting first character

When specifying a minimumScaleFactor for a TextField in SwiftUI the TextField behaves normally while you enter text and reduces the font as specified when the content does not fit the TextView. However, if you start deleting characters everything works as usual until you delete the first character. Everything freezes.
At the beginning I though it was something in the way I was handling the variable that stores the text that in my application I have it as an ObservedObject. However, after debugging the frozen app I noticed that the code was circling around the drawing of the TextField over and over, function after function everything pointed to an error in the drawing of the object on the screen.
The following code illustrates the issue. The TextField works perfectly when you enter characters and delete them until you get to the first one. The it freezes.
import SwiftUI
struct ContentView: View {
#State var sensorNumber: String = ""
var body: some View {
TextField("WC0.000.000.000", text: $sensorNumber)
.padding(.all, 5.0)
.font(Font.custom("Helvetica", size:40.0))
.minimumScaleFactor(0.90)
}
}
The problem seems to be related to the interaction of the Custom Font. Obviously, my application is using custom fonts but here I just wanted to simplify the code.
This code does not fail if you don't use a custom font or if you don't specify a minimumScaleFactor. I have found a workaround that is not very elegant but it works until Apple fixes this bug:
import SwiftUI
struct ContentView: View {
#State var sensorNumber: String = ""
var body: some View {
TextField("WC0.000.000.000", text: $sensorNumber)
.padding(.all, 5.0)
.font(Font.custom("Helvetica", size:40.0))
.minimumScaleFactor(sensorNumber.count < 2 ? 1.0 : 0.90)
}
}
I am submitting a radar to Apple but looking for a better solution for the problem here.