Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VStack inside ScrollView bottom alignment in SwiftUI

Currently building a chat application and I need new messages to appear at the bottom of the screen. I also need to have messages aligned to the bottom. However, using VStack inside ScrollView features top alignment by default.

a busy swiftui

    ScrollView {
        VStack(alignment: .leading, spacing: 16) {
            Spacer()
            .frame(minWidth: 0, maxWidth: .infinity, minHeight:0, maxHeight: .infinity, alignment: Alignment.topLeading)
            ForEach(notList, id: \.self) { not in
                NotRow(not: not)
                    
            }
            
        }
        .padding()
        .frame(minWidth: 0, maxWidth: .infinity, minHeight:0, alignment: Alignment.topLeading)
        
    }

What should I do to fix this?

like image 840
Hekes Pekes Avatar asked Sep 15 '19 17:09

Hekes Pekes


4 Answers

A bit late to answer that one but it might help someone else. You could use a good old double rotation trick to achieve the result you want. Other solutions does not work because the maximum size inside a scroll view is undefined as it depends on its child views to compute its own content size.

ScrollView {
  VStack(alignment: .leading, spacing: 16) {
      Spacer()
      .frame(minWidth: 0, maxWidth: .infinity, minHeight:0, maxHeight: .infinity, alignment: Alignment.topLeading)
      ForEach(notList, id: \.self) { not in
          NotRow(not: not)
      }

  }
  .padding()
  .rotationEffect(Angle(degrees: 180))
}
.rotationEffect(Angle(degrees: 180))
like image 122
Antoine Lamy Avatar answered Oct 18 '22 11:10

Antoine Lamy


ScrollView does not propose the same height to its children (VStack in this case) as it was proposed to it. It just asks for minimal size. The solution is to make its direct child respond with the minimum height which was proposed to ScrollView itself. We can achieve this by reading the proposed height via GeometryReader and setting that as minimum height of the child.

GeometryReader { reader in
    ScrollView {
        VStack {
            /// Spacer() or Color.red will now behave as expected
        }
        .frame(minHeight: reader.size.height)
    }
}
like image 43
Orkhan Alikhanov Avatar answered Oct 18 '22 11:10

Orkhan Alikhanov


I think you're missing a maxHeight in VStack

VStack(alignment: .leading) {
  Spacer().frame(maxWidth: .infinity)
  // content here
}
.frame(maxHeight: .infinity) // <- this
like image 35
Darlan Mendonça Avatar answered Oct 18 '22 11:10

Darlan Mendonça


If you remove Spacer() and put it after the closing braces of your ForEach, it will fix it. Here is how your updated code will look like:

ScrollView {
        VStack(alignment: .leading, spacing: 16) {
            .frame(minWidth: 0, maxWidth: .infinity, minHeight:0, maxHeight: .infinity, alignment: Alignment.topLeading)
            ForEach(notList, id: \.self) { not in
                NotRow(not: not)

            }
            Spacer()
        }
        .padding()
        .frame(minWidth: 0, maxWidth: .infinity, minHeight:0, alignment: Alignment.topLeading)

    }
like image 33
Fateh Avatar answered Oct 18 '22 10:10

Fateh