For my app, I have a collection view that sets the background color of the cells based on a variable in the ViewController.
When MoPub places ads into the CollectionView how can I set the ad's background to match the other cells?
class RestController: UIViewController {
#IBOutlet weak var collectionView: UICollectionView!
var category: Category!
// Ads
var placer = MPCollectionViewAdPlacer()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
collectionView.mp_reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
// AD Cell
collectionView.register(AdCell.self, forCellWithReuseIdentifier: "cell")
let settings = MPStaticNativeAdRendererSettings()
settings.renderingViewClass = AdCell.self
settings.viewSizeHandler = { (maxWidth: CGFloat) -> CGSize in
return CGSize(width: 160, height: 100)
}
let config = MPStaticNativeAdRenderer.rendererConfiguration(with: settings)
placer = MPCollectionViewAdPlacer(collectionView: collectionView, viewController: self, rendererConfigurations: [config as Any])
let targeting = MPNativeAdRequestTargeting()
targeting.desiredAssets = [ kAdStarRatingKey, kAdIconImageKey, kAdTitleKey, kAdPrivacyIconUIImageKey ]
placer.loadAds(forAdUnitID: unitId, targeting: targeting)
collectionView.mp_setDelegate(self)
collectionView.mp_setDataSource(self)
}
}
// MARK: UICollectionViewDataSource
extension RestController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return results.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.mp_dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! RestCell
cell.backgroundColor = category.colors[1]
return cell
}
}
Is there any way to pass this information to the Ad Cell or any method that MoPub offers to set the design of the cell?
Related
I am using storyboards, and my UICollectionView with a basic custom cell is not showing at all? My simulator is constantly running a version of my storyboard when my "Next" button was at the middle of the screen, obviously now it is at the bottom as shown here along with all the identities and links created in the storyboard: https://imgur.com/a/R8iTm9n
import UIKit
class CategoryViewController: UIViewController{
#IBOutlet weak var categoryCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
categoryCollectionView.delegate = self
categoryCollectionView.dataSource = self
NetworkingClient.fetchRecipeCategories{ (recipeCategories) in
//print(recipeCategories)
}
categoryCollectionView.reloadData()
}
}
extension CategoryViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.deselectItem(at: indexPath, animated: true)
print("Taptaptap")
}
}
extension CategoryViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 12
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
var cell = UICollectionViewCell()
if let testCell = collectionView.dequeueReusableCell(withReuseIdentifier: "categoryCell", for: indexPath) as? CategoryCollectionViewCell{
testCell.configure(with: indexPath.row)
cell = testCell
print("test1")
}
print("test2")
return cell
}
}
/*
extension CategoryViewController: UICollectionViewDelegateFlowLayout {
}
*/
And my my custom view cell :
class CategoryCollectionViewCell: UICollectionViewCell {
static let identifier: String = "CategoryCollectionViewCell"
#IBOutlet weak var categoryImageView: UIImageView!
#IBOutlet private weak var testLabel: UILabel!
func configure(with id: Int){
testLabel.text = String(id)
categoryImageView.clipsToBounds = true
categoryImageView.contentMode = .scaleAspectFit
}
}
Sorry for the formatting...
Register your custom collectionview cell named "categoryCell" in viewDidLoad()
categoryCollectionView.register(UINib(nibName: "categoryCell", bundle:
nil),forCellWithReuseIdentifier: "categoryCell")
categoryCollectionView.delegate = self
categoryCollectionView.dataSource = self
categoryCollectionView.reloadData()
in my view controller I Am loading a custom CollectionViewCell with subclass. Based on the position of a cell's indexpath I want to format the text labels differently. I.e. first row has only one cell with bigger text, whereas the second has two cell with smaller text.
How can I access the indexpath from my UICollectionView in my UICollectionViewCell subclass? I tried a delegate protocol but this always returns nil.
Code below and Thanks so much!
Markus
UICollectionViewController:
import UIKit
protocol WorkoutDataViewControllerCVDataSource: AnyObject {
func workoutType(for workoutDataViewControllerCV: WorkoutDataViewControllerCV) -> WorkoutType
func workoutDistance(for workoutDataViewControllerCV: WorkoutDataViewControllerCV) -> Double
func workoutDuration(for workoutDataViewControllerCV: WorkoutDataViewControllerCV) -> Double
func workoutInstantVelocity(for workoutDataViewControllerCV: WorkoutDataViewControllerCV) -> Double
}
final class WorkoutDataViewControllerCV: UIViewController {
#IBOutlet weak var collectionView: UICollectionView!
weak var dataSource: WorkoutDataViewControllerCVDataSource!
private lazy var velocityFormatter = VelocityFormatter(dataSource: self, delegate: self)
private lazy var averageVelocityFormatter = VelocityFormatter(dataSource: self, delegate: self)
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView.register(MeasurementCollectionViewCell.preferredNib, forCellWithReuseIdentifier: MeasurementCollectionViewCell.preferredReuseIdentifier)
}
}
// MARK: - Managing UICollectionView
extension WorkoutDataViewControllerCV: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Measurement Cell", for: indexPath)
return cell
}
}
extension WorkoutDataViewControllerCV: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
let availableWidth = self.view.frame.width
switch indexPath.row {
case 0: return CGSize(width: availableWidth, height: 150)
case 1: return CGSize(width: availableWidth/2.1, height: 150)
case 2: return CGSize(width: availableWidth/2.1, height: 150)
case 3: return CGSize(width: availableWidth, height: 150)
default:
return CGSize(width: availableWidth/2.1, height: 150)
}
}
}
// MARK: - Managing VelocityFormatter
extension WorkoutDataViewControllerCV: VelocityFormatterDataSource {
func duration(for velocityFormatter: VelocityFormatter) -> Double {
return dataSource.workoutDuration(for: self)
}
func distance(for velocityFormatter: VelocityFormatter) -> Double {
return dataSource.workoutDistance(for: self)
}
func instantVelocity(for velocityFormatter: VelocityFormatter) -> Double {
return dataSource.workoutInstantVelocity(for: self)
}
}
UICollectionViewCell.swift
import UIKit
final class MeasurementCollectionViewCell: UICollectionViewCell {
#IBOutlet private var measurementPropertyLabel: UILabel!
#IBOutlet private var measurementValueLabel: UILabel!
#IBOutlet private var measurementUnitLabel: UILabel!
static let preferredReuseIdentifier = "Measurement Cell"
static let preferredNib = UINib(nibName: "MeasurementCollectionViewCell", bundle: nil)
override func awakeFromNib() {
super.awakeFromNib()
updateMeasurement(property: "Speed", value: "100", unit: "km/h")
//measurementValueLabel.font = measurementValueLabel.font.monospacedDigitFont
}
func updateMeasurement(property: String, value: String, unit: String?) {
measurementPropertyLabel.text = property
measurementValueLabel.text = value
measurementUnitLabel.text = unit
}
}
Get the instance of cell in UICollectionView delegate method collectionView(_, didSelectItemAt _).
extension WorkoutDataViewControllerCV: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let cell = collectionView.cellForItem(at: indexPath) as? MeasurementCollectionViewCell {
cell.selectedIndexPath(indexPath)
}
}
}
The indexPath will be passed as an argument in method selectedIndexPath to MeasurementCollectionViewCell from above method.
class MeasurementCollectionViewCell: UICollectionViewCell {
......
func selectedIndexPath(_ indexPath: IndexPath) {
//Do your business here.
}
}
You can use the responder chain to get the collection view of a cell with which you can get the index path. Just add these extensions in a new file called UICollectionViewCell+IndexPath.swift.
extension UIResponder {
func next<T: UIResponder>(_ type: T.Type) -> T? {
return next as? T ?? next?.next(type)
}
}
extension UICollectionViewCell {
var indexPath: IndexPath? {
return next(UICollectionView.self)?.indexPath(for: self)
}
}
Now inside your cell, you can use self.indexPath
Pretty straight forward way would be storing the indexPath into the subclass of UICollectionViewCell class. Assign it while returning from cellForRow at: index path. So now the subclassed collectionviewcell has access to the indexpath of it's own
I have the structure like this:
UITableView -> UITableViewCell -> UICollectionView ->
UICollectionViewCell
So what I’m trying to achieve is that I want to make UICollectionViews in UITableViewCells to scroll synchronised. For example when you scroll manually the first UICollectionView on the first row, I want the rest of UICollectionViews to follow, but the Text Labels to stay in the same position all the time. (Please see the image below)
EDIT: I know that I have to use contentOffset somehow, but don’t know how to implement in this case scenario. Any help would be appreciated.
Click to see the image
Click to see the gif
Okay I managed to get this working, Please keep in mind the code is just for the question purposes and contains lot of non-generic parameters and force casting that should be avoided at any cost.
The class for MainViewController containing the tableView:
protocol TheDelegate: class {
func didScroll(to position: CGFloat)
}
class ViewController: UIViewController, TheDelegate {
func didScroll(to position: CGFloat) {
for cell in tableView.visibleCells as! [TableViewCell] {
(cell.collectionView as UIScrollView).contentOffset.x = position
}
}
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 100
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath) as? TableViewCell else { return UITableViewCell() }
cell.scrollDelegate = self
return cell
}
}
The class for your tableViewCell:
class TableViewCell: UITableViewCell {
#IBOutlet var collectionView: UICollectionView!
weak var scrollDelegate: TheDelegate?
override func awakeFromNib() {
super.awakeFromNib()
(collectionView as UIScrollView).delegate = self
collectionView.dataSource = self
}
}
extension TableViewCell: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 100
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCell", for: indexPath) as! CollectionViewCell
cell.imageView.image = #imageLiteral(resourceName: "litecoin.png")
return cell
}
}
extension TableViewCell: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
scrollDelegate?.didScroll(to: scrollView.contentOffset.x)
}
}
The class for the collectionViewCell is irelevant since it's just implementation detail. I will post this solution to github in a second.
Disclaimer: This works just for visible cells. You need to implement the current scroll state for the cells ready for reuse as well. I will extend the code on github.
I came up with a working solution you can test on a playground:
//: A UIKit based Playground for presenting user interface
import UIKit
import PlaygroundSupport
class MyCollectionCell: UITableViewCell, UICollectionViewDataSource, UICollectionViewDelegate {
var originatingChange: Bool = false
var observationToken: NSKeyValueObservation!
var offsetSynchroniser: OffsetSynchroniser? {
didSet {
guard let offsetSynchroniser = offsetSynchroniser else { return }
collection.setContentOffset(offsetSynchroniser.currentOffset, animated: false)
observationToken = offsetSynchroniser.observe(\.currentOffset) { (_, _) in
guard !self.originatingChange else { return }
self.collection.setContentOffset(offsetSynchroniser.currentOffset, animated: false)
}
}
}
lazy var collection: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: 40, height: 40)
layout.scrollDirection = .horizontal
let collection = UICollectionView(frame: .zero, collectionViewLayout: layout)
collection.backgroundColor = .white
collection.dataSource = self
collection.delegate = self
collection.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
return collection
}()
override func layoutSubviews() {
super.layoutSubviews()
collection.frame = contentView.bounds
contentView.addSubview(collection)
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
cell.layer.borderColor = UIColor.black.cgColor
cell.layer.borderWidth = 1
cell.backgroundColor = .white
return cell
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
originatingChange = true
offsetSynchroniser?.currentOffset = scrollView.contentOffset
originatingChange = false
}
}
class OffsetSynchroniser: NSObject {
#objc dynamic var currentOffset: CGPoint = .zero
}
class MyViewController : UIViewController, UITableViewDataSource {
var tableView: UITableView!
let offsetSynchroniser = OffsetSynchroniser()
override func loadView() {
let view = UIView()
view.backgroundColor = .white
tableView = UITableView(frame: .zero, style: .plain)
tableView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(tableView)
tableView.dataSource = self
tableView.register(MyCollectionCell.self, forCellReuseIdentifier: "cell")
self.view = view
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.reloadData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyCollectionCell
cell.selectionStyle = .none
cell.collection.reloadData()
cell.offsetSynchroniser = offsetSynchroniser
return cell
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()
To make it work with a playground you will see a lot of code that if you are using storyboards or xib is not needed. I hope anyway that the base idea is clear.
Explanation
Basically I created an object called OffsetSynchroniser which has an observable property called currentOffset. Each cell of the tableView accepts an offsetSynchroniser and on didSet they register with KVO for notifications of currentOffset changes.
Each cells also registers to its own collection's delegate and implements the didScroll delegate method.
When any of those collectionView causes this method to be triggered the currentOffset var of the synchroniser is changed and all the cells that are subscribed through KVO will react to the changes.
The Observable object is very simple:
class OffsetSynchroniser: NSObject {
#objc dynamic var currentOffset: CGPoint = .zero
}
then your tableViewCell will have an instance of this object type and on didSet will register with KVO to the var currentOffset:
var originatingChange: Bool = false
var observationToken: NSKeyValueObservation!
var offsetSynchroniser: OffsetSynchroniser? {
didSet {
guard let offsetSynchroniser = offsetSynchroniser else { return }
collection.setContentOffset(offsetSynchroniser.currentOffset, animated: false)
observationToken = offsetSynchroniser.observe(\.currentOffset) { (_, _) in
guard !self.originatingChange else { return }
self.collection.setContentOffset(offsetSynchroniser.currentOffset, animated: false)
}
}
}
The originatingChange variable is to avoid that the collectionView that is actually initiating the offset change will react by causing the offset to be re-set twice.
Finally, always in your TableViewCell, after registering itself as collectionViewDelegate you will implement the method for didScroll
func scrollViewDidScroll(_ scrollView: UIScrollView) {
originatingChange = true
offsetSynchroniser?.currentOffset = scrollView.contentOffset
originatingChange = false
}
In here we can change the currentOffset of the synchroniser.
The tableViewController will at this point just have the ownership for the synchroniser
class YourTableViewController: UItableViewController { // or whatever ViewController contains an UITableView
let offsetSynchroniser = OffsetSynchroniser()
...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyCollectionCell
...
cell.offsetSynchroniser = offsetSynchroniser
return cell
}
}
The best way I can think of off the top of my head to do something like this would be to store all of your collectionViews in a collection object. You can then use the UIScrollView's scrollViewDidScroll delegate method from those collectionViews. Just make sure you have your delegate set correctly.
func scrollViewDidScroll(_ scrollView: UIScrollView) {
for view in collectionViewCollection where view.scrollView != scrollView{
view.scrollView.contentOffset = scrollView.contentOffset
}
}
This is untested code, so not a complete answer but it should get you started.
I got my data from a url as json string. in my codes, titles variable is an array of my url images.
private let reuseIdentifier = "cell_supporters"
class SupportersCollectionViewController: UICollectionViewController {
var ids = [String]()
var titles = [String]()
#IBOutlet var collection_supporters: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
collection_supporters.delegate = self
// Register cell classes
self.collectionView!.register(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
getSupporters()
}
// MARK: UICollectionViewDataSource
// override func numberOfSections(in collectionView: UICollectionView) -> Int {
// // #warning Incomplete implementation, return the number of sections
// return 1
// }
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
return self.titles.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath as IndexPath) as! SupportersCollectionViewCell
print("Hello collectionView")
let url_img = URL(string: self.titles[indexPath.row])!
print(url_img)
cell.img_logo.af_setImage(
withURL: url_img
)
return cell
}
func getSupporters() {
RestApiManager.sharedInstance.getSupporters { (json: JSON) in
if let results = json.array {
for entry in results {
// print(entry["title"])
//self.ids.append(entry["id"].string!)
self.titles.append(entry["title"].string!)
}
print(self.titles.count)
DispatchQueue.main.async{
self.collection_supporters.reloadData()
}
}
}
}
}
in my code :
print(self.titles.count) // it shows 5
but:
print("Hello collectionView") // not show anything !
If you're using the default UICollectionViewFlowLayout class for the layout you can try implementing the delegate method that returns the size of each item in the collectionView. The UICollectionView doesn't call the cellForItemAt dataSource method at all if it doesn't have the size information or if they're zero.
Try adding this:
extension SupportersCollectionViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 40, height: 40) // Return any non-zero size here
}
}
Dont register cell classes. Delete following line from viewDidLoad function :
self.collectionView!.register(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
Add this line in your ViewDidLoad() method:
self.collectionView!.delegate = self
Change it to this:
private let reuseIdentifier = "cell_supporters"
class SupportersCollectionViewController: UICollectionViewController {
var ids = [String]()
var titles = [String]()
override func viewDidLoad() {
super.viewDidLoad()
// Register cell classes
self.collectionView!.register(SupportersCollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
getSupporters()
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
return self.titles.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath as IndexPath) as! SupportersCollectionViewCell
print("Hello collectionView")
let url_img = URL(string: self.titles[indexPath.row])!
print(url_img)
cell.img_logo.af_setImage(
withURL: url_img
)
return cell
}
func getSupporters() {
RestApiManager.sharedInstance.getSupporters { (json: JSON) in
if let results = json.array {
for entry in results {
// print(entry["title"])
//self.ids.append(entry["id"].string!)
self.titles.append(entry["title"].string!)
}
print(self.titles.count)
DispatchQueue.main.async{
self.collectionView!.reloadData()
}
}
}
}
}
First, you don't required this:
#IBOutlet var collection_supporters: UICollectionView!
Because your view controller is inherited from UICollectionViewController
Also I changed the register of the UICollectionViewCell class to this so it won't crash when you the cells are created:
self.collectionView!.register(SupportersCollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
I'm really new in iOS/Swift and i'm in a small project. In this project i have a UITableView inside ViewController. And i have another file custom CollectionViewCell in side UITableViewCell.
I want when user click a cell in collectionview it will open another ViewController and it get data from this collectionviewcell.
This is my uitableview swift file:
class IndexRow: UITableViewCell, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
var names:[String] = ["Movie 1","Movie 2","Movie 3","Movie 4","Movie 5","Movie 6"]
#IBOutlet weak var collectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
collectionView.registerClass(indexOneMovie.self, forCellWithReuseIdentifier: "onemovie")
let nib = UINib(nibName: "indexOneMovie",bundle: nil)
collectionView.registerNib(nib, forCellWithReuseIdentifier: "onemovie")
self.collectionView.backgroundColor = UIColor.clearColor()
self.collectionView.delegate = self
self.collectionView.dataSource = self
print("Hello")
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return names.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = self.collectionView.dequeueReusableCellWithReuseIdentifier("onemovie", forIndexPath: indexPath) as! indexOneMovie
cell.poster.image = UIImage(named: "poster.jpg")
cell.name.text = names[indexPath.row]
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
print(indexPath.item)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let itemsPerRow:CGFloat = 2
let hardCodedPadding:CGFloat = 0
let itemWidth = (collectionView.bounds.width / itemsPerRow) - hardCodedPadding
let itemHeight = collectionView.bounds.height - (hardCodedPadding)
return CGSize(width: itemWidth, height: itemHeight)
}
How i can do it?
ok i have recently implemented the same in my app these are the links where i refered initially -
https://ashfurrow.com/blog/putting-a-uicollectionview-in-a-uitableviewcell-in-swift/
http://www.thorntech.com/2015/08/want-your-swift-app-to-scroll-in-two-directions-like-netflix-heres-how/
you are making uicollectionview delegate confirms to uitableview cell so you cannot present or push to other view controller.
here is my code hope it will help you
homeController.swift which contains uitableview
extension HomeController : UITableViewDelegate {
func tableView(tableView: UITableView,willDisplayCell cell: UITableViewCell,forRowAtIndexPath indexPath: NSIndexPath) {
guard let tableViewCell = cell as? TableViewCell else { return }
//here setting the uitableview cell contains collectionview delgate conform to viewcontroller
tableViewCell.setCollectionViewDataSourceDelegate(self, forRow: indexPath.row, andForSection: indexPath.section)
tableViewCell.collectionViewOffset = storedOffsets[indexPath.row] ?? 0
}
func tableView(tableView: UITableView,didEndDisplayingCell cell: UITableViewCell,forRowAtIndexPath indexPath: NSIndexPath) {
guard let tableViewCell = cell as? TableViewCell else { return }
storedOffsets[indexPath.row] = tableViewCell.collectionViewOffset
}
}
extension HomeController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(collectionView: UICollectionView,numberOfItemsInSection section: Int) -> Int {
let element : [CollectionViewElement] = self.returnCollectionViewElementAccordingToIndex(collectionView.tag)
return element.count
}
func collectionView(collectionView: UICollectionView,cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell",forIndexPath: indexPath) as! horizontalCollectionViewCell
let element : [CollectionViewElement] = self.returnCollectionViewElementAccordingToIndex(collectionView.tag)
cell.cellTitleLabel.text = element[indexPath.row].videos.title
cell.cellGenerLabel.text = element[indexPath.row].videos.gener
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath){
print("collectionviewtag:\(collectionView.tag) + indexpathrow:\(indexPath.row)")
//from here you can do push or present to anyview controller
// collectionviewtag is tableView cell row value and indexpathrow return collectionView cell row value.
}
}
TableViewCell.swift :custom UITableViewCell which contains collectionView
class TableViewCell: UITableViewCell {
#IBOutlet private weak var collectionView: UICollectionView!
#IBOutlet weak var cellLabel: UILabel!
#IBOutlet weak var cellButton: UIButton!
#IBAction func CellButtonActionTry(sender: UIButton) {
print("Dude \(cellButton.tag)")
}
var collectionViewOffset: CGFloat {
get {
return collectionView.contentOffset.x
}
set {
collectionView.contentOffset.x = newValue
}
}
func setCollectionViewDataSourceDelegate<D: protocol<UICollectionViewDataSource, UICollectionViewDelegate>>
(dataSourceDelegate: D, forRow row: Int , andForSection section : Int) {
collectionView.delegate = dataSourceDelegate
collectionView.dataSource = dataSourceDelegate
collectionView.tag = row // tableView indexpathrow equals cell tag
collectionView.reloadData()
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
You can do it like this :
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
print(indexPath.item)
let name = names[indexPath.item]
let distinationViewController = DistinationViewController()
distinationViewController.name = name
if let navVC: UINavigationController = UIApplication.sharedApplication().keyWindow?.rootViewController as? UINavigationController {
navVC.pushViewController(distinationViewController, animated: true)
}
}
This is just a way to do it i dont know which view you want to push or what your names array contains so kindly change those things accordingly.
get root navigationcontroller from uiapplication and perform push on it.