如何使两个vstack垂直对齐?

huangapple go评论53阅读模式
英文:

How to make 2 vstacks align properly?

问题

我一直在尝试为一个应用程序设计一个好的界面,但是我遇到了一个问题。界面由一个水平堆叠 (HStack) 中的两个垂直堆叠 (VStack) 组成,问题出现在垂直堆叠中的文本视图 (TextView) 换行时。这会导致垂直堆叠下方的文本视图对齐不准确。是否有办法让它们始终对齐?以下是相关的代码。

这是单个垂直行的文件,问题出现在这里,我假设:

import SwiftUI

struct VerticalRowView: View {
    var whichOfTheFour: Int
    var movie: Movie
    @Binding var detailScreenShown: Bool
    
    var body: some View {
        HStack(alignment: .firstTextBaseline) {
            VStack(alignment: .leading, spacing: 25) {
                if whichOfTheFour == 1 {
                    Text("Title:")
                        .onTapGesture {
                            detailScreenShown = true
                        }
                        .foregroundColor(.cyan)
                    Text("Genre:")
                    Text("Released:")
                    Text("Origin:")
                    Text("Rated:")
                    Text("Runtime:")
                    Text("Plot:")
                }
                else if whichOfTheFour == 2 {
                    Text("Director:")
                    Text("Actor:")
                    Text("Writer:")
                    Text("Languages:")
                    Text("Box office:")
                }
                else if whichOfTheFour == 3 {
                    Text("Awards:")
                    Text("Metascore:")
                    Text("IMDB Rating:")
                    Text("IMDB Votes:")
                }
                else if whichOfTheFour == 4 {
                    Text("DVD:")
                    Text("Production:")
                }
            }
            VStack(alignment: .leading, spacing: 25) {
                if whichOfTheFour == 1 {
                    Text(movie.title ?? "Unknown")
                        .onTapGesture {
                            detailScreenShown = true
                        }
                        .foregroundColor(.cyan)
                    Text(movie.genre ?? "Unknown")
                    Text(movie.released ?? "Unknown")
                    Text(movie.country ?? "Unknown")
                    Text(movie.rated ?? "Unknown")
                    Text(movie.runtime ?? "Unknown")
                    Text(movie.plot ?? "Unknown")
                }
                else if whichOfTheFour == 2 {
                    Text(movie.director ?? "Unknown")
                    Text(movie.actor ?? "Unknown")
                    Text(movie.writer ?? "Unknown")
                    Text(movie.language ?? "Unknown")
                    Text(movie.boxOffice ?? "Unknown")
                }
                else if whichOfTheFour == 3 {
                    Text(movie.awards ?? "Unknown")
                    Text(movie.metascore ?? "Unknown")
                    Text(movie.imdbRating ?? "Unknown")
                    Text(movie.imdbVotes ?? "Unknown")
                }
                else if whichOfTheFour == 4 {
                    Text(movie.DVD ?? "Unknown")
                    Text(movie.production ?? "Unknown")
                }
            }
        }
    }
}

这是实现部分:

struct MovieDetailView: View {
    @Binding var result: Movie
    @Binding var detailScreenShown: Bool
    
    var body: some View {
        VStack() {
            CustomDivider()
            
            AsyncImage(url: URL(string: result.poster ?? ""))
            
            CustomDivider()
            
            VerticalRowView(whichOfTheFour: 1, movie: result, detailScreenShown: $detailScreenShown)

            CustomDivider()
            
            VerticalRowView(whichOfTheFour: 2, movie: result, detailScreenShown: $detailScreenShown)
            
            CustomDivider()
            
            VerticalRowView(whichOfTheFour: 3, movie: result, detailScreenShown: $detailScreenShown)
            
            CustomDivider()
            
            VerticalRowView(whichOfTheFour: 4, movie: result, detailScreenShown: $detailScreenShown)
        }
    }
}

我一直尝试解决这个问题已经超过6个小时了,我仍然是个新手,我相信解决方案非常简单。

英文:

i've been trying to make a good design for an app, however i've run into a problem. The design consists of 2 vstacks in 1 hstack and the problem occurs when a text view in a vstack wraps. this makes the text views that are under the vstack be unaligned. is there any way to make them always aligned? here is the relevant code.

this is file of a single vertical row, where the problem is located at, i presume

import SwiftUI
struct VerticalRowView: View {
var whichOfTheFour: Int
var movie: Movie
@Binding var detailScreenShown: Bool
var body: some View {
HStack(alignment: .firstTextBaseline) {
VStack(alignment: .leading, spacing: 25) {
if whichOfTheFour == 1 {
Text("Title:")
.onTapGesture {
detailScreenShown = true
}
.foregroundColor(.cyan)
Text("Genre:")
Text("Released:")
Text("Origin:")
Text("Rated:")
Text("Runtime:")
Text("Plot:")
}
else if whichOfTheFour == 2 {
Text("Director:")
Text("Actor:")
Text("Writer:")
Text("Languages:")
Text("Box office:")
}
else if whichOfTheFour == 3 {
Text("Awards:")
Text("Metascore:")
Text("IMDB Rating:")
Text("IMDB Votes:")
}
else if whichOfTheFour == 4 {
Text("DVD:")
Text("Production:")
}
}
VStack(alignment: .leading, spacing: 25) {
if whichOfTheFour == 1 {
Text(movie.title ?? "Unknown")
.onTapGesture {
detailScreenShown = true
}
.foregroundColor(.cyan)
Text(movie.genre ?? "Unknown")
Text(movie.released ?? "Unknown")
Text(movie.country ?? "Unknown")
Text(movie.rated ?? "Unknown")
Text(movie.runtime ?? "Unknown")
Text(movie.plot ?? "Unknown")
}
else if whichOfTheFour == 2 {
Text(movie.director ?? "Unknown")
Text(movie.actor ?? "Unknown")
Text(movie.writer ?? "Unknown")
Text(movie.language ?? "Unknown")
Text(movie.boxOffice ?? "Unknown")
}
else if whichOfTheFour == 3 {
Text(movie.awards ?? "Unknown")
Text(movie.metascore ?? "Unknown")
Text(movie.imdbRating ?? "Unknown")
Text(movie.imdbVotes ?? "Unknown")
}
else if whichOfTheFour == 4 {
Text(movie.DVD ?? "Unknown")
Text(movie.production ?? "Unknown")
}
}
}
}
}

this is the implementation

struct MovieDetailView: View {
@Binding var result: Movie
@Binding var detailScreenShown: Bool
var body: some View {
VStack() {
CustomDivider()
AsyncImage(url: URL(string: result.poster ?? ""))
CustomDivider()
VerticalRowView(whichOfTheFour: 1, movie: result, detailScreenShown: $detailScreenShown)
CustomDivider()
VerticalRowView(whichOfTheFour: 2, movie: result, detailScreenShown: $detailScreenShown)
CustomDivider()
VerticalRowView(whichOfTheFour: 3, movie: result, detailScreenShown: $detailScreenShown)
CustomDivider()
VerticalRowView(whichOfTheFour: 4, movie: result, detailScreenShown: $detailScreenShown)
}
}
}

ive been trying to solve this for over 6 hours, im still a newbie and i believe the solution is very silly.

答案1

得分: 0

按我所说,我建议使用表格(Table) - 它完全符合你的用例,但如果你不得不在没有表格的情况下复制相同的行为,那么我会这样做:

首先,不要使用两个VStack,而是使用一个。在其中,将每一行表示为HStack,使用GeometryReader来确保左列和右列对齐。

像这样:

首先,是行视图,包括标题和可选值,如果没有值,我们将其解析为“未知”:

struct MovieRowView: View {
    
    let title: String
    let value: String?
    
    var body: some View {
        GeometryReader { metrics in
            HStack {
                Text("\(title):")
                    .frame(
                        width: metrics.size.width * 0.4,
                        alignment: .topTrailing
                    )
                Text(value ?? "Unknown")
                    .frame(
                        width: metrics.size.width * 0.6,
                        alignment: .topLeading
                    )
            }
        }
        .frame(maxWidth: .infinity)
    }
}

正如你所看到的,GeometryReader用于确保每一行在左列和右列之间具有完全相同的分隔。此外,我们可以将左列对齐到“trailing”边缘,右列对齐到“leading”边缘,使它们更加接近。当然,你可以根据需要更改任何比例/对齐方式。

接下来,让我们将所有行放入VStack

struct MovieView: View {
    
    // ...
    
    var body: some View {
        VStack {
            MovieRowView(title: "Title", value: movie.title)
                .onTapGesture {
                    detailScreenShown = true
                }
                .foregroundColor(.cyan)
            MovieRowView(title: "Genre", value: movie.genre)
            MovieRowView(title: "Released", value: movie.released)
            // 等等
        }
    }
}

希望这对你有所帮助。

英文:

As I said, I recommend using Table - it fits your use case like a glove, but if you have to replicate the same behavior without a Table, then I would do this:

  • First of all, instead of having 2 VStacks, have one
  • And inside it, express each row as HStack, using the GeometryReader to ensure that all left and right columns align.

Something like this:

First, the row view, with title and optional value, which we will resolve to Unknown if it has no value:

struct MovieRowView: View {
let title: String
let value: String?
var body: some View {
GeometryReader { metrics in
HStack {
Text("\(title):")
.frame(
width: metrics.size.width * 0.4,
alignment: .topTrailing
)
Text(value ?? "Unknown")
.frame(
width: metrics.size.width * 0.6,
alignment: .topLeading
)
}
}
.frame(maxWidth: .infinity)
}
}

As you see, the GeometryReader is used to ensure that every row will have exactly the same split between left and right column. In addition, we can align left column to the trailing edge, and right column to leading edge, so they are closer to each other. You can change any of the proportions / alignment based on your needs of course.

Next, lets put all the rows into VStack:

struct MovieView: View {
// ...
var body: some View {
VStack {
MovieRowView(title: "Title", value: movie.title)
.onTapGesture {
detailScreenShown = true
}
.foregroundColor(.cyan)
MovieRowView(title: "Genre", value: movie.genre)
MovieRowView(title: "Released", value: movie.released)
// etc
}
}
}

huangapple
  • 本文由 发表于 2023年2月9日 01:38:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/75389700.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定