I consider how to create SwitUI List that has as its row custom UIViews.
I create List:
List {
RowView()
}
RowView is UIViewRepresentable of UIRowView
struct RowView : UIViewRepresentable {
func makeUIView() -> UIRowView { ... }
}
UIRowView is custom view
UIRowView: UIView { ... }
Currently first rows are displayed but they are usually not layout properly and while scrolling this views disappear instead of being recycled
UPDATE
Example 1
struct NoteView: UIViewRepresentable {
// MARK: - Properties
let note: Note
let date = Date()
func makeUIView(context: Context) -> UINoteView {
let view = UINoteView()
view.note = note
return view
}
func updateUIView(_ uiView: UINoteView, context: Context) {
uiView.note = note
print("View bounds: \(uiView.bounds)")
}
}
var body: some View {
List {
ForEach(Array(notes.enumerated()), id: \.1) { (i, note) in
NoteView(note: note)
.background(Color.green)
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
}
}.background(Color.red)
}
Example 2 - Simplified
struct TestView : UIViewRepresentable {
let text : String
func makeUIView(context: Context) -> UILabel {
UILabel()
}
func updateUIView(_ uiView: UILabel, context: Context) {
uiView.text = text
}
}
var body: some View {
List {
ForEach(0..<30, id: \.self) { i in
TestView(text: "\(i)")
}
}
}
Both seems to work incorrectly, as rows dissapears I had also issue with views not keeping padding and going outside of the screen if there was more content. Only several first rows (visible initially on screen layouts correctly) other disappears or jump somewhere.
UPDATE 2
Here is Autosizable UINoteView
class UINoteView: UIView {
// MARK: - Init
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupViews()
}
// MARK: - Properties
var note: Note? {
didSet {
textView.attributedText = note?.content?.parsedHtmlAttributedString(textStyle: .html)
noteFooterViewModel.note = note
}
}
// MARK: - Views
lazy var textView: UITextView = {
let textView = UITextView()
textView.translatesAutoresizingMaskIntoConstraints = false
textView.backgroundColor = UIColor.yellow
textView.textContainer.lineBreakMode = .byWordWrapping
textView.textContainerInset = .zero
textView.textContainer.lineFragmentPadding = 0
textView.isScrollEnabled = false
textView.isSelectable = true
textView.isUserInteractionEnabled = true
textView.isEditable = false
textView.textContainer.maximumNumberOfLines = 0
return textView
}()
lazy var label: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "TEST ROW \(note?.id ?? "")"
return label
}()
lazy var vStack: UIStackView = {
let stack = UIStackView(arrangedSubviews: [
textView,
noteFooter
])
stack.axis = .vertical
stack.alignment = .fill
stack.distribution = .fill
stack.translatesAutoresizingMaskIntoConstraints = false
return stack
}()
var noteFooterViewModel = NoteFooterViewModel()
var noteFooter: UIView {
let footer = NoteFooter(viewModel: noteFooterViewModel)
let hosting = UIHostingController(rootView: footer)
hosting.view.translatesAutoresizingMaskIntoConstraints = false
return hosting.view
}
private func setupViews() {
self.backgroundColor = UIColor.green
self.addSubview(vStack)
NSLayoutConstraint.activate([
vStack.leadingAnchor.constraint(equalTo: self.leadingAnchor),
vStack.trailingAnchor.constraint(equalTo: self.trailingAnchor),
vStack.topAnchor.constraint(equalTo: self.topAnchor),
vStack.bottomAnchor.constraint(equalTo: self.bottomAnchor)
])
}
}