web-dev-qa-db-fra.com

Aligner deux vues de texte SwiftUI dans HStack avec un alignement correct

J'ai une vue de liste simple qui contient deux lignes.

Chaque ligne contient deux vues de texte. Afficher un et afficher deux.

Je voudrais aligner la dernière étiquette (Voir deux) dans chaque ligne afin que les étiquettes de nom soient alignées en tête et continuent à être alignées quelle que soit la taille de la police.

La première étiquette (Afficher une) doit également être alignée au début.

J'ai essayé de définir une largeur d'image minimale sur la première étiquette (View One) mais cela ne fonctionne pas. Il semble également impossible de définir la largeur minimale et également d'obtenir une vue de texte à aligner en tête dans View One.

Des idées? C'est assez simple dans UIKit.

List View

6
Edward

Voici trois options pour le faire statiquement.

struct ContentView: View {
    @State private var width: CGFloat? = 100

    var body: some View {
        List {
            HStack {
                Text("1. ")
                    .frame(width: width, alignment: .leading)
                    .lineLimit(1)
                    .background(Color.blue)
                // Option 1
                Text("John Smith")
                    .multilineTextAlignment(.leading)
                    //.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
                    .background(Color.green)
            }
            HStack {
                Text("20. ")
                    .frame(width: width, alignment: .leading)
                    .lineLimit(1)
                    .background(Color.blue)
                // Option 2 (works mostly like option 1)
                Text("Jane Done")
                    .background(Color.green)
                Spacer()
            }
            HStack {
                Text("2000. ")
                    .frame(width: width, alignment: .leading)
                    .lineLimit(1)
                    .background(Color.blue)
                // Option 3 - takes all the rest space to the right
                Text("Jax Dax")
                    .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
                    .background(Color.green)
            }
        }
    }
}

Voici à quoi cela ressemble: simulator1

Nous pouvons calculer la largeur sur la base de l'entrée longue comme suggéré dans cette réponse .

Le calcul dynamique de la largeur peut être fait de cette façon:

import SwiftUI
import Combine

struct WidthGetter: View {
    let widthChanged: PassthroughSubject<CGFloat, Never>
    var body: some View {
        GeometryReader { (g) -> Path in
            print("width: \(g.size.width), height: \(g.size.height)")
            self.widthChanged.send(g.frame(in: .global).width)
            return Path() // could be some other dummy view
        }
    }
}

struct ContentView: View {
    let event = PassthroughSubject<CGFloat, Never>()

    @State private var width: CGFloat?

    var body: some View {
        List {
            HStack {
                Text("1. ")
                    .frame(width: width, alignment: .leading)
                    .lineLimit(1)
                    .background(Color.blue)
                    .background(WidthGetter(widthChanged: event))

                // Option 1
                Text("John Smith")
                    .multilineTextAlignment(.leading)
                    //.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
                    .background(Color.green)
            }
            HStack {
                Text("20. ")
                    .frame(width: width, alignment: .leading)
                    .lineLimit(1)
                    .background(Color.blue)
                    .background(WidthGetter(widthChanged: event))
                // Option 2 (works mostly like option 1)
                Text("Jane Done")
                    .background(Color.green)
                Spacer()
            }
            HStack {
                Text("2000. ")
                    .frame(width: width, alignment: .leading)
                    .lineLimit(1)
                    .background(Color.blue)
                    .background(WidthGetter(widthChanged: event))
                // Option 3 - takes all the rest space to the right
                Text("Jax Dax")
                    .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
                    .background(Color.green)
            }
        }.onReceive(event) { (w) in
            print("event ", w)
            if w > (self.width ?? .zero) {
                self.width = w
            }
        }
    }
}

Le résultat ressemble à ceci: simulator2

1
Paul B

Vous pouvez définir une largeur fixe pour une vue numérique Text. Il rend ce composant Text avec une taille fixe.

image

HStack {
        Text(item.number)
            .multilineTextAlignment(.leading)
            .frame(width: 30)
        Text(item.name)
}

L'inconvénient de cette solution est que si vous avez un texte plus long, il sera encapsulé et se terminera par "...", mais dans ce cas, je pense que vous pouvez approximativement estimer la largeur qui sera suffisante.

1
kamwysoc
HStack {
            HStack {
                Spacer()
                Text("5.")
            }
            .frame(width: 40)

            Text("Jon Smith")
        }

Mais cela ne fonctionnera qu'avec une largeur fixe. .frame(minWidth: 40) remplira la vue entière à cause de Space()

.multilineTextAlignment(.leading) n'a aucun effet dans mes tests.

0
Stefan Wieland