Get width of Text in SwiftUI - ios

how can I get the width of a Text component?
I want to make my Button that is under the Text, the same width as the Text itself.
VStack(alignment: .center, spacing: 20) {
Text("Finde heraus, was gerade in der Welt los ist.")
.font(.largeTitle).bold().lineLimit(3).multilineTextAlignment(.leading)
Button(action: {
}, label: {
Text("Account erstellen").bold()
.frame(minWidth: 0, maxWidth: .infinity)
.frame(height: 40).padding(.top, 0)
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(20)
})
}.padding([.leading, .trailing], 25)
Which is giving me this result, its pretty ugly in my opinion:
On the iPad the width between the text and the button is even bigger
How can I solve this issue.
Thanks In advance.

It seems there is a bug in the bold() attribute. Removing it caused the text to align as you are expecting. You can try filing a bug, or wait it out and see if it gets fixed over the course of the beta period.
Text("Finde heraus, was gerade in der Welt los ist.")
.font(.largeTitle)
.lineLimit(3)
.multilineTextAlignment(.leading)

Related

How to vertically align emoji with text in iOS using SwiftUI?

I have emoji inside Text view (SwiftUI) and it doesn't vertically align with the rest of the text.
Code I have:
var body: some View {
VStack {
Text("PUT THE BULLLS EYE 🎯 AS CLOSE AS YOU CAN TO THE")
.bold()
.kerning(2.0)
.multilineTextAlignment(.center)
.lineSpacing(4.0)
.font(.system(size: 13, weight: .medium, design: .default))
Text("89")
HStack {
Text("1")
Slider(value: Binding.constant(50), in: 1.0...100.0)
Text("100")
}
Button(action: {}) {
Text("Hit Me!")
}
}
Notice in the screenshot target emoji 🎯 sits below the text and I want to align with the rest of the text in the same line. Any ideas?
You can use + to attach Text components. Then, you can change the baseline of one of the elements:
Group {
Text("PUT THE BULLLS EYE ").bold().kerning(2.0)
+ Text("🎯").baselineOffset(3) + Text(" AS CLOSE AS YOU CAN TO THE").bold().kerning(2.0)
}
.multilineTextAlignment(.center)
.lineSpacing(4.0)
.font(.system(size: 13, weight: .medium, design: .default))
The version I have above is fragile since it depends on a magic number (3) for the current font size, but you could do some work to calculate what it would be for other sizes.

How to limit width of Text in SwiftUI

I was trying to make a speech bubble like so:
Text("Hello my name is Johnny Miller and I am new here")
.foregroundColor(.white)
.padding()
.background(.blue)
.cornerRadius(25)
However I thought the speech bubble looked way wider than it needed to be. Therefore I tried to limit how far out the bubble can stretch before it goes to a new line. The easiest way which came to mind was this:
Text("Hello my name is Johnny Miller and I am new here")
.foregroundColor(.white)
.padding()
.background(.blue)
.cornerRadius(25)
.frame(maxWidth: 300) // << Limits how wide it can stretch
This worked for long messages but when the text was small such as "Hello," the frame would stay at 300pts and refused to resize to its ideal width.
I tried using .fixedSize() but this would cause truncation when the text was long.
I couldn't find a way to cap the width of the text and still have it be its ideal size. If someone could propose a solution I would be extremely grateful.
In short: The text frame should never cross 300pts in width but it can be as tall as it wants.
Thanks in advance!
Edit
These are the things I've tried so far:
Text("Hello")
.foregroundColor(.white)
.padding()
.background(.blue)
.cornerRadius(25)
.frame(maxWidth: 300)
.lineLimit(nil)
which causes the "Hello" bubble to have a frame of 300 (I've provided an image above)
and I've tried:
Text("Hello my name is Johnny Miller and I am new here")
.foregroundColor(.white)
.padding()
.background(.blue)
.cornerRadius(25)
.frame(maxWidth: 300)
.lineLimit(nil)
.fixedSize()
which gave me:

Add horizontal padding to TextEditor but prevent it from shifting scrollbar inside as a result

I'm using a TextEditor that I'd like to include horizontal padding for, so that the text doesn't stick to either edge. However, the problem is if I include it, and the text within is scrollable, then the scrollbar is not positioned to the far-right, but has instead been moved inside by the padding amount.
TextEditor(text: $text)
.background(Color.white)
.foregroundColor(Color.black)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.customFont(.body)
.lineSpacing(8)
.padding(.leading)
.padding(.trailing)
You added padding to external frame, but need to indent internal text container. The possible solution (as TextEditor is actually UITextView) to use appearance. So the solution would be to add the following in parent view of TextEditor
init() {
UITextView.appearance().textContainerInset =
UIEdgeInsets(top: 0, left: 12, bottom: 0, right: 12) // << !!
}
// ... other code
TextEditor(text: $text)
.background(Color.white)
.foregroundColor(Color.black)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.customFont(.body)
.lineSpacing(8)
Tested with Xcode 12 / iOS 14

SwiftUI how to add an Underline to a Text View?

Is there a way to modify a Text view to have an underline? For example like this text below:
yÍŸoÍŸuÍŸrÍŸ tÍŸeÍŸxÍŸtÍŸ
Text(Constants.chooseText)
.font(Font.system(size: 26))
.foregroundColor(Color.white)
.padding(.bottom, 80)
Add the underline modifier, on the Text View
Text("Hello, world!")
.underline()
UPDATE adding underline() as the first modifier solved the issue.
Text(Constants.chooseText)
.underline()
.font(Font.system(size: 26))
.foregroundColor(Color.white)
.padding(.bottom, 80)
You may use below like:
Text("Forget User ID")
.underline(true, color: .gray)
iOS 16
You can set background and in bg you can set height, offset and color of underline.
Sample Code:
Text("Gurjinder Singh")
.font(.largeTitle)
.fontWeight(.heavy)
.background(
Color.accentColor
.frame(height: 6) // underline's height
.offset(y: 24) // underline's y pos
)
Output

SwiftUI text-alignment

Among the many properties of the Text view, I couldn't find any related to text alignment. I've seen in a demo that it automatically handles RTL, and when placing stuff using View's body, it always centers it automatically.
Is there some concept that I'm missing about layout system in SwiftUI and if not, how can I set the text alignment properties to the Text?
You can do this via the modifier .multilineTextAlignment(.center).
Text("CENTER")
.multilineTextAlignment(.center)
Apple Documentation
From SwiftUI beta 3 forward, you can center a text view with the frame modifier:
Text("Centered")
.frame(maxWidth: .infinity, alignment: .center)
Was trying to understand this myself as other answers here mention Text.multilineTextAlignment(_:) / VStack(alignment:) / frame(width:alignment:) but each solution solves a specific problem. Eventually it depends on the UI requirement and a combination of these.
VStack(alignment:)
The alignment here is for the inner views in respective to one another.
So specifying .leading would associate all inner views to have their leading aligned with one another.
VStack(alignment: .leading, spacing: 6) {
Text("Lorem ipsum dolor")
.background(Color.gray.opacity(0.2))
Text("sit amet")
.background(Color.gray.opacity(0.2))
}
.background(Color.gray.opacity(0.1))
.frame
In frame(width:alignment:) or frame(maxWidth:alignment:), the alignment is for the contents within the given width.
VStack(alignment: .leading, spacing: 6) {
Text("Lorem ipsum dolor")
.background(Color.gray.opacity(0.2))
Text("sit amet")
.background(Color.gray.opacity(0.2))
}
.frame(width: 380, alignment: .trailing)
.background(Color.gray.opacity(0.1))
The inners views are leading aligned respective to one another but the views themselves are trailing aligned respective to the VStack.
.multilineTextAlignment
This specifies the alignment of the text inside and can be seen best when there are multiple lines otherwise without a defined frame(width:alignment), the width is automatically adjusted and gets affected by the default alignments.
VStack(alignment: .trailing, spacing: 6) {
Text("0. automatic frame\n+ view at parent's specified alignment\n+ multilineTA not set by default at leading")
.background(Color.gray.opacity(0.2))
Text("1. automatic frame\n+ view at parent's specified alignment\n+ multilineTA set to center")
.multilineTextAlignment(.center)
.background(Color.gray.opacity(0.2))
Text("2. automatic frame\n+ view at parent's specified alignment\n+ multilineTA set to trailing")
.multilineTextAlignment(.trailing)
.background(Color.gray.opacity(0.2))
}
.frame(width: 380, alignment: .trailing)
.background(Color.gray.opacity(0.1))
Tests with combinations:
VStack(alignment: .trailing, spacing: 6) {
Text("1. automatic frame, at parent's alignment")
.background(Color.gray.opacity(0.2))
Text("2. given full width & leading alignment\n+ multilineTA at default leading")
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color.gray.opacity(0.2))
Text("3. given full width & center alignment\n+ multilineTA at default leading")
.frame(maxWidth: .infinity, alignment: .center)
.background(Color.gray.opacity(0.2))
Text("4. given full width & center alignment\n+ multilineTA set to center")
.multilineTextAlignment(.center)
.frame(maxWidth: .infinity, alignment: .center)
.background(Color.gray.opacity(0.2))
Text("5. given full width & center alignment\n+ multilineTA set to trailing")
.multilineTextAlignment(.trailing)
.frame(maxWidth: .infinity, alignment: .center)
.background(Color.gray.opacity(0.2))
Text("6. given full width but no alignment\n+ multilineTA at default leading\n+ leading is based on content, looks odd sometimes as seen here")
.frame(maxWidth: .infinity)
.background(Color.gray.opacity(0.2))
}
.frame(width: 380)
.background(Color.gray.opacity(0.1))
I've actually run into the problem where I had to align text on a single line. What I've found to work is this:
Text("some text")
.frame(alignment: .leading)
If you combine this with the frame width parameter you can get some nice text block formatting for labels and such.
I guess SwiftUI wants us to use wrappers like stacks for such things.
So instead of writing something like Text("Hello World").aligned(.leading), the following is encouraged:
VStack(alignment: .leading) {
Text("Hello World")
}
We need to align the Text and not the Stack it's in. So calling multilineTextAlignment(.center) and setting the line limits I can be able to see the texts aligned to center. I don't know why I have to set the line limits, I thought it would expand if you have a large text.
Text("blahblah")
.font(.headline)
.multilineTextAlignment(.center)
.lineLimit(50)
If you would like to keep constant width for the Text, the ".multilineTextAlignment(.leading)" won't take any effect until there is only one line of text.
This is the solution that worked for me:
struct LeftAligned: ViewModifier {
func body(content: Content) -> some View {
HStack {
content
Spacer()
}
}
}
extension View {
func leftAligned() -> some View {
return self.modifier(LeftAligned())
}
}
Usage:
Text("Hello").leftAligned().frame(width: 300)
I had the same problem.
i used this for fixing that.
Text("Test")
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
You can set alignment for Vertical stackView as leading. Like below
VStack(alignment: .leading) {
Text("Turtle Rock")
.font(.title)
Text("Joshua Tree National Park")
.font(.subheadline)
}
I'd like to use Spacer() view to aligning text block.
This example show text at the trailing side:
HStack{
Spacer()
Text("Wishlist")
}
You can always add a frame to the Text field and can modify it's alignment.
Text("Hello World!")
.frame(alignment : .topLeading)
Since, this is just for a couple of lines - this is better than using alignment on either of the Stacks
Not sure if this is the answer you are looking for but I have experienced that SwiftUI automatically switches to RTL for languages like Arabic, you don't need to explicitly specify that like in UIKit.
You can use this property of SwiftUI
multilineTextAlignment
for TextAlignment.
VStack {
Text("Your Text")
.multilineTextAlignment(.center)
}

Resources