Views compressed by other views in SwiftUI VStack

2020-08-09 10:39发布

问题:

In my SwiftUI application, I'm trying to implement a UI similar to this:

I've added the two rows for category 1 and category 2. The result looks like this:

NavigationView {
    VStack(alignment: .leading) {
        CategoryRow(...)
        CategoryRow(...)
        Spacer()
    }
    .navigationBarTitle(Text("Featured"))
}

Now, when added the view for the third category – an VStack with images – the following happens:

This happened, after I replaced Spacer(), with said VStack:

VStack(alignment: .leading) {
    Text("Rivers")
        .font(.headline)
    ForEach(self.categories["Rivers"]!.identified(by: \.self)) { landmark in
        landmark.image(forSize: 200)
    }
}

My CategoryRow is implemented as follows:

VStack(alignment: .leading) {
    Text(title)
        .font(.headline)
    ScrollView {
        HStack {
            ForEach(landmarks) { landmark in
                CategoryItem(landmark: landmark, isRounded: self.isRounded)
            }
        }
    }
}

Question

It seems that the views are compressed. I was not able to find any compression resistance or content hugging priority modifiers to fix this.
I also tried to use .fixedSize() and .frame(width:height:) on CategoryRow.

How can I prevent the compression of these views?


Update

I've tried embedding the whole outer stack view in a scroll view:

NavigationView {
    ScrollView { // also tried List
        VStack(alignment: .leading) {
            CategoryRow(...)
            CategoryRow(...)
            ForEach(...) { landmark in
                landmark.image(forSize: 200)
            }
        }
        .navigationBarTitle(Text("Featured"))
    }
}

...and the result is worse:

回答1:

You might prevent the views in VStack from being compressed by using

  .fixedSize(horizontal: false, vertical: true)

For example: I have the following VStack:

VStack(alignment: .leading){
        ForEach(group.items) {
            FeedCell(item: $0)
        }
    }

Which render compressed Text()

VStack with compressed elements

When I add .fixedSize(horizontal: false, vertical: true) it doesn't compress anymore

VStack(alignment: .leading){
        ForEach(group.items) {
            FeedCell(item: $0)
                .fixedSize(horizontal: false, vertical: true)
        }
    }

VStack doesn't compresss content



回答2:

You could try to add a layoutPriority()operator to your first VStack. This is what the documentation says about the method:

In a group of sibling views, raising a view’s layout priority encourages that view to shrink later when the group is shrunk and stretch sooner when the group is stretched.

So it's a bit like the content compression resistance priority in Autolayout. But the default value here is 0, so you just have to set it to 1 to get the desired effect, like this:

VStack(alignment: .leading) {
    CategoryRow(...)
    CategoryRow(...)
    Spacer()
}.layoutPriority(1)
VStack(alignment: .leading) {
    ...
}

Hope it works!



回答3:

It looks like is not enough space for all your views in VStack, and it compresses some of them. You can embed it into the ScrollView

NavigationView {
 ScrollView {
   VStack(alignment: .leading) {
      CategoryRow(...)
      CategoryRow(...)
      /// you images and so on
   }
  }
}


回答4:

I think your topmost view (in the NavigationView) needs to be a List, so that it is scrollable:

NavigationView {
            List {
                ...

Or use a ScrollView.

A stack automatically fits within a screen. If you want your content to exceed this, you would have used a ScrollView or a TableView etc i UIKit

EDIT:

Actually, a little Googling brought this result, which seems to be exactly what you are making: https://developer.apple.com/tutorials/swiftui/composing-complex-interfaces



标签: swift swiftui