SwiftUi scaling text differently on device - swiftui

I'm using the following code to display a large number on screen using SwiftUI:
return GeometryReader() { geometry in
Text(series.split(separator: ",")[self.calculator.pointsIndex])
.font(Font.system(size: round(geometry.size.height * 1.5),
weight: .light,
design: .rounded))
.minimumScaleFactor(0.2)
.scaledToFit()
.allowsTightening(true)
.background(Color.red.opacity(0.25))
}
On the simulator it looks like this:
On the device it looks like this:
I've been racking my head trying to work out why the number is so much smaller on device. Any ideas?

This round(geometry.size.height * UIScreen.main.scale * 1.2 gives different results on a device (and different devices) and simulator.
I prefer to use the following combination when need text scaled to available parent space
Text("any text here")
.font(.system(size: 1000))
.minimumScaleFactor(0.01)
.lineLimit(1)
so you can try the following modified your code
return GeometryReader { _ in // just to consume all available space
Text(series.split(separator: ",")[self.calculator.pointsIndex])
.font(.system(size: 1000, weight: .light, design: .rounded))
.minimumScaleFactor(0.01)
.lineLimit(1)
.background(Color.red.opacity(0.25))
}

Related

How to get toolbar separator in SwiftUI?

I would like to get the separator in SwiftUI, but I didn't find the way. This was screenshot from mail.app.
If your view elements are in a HStack (like your mail.app suggest) using Divider() will give you a vertical "separator".
Elsewhere Divider() will give you a horizontal "separator".
You can adjust its size, like this: Divider().frame(width: 123)
You can of course do more things with Dividers, such as set its thickness or height with different color:
HStack {
Divider().frame(width: 5, height: 50).background(Color.blue)
Image(systemName: "line.3.horizontal.decrease.circle")
Divider().frame(width: 10, height: 100).background(Color.pink)
Image(systemName: "envelope")
Divider().frame(width: 15, height: 150).background(Color.green)
}
Here is the right way of doing such thing, do not use Divider, because it has lots of issues. With Divider you cannot control the thickness, also it has issue with updating color, wired Xcode complain in console in some cases, also space issue, it takes more space than it needs. In general it does not worth to use it.
struct ContentView: View {
var body: some View {
HStack {
Group {
Image(systemName: "mail")
Capsule().fill(Color.secondary).frame(width: 2.0)
Image(systemName: "trash")
}
.frame(width: 25, height: 25)
}
}
}
One alternative solution that may be more useful in some cases (e.g if you want a customisable toolbar the accepted solution won't work):
ToolbarItem (placement: .primaryAction) {
HStack {
Divider()
}
}

SwiftUI Text unexpected padding bottom and top

I need precise control over the area taken by Text. I created the most basic program that shows unexpected top and bottom spacing being added to a text. Where is this extra padding coming from? How to get rid of it?
#main
struct myApp: App {
init() { }
var body: some Scene {
WindowGroup {
Text("80")
.font(.system(size: 30, weight: .bold, design: .default))
.background(Color.red)
}
}
}
Text seems to have default padding as seen here
You can get past that by adjusting the padding to a negative amount
Replace your code with this
Text("80")
.font(.system(size: 30, weight: .bold, design: .default))
.padding(.vertical, -6)
.background(Color.red)
Here is a solution if you want to make it dynamic
struct TestView: View {
var fontSize: CGFloat = 110
var paddingSize: CGFloat {
-(fontSize * 0.23)
}
var body: some View {
Text("80")
.font(.system(size: fontSize, weight: .bold, design: .default))
.padding(.vertical, paddingSize)
.background(Color.red)
Text("Hello")
}
}
So even with a large font size of 110 like in the picture you can render it how you like
You'll need to tweak the multiplier how you see fit
Turns out that the padding top and bottom is actually not there at all. In my example with numbers this looks like wasted space, but actually certain characters do need this room as can be seen on this picture:
Since I am only going to show numbers I have used the solution by #Sergio to correct for this overspace.

SwiftUI: How-to append view to ending of multiline text?

Current
I have something like the following:
Short text with badge:
It's done simple with HStack atm:
HStack {
Text("Lorem ipsum dolor sit amet.")
.font(.title2)
Text("foo")
.font(.system(size: 14, weight: .bold))
.foregroundColor(.white)
.padding(.horizontal, 4)
.padding(.vertical, 2)
.background(Color.red)
.cornerRadius(5)
}
My Problem is that the main text is multiline and if it wraps, it looks like this:
Larger multiline text with badge:
Goal
But my goal is that the foo badge is always displayed after the last word of the main text, which should look like this:
Goal: Solution like Text + Text:
In other words I want the same behaviour as if I would use the concatenating feature of SwiftUI's Text (Text() + Text()), but I can't use that because of the formatting of the badge. The formatting modifiers like background() will change the return type to View and then the + operator doesn't work anymore.
What is the most elegant solution to achieve my goal? I would prefer not using UIKit.
This below solution gives the result but, the badge will be at the end of the line.
If, it is static text, you can use offset(x: ) to achieve that manually.
ZStack(alignment: .bottomTrailing) {
Text("But my goal is that the foo badge is always displayed after the last word of the main text, which should look like this:")
.font(.title2)
Text("foo")
.font(.system(size: 14, weight: .bold))
.foregroundColor(.white)
.padding(.horizontal, 4)
.padding(.vertical, 2)
.background(Color.red)
.cornerRadius(5)
.alignmentGuide(.bottom) { d in d[.bottom] }
// .offset(x: 50)
}

How to have text in shapes in SwiftUI?

I want to add text (eg. Hi) in a shape (eg. Square) in SwiftUI and make them act as a single object.
It looks like there's no direct way to add text in shape in SwiftUI.
Here is what I consider to be a more comprehensive answer. This will work as of Xcode 11.5:
Text(question)
.fixedSize(horizontal: false, vertical: true)
.multilineTextAlignment(.center)
.padding()
.frame(width: 300, height: 200)
.background(Rectangle().fill(Color.white).shadow(radius: 3))
Notes:
fixedSize() will let the text wrap (since .lineLimit(nil) no longer is working). You can omit it if you simply want one line of text with ellipsis
multilineTextAlignment() allows you to center or align the text in any way
padding() gives the text more space to breathe within the Rectangle()
frame() sets the width and height of the Text() and hence, the Rectangle(), since it is the background of the Text()
background() sets the shape of the Text()'s background. I have added a fill color and a drop shadow here as well
The end result of this example is the text looks to appear within a cue card like shape!
Here is, IMO, most simple approach:
Generic schema
Text(_any_of_text_)
.background(_any_of_Shape)
eg:
Text("Hello, World!")
.background(Rectangle().stroke())
Text("Hello, World!")
.background(RoundedRectangle(cornerRadius: 4).stroke())
Using Swift built-in shapes such as Capsule(), RoundedRectangle() and etc. Then, you can apply .overlay to the shape. The overlay take in any view such as text.
Example:
var body: some View {
Capsule()
.fill(Color.blue)
.overlay(
Text("Hello World")
)
}
Outcome:
Text("Hi")
.frame(width: 40, height: 40, alignment: .center)
.background(Color.black)
.clipShape(Rectangle())
Create a new SwiftUI View and make use of a Z-Stack to create your goal.
struct YourCustomObject: View {
var body: some View {
ZStack {
Rectangle()
.fill(Color.secondary)
.frame(width: 200, height: 200)
Text("Your desired text")
.foregroundColor(.white)
}
}
}

SwiftUI full-screen image above safe areas

I am trying to make an image fill the screen (including the safe area under under the notch of the iPhone X series and near the app switcher bar).
import SwiftUI
struct ContentView : View {
var body: some View {
ZStack() {
Image("background")
.resizable()
.aspectRatio(UIImage(named: "background")!.size, contentMode: .fill)
Text("SwiftUI Example")
.font(.largeTitle)
.background(Color.black)
.foregroundColor(.white)
}
}
}
The above code produces the following result, which still has the white bars on the top and bottom. Is there a way to make the image truly fill the screen?
SwiftUI by default takes the safe areas into consideration. In order to get the desired result, you must inform SwiftUI that it can ignore the safe areas with the following statement appended to the last object:
.edgesIgnoringSafeArea(.all)
This means that the new code will be:
ZStack() {
Image("background")
.resizable()
.aspectRatio(UIImage(named: "background")!.size, contentMode: .fill)
Text("SwiftUI Example")
.font(.largeTitle)
.background(Color.black)
.foregroundColor(.white)
}.edgesIgnoringSafeArea(.all)