Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI different alignment text in VStack

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:

enter image description here

but if it's short EXAMPLE 2:

enter image description here

if I remove Spacer() EXAMPLE 3, the chat is ok, but the hour it's not on the right:

enter image description here

Any idea? thanks

like image 619
Simone Pistecchia Avatar asked Jan 30 '20 20:01

Simone Pistecchia


People also ask

How do I align text horizontally in SwiftUI?

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 .

How do I move text in SwiftUI?

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.

How do you change the alignment of a text box?

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.

How do I align text in Xcode?

Select the text you want to Align And then press Control(ctrl)+I.


1 Answers

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:

enter image description here

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()
        }
    }
}
like image 57
user3441734 Avatar answered Sep 23 '22 22:09

user3441734