Cam Crain
Cam Crain

Reputation: 69

SwiftUI ScrollView won't scroll when using fixedSize() to keep text from truncating

While trying to create a ScrollView with text inside it, my text was truncating so that it never expanded beyond the height of the view. While googling the issue, I found the solution of including .fixedSize(horizontal: false, vertical: true) on the text, which solved the truncation issue. But now my ScrollView won't scroll unless I don't specify a frame height for the VStack inside the ScrollView (I can't do that because I need the contents of the VStack to align to the bottom of the ScrollView).

Here is a simplified version of the code to reproduce the issue:

import SwiftUI

struct TestView: View {
    var body: some View {
        GeometryReader { geo in
            ScrollView(.vertical, showsIndicators: false) {
                VStack(spacing: 24) {
                    Text("START")
                    
                    Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc blandit elit non magna bibendum, id mattis turpis tristique. Sed non rhoncus dui. Proin consequat scelerisque eros, in interdum velit pellentesque et. Proin at odio nec tellus feugiat suscipit ac nec tellus. Integer ac consectetur justo. Aenean in sagittis nisi. Duis et ultricies elit. Aliquam erat volutpat. Nam iaculis eget mi at fermentum. Proin ut sapien leo. Aliquam elementum vehicula arcu sit amet placerat. Quisque gravida felis ante, et rhoncus est congue viverra. Sed sagittis ornare mollis. Vivamus lorem libero, tincidunt vel feugiat nec, ultricies sed orci. Nulla facilisi. Etiam imperdiet condimentum eros, at sagittis quam euismod et. Maecenas cursus imperdiet mi, at ultrices nulla lacinia lobortis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc blandit elit non magna bibendum, id mattis turpis tristique. Sed non rhoncus dui. Proin consequat scelerisque eros, in interdum velit pellentesque et. Proin at odio nec tellus feugiat suscipit ac nec tellus. Integer ac consectetur justo. Aenean in sagittis nisi. Duis et ultricies elit. Aliquam erat volutpat. Nam iaculis eget mi at fermentum.")
                        .fixedSize(horizontal: false, vertical: true)
                    
                    Text("END")
                }
                .padding(.horizontal, 80)
                .padding(.top, 160)
                .frame(width: geo.size.width, height: geo.size.height, alignment: .bottom)
            }
        }
    }
}

Does anyone know what I'm doing wrong here? Any ideas would be much appreciated!

Things I've tried:

Upvotes: 1

Views: 407

Answers (2)

Benzy Neez
Benzy Neez

Reputation: 20459

As you already identified in the question, the problem is being caused by setting the frame size on the VStack. This is stopping the scrolling, because the item inside the ScrollView is already showing at full height.

If I understand correctly, you are setting the frame size because you want to align the contents of the VStack to the bottom of the ScrollView. Another way to achieve this is to auto-position the ScrollView to the bottom when the view appears. Doing it this way, the frame is not needed and the problems caused by the frame disappear.

With the following changes, the scroll view is positioned to the bottom, scrolling works and the text is not truncated:

  • remove the frame from the VStack
  • the frame was also why you were seeing truncation in the first place, so with the frame removed you don't need the .fixedSize modifier any more either
  • the GeometryReader is redundant and can also be removed
  • nest the ScrollView in a ScrollViewReader
  • set an id on the VStack
  • scroll to the id in onAppear.

Here you go:

var body: some View {
    ScrollViewReader { proxy in
        ScrollView(.vertical, showsIndicators: false) {
            VStack(spacing: 24) {
                Text("START")

                Text("Lorem ipsum...")

                Text("END")
            }
            .padding(.horizontal, 80)
            .padding(.top, 160)
            .id(-1)
        }
        .onAppear {
            proxy.scrollTo(-1, anchor: .bottom)
        }
    }
}

Upvotes: 1

Cam Crain
Cam Crain

Reputation: 69

Found a fix by @antoine-lamy! It's very hacky but it works. Double Rotation Trick

Here's the working version of the simplified code:

struct TestView: View {
var body: some View {
    GeometryReader { geo in
        ScrollView(.vertical, showsIndicators: false) {
            VStack(spacing: 24) {
                Spacer()
                
                Text("START")
                
                Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc blandit elit non magna bibendum, id mattis turpis tristique. Sed non rhoncus dui. Proin consequat scelerisque eros, in interdum velit pellentesque et. Proin at odio nec tellus feugiat suscipit ac nec tellus. Integer ac consectetur justo. Aenean in sagittis nisi. Duis et ultricies elit. Aliquam erat volutpat. Nam iaculis eget mi at fermentum. Proin ut sapien leo. Aliquam elementum vehicula arcu sit amet placerat. Quisque gravida felis ante, et rhoncus est congue viverra. Sed sagittis ornare mollis. Vivamus lorem libero, tincidunt vel feugiat nec, ultricies sed orci. Nulla facilisi. Etiam imperdiet condimentum eros, at sagittis quam euismod et. Maecenas cursus imperdiet mi, at ultrices nulla lacinia lobortis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc blandit elit non magna bibendum, id mattis turpis tristique. Sed non rhoncus dui. Proin consequat scelerisque eros, in interdum velit pellentesque et. Proin at odio nec tellus feugiat suscipit ac nec tellus. Integer ac consectetur justo. Aenean in sagittis nisi. Duis et ultricies elit. Aliquam erat volutpat. Nam iaculis eget mi at fermentum.")
                    .fixedSize(horizontal: false, vertical: true)
                
                Text("END")
            }
            .padding(.horizontal, 80)
            .padding(.top, 160)
            .rotationEffect(Angle(degrees: 180))
        }
        .rotationEffect(Angle(degrees: 180))
    }
}}

Upvotes: 1

Related Questions