This repository was archived by the owner on Feb 17, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 264
This repository was archived by the owner on Feb 17, 2021. It is now read-only.
Problem with ViewReuseId #164
Copy link
Copy link
Open
Labels
Description
Hi,
As I understand it, you should be able to use the same viewReuseId for different layouts as long as they create the same UIView class and configure the same view properties. When I'm doing this and using my layouts with ReloadableViewLayoutAdapter on a UICollectionView, it's not cleaning up views correctly on a re-used UICollectionViewCell.
Here's a Playground example that reproduces the problem:
import Foundation
import UIKit
import LayoutKit
import PlaygroundSupport
struct FeedItem {
let name: String
let text: String
}
struct BannerItem {
let headline: String
let subtitle: String?
}
class MyViewController : UIViewController {
let items: [Any] = [
FeedItem(name: "User X", text: "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo"),
BannerItem(headline: "Ad 1", subtitle: "Best market ever!"),
FeedItem(name: "User Y", text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. An nisi populari fama? Scaevolam M. At enim sequor utilitatem. Duo Reges: constructio interrete. Bonum valitudo: miser morbus."),
BannerItem(headline: "Ad 2", subtitle: nil),
FeedItem(name: "User Z", text: "Rationis enim perfectio est virtus; Certe non potest. Ille incendat? Ut pulsi recurrant?"),
BannerItem(headline: "Ad 3", subtitle: "Best lib ever!")
]
let collectionViewLayout: UICollectionViewFlowLayout = {
let layout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 10, left: 0, bottom: 10, right: 0)
return layout
}()
lazy var layoutAdapterCollectionView: LayoutAdapterCollectionView = {
let collectionView = LayoutAdapterCollectionView(frame: .zero, collectionViewLayout: self.collectionViewLayout)
collectionView.backgroundColor = .lightGray
collectionView.alwaysBounceVertical = true
return collectionView
}()
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.layoutAdapterCollectionView.frame = self.view.bounds
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
self.view.addSubview(self.layoutAdapterCollectionView)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let sections: [[Any]] = [
self.items,
self.items,
self.items
]
self.layoutAdapterCollectionView.layoutAdapter.reload(
width: self.layoutAdapterCollectionView.bounds.width,
synchronous: true,
layoutProvider: { (Void) -> [Section<[Layout]>] in
let sections: [Section<[Layout]>] = sections.enumerated().flatMap({ (index, section) in
let layouts: [Layout] = section.flatMap { item in
if let feedItem = item as? FeedItem {
return self.feedItemLayout(for: feedItem)
}
if let bannerItem = item as? BannerItem {
return self.bannerLayout(for: bannerItem)
}
return nil
}
let sectionLayout = self.sectionLayout(index: index)
return Section<[Layout]>(header: sectionLayout, items: layouts)
})
return sections
},
completion: nil
)
}
private func sectionLayout(index: Int) -> Layout {
let labelLayout = LabelLayout(
text: "Section \(index)",
font: UIFont.boldSystemFont(ofSize: 20),
config: { label in
label.textColor = .white
}
)
return InsetLayout(
insets: UIEdgeInsets(top: 20, left: 10, bottom: 0, right: 10),
sublayout: labelLayout,
config: { view in
view.backgroundColor = .black
}
)
}
private func bannerLayout(for bannerItem: BannerItem) -> Layout {
let headlineLayout = LabelLayout(
text: bannerItem.headline,
font: UIFont.systemFont(ofSize: 18),
numberOfLines: 0,
viewReuseId: "labelWithTextColorAndBackgroundColor",
config: { label in
label.textColor = .white
label.backgroundColor = .black
}
)
var subtitleLayout: Layout?
if let subtitle = bannerItem.subtitle {
subtitleLayout = LabelLayout(
text: subtitle,
font: UIFont.systemFont(ofSize: 18),
numberOfLines: 0,
viewReuseId: "labelWithTextColorAndBackgroundColor",
config: { label in
label.textColor = .green
label.backgroundColor = .red
}
)
}
return StackLayout(
axis: .vertical,
viewReuseId: "viewWithBackgroundColor",
sublayouts: [
headlineLayout,
subtitleLayout
].flatMap({ $0 }),
config: { view in
view.backgroundColor = .white
}
)
}
private func feedItemLayout(for feedItem: FeedItem) -> Layout {
let imagePlaceholderLayout = SizeLayout(
width: 80,
height: 80,
viewReuseId: "viewWithBackgroundColor",
config: { view in
view.backgroundColor = .gray
}
)
let nameLayout = LabelLayout(
text: feedItem.name,
font: UIFont.systemFont(ofSize: 14),
numberOfLines: 0,
viewReuseId: "labelWithTextColorAndBackgroundColor",
config: { label in
label.textColor = .black
label.backgroundColor = .clear
}
)
let textLayout = LabelLayout(
text: feedItem.text,
font: UIFont.systemFont(ofSize: 12),
numberOfLines: 0,
viewReuseId: "labelWithTextColorAndBackgroundColor",
config: { label in
label.textColor = .black
label.backgroundColor = UIColor.groupTableViewBackground
}
)
let verticalStackLayout = StackLayout(
axis: .vertical,
sublayouts: [
nameLayout,
textLayout
]
)
return StackLayout(
axis: .horizontal,
viewReuseId: "viewWithBackgroundColor",
sublayouts: [
imagePlaceholderLayout,
verticalStackLayout
],
config: { view in
view.backgroundColor = .yellow
}
)
}
}
PlaygroundPage.current.liveView = MyViewController()
PlaygroundPage.current.needsIndefiniteExecution = trueIt initially builds a list that looks like this:

But after scrolling down and then back up it looks like this:

Ad 2 and the item below now has a yellow view that is not removed after a re-use.