I have an chat example, with 3 texts, name, text and hour. I'd like to alignment the first two texts to left and the other one to right.
var body: some View {
HStack {
if self.cloudPosition == .dx {Spacer(minLength: 20)}
VStack (alignment: .leading) {
Text("\(self.text.name)")
.font(.system(size: 15))
.foregroundColor(Self.getColor(index: self.text.colorIndex))
.padding(EdgeInsets(top: 3, leading: 15, bottom: 3, trailing: 10))
Text("\(self.text.text)")
.font(.system(size: 15))
.padding(EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 8))
HStack {
Spacer() //I remove this in example 3
Text("\(self.text.date, formatter: Self.timeFormat) ")
.font(.system(size: 9))
.foregroundColor(.gray)
.padding(3)
}
}
.background(self.cloudColor)
.cornerRadius(10)
.padding(10)
if self.cloudPosition == .sx {Spacer(minLength: 20)}
}
}
The enum:
enum CloudPosition {
case dx,sx
}
if the text is log, it's ok EXAMPLE 1:
but if it's short EXAMPLE 2:
if I remove Spacer() EXAMPLE 3, the chat is ok, but the hour it's not on the right:
Any idea? thanks
To align a text view along the horizontal axis, you need to use . frame() modifier with maxWidth set to . infinity and alignment to the alignment you want. In this example, we align our text to the traling edge with .
SwiftUI gives us a number of valuable ways of controlling the way views are aligned, and I want to walk you through each of them so you can see them in action. You can then use offset(x:y:) to move the text around inside that frame.
Right-click the text box for which you want to set vertical alignment. On the shortcut menu, click Format Text Box. In the Format Text Box dialog box, click the Text Box tab. In the Vertical alignment box, select Top, Middle, or Bottom.
Select the text you want to Align And then press Control(ctrl)+I.
One of possibilities ... check it with Playground
There is not to much to explain, the "trick" is done with proper combination of different stack, alignment, .fixedSize(horizontal:, vertical:)
, Color.clear.frame(height:0)
replacement of Spacer()
. All together makes this "automatic" message view expansion, based on message text.
import SwiftUI
import PlaygroundSupport
struct ContentView: View {
var body: some View {
VStack {
HStack {
Spacer()
HStack {
VStack (alignment: .leading) {
Text("Lorem ipsum")
.font(.title)
.fixedSize()
Text("""
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
""")
.font(.system(size: 15))
.fixedSize(horizontal: false, vertical: true)
HStack {
Color.clear.frame(height: 0)
Text("22:13").fixedSize()
}
}
.padding()
.background(Color.yellow)
.cornerRadius(10)
.padding()
}
.scaledToFit()
}
.border(Color.red)
HStack {
Spacer()
HStack {
VStack (alignment: .leading) {
Text("Lorem ipsum")
.font(.title)
.fixedSize()
Text("?")
.font(.system(size: 15))
.fixedSize(horizontal: false, vertical: true)
HStack {
Color.clear.frame(height: 0)
Text("22:13").fixedSize()
}
}
.padding()
.background(Color.yellow)
.cornerRadius(10)
.padding()
}
.scaledToFit()
}
.border(Color.red)
HStack {
Spacer()
HStack {
VStack (alignment: .leading) {
Text("?")
.font(.title)
.fixedSize()
Text("Lorem ipsum")
.font(.system(size: 15))
.fixedSize(horizontal: false, vertical: true)
HStack {
Color.clear.frame(height: 0)
Text("22:13").fixedSize()
}
}
.padding()
.background(Color.yellow)
.cornerRadius(10)
.padding()
}
.scaledToFit()
}
.border(Color.red)
Spacer()
}
}
}
PlaygroundPage.current.setLiveView(ContentView())
RESULT:
THE SAME CODE IS REPEATED 3 TIMES, JUST BECAUSE I AM LAZY :-)
Finally you could use something like
struct Message<Header: View, Footer: View>: View {
let header: Header
let footer: Footer
let message: String
let color: Color
var body: some View {
HStack {
Spacer()
HStack {
VStack (alignment: .leading) {
header.fixedSize()
Text(message)
.fixedSize(horizontal: false, vertical: true)
HStack {
color.frame(height: 0)
footer.fixedSize()
}
}
.padding()
.background(color)
.cornerRadius(10)
.padding()
}
.scaledToFit()
}
}
}
or using @ViewBulder for header and footer
struct MessageBuilder<Header, Footer>: View where Header: View, Footer: View {
let header: () -> Header
let footer: () -> Footer
let message: String
let color: Color
init(@ViewBuilder header: @escaping () -> Header, @ViewBuilder footer: @escaping () -> Footer, message: String, color: Color) {
self.header = header
self.footer = footer
self.message = message
self.color = color
}
var body: some View {
HStack {
Spacer()
HStack {
VStack (alignment: .leading) {
header().fixedSize()
Text(message)
.fixedSize(horizontal: false, vertical: true)
HStack {
color.frame(height: 0)
footer().fixedSize()
}
}
.padding()
.background(color)
.cornerRadius(10)
.padding()
}
.scaledToFit()
}
}
}
and next use it in your code
struct ContentView: View {
var body: some View {
VStack {
Message(header: Text("Header").font(.title), footer: Text("22:13"), message: "long or short message text", color: Color.blue.opacity(0.2))
MessageBuilder(header: {
HStack {
Image(systemName: "square.and.arrow.down")
Text("Fred")
}
}, footer: {
Image(systemName: "clock")
}, message: "message text", color: Color.gray.opacity(0.2))
Spacer()
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With