4

I have this List:

struct SignInList: View {
    @ObservedObject var model:SignInModel
    
    var body: some View {
        List(model.currentSignIns) { signIn in
            SignInRow(description: signIn)
        }
    }
}

With this list row:

struct SignInRow: View, Identifiable {
    let id = UUID()
    let description: SignInDescription
    
    var body: some View {
        VStack {
            ButtonView(view: description.button)
        }
    }
}

// Map a UIView to a View. Will be using this to hold a UIView based sign-in button
// https://developer.apple.com/tutorials/swiftui/creating-and-combining-views
struct ButtonView: UIViewRepresentable {
    let view: UIView
    
    func makeUIView(context: Context) -> UIView {
        return view
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {
    }
}

but when I scroll the list, the cells of the list disappear:

Cells Disappearing

If I change the list cells to purely SwiftUI, e.g.,

struct SignInRow: View, Identifiable {
    let id = UUID()
    let description: SignInDescription
    
    var body: some View {
        VStack {
            Rectangle()
        }
    }
}

I do not get this effect. The cells do not disappear when scrolling.

I have tried some ideas on SO (e.g., SwiftUI and ScrollView: Views Disappear After Device Rotation and Content in scrollview as a list item disappears when scrolling (swiftui), why?) but no real improvement so far. (When I embed a ForEach in a ScrollView, I get different problems-- only one of my two rows shows up and the buttons are no longer tappable).

2 Answers 2

2

I think @Asperi is on the right track with List's being the issue. I'm switching away from using them. Here's what's working for me now:

struct SignInList: View {
    @ObservedObject var model:SignInModel
    
    var body: some View {
        ScrollView() {
            ForEach(model.currentSignIns) { signIn in
                SignInRow(description: signIn)
                    .padding(.horizontal, 20)
            }
        }
    }
}

struct SignInRow: View, Identifiable {
    let id = UUID()
    let description: SignInDescription
    
    var body: some View {
        VStack {
            ButtonView(view: description.button)
        }.frame(height: 40)
    }
}
Sign up to request clarification or add additional context in comments.

Comments

0

I assume the issue is because List reuses rows, so it removes your externally injected UIView from superview, but afterwards do not insert it again (it is not the way representable works), but just updates.

In general the pattern is that you should provide data, but view should be created in makeView and updated in updateView.

Here is simplified demo on some replicated from your code. Tested with Xcode 12.1 / iOS 14.1.

demo

class SignInModel: ObservableObject {
    @Published var currentSignIns = (1..<100).map { "\($0)" }
}

struct SignInList: View {
    @ObservedObject var model = SignInModel()
    
    var body: some View {
        List(model.currentSignIns) { signIn in
            SignInRow(description: signIn)
        }
    }
}

struct SignInRow: View, Identifiable {
    let id = UUID()
    let description: String
    
    var body: some View {
        VStack {
            ButtonView(title: description)
        }
    }
}

struct ButtonView: UIViewRepresentable {
    let title: String
    
    func makeUIView(context: Context) -> UIView {
        let button = UIButton(type: .system)
        button.setTitle(title, for: .normal)
        return button
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {
    }
}

1 Comment

Hey, thanks. Perhaps some variation of this can solve the problem. I think there's still something missing though. If you change your new ButtonView struct to have a constructor that makes the UIButton and just returns that same UIButton instance on each call to makeUIView, this still works in the same manner. I.e., the List cells don't disappear.

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.