I noticed that a Text with .italic() clips letters:
Setting frame size doesn't help:
.paddings() doesn't help either. kerning(5) I don't want to use as it fixes the problem partially, at the right edge only, but it adds unwanted letter spacing.
struct ItalicTest: View {
var body: some View {
Text("F")
.font(Font.system(size: 60))
.italic()
.fontWeight(.black)
.frame(width: 60, height: 60)
.background(Color.red)
}
}
I'd like to prevent clipping. Do you know a solution using pure SwiftUI?
I know this is an old question, but I just had the same issue and found a propper solution.
You will have to add padding to your text and ask swiftui to collapse the padding and text before rendering it.
struct ItalicTest: View {
var body: some View {
Text("F")
.font(Font.system(size: 60))
.italic()
.fontWeight(.black)
.padding(.horizontal) // <-- add padding
.drawingGroup() // collapse the view and render together
}
}
Related
I am still a beginner in swiftUI.
Adding code and screenshot which will have explain my problem better. In the below screenshot, how can I align 'E' of first line with 'T' of 2nd line. I want both 'Text' elements to have same leading space i.e. both should start from the same position from left.
I have seen cases where people are using just one Text element and '\n' to move text to the next line and that aligns the text, but in my case I will be having more elements such as TextField and some more Text elements below these 2 texts hence I can't use the '\n' idea.
Code:
struct TestData: View {
var body: some View {
ZStack {
Image("backgroundImage").resizable().edgesIgnoringSafeArea(.all).scaledToFill()
VStack(alignment: .leading, spacing: 10) {
Text("Enter your Data")
.font(.largeTitle).bold()
.frame(width: UIScreen.main.bounds.width-50, height: 33.0)
Text("This is a very very long text to wrap on the next line. This text is of 2 lines.")
.font(.callout)
.frame(width: UIScreen.main.bounds.width-50, height: 80.0)
.foregroundColor(.gray)
.lineLimit(nil)
HStack {
// Contains image and textfield. Data will be entered in textfield.
}
// Move Text and Button elements.
}.offset(x: -10, y: -100)
}
}
}
struct TestData_Previews: PreviewProvider {
static var previews: some View {
TestData()
}
}
Screenshot:
In general, don't set fixed frames; SwiftUI tends to work better when you let the layout engine do its thing. Using maxWidth/maxHeight and minWidth/minHeight can be useful for giving clues to the layout engine about what you want.
Similarly with offset - This moves things around but doesn't change their layout bounding box, so you can end up with overlapping elements (which is fine if that is what you want).
For your layout, you can simply remove the frame and offset and use some padding to shift everything in from the leading edge:
VStack(alignment: .leading, spacing: 10) {
Text("Enter your Data").font(.largeTitle)
.bold()
Text("This is a very very long text to wrap on the next line. This text is of 2 lines.").font(.callout)
.foregroundColor(.gray)
.lineLimit(nil)
HStack {
// Contains image and textfield. Data will be entered in textfield.
}
}.padding(.leading,50)
When putting Text() views that have enough text to cause it to wrap, one after the other, they don't have the same alignment / padding unless they have a similar word structure.
I would like to both have a solution to this problem that allows for every Text view to have the same alignment and padding, as well as understand the SwiftUI Magic that I am apparently trying to fight.
I believe it has to do with the default "auto centering" alignment behavior of swiftUI but not sure why sentences of similar length don't appear with the same alignment / padding. And when I have tried to apply a group to the text views and apply collective padding or multiLineAlignment etc it doesn't seem to change the output.
struct TutorialView: View {
var body: some View {
VStack {
Text("About This App.")
.padding([.top, .bottom] , 20)
.font(.system(size: 30))
Text("This example text is meant to be long enough to wrap because when it is, then the alignment aint what we thought it would be...")
Text("This is meant to wrap and it will look different than the text above. even though it wraps too")
Text("It isn't always clear which will appear to have padding and which will hug the wall")
Text("Literally all of these are differnt...")
Spacer()
}
}
}
Approach
You are right, default alignment is center
Add different background colors and you will understand how they are aligned.
Code
I have modified your code just to demonstrate the layout
struct ContentView: View {
var body: some View {
VStack {
Text("About This App.")
.padding([.top, .bottom] , 20)
.font(.system(size: 30))
.background(.orange)
VStack(alignment: .leading) {
Text("This example text is meant to be long enough to wrap because when it is, then the alignment aint what we thought it would be...")
.background(.green)
Text("This is meant to wrap and it will look different than the text above. even though it wraps too")
.background(.blue)
Text("It isn't always clear which will appear to have padding and which will hug the wall")
.background(.red)
Text("Literally all of these are differnt...")
.background(.yellow)
Spacer()
}
}
}
}
Note:
There are times .fixedSize(horizontal:, vertical:) would come in handy (not used in this example)
I’m new to SwiftUI and I’m making a widget. The default code included a text view which is both x-centered and y-centered in the super view(which I don’t know if there’s the same concept in SwiftUI).
This is my code:
struct WidgetEntryView : View {
var entry: Provider.Entry
var body: some View {
VStack(alignment: .leading){
Text(Date(), style: .time)
.padding(.leading)
}
}
}
I want to align the view’s leading to the super view’s leading instead of positioning the text in the center. So I tried to add a padding to the text’s leading, strangely, it seems that the text view is not a direct subview of the superview, it is positioned in a invisible centered view instead, since I end up with having a text view that slightly deviate the center, looks like this:
This is what I want:
I tried the position method and it was the only one worked, not perfectly though, since it is based on the center point.
I’m looking for a better solution.
Here is a Playground that gives an example of a view that looks like your picture:
import UIKit
import SwiftUI
import PlaygroundSupport
struct ViewWithText : View {
var body : some View {
HStack {
Text("Here")
.background(Color.yellow)
}
.frame(width: 320, height: 480, alignment: .leading)
.background(Color.gray)
}
}
let hostingController = UIHostingController(rootView: ViewWithText())
PlaygroundSupport.PlaygroundPage.current.liveView = hostingController
With simple padding and background you can see why it does not work for you as you want.
VStack(alignment: .leading){
Text(Date(), style: .time)
.padding(.leading)
.background(.yellow)
}
.padding()
.background(Color.gray)
The base size of the VStack is the same as the size of it's children. Solution would be to increase the size of the VStack or the size of the Text
In widget I suggest to set the parent (V)Stack's size (maxWidth) as big as it can get (.infinity) :
VStack(alignment: .leading){
Text(Date(), style: .time)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
Btw setting padding(.leading) is causing the "text view that slightly deviate the center" as this added a base padding to the left size of the Text. It just increases the width of the text, but still not fully to the available width.
I've been messing with this for quite some time now and cannot for the life of me figure out where this little white line is coming from. I tried setting .padding(0) and using a .frame() but nothing seems to work to remove it. If I remove the Form and use something like just a list, it goes away but I like the Inset look of Form. If I add the style for the inset look on the list, the issue comes back.
var body: some View {
VStack {
Rectangle()
.foregroundColor(settings.accentColor)
.overlay(
Group {
Text("x").font(.system(size: 50, weight: .heavy))
Text("xxxxxxxxx").font(.system(size: 36, weight: .regular))
}.foregroundColor(.white)
)
Form {
TextField("Test", text: $test)
}
}
}
Add spacing parameter to your VStack
VStack(spacing: 0) {
// ...
}
I have a HStack with multiple elements, particularly two Texts with different font sizes. I want both text to be aligned to the top of the view.
HStack(alignment: .top) {
Image(systemName: "cloud.drizzle.fill")
Text("14°")
.font(.largeTitle)
Text("86%")
.font(.callout)
Spacer()
}
However, the first (larger) Text is outputted below the other two:
Actually it's aligned correctly , add backgrounds to each Text and you will find that the frame of the Text is aligned correctly
but to solve the case that you are looking for , I did a hack for you , by doing some calculs
The result:
1) Alignement of the two Text
Put both of them in one HStack , with alignment: .firstTextBaseline
Then play on the second text , by adding a baselineOffset with (bigFont.capHeight - smallFont.capHeight)
You can learn more about fonts , but the main information that you need is this :
So your code will be :
HStack(alignment: .firstTextBaseline) {
Text("14°")
.font(Font(bigFont))
.background(Color.blue)
Text("86%")
.font(Font(smallFont))
.baselineOffset((bigFont.capHeight - smallFont.capHeight))
.background(Color.yellow)
Spacer()
}
2) Align the Image with the text :
by adding a padding which will be equal to bigFont.lineHeight-bigFont.ascender (go back to the picture on top , to see how I calculated it )
And the final code :
struct ContentView: View {
#State var pickerSelection = ""
let bigFont = UIFont.systemFont(ofSize: 50)
let smallFont = UIFont.systemFont(ofSize: 15)
var body: some View {
HStack(alignment:.top) {
Image(systemName: "cloud.drizzle.fill")
.background(Color.red)
.padding(.top, bigFont.lineHeight-bigFont.ascender)
HStack(alignment: .firstTextBaseline) {
Text("14°")
.font(Font(bigFont))
.background(Color.blue)
Text("86%")
.font(Font(smallFont))
.baselineOffset((bigFont.capHeight - smallFont.capHeight))
.background(Color.yellow)
Spacer()
}
}
}
}
PS : I added backgrounds to show you the real frames of each view
Currently the texts are aligned by top. but the large text has ascent height that is larger than small text. so the align is not top of text.
Unfortunately, SwiftUI doesn't support the alignment of top of text.
But you can align the top of text manually like as following code.
HStack(alignment: .top) {
Image(systemName: "cloud.drizzle.fill")
Text("14°")
.font(.largeTitle).padding(.top, -5.0)
Text("86%")
.font(.callout)
Spacer()
}