Prerequisites
The SDK provides a universal way to display advertisements inside the cell of scrollable controls, such as UITableView and UICollectionView.
Keep in mind that the cell item should provide an empty wrapper view to the SDK, so the SDK will use that wrapper view to place an advertisement in it. Therefore the cell size should be dynamic, because the advertisement size is dynamic as well.
As an alternative approach, to manually adjust cell’s layout, track the size of the advertisement by using childAdLifecycle
parameter of RefineryAdFactory.shared.getInfiniteScrollAdForIndex
method.
Display Ad Inside UITableView
To place an Ad inside the cell item, SDK provides three main methods, one to generate infiniteScrollID
via calling RefineryAdFactory.shared.createManualInfiniteScroll
, next to place an ad inside the wrapper for the cell position RefineryAdFactory.shared.getInfiniteScrollAdForIndex(...)
, and the last to hide the advertisement for a position RefineryAdFactory.shared.hideInfiniteScrollAdForIndex(...)
.
1. Prepare the Item Cell
Let’s start by creating a cell item, the AdItemCell
. It contains two child views, one is the UILabel
which will display the cell position, and the other is UIView
which is the wrapper container for the advertisement.
class AdItemCell: UITableViewCell { let centeredLabel = UILabel() let adContainer:UIView = { let view = UIView() view.translatesAutoresizingMaskIntoConstraints = false return view }() private var position:Int32 = -1; private var infiniteScrollId:Int32 = -1; … override func prepareForReuse() { if position != -1 && infiniteScrollId != -1 { // Hide the advertisement for a given position RefineryAdFactory.shared.hideInfiniteScrollAdForIndex(infiniteScrollId: infiniteScrollId, itemIndex: position) } } // This method is get called from the UITableViewDataSource. func loadAd(position:Int32,infiniteScrollId:Int32){ self.position = position self.infiniteScrollId = infiniteScrollId // Show the advertisement for a given position RefineryAdFactory.shared.getInfiniteScrollAdForIndex(infiniteScrollId: infiniteScrollId, itemIndex: position, itemAdWrapper: adContainer, childAdLifecycle: BannerEventListener()) } … }
O loadAd()
method is called from the UITableViewDataSource
whenever the cellForRowAt
delegate method is called, and it uses the getInfiniteScrollAdForIndex
method to let the SDK determine whether to place an Ad for a given position or not.
O prepareForReuse()
method is called whenever the cell will be reused, so for that, we need to request SDK to hide the advertisement hideInfiniteScrollAdForIndex
, because after reusing the cell, a new position will be assigned to the cell and the cell might not be needed to display the ad for its new position.
2. Prepare the UITableView
Next is to generate infiniteScrollId
by using RefineryAdFactory.shared.createManualInfiniteScroll
method
class InfiniteScrollViewController: UIViewController { var tableView:UITableView! var infiniteScrollId: Int32! override func viewDidLoad() { super.viewDidLoad() // Generate the infiniteScrollId let infiniteScrollConfigID = ConfigBuilder.companion.INFINITE_SCROLL_TEST_R89_CONFIG_ID infiniteScrollId = RefineryAdFactory.shared.createManualInfiniteScroll(configurationID: infiniteScrollConfigID, lifecycleCallbacks: nil) // Table view configuration tableView = UITableView(frame: self.view.bounds, style: .plain) tableView.register(AdItemCell.self, forCellReuseIdentifier: “cell”) tableView.dataSource = self tableView.delegate = self tableView.rowHeight = UITableView.automaticDimension self.view.addSubview(tableView) … } }
3. Prepare the UITableViewDelegate
e UITableViewDataSource
Last, we need to bind together the cell and the table view.
extension InfiniteScrollViewController: UITableViewDelegate, UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 1000 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: “cell”, for: indexPath) as! AdItemCell cell.centeredLabel.text = “Row \(indexPath.row)” // Here we set the item’s position and generated infiniteScrollId cell.loadAd(position: Int32(indexPath.row), infiniteScrollId: Int32(infiniteScrollId)) return cell } }
Inside the cellForRowAt
delegate’s method, we are passing the generated infiniteScrollId
to the cell item.
Lifecycle Events
There are two paths available to track the advertisement events for the infinite scroll.
The first one is the general event listener, which notifies about all Ad events in the scrollable view.
Use InfiniteScrollEventListener
to listen to general events in the scroll view by passing its instance to RefineryAdFactory.shared.createManualInfiniteScroll
method while generating an infiniteScrollId
, as demonstrated below
override func viewDidLoad() { super.viewDidLoad() … let infiniteScrollConfigID = ConfigBuilder.companion.INFINITE_SCROLL_TEST_R89_CONFIG_ID infiniteScrollId = RefineryAdFactory.shared.createManualInfiniteScroll(configurationID: infiniteScrollConfigID, lifecycleCallbacks: LoggerInfiniteScrollEventListener()) … }
Here is the implementation of LoggerInfiniteScrollEventListener
.
class LoggerInfiniteScrollEventListener: InfiniteScrollEventListener{ override func onRoll(itemIdInData: Int32) { print(“onRoll”,”itemIdInData=\(itemIdInData)”) } override func onRollFailed(itemIdInData: Int32) { print(“onRollFailed”,”itemIdInData=\(itemIdInData)”) } override func onAdItemFailedToCreate(message: String) { print(“onAdItemFailedToCreate”,”message=\(message)”) } override func onAdItemOpen(itemIdInData: Int32) { print(“onAdItemOpen”,”itemIdInData=\(itemIdInData)”) } override func onAdItemClick(itemIdInData: Int32) { print(“onAdItemClick”,”itemIdInData=\(itemIdInData)”) } override func onAdItemClose(itemIdInData: Int32) { print(“onAdItemClose”,”itemIdInData=\(itemIdInData)”) } override func onAdItemLoaded(itemIdInData: Int32) { print(“onAdItemLoaded”,”itemIdInData=\(itemIdInData)”) } override func onAdItemImpression(itemIdInData: Int32) { print(“onAdItemImpression”,”itemIdInData=\(itemIdInData)”) } override func onAdItemCreated(adapterId: Int32, probability: Double) { print(“onAdItemCreated”,”adapterId=\(adapterId)”,”probability=\(probability)”) } override func onAdItemFailedToLoad(itemIdInData: Int32, error: R89LoadError) { print(“onAdItemFailedToLoad”,”itemIdInData=\(itemIdInData)”,”error=\(error)”) } }
The other way to track advertisement lifecycle events is to pass an instance of BannerEventListener
to the RefineryAdFactory.shared.getInfiniteScrollAdForIndex
method. In contrast with the first approach, this one will listen to a single advertisement’s lifecycle events for a given position.
func loadAd(position:Int32,infiniteScrollId:Int32){ self.position = position self.infiniteScrollId = infiniteScrollId // Show the advertisement for a given position RefineryAdFactory.shared.getInfiniteScrollAdForIndex(infiniteScrollId: infiniteScrollId, itemIndex: position, itemAdWrapper: adContainer, childAdLifecycle: BanneEventLogger()) }
Here is the implementation of BanneEventLogger
.
class BanneEventLogger: BannerEventListener { override func onLayoutChange(width: Int32, height: Int32) { print(“onLayoutChange”,”width=\(width)”,”height=\(height)”) } override func onLoaded() { print(“onLoaded”) } override func onOpen() { print(“onOpen”) } override func onClick() { print(“onClick”) } override func onClose() { print(“onClose”) } override func onImpression() { print(“onImpression”) } override func onFailedToLoad(error: R89LoadError) { print(“onFailedToLoad”,”error=\(error)”) } }