Comparing two Fonts (SwiftUI) - swiftui

I have two custom Font variables using a custom font. The catch is that that are both of the same font class and size.
/// Font: Oswald-Regular
/// Size: 16
static var normalText: Font { Font.custom("Oswald-Regular", size: 16) }
/// Font: Oswald-Light
/// Size: 16
static var lightText: Font { Font.custom("Oswald-Regular", size: 16) }
The issue occurs when I call something like Font.normalText == Font.lightText. I am currently getting a result of True here. I would like to get a result of False from this call so I can apply different letter spacing, capitalization, etc.
How should I go about making sure this equals call returns False for two different instances of the same custom font?

The fonts are the same, they will always be equaled.
If you need to compare them and get false, you could use an enum. In the example below the enum can be used to compare two different cases and will return false; when you want to use the fonts, however, it will require you to specify it by using the property .font.
The enum is not an extension of Font, you will have to use a different name. So, you cannot use the notation .font(.normalText) but rather .font(FontEnum.normalText.font).
struct FontView: View {
/// Font: Oswald-Regular
/// Size: 16
static var normalText: Font { Font.custom("Oswald-Regular", size: 16) }
/// Font: Oswald-Light
/// Size: 16
static var lightText: Font { Font.custom("Oswald-Regular", size: 16) }
var body: some View {
VStack {
Group {
Text("\(String(FontView.normalText == FontView.lightText))") // true
Text("\(String(FontEnum.normalText == FontEnum.lightText))") // false
Text("\(String(FontEnum.normalText.font == FontEnum.lightText.font))") // true
Text("Using the font")
.font(FontEnum.normalText.font)
}
.padding()
}
}
enum FontEnum {
case normalText, lightText
var font: Font {
switch self {
case .normalText:
return Font.custom("Oswald-Regular", size: 16)
case .lightText:
return Font.custom("Oswald-Regular", size: 16)
}
}
}
}

Related

SwiftUI - Change List row background colour programatically

I'm trying to change the background colour of a row in a list based on a value
I have an Int16 value stored in card.owned and I want to change the background if this value is above 0, otherwise use the normal background.
Previously with a table view I could change it with the cellForRowAtIndexPath method, but not sure how to do it with SwiftUI without changing every row
Currently I have
List {
ForEach(cards) { section in
let header: String = nameForSectionHeader(sectionID: section.id)
Section(header: Text(header)) {
ForEach(section) { card in
NavigationLink(destination: CardView(card: card)) {
VStack(alignment: .leading) {
if let name = card.name, let id = card.cardID {
Text("\(id) - \(name)")
}
if let set = card.set, let setName = set.name {
Text("Set: \(setName)")
}
if card.owned > 0 {
Text("Owned: \(card.owned)")
}
}
}
}
}
}
.listRowBackground(lightGreen)
}

SwiftUI - Ternary operator on padding modifier crashes program

I've got a ZStack in SwiftUI filled with some components delivered by a ForEach, as follows:
ForEach(0..<arr.count) { i in
ZStack {
...
}
// I use i later in this code
...
}
The program runs perfectly like this.
But I want to add padding to the ZStack only if i == 0, so I tried adding this modifier to the ZStack: .padding(.top, i == 0 ? 70 : 0)
When I try to build it with this modifier it fails, but doesn't even say "build failed." It takes about 5 minutes attempting to build (when it usually takes 5 seconds) then decides to crash. Can anyone explain why this is happening and how I can get this conditional padding without breaking my program?
Try this:
ForEach(0..<arr.count) { i in
ZStack {
...
}
.padding(.top, getPadding(i))
// I use i later in this code
...
}
func getPadding(_ i: Int) -> CGFloat {
if i == 0 {
return CGFloat(70)
}
return CGFloat(0)
}
func setPadding(_ statement: String) -> CGFloat {
if statement == " Put your statement " {
return CGFloat(your requirement padding)
} else {
return CGFloat("According to your requirement padding")
}

How to set the List Height when List is empty?

I got my data from API and put them in a list. My problem is that is it possible to set fixed height when the array in the list were all deleted? I use environment(.defaultMinListRowHeight, 80) but it didn't work.Please help. Thank you
func containedView() -> AnyView {
switch self.selectedIndex {
case 0:
return AnyView(
List(userNotifications1.userNotificationsArray) { userNotification in
UserNotificationCellView(userNotification: userNotification,userNotifications: self.userNotifications1)
}.environment(\.defaultMinListRowHeight, 80)
.environment(\.defaultMinListHeaderHeight, 10)
)
case 1:
return AnyView(
List {
ForEach(managerNotifications, id: \.id) { (managernotification) in
ManagerNotificationCellView(managerNotification : managernotification)
}.onDelete(perform: self.deleteManagerNotification)
}
)
default:
return AnyView(Text("22").padding(40))
}
when list has data, the cell's height are bigger
when list is empty,the cell's height was small
Make sure to set environment variable in correct place. Below tested as works with Xcode 11.2 / iOS 13.2.
List {
// ... list content here
}
.environment(\.defaultMinListRowHeight, 80) // << should be for List

Change default system font in SwiftUI

I'm trying to set a custom default font in my SwiftUI app. I tried several suggestions from this thread Set a default font for whole iOS app?.
However, none of those seem to work with SwiftUI. For example with this approach:
// Constants.swift
struct Fonts {
static var plex = "IBMPlexMono-Text"
}
// FontExtension.swift
extension UILabel {
var substituteFontName : String {
get { return self.font.fontName }
set { self.font = UIFont(name: Fonts.plex, size: 17)! }
}
}
// AppDelegate.swift in didFinishLaunchingWithOptions-function
UILabel.appearance().substituteFontName = Fonts.plex
When I start the app, the custom font appears for a split second and then changes back to the default font by Apple. Why does it change back to Apple's font and how can it be done permanently?
Is it maybe possible with an extension on Text-View?
You can have:
extension Font {
static let mediumFont = Font.custom("Sans-Regular", size: Font.TextStyle.subheadline.size, relativeTo: .caption)
static let mediumSmallFont = Font.custom("Sans-Regular", size: Font.TextStyle.footnote.size, relativeTo: .caption)
static let smallFont = Font.custom("Sans-Regular", size: Font.TextStyle.caption.size, relativeTo: .caption)
static let verySmallFont = Font.custom("Sans-Regular", size: Font.TextStyle.caption2.size, relativeTo: .caption)
}
extension Font.TextStyle {
var size: CGFloat {
switch self {
case .largeTitle: return 60
case .title: return 48
case .title2: return 34
case .title3: return 24
case .headline, .body: return 18
case .subheadline, .callout: return 16
case .footnote: return 14
case .caption: return 12
case .caption2: return 10
#unknown default:
return 8
}
}
}
and use it like this:
Text("Edit Profile")
.font(.mediumSmallFont)
this is the closest I could find to have a self-contained swift file that will change the font everywhere. make sure to call Font.setup in the app delegate on launch:
//
// Font.swift
// Hockey
//
// Created by #yspreen on 11/11/22.
//
import SwiftUI
extension Font {
static var brand = Font
.custom("Some Font", size: UIFont.preferredFont(
forTextStyle: .body
).pointSize)
static func setUp() {
let appearance = UINavigationBar.appearance()
let largeTitle = UIFont.preferredFont(
forTextStyle: .largeTitle
).pointSize
let body = UIFont.preferredFont(
forTextStyle: .body
).pointSize
let caption1 = UIFont.preferredFont(
forTextStyle: .caption1
).pointSize
print(UIFont.preferredFont(forTextStyle: .largeTitle))
appearance.largeTitleTextAttributes = [
.font : UIFont(
name: "SomeFont-Bold", size: largeTitle
)!
]
appearance.titleTextAttributes = [
.font : UIFont(
name: "SomeFont-Medium", size: body
)!
]
UITabBarItem.appearance().setTitleTextAttributes([.font: UIFont(name: "SomeFont-Regular", size: caption1)!], for: .normal)
UITabBarItem.appearance().setTitleTextAttributes([.font: UIFont(name: "SomeFont-Regular", size: caption1)!], for: .selected)
}
}
func Text(_ content: any StringProtocol) -> SwiftUI.Text {
.init(content).font(.brand)
}
func TextField(_ titleKey: LocalizedStringKey, text: Binding<String>, axis: Axis = .horizontal) -> some View {
SwiftUI.TextField(titleKey, text: text, axis: axis).font(.brand)
}
You can use a custom font like this:
Font.custom("Font-Family-Name", size: fontSize)
Example:
Text("Testing")
.font(Font.custom("Font-Family-Name", size: 16))
For using the font anywhere in the app, create a structure with as follows. Be sure to import SwiftUI in the file that will contain the font structure as:
import SwiftUI
struct AppFont {
static func commonFont(fontSize: CGFloat) -> Font {
return Font.custom("Font-Family-Name", size: fontSize)
}
}
Now you can use them anywhere in the app like this:
Text("Testing")
.font(AppFont.commonFont(fontSize: 16))

Check state of Option-Key in SwiftUI (macOS)

I'm looking for a way to check the state of the option-key in SwiftUI on macOS.
I.e. depending on whether the option key is pressed or not I want to perform different actions in the .onTapGesture closure.
macOS-only SwiftUI has .modifiers modifier to specify EventModifiers, so your case is covered like in below example:
Rectangle()
.fill(Color.yellow)
.frame(width: 100, height: 40)
.gesture(TapGesture().modifiers(.option).onEnded {
print("Do anyting on OPTION+CLICK")
})
.onTapGesture {
print("Do anyting on CLICK")
}
While using the modifiers method on the gesture should probably be preferred, one can also actually test for the option key itself using CGEventSource in CoreGraphics:
import CoreGraphics
extension CGKeyCode
{
static let kVK_Option : CGKeyCode = 0x3A
static let kVK_RightOption: CGKeyCode = 0x3D
var isPressed: Bool {
CGEventSource.keyState(.combinedSessionState, key: self)
}
static var optionKeyPressed: Bool {
return Self.kVK_Option.isPressed || Self.kVK_RightOption.isPressed
}
}
This lets you detect the option key (or any other keys for that matter) in contexts where there isn't a modifier property or method.
The key codes in the extension can be renamed to be more Swifty, but those are the names that go way back to Classic MacOS's Toolbox and were defined in Inside Macintosh. I have a gist containing all the old key codes.
2022
.onTapGesture {
if NSEvent.modifierFlags.contains(.option) {
print("Option key Tap")
} else {
print("Tap")
}
}
.onDrag {
if NSEvent.modifierFlags.contains(.option) {
return NSItemProvider(object: "\(item.id)" as NSString)
}
return NSItemProvider()
}