SwiftUI视图位于中间而不是顶部

53

我正在尝试在SwiftUI中创建一个视图。在预览中,它看起来应该是对的,但是在我的iPhone上运行(或在实时预览中)它看起来是偏移的。

我尝试将padding设置为-150,但是然后TextField无法响应触摸。

VStack {
    Text("Name:")
        .padding(.bottom, 1)
    TextField($name)
        .padding(.horizontal, 25.0)
        .textFieldStyle(.roundedBorder)
        .frame(maxWidth: 500)
    Text("Image:")
        .padding(.top, 1)
    Image(uiImage: image!)
        .resizable(capInsets: EdgeInsets(), resizingMode: .stretch)
        .scaledToFit()
        .frame(width: 250, height: 250)
        .clipShape(RoundedRectangle(cornerRadius: 10))
        .padding(.top, 5)
    Button(action: {
        withAnimation {
            self.showImagePicker = true
        }
    }) {
        Text("Select Image")
            .color(.init(red: 20/255, green: 146/255, blue: 81/255))
    }
    Button(action: {
        let list = LSList( title: self.name,
                                           image: self.image!,
                                           id: 0)
        list.add()
        self.userData.listsData.append(list)
    }) {
        Text("Add List")
            .color(.white)
            .font(.system(size: 25))
            .bold()
            .padding(.horizontal, 7)
            .frame(height: 35)
            .background(Color.green)
            .clipShape(RoundedRectangle(cornerRadius: 3))
    }
    Spacer()
} .navigationBarTitle(Text("Add List"))

预览中的视图: The view in the preview

我的 iPhone 上的视图: The view on my iPhone


你的 VStack 是否被 NavigationView 包裹? - M Reza
1
@MoRezaFarahani 是的 - Shahar Melamed
6个回答

92

我曾经遇到同样的问题,但发现我的问题在于多次使用navigationView。

我以为每个视图都应该有NavigationView,但很明显,我们只需要将NavigationView放置在应用程序的主视图中,在通过NavigationView进入的其他所有视图中,都会自动获得返回选项,而不需要再次提及NavigationView。

因此,请检查您的代码中是否使用了多个NavigationView。

奇怪的是,即使在没有提及NavigationView的视图中,我们仍然可以指定navigationBarTitle,这是因为NavigationView位于父视图中。使用"displayMode: .inline",使导航区域尽可能简洁,这将节省屏幕空间。

另一件要做的事情就是使用Spacer()。如果您想让所有项目都在顶部,则只需将Spacer()放置在VStack中的最后一项,它将将所有项目向上推。

请参见以下示例:

VStack {
    // What you care about displaying
    Text("Something to Show 1")
    Text("Something to Show 2")
    Text("Something to Show 3")

    // This should be the last, put everything to the top
    Spacer()             
}
.navigationBarTitle(Text("The Title"), displayMode: .inline)

嗨,iSpain,我在我的代码中有一个navigationLink并且它正在工作,你能分享一下你的代码吗? - Guy Nir
哦,谢谢。我也遇到了一个子视图是导航视图的问题。我没有找到任何文档说你只应该在堆栈顶部使用导航视图,但看起来似乎是必需的。 - neils4fun
1
这应该是SwiftUI添加VStack(aligment: .leading) { Spacer() }的被接受答案,并将Spacer()添加为VStack中的最后一个元素。 - Juan Ricardo
谢谢@Juan Ricardo。我没有提到(alignment: .leading),因为它取决于开发人员想要对齐的内容,对齐到.center也可以是有效的解决方案,这取决于需求。 - Guy Nir
只是一点说明:有些情况下,您可以拥有多个导航栈。就像在UIKit中,有时您可能需要多个导航控制器视图一样。 - undefined

49

我遇到了类似的问题,我想要一个VStack使其内容在屏幕顶部对齐,并且只在父级中使用了NavigationView,但是VStack显示为居中。对我有用的解决方法是使用Spacer(),像这样:

    VStack(alignment: .leading, spacing: 10){
        HStack(alignment: .center, spacing: 5.0) {
            ...
        }
        Group{
            ...
        }
        Spacer() //<-- This solved my problem
   }

8
假设您的VStack被包裹在NavigationView中,这就是它在模拟器中无法正确渲染的原因。之所以在预览中显示正常是因为它没有显示导航栏(其中包括返回按钮),因为画布不知道此视图可能会被推送,但在运行时,导航栏添加了,同时您也使用了额外的NavigationView
要修复它,请从NavigationView中取消包装VStack,并从子视图中简单地删除此NavigationView

1
我试图从VStack中将其移除,但没有任何变化。我将堆栈的背景更改为蓝色,以查看其高度是否正确,结果如下:https://imgur.com/a/76vQIkG - Shahar Melamed
@Shahar,你的屏幕截图中导航栏问题已经解决了!它现在固定在顶部。现在可能是 VStack 出了问题。我会更新我的帖子。 - M Reza
@Shahar,请删除您添加的任何额外填充/偏移量。只需尝试您在问题中提供的代码即可。对我来说,它可以正常工作! - M Reza
如果您不想删除 NavigationView,则可以在 VStack 上设置 .navigationBarHidden(true) - nonamorando

0
  1. 为了使导航项在预览中正确显示(即使是子视图),您需要将View包装到NavigationView { }中,因为Canvas是一个空的干净环境,它不知道View可能被推入NavigationView中。
  2. 要在iPhone上修复它,请确保正确推送子视图。应该是NavigationButton(destination: AddList()) {}

RowView实现示例:

   NavigationButton(destination: CarDetail(car: car)) {
      HStack {
        VStack(alignment: .leading) {
          Text(car.name)
          Text(car.isAvailable ? "Is Available" : "Out of stock")
            .font(.subheadline)
            .foregroundColor(.secondary)
        }
      }
    }

它在 NavigationView { } 中,列表中的 NavigationButton 如下:NavigationButton(destination: AddList().environmentObject(self.userData)) { Text("Add List") } - Shahar Melamed

0

SwiftUI

iOS 15及更高版本

在您的VStackText(...)中添加.multilineTextAlignment(.leading)

经过验证和测试。


-3
 ScrollView(.vertical){
   VStack {
    Text("Name:")
        .padding(.bottom, 1)
    TextField($name)
        .padding(.horizontal, 25.0)
        .textFieldStyle(.roundedBorder)
        .frame(maxWidth: 500)
    Text("Image:")
        .padding(.top, 1)
    Image(uiImage: image!)
        .resizable(capInsets: EdgeInsets(), resizingMode: .stretch)
        .scaledToFit()
        .frame(width: 250, height: 250)
        .clipShape(RoundedRectangle(cornerRadius: 10))
        .padding(.top, 5)
    Button(action: {
        withAnimation {
            self.showImagePicker = true
        }
    }) {
        Text("Select Image")
            .color(.init(red: 20/255, green: 146/255, blue: 81/255))
    }
    Button(action: {
        let list = LSList( title: self.name,
                                           image: self.image!,
                                           id: 0)
        list.add()
        self.userData.listsData.append(list)
    }) {
        Text("Add List")
            .color(.white)
            .font(.system(size: 25))
            .bold()
            .padding(.horizontal, 7)
            .frame(height: 35)
            .background(Color.green)
            .clipShape(RoundedRectangle(cornerRadius: 3))
    }
    Spacer()
} .navigationBarTitle(Text("Add List"))
}

3
你能否详细解释并向发帖者说明你的代码为什么有效/应该有效? - Anth0
不提供上下文描述的答案,不要简单地从其他地方复制粘贴代码,需要对其进行解释。 - c-sharp-and-swiftui-devni

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接