Skip to content

Commit

Permalink
Refactor processor to support externally-created views (#1569)
Browse files Browse the repository at this point in the history
* Rename LazyListUpdateProcessor.Cell to Binding

This new name fits its use better.

* Refactor processor to support externally-created views

* Don't extend both Objective-C and Kotlin types
  • Loading branch information
squarejesse authored Oct 10, 2023
1 parent 86d0b3d commit d1d4e04
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 155 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import app.cash.redwood.layout.api.CrossAxisAlignment
import app.cash.redwood.lazylayout.api.ScrollItemIndex
import app.cash.redwood.lazylayout.widget.LazyList
import app.cash.redwood.lazylayout.widget.LazyListUpdateProcessor
import app.cash.redwood.lazylayout.widget.LazyListUpdateProcessor.Binding
import app.cash.redwood.lazylayout.widget.RefreshableLazyList
import app.cash.redwood.ui.Margin
import app.cash.redwood.widget.ChangeListener
Expand Down Expand Up @@ -73,25 +74,6 @@ internal open class UIViewLazyList(
protected var onViewportChanged: ((firstVisibleItemIndex: Int, lastVisibleItemIndex: Int) -> Unit)? = null

private val processor = object : LazyListUpdateProcessor<LazyListContainerCell, UIView>() {
override fun createCell(
cell: Cell<LazyListContainerCell, UIView>,
widget: Widget<UIView>,
index: Int,
): LazyListContainerCell {
val result = tableView.dequeueReusableCellWithIdentifier(
identifier = reuseIdentifier,
forIndexPath = NSIndexPath.indexPathForItem(index.convert(), 0.convert()),
) as LazyListContainerCell
require(result.cell == null)
result.cell = cell
result.setWidget(widget.value)
return result
}

override fun setWidget(cell: LazyListContainerCell, widget: Widget<UIView>) {
cell.setWidget(widget.value)
}

override fun insertRows(index: Int, count: Int) {
// TODO(jwilson): pass a range somehow when 'count' is large?
tableView.insertRowsAtIndexPaths(
Expand All @@ -107,6 +89,10 @@ internal open class UIViewLazyList(
UITableViewRowAnimationNone,
)
}

override fun setContent(view: LazyListContainerCell, content: Widget<UIView>) {
view.content = content
}
}

override val placeholder: Widget.Children<UIView> = processor.placeholder
Expand All @@ -125,7 +111,26 @@ internal open class UIViewLazyList(
override fun tableView(
tableView: UITableView,
cellForRowAtIndexPath: NSIndexPath,
) = processor.getCell(cellForRowAtIndexPath.item.toInt())
): LazyListContainerCell {
val index = cellForRowAtIndexPath.item.toInt()
return processor.getOrCreateView(index) { binding ->
createView(tableView, binding, index)
}
}

private fun createView(
tableView: UITableView,
binding: Binding<LazyListContainerCell, UIView>,
index: Int,
): LazyListContainerCell {
val result = tableView.dequeueReusableCellWithIdentifier(
identifier = reuseIdentifier,
forIndexPath = NSIndexPath.indexPathForItem(index.convert(), 0.convert()),
) as LazyListContainerCell
require(result.binding == null)
result.binding = binding
return result
}
}

private val tableViewDelegate: UITableViewDelegateProtocol =
Expand Down Expand Up @@ -214,8 +219,18 @@ internal class LazyListContainerCell(
style: UITableViewCellStyle,
reuseIdentifier: String?,
) : UITableViewCell(style, reuseIdentifier) {
internal var cell: LazyListUpdateProcessor.Cell<LazyListContainerCell, UIView>? = null
internal var widgetView: UIView? = null
internal var binding: Binding<LazyListContainerCell, UIView>? = null
internal var content: Widget<UIView>? = null
set(value) {
field = value

removeAllSubviews()
if (value != null) {
contentView.addSubview(value.value)
contentView.translatesAutoresizingMaskIntoConstraints = false
}
setNeedsLayout()
}

override fun initWithStyle(
style: UITableViewCellStyle,
Expand All @@ -234,43 +249,34 @@ internal class LazyListContainerCell(

// Confirm the cell is bound when it's about to be displayed.
if (superview == null && newSuperview != null) {
require(cell!!.isBound) { "about to display a cell that isn't bound!" }
require(binding!!.isBound) { "about to display a cell that isn't bound!" }
}

// Unbind the cell when its view is detached from the table.
if (superview != null && newSuperview == null) {
removeAllSubviews()
cell?.unbind()
cell = null
binding?.unbind()
binding = null
}
}

override fun prepareForReuse() {
super.prepareForReuse()
removeAllSubviews()
cell?.unbind()
cell = null
}

fun setWidget(widgetView: UIView) {
this.widgetView = widgetView

removeAllSubviews()
contentView.addSubview(widgetView)
contentView.translatesAutoresizingMaskIntoConstraints = false
setNeedsLayout()
binding?.unbind()
binding = null
}

override fun layoutSubviews() {
super.layoutSubviews()

val widgetView = this.widgetView ?: return
widgetView.setFrame(bounds)
val content = this.content ?: return
content.value.setFrame(bounds)
contentView.setFrame(bounds)
}

override fun sizeThatFits(size: CValue<CGSize>): CValue<CGSize> {
return widgetView?.sizeThatFits(size) ?: return super.sizeThatFits(size)
return content?.value?.sizeThatFits(size) ?: return super.sizeThatFits(size)
}

private fun removeAllSubviews() {
Expand Down
Loading

0 comments on commit d1d4e04

Please sign in to comment.