0

I have ScrollView in LazyVGrid. Inside there is forEach cycle create views that appear. User can create new item in this scrollView. When new view is created using ScrollViewReader I observe change of custom Bool property that toggled and scroll view to top using

.onChange(of: boolProperty) { _ in
                    withAnimation {
                        reader.scrollTo(viewModel.items.[0].id, anchor: .top)
                    }
                }

and everything works fine, but if i change [0] to .first like this

.onChange(of: boolProperty) { _ in
                    withAnimation {
                        reader.scrollTo(viewModel.items.first?.id, anchor: .top)
                    }
                }

behavior isn't the same and view scrolls only a little bit and not to the top

2 Answers 2

3

first returns an optional type (returns nil when the array is empty), so viewModel.items.first?.id is of type ID?, where ID is the type of id.

On the other hand, viewModel.items.[0].id is of the non-optional type ID. The subscript returns a non-optional type, and crashes when the array is empty.

scrollTo scrolls to a view in the scroll view, that has the id you specified. Your views probably has non-optional IDs, so passing a value of an optional type will never match any view you have, and therefore doesn't scroll to the desired view.

Sign up to request clarification or add additional context in comments.

3 Comments

Small addition, just to be on the very safe side: when using items[0] you should wrap the code in if !items.isEmpty { ... }. Using .first (as it's an Optional) will make sure the code will not crash. If you blindly get items[0], your app will crash if the items array is empty.
What JanMensch could be extended to any index really, for example you could define extension Array { func element(at index: Index) -> Element? { indices.contains(index) ? self[index] : nil } } or similar. An actual Element if the index exists, or nil if it doesn't, effectively working similar to first, last, etc.
Or using a subscript like this one.
1

It's different, items[0].id is non-optinal, that's, i.e, an Int. And items.first?.id is opposite, Optional<Int>. Basically, it won't match that's why scroll does not work. Try this:

withAnimation {
    if let firstID = viewModel.items.first?.id {
        reader.scrollTo(firstID, anchor: .top)
    }
}

2 Comments

thank you, solution works but i was looking to more clarifying answer like answer above from Sweeper
It's ok, you got the idea.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.