I am very new to admob nativeads and I checked every tutorial
online on how to add ads in tableview, but I did not find any luck
This is the code I have so far in my cellforrowat function:
let cell = Bundle.main.loadNibNamed("NativeAdTableViewCell", owner: self, options: nil)?.first as! NativeAdTableViewCell
print("ad = \(ad == nil)")
cell.adTitle.text = ad?.headline
cell.adSubtitle.text = ad?.body
cell.img.image = ad?.icon?.image
cell.selectionStyle = UITableViewCell.SelectionStyle.none
return cell
Other code:
func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADUnifiedNativeAd) {
nativeAd.delegate = self
ad = nativeAd
}
Thank you in advanced
You can simply add an empty element in your tableView dataSource array when receive your add like below:
func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADUnifiedNativeAd {
nativeAd.delegate = self
self.yourDataSource.insert("", at: 0) // add empty element in where you show your ads
ad = nativeAd
yourTableView.reloadData()
}
After that your tableViewCell look like :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let data = self.yourDataSource[indexPath.row]as? [String]
if data == nil {
let nativeAd = self.ad //Your native ads object
nativeAd.rootViewController = self
let cell = tableView.dequeueReusableCell(withIdentifier: "nativecell", for: indexPath)as! nativecell // nativecell is your native ad cell
let adView = cell.adview
adView!.nativeAd = nativeAd
cell.headline.text = nativeAd.headline
cell.icon.image = nativeAd.icon?.image
cell.body.text = nativeAd.body
cell.action.isUserInteractionEnabled = false
cell.action.setTitle(nativeAd.callToAction, for: UIControl.State.normal)
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "regularCell", for: indexPath)as! regularCell
return cell
}
}
Thanks
Related
fairly new to Admob. I've been trying to implement AdMob native ads on UICollectionView but I've had little to no luck. I've been able to load and show the ad in a cell but events are not registered e.g views or clicks with the GADNativeAdDelegate. This is the code so far:
// In main view controller
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "exampleCell", for: indexPath) as! exampleCell
let myItem = myItemList[indexPath.item]
if myItem is GADNativeAd {
let nAd = myItems as! GADNativeAd
let nibView = Bundle.main.loadNibNamed("UnifiedNativeAdView", owner: nil, options: nil)?.first
let nativeAdView = nibView as! GADNativeAdView
// Prepare ad content
let nativeAd = nAd
// Add content to native view
(nativeAdView.headlineView as? UILabel)?.text = nativeAd.headline
nativeAdView.mediaView?.mediaContent = nativeAd.mediaContent
(nativeAdView.bodyView as? UILabel)?.text = nativeAd.body
nativeAdView.bodyView?.isHidden = nativeAd.body == nil
(nativeAdView.iconView as? UIImageView)?.image = nativeAd.icon?.image
nativeAdView.iconView?.isHidden = nativeAd.icon == nil
(nativeAdView.advertiserView as? UILabel)?.text = nativeAd.advertiser
nativeAdView.advertiserView?.isHidden = nativeAd.advertiser == nil
nativeAdView.callToActionView?.isUserInteractionEnabled = false
nativeAdView.nativeAd?.delegate = self
nativeAdView.nativeAd?.rootViewController = self
cell.addSubview(nativeAdView)
return cell
}
}
My cell is a basic UICollectionViewCell that is empty as follows:
class exampleCell: UICollectionViewCell {
override func awakeFromNib() {
super.awakeFromNib()
}
}
I've had a look at this answer but it doesn't seem to be applicable.
In cellForItemAt delegate
try this
// Remove previous GADBannerView from the content view before adding a new one.
for subview in reusableAdCell.contentView.subviews {
subview.removeFromSuperview()
}
i have created a tableview with searchbar. My dataset looks like the following :
var data : [[ContactObject]] = []
Everything is working well but if i'm trying to search it doesnt really work.
Here is my search method:
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filteredGroups = self.data[1].filter({(bo: ContactObject ) -> Bool in
return bo.name!.lowercased().contains(searchText.lowercased())
})
filteredUsers = self.data[2].filter({(bo: ContactObject ) -> Bool in
return bo.name!.lowercased().contains(searchText.lowercased())
})
self.filteredData.append(self.myStories)
self.filteredData.append(self.filteredGroups )
self.filteredData.append(self.filteredUsers)
collectionView.reloadData()
}
i'm adding self.myStories always because its static content in my tableview. To show the suitable data i have extended my cell for item at like the following:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if !isFiltering(){
if data[indexPath.section][indexPath.row].name == "Freunde" || data[indexPath.section][indexPath.row].name == "Interessen (öffentlich)"{
var cell1 = tableView.dequeueReusableCell(withIdentifier: "selectStory", for: indexPath) as! StorySelectionTableViewCell
cell1.label.text = data[indexPath.section][indexPath.row].name
cell1.select.setOn(false, animated: true)
cell1.select.tag = indexPath.row
cell1.select.addTarget(self, action: #selector(handleSwitch), for: .valueChanged)
return cell1
}
var cell = tableView.dequeueReusableCell(withIdentifier: "contactCell", for: indexPath) as! ContactsTableViewCell
cell.select.tag = indexPath.row
cell.thumb.layer.masksToBounds = false
cell.thumb.layer.cornerRadius = cell.thumb.frame.height/2
cell.thumb.clipsToBounds = true
cell.name.text = data[indexPath.section][indexPath.row].name
cell.select.addTarget(self, action: #selector(handleButtonPress), for: .touchDown)
if data[indexPath.section][indexPath.row].imageUrl != "" && data[indexPath.section][indexPath.row].imageUrl != nil{
let url = URL(string: data[indexPath.section][indexPath.row].imageUrl!)
cell.thumb.kf.setImage(with: url)
}
return cell
}else{
if filteredData[indexPath.section][indexPath.row].name == "Freunde" || filteredData[indexPath.section][indexPath.row].name == "Interessen (öffentlich)"{
var cell1 = tableView.dequeueReusableCell(withIdentifier: "selectStory", for: indexPath) as! StorySelectionTableViewCell
cell1.label.text = filteredData[indexPath.section][indexPath.row].name
cell1.select.setOn(false, animated: true)
cell1.select.tag = indexPath.row
cell1.select.addTarget(self, action: #selector(handleSwitch), for: .valueChanged)
return cell1
}
var cell = tableView.dequeueReusableCell(withIdentifier: "contactCell", for: indexPath) as! ContactsTableViewCell
cell.select.tag = indexPath.row
cell.thumb.layer.masksToBounds = false
cell.thumb.layer.cornerRadius = cell.thumb.frame.height/2
cell.thumb.clipsToBounds = true
cell.name.text = filteredData[indexPath.section][indexPath.row].name
cell.select.addTarget(self, action: #selector(handleButtonPress), for: .touchDown)
if data[indexPath.section][indexPath.row].imageUrl != "" && data[indexPath.section][indexPath.row].imageUrl != nil{
let url = URL(string: filteredData[indexPath.section][indexPath.row].imageUrl!)
cell.thumb.kf.setImage(with: url)
}
return cell
}
}
and my numbersOfRowsInSection like this:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isFiltering(){
return filteredData[section].count
}
return data[section].count
}
the result is no matter which word i'm typing in, my third section (self.filteredUsers) is always empty and self.filteredGroups always complete.
This is just a guess, but I think you should not append to filteredData here:
self.filteredData.append(self.myStories)
self.filteredData.append(self.filteredGroups )
self.filteredData.append(self.filteredUsers)
This will make filteredData longer and longer, and the cellForRowAt only makes use of the first three items. You should instead replace the whole array with the three subarrays:
filteredData = [myStories, filteredGroups, filteredUsers]
The other thing I noticed is that you are reloading a collection view after the three lines above, but the search bar seems to be installed on a table view. Maybe you should be reloading the table view instead, or this is a mere typo.
I am trying to use the segment controller with 3 segments. If I click on first segment, I should get one tableview. When I click on second segment, I should get second tableview and for third segment I should get 3rd table view. Here I am using XIB's for tableview cell. I tried something but I am not getting any data in the table. The table is loading. But the cell is not loading. I am giving my code below. If any one helps me, would be very great. Thanks in advance.
var arr1 = ["1","2","3","4"]
var imagesarray = [UIImage(named: "11.png")!, UIImage(named: "22.png")!, UIImage(named: "33.png")!,UIImage(named: "11.png")!,UIImage(named: "22.png")!, UIImage(named: "33.png")!]
override func viewDidLoad() {
super.viewDidLoad()
view_track.isHidden = false
view_watch.isHidden = true
view_ebooks.isHidden = true
table_track.register(UINib(nibName: "ProgramMListenTableViewCell", bundle: nil), forCellReuseIdentifier: "ProgramMListenTableViewCell")
table_watch.register(UINib(nibName: "ProgramMWatchTableViewCell", bundle: nil), forCellReuseIdentifier: "ProgramMWatchTableViewCell")
table_watch.register(UINib(nibName: "ProgramEbooksTableViewCell", bundle: nil), forCellReuseIdentifier: "ProgramEbooksTableViewCell")
table_ebooks.delegate = self
table_ebooks.dataSource = self
table_track.delegate = self
table_track.dataSource = self
table_watch.delegate = self
table_watch.dataSource = self
self.navigationController?.setNavigationBarHidden(true, animated: false)
}
#IBAction func Segment(_ sender: Any) {
switch segment_program.selectedSegmentIndex
{
case 0:
view_track.isHidden = false
view_watch.isHidden = true
view_ebooks.isHidden = true
self.table_track.reloadData()
break
case 1:
view_track.isHidden = true
view_watch.isHidden = false
view_ebooks.isHidden = true
self.table_watch.reloadData()
name_program.text = "Videos"
break
case 2:
view_track.isHidden = true
view_watch.isHidden = true
view_ebooks.isHidden = false
self.table_ebooks.reloadData()
name_ebooks.text = "Ebooks"
break
default:
break
}
}
}
extension ProgramMListenViewController: UITableViewDataSource,UITableViewDelegate{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == table_track{
return self.arr1.count
}else if tableView == table_watch{
return self.imagesarray.count
}else{
return self.arr1.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == table_track{
let cell = table_track.dequeueReusableCell(withIdentifier: "ProgramMListenTableViewCell") as! ProgramMListenTableViewCell
}else if tableView == table_watch{
let cell = table_watch.dequeueReusableCell(withIdentifier: "ProgramMWatchTableViewCell") as! ProgramMWatchTableViewCell
cell.img_watch.image = imagesarray[indexPath.row]
}else if tableView == table_ebooks{
let cell = table_ebooks.dequeueReusableCell(withIdentifier: "ProgramEbooksTableViewCell") as! ProgramEbooksTableViewCell
cell.image_ebooks.image = imagesarray[indexPath.row]
}
return UITableViewCell()
}
}
You have to return your cell, instead of always returning UITableViewCell()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == table_track{
let cell = table_track.dequeueReusableCell(withIdentifier: "ProgramMListenTableViewCell") as! ProgramMListenTableViewCell
return cell
}else if tableView == table_watch{
let cell = table_watch.dequeueReusableCell(withIdentifier: "ProgramMWatchTableViewCell") as! ProgramMWatchTableViewCell
cell.img_watch.image = imagesarray[indexPath.row]
return cell
}else if tableView == table_ebooks{
let cell = table_ebooks.dequeueReusableCell(withIdentifier: "ProgramEbooksTableViewCell") as! ProgramEbooksTableViewCell
cell.image_ebooks.image = imagesarray[indexPath.row]
return cell
}
return UITableViewCell()
}
As mentioned before you need to return the respective UITableViewCell, depending on the table in order for it to be shown. You should watch for errors in dequeueReusableCell(), thus I recommend the following implementation:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var returnCell = UITableViewCell()
if tableView == table_track{
guard let cell = table_track.dequeueReusableCell(withIdentifier: "ProgramMListenTableViewCell") as? ProgramMListenTableViewCell else {
print("Error getting cell as ProgramMListenTableViewCell")
return returnCell
}
/*Customize your cell*/
returnCell = cell
}else if tableView == table_watch{
guard let cell = table_watch.dequeueReusableCell(withIdentifier: "ProgramMListenTableViewCell") as? ProgramMWatchTableViewCell else {
print("Error getting cell as ProgramMWatchTableViewCell")
return returnCell
}
/*Customize your cell*/
cell.img_watch.image = imagesarray[indexPath.row]
returnCell = cell
}else if tableView == table_ebooks{
guard let cell = table_ebooks.dequeueReusableCell(withIdentifier: "ProgramMListenTableViewCell") as? ProgramEbooksTableViewCell else {
print("Error getting cell as ProgramEbooksTableViewCell")
return returnCell
}
cell.image_ebooks.image = imagesarray[indexPath.row]
returnCell = cell
}
return returnCell
}
This way you have a safe way of getting the correct type of your cell, editing it and returning it to the corresponding table.
I have a keyboard extension in iOS 11 that includes a collection view of articles coming in from JSON. I have a button in the prototype cell that I would like to allow a user to press to open the article in Safari external to the keyboard. I can get it to open all links in a static URL, but I cant get it to open each article's URL. What am I missing?
I've put an example of the working simple static action and also included what I have tried but doesn't work in this code:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if(collectionView == self.key.colImages)
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "gifCollectionViewCell", for: indexPath) as! gifCollectionViewCell
cell.lblTitle.text = self.articles[indexPath.row].headline
let prefix: String = "https://res.cloudinary.com/djvbbwrnm/image/fetch/"
let options: String = "w_0.2/"
if let imageURL = self.articles[indexPath.row].imageURL
{
let articleURL = self.articles[indexPath.row].url
let url = URL(string: articleURL!)
let urlAppended = prefix+options+imageURL
cell.imgView.sd_setImage(with: URL(string: urlAppended), completed: nil)
//This works
cell.shareButton.addTarget(self, action: #selector(openLink), for: .touchUpInside)
//This doesn't
cell.shareButton.addTarget(self, action: #selector(openUrl(url: url)), for: .touchUpInside)
}
return cell
}
else
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "catCollectionViewCell", for: indexPath) as! catCollectionViewCell
cell.imgView.image = buttPics[indexPath.row]
cell.imgView.layer.cornerRadius = 2
cell.imgView.layer.masksToBounds = true
return cell
}
}
#objc func openLink(){
let articleURL = "http://google.com"
let url = URL(string: articleURL)
openUrl(url: url)
}
#objc func openUrl(url: URL?) {
let selector = sel_registerName("openURL:")
var responder = self as UIResponder?
while let r = responder, !r.responds(to: selector) {
responder = r.next
}
_ = responder?.perform(selector, with: url)
}
You cant add any other DataTypes as arguments. Because, you are adding addTarget for UIButton.
#objc func openLink(){
}
#objc func openLink(sender: UIButton){ // URL is not possible.
}
The above two codes are same. In second one, you can access that UIButton's property.
Runnable Code
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if(collectionView == self.key.colImages)
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "gifCollectionViewCell", for: indexPath) as! gifCollectionViewCell
cell.lblTitle.text = self.articles[indexPath.row].headline
let prefix: String = "https://res.cloudinary.com/djvbbwrnm/image/fetch/"
let options: String = "w_0.2/"
if let imageURL = self.articles[indexPath.row].imageURL
{
//let articleURL = self.articles[indexPath.row].url
//let url = URL(string: articleURL!)
let urlAppended = prefix+options+imageURL
cell.imgView.sd_setImage(with: URL(string: urlAppended), completed: nil)
//This works
cell.shareButton.addTarget(self, action: #selector(openLink), for: .touchUpInside)
//This doesn't
//cell.shareButton.addTarget(self, action: #selector(openUrl(url: url)), for: .touchUpInside)
cell.shareButton.tag = indexPath.row // SET TAG TO UIBUTTON
}
return cell
}
else
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "catCollectionViewCell", for: indexPath) as! catCollectionViewCell
cell.imgView.image = buttPics[indexPath.row]
cell.imgView.layer.cornerRadius = 2
cell.imgView.layer.masksToBounds = true
return cell
}
}
#objc func openLink(sender: UIButton){ // USE THIS.
let buttonTag : Int = sender.tag
let articleURL = self.articles[buttonTag].url
let url = URL(string: articleURL!)
// You can achieve by this way.
// Since I am in a keyboard extension, I added the follwoing code and it is working now.
let selector = sel_registerName("openURL:")
var responder = self as UIResponder?
while let r = responder, !r.responds(to: selector) {
responder = r.next
}
_ = responder?.perform(selector, with: url)
}
My app loads images from a backend and displays them in a UITableViewCell, that contains a UIImageView to display it and some labels and buttons.
I've added the suggested contraints to the UITableViewCell with the 'Reset to suggested contraints' option.
Here's some of the code after retrieving the data:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = PostTableViewCell()
if (self.posts.count == 0) { return cell }
let post = posts[indexPath.row]
// Instancia o reuse identifier
if post["post_image"] != nil {
cell = tableView.dequeueReusableCell(withIdentifier: Storyboard.PostWithImage, for: indexPath) as! PostTableViewCell
} else {
cell = tableView.dequeueReusableCell(withIdentifier: Storyboard.PostWithoutImage, for: indexPath) as! PostTableViewCell
}
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var cell = PostTableViewCell()
cell = tableView.dequeueReusableCell(withIdentifier: Storyboard.PostWithImage) as! PostTableViewCell
return cell.bounds.size.height;
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var cell = PostTableViewCell()
cell = tableView.dequeueReusableCell(withIdentifier: Storyboard.PostWithImage) as! PostTableViewCell
return cell.bounds.size.height;
}
private func configureCell(cell: PostTableViewCell, atIndexPath indexPath: IndexPath) {
cell.queue.cancelAllOperations()
let operation: BlockOperation = BlockOperation()
operation.addExecutionBlock { [weak operation] () -> Void in
DispatchQueue.main.sync(execute: { [weak operation] () -> Void in
if (operation?.isCancelled)! { return }
let post = self.posts[indexPath.row]
cell.accessibilityIdentifier = post.recordID.recordName
guard let postTitle = post["post_title"], let postBody = post["post_body"] else {
return
}
if let asset = post["post_image"] as? CKAsset {
self.imageCache.queryDiskCache(forKey: post.recordID.recordName, done: { (image, cachetype) in
if image != nil {
cell.postImageView.contentMode = .scaleAspectFill
cell.postImageView.autoresizingMask = [.flexibleBottomMargin,
.flexibleHeight,
.flexibleLeftMargin,
.flexibleRightMargin,
.flexibleTopMargin,
.flexibleWidth ];
cell.postImageView.image = image!
} else {
do {
let data = try Data(contentsOf: asset.fileURL)
let image = UIImage(data: data)
cell.postImageView.contentMode = .scaleAspectFill
cell.postImageView.autoresizingMask = [.flexibleBottomMargin,
.flexibleHeight,
.flexibleLeftMargin,
.flexibleRightMargin,
.flexibleTopMargin,
.flexibleWidth ];
cell.postImageView.image = image!
self.imageCache.store(image!, forKey: post.recordID.recordName)
} catch {
print("Error 1001 = \(error.localizedDescription)")
}
}
})
}
cell.titleLabel.text = postTitle as? String
cell.bodyLabel.text = postBody as? String
})
}
cell.queue.addOperation(operation)
}
Here's some prints from the app itself that shows the image overlapping over the labels.
It only overlaps if the image is in portrait mode, if the image was taken in landscape it suits well.
What's the best way to bypass this issue?
You can programmatically tell the image to draw only in the given image area. If your constraints are working properly and it is staying the correct size, the image may just be drawing beyond the View bounds because of the .scaleAscpedtFill setting.
Do this by using .clipToBounds = true.
cell.postImageView.clipToBounds = true
Or, you can set it in interface builder as well, per the image below.
Give that a try and see if that helps?