0
votes

I'm trying to implement a View where I have a long text and the text scrolls with a Drag gesture. (ScrollView). The trick I'm trying to achieve is to have a gradient so at the to and at the Botton the text should have a kind o opacity:

enter image description here

I was able to do that using a ZStack and a mass gradient but as soon I move the rectangle over my text, the scroll from ScrollView doesn't work anymore.

Here the animated version what I'm trying to do: https://media.giphy.com/media/j3bXQOV1vZMxZS6GAk/giphy.gif

Here my code:

struct ContentView: View {
    var body: some View {
        GeometryReader { fullView in
            ZStack {
                ScrollView() {
                    Text("Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.")
                }
                
                LinearGradient(gradient: Gradient(colors: [.white, .clear,.clear, .white]), startPoint: .top, endPoint: .bottom)
                    .mask(
                        Rectangle()
                )
            }
        }
    }
}

Did you guys have such need?

Thanks and Regards, Max

1

1 Answers

0
votes

Yeah I actually wanted to do this once, but I never did. However, looking at your code you could probably do something like:

//useful for testing large text blocks
func * (lhs: Text, rhs: Int) -> Text {
    var out = lhs
    for _ in 0..<rhs { out = out + lhs }
    return out
}
struct ContentView: View {
    var body: some View {
        //first geometry reader, used to determine the _size_ of the gradient
        GeometryReader { fullView in
            ScrollView() {
                ZStack{
                    Text("Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.") * 60
                    //second geometry reader, used to determin the _offset_ of the gradient
                    GeometryReader{ geo in
                        LinearGradient(gradient:
                            Gradient(colors: [
                                .white,
                                .clear,
                                .clear,
                                .white
                            ]), startPoint: .top, endPoint: .bottom)
                            .mask( Rectangle() )
                            .frame(width: fullView.size.width, height: fullView.size.height)
                            .offset(x: 0, y: -geo.frame(in: .global).origin.y)
                    }
                }
                
            }
        }
        .edgesIgnoringSafeArea(.all)
    }
}

What's going on here is we are setting the size of the linear gradient using the fullview Geometry Reader, and we are setting the offset based on the frame of the geo Geometry Reader, the locations of both geometry readers in the view "hierarchy" is important.


Also, I wanted to note, that your gradient looks kind of dark in some places... By looking at the code, this probably isn't what you intended to do. It's happening because Color.clear is actually an rgb value of 0,0,0 with an alpha of 0. So as the color is interpolated along it transitions to black or grey.

You could fix it by replacing .clear with:

.init(UIColor(red: 1, green: 1, blue: 1, alpha: 0))

Here is a screenshot where I set the top color to .init(UIColor(red: 1, green: 1, blue: 1, alpha: 0)) and the bottom color to.clear:

example image, the top is fully white and the bottom has some dark areas