After hours of googling it seems that I need a hint from society.
So the problem is:
I have two custom prototype cells. First one contains UICollectionView with 12 cells, second one contains only a label.
My task is to pass indexPath.row from that collectionView from first cell to the label from the second cell.
didSelectItemAtIndexPath: not working or I didn't tuned it properly.
Any ideas on how to implement will be very appreciated!
Here's my code (sorry for poor StackOverflow formatting)
import UIKit
class MainTableViewController: UITableViewController {
var storedOffsets = [Int: CGFloat]()
var descrLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
}
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return .LightContent
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCellWithIdentifier("MainCell", forIndexPath: indexPath) as! MainTableViewCell
let bgImg = UIImageView(image: UIImage(named: "background"))
bgImg.contentMode = UIViewContentMode.ScaleAspectFill
cell.backgroundView = bgImg
return cell
}
else {
let cell = tableView.dequeueReusableCellWithIdentifier("DescriptionCell", forIndexPath: indexPath) as! DescriptionTableViewCell
cell.descriptionLabel.text = self.descrLabel.text
return cell
}
}
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
guard let tableViewCell = cell as? MainTableViewCell else { return }
tableViewCell.setCollectionViewDataSourceDelegate(self, forRow: indexPath.row)
tableViewCell.collectionViewOffset = storedOffsets[indexPath.row] ?? 0
}
override func tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
guard let tableViewCell = cell as? MainTableViewCell else { return }
storedOffsets[indexPath.row] = tableViewCell.collectionViewOffset
}
}
extension MainTableViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 12
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("MainCollectionViewCell", forIndexPath: indexPath) as! MainCollectionViewCell
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
print("Collection view at row \(collectionView.tag) selected index path \(indexPath.row)")
self.descrLabel.text = "testText"
}
}
I played around in playground and made this.
It's not tested, but it should give you idea.
protocol CustomDelegate{
func passData(data: AnyObject)
}
class CustomColletionView : UICollectionView, UICollectionViewDelegate{
var customDelegate : CustomDelegate!
func didSelectItemAtIndexPath(collectionView : UICollectionView, indexPath : NSIndexPath){
let cell = collectionView.cellForItemAtIndexPath(indexPath)
let someData = ""
customDelegate.passData(someData)
}
}
class ViewController: UITableViewController, CustomDelegate{
var labelCellData : AnyObject?{
didSet{
//reloadCell when data is received
tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: 1, inSection: 0)], withRowAnimation: .Bottom)
}
}
func passData(data: AnyObject) {
labelCellData = data
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerClass(CustomTableViewCell.self, forCellReuseIdentifier:"Indetifier1")
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "simpleCell")
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 0
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
switch indexPath.row{
case 0:
//this should contain CustomCollectionView
let cell = tableView.dequeueReusableCellWithIdentifier("Indetifier1") as! CustomTableViewCell
cell.collectionView.customDelegate = self
return cell
case 1:
let cell = tableView.dequeueReusableCellWithIdentifier("simpleCell")
cell?.textLabel?.text = labelCellData as? String
return cell!
default:
break
}
return UITableViewCell()
}
}
class CustomTableViewCell: UITableViewCell {
var collectionView : CustomColletionView!
// You need to implement it
}
Related
I have attached the image click the card view expands the same card inside the table cell dynamically its passible to achieve this?
I have searched a lot but not working
Hear my code added header cell with CardView
added arrow button to click the button expand the cell
its able expand but not in parent card it was showing diff card
I have adde my source code
var hiddenSections = Set<Int>()
let tableViewData = [
["1","2","3","4","5"],
["1","2","3","4","5"],
["1","2","3","4","5"],
]
override func viewDidLoad() {
super.viewDidLoad()
let CustomeHeaderNib = UINib(nibName: "CustomSectionHeader", bundle: Bundle.main)
historyTableView.register(CustomeHeaderNib, forHeaderFooterViewReuseIdentifier: "customSectionHeader")
}
func numberOfSections(in tableView: UITableView) -> Int {
return self.tableViewData.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if self.hiddenSections.contains(section) {
return 0
}
return self.tableViewData[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = self.tableViewData[indexPath.section][indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return view.frame.width/4
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = self.historyTableView.dequeueReusableHeaderFooterView(withIdentifier: "customSectionHeader") as! CustomSectionHeader
header.setupCornerRadious()
let sectionButton = header.expandBtn
sectionButton?.setTitle(String(section),
for: .normal)
sectionButton?.tag = section
sectionButton?.addTarget(self,action: #selector(self.hideSection(sender:)), for: .touchUpInside)
return header
}
#objc
private func hideSection(sender: UIButton) {
let section = sender.tag
func indexPathsForSection() -> [IndexPath] {
var indexPaths = [IndexPath]()
for row in 0..<self.tableViewData[section].count {
indexPaths.append(IndexPath(row: row,
section: section))
}
return indexPaths
}
if self.hiddenSections.contains(section) {
self.hiddenSections.remove(section)
self.historyTableView.insertRows(at: indexPathsForSection(),
with: .fade)
} else {
self.hiddenSections.insert(section)
self.historyTableView.deleteRows(at: indexPathsForSection(),
with: .fade)
}
}
With out sections also you can achieve this. To do this,
1.Return cell height as section height. If user clicks on the cell then return total content height to the particular cell.
2.You need to take an array, if user selects cell, add indexPath number in to array. If selects already expand cell remove it from array. In height for row at index check indexPath is in array or not.
This is one of the way. With sections also you can do that.
//MARK:- UITableView Related Methods
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrDict.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
// var cel = tblExpandedTest.dequeueReusableCellWithIdentifier("expCell", forIndexPath: indexPath) as! CDTableViewCell
var cel : CaseHearingTabTVC! = tableView.dequeueReusableCell(withIdentifier: "caseHearingTabCell") as! CaseHearingTabTVC
if(cel == nil)
{
cel = Bundle.main.loadNibNamed("caseHearingTabCell", owner: self, options: nil)?[0] as! CaseHearingTabTVC;
}
//cell?.backgroundColor = UIColor.white
cel.delegate = self
if indexPath != selctedIndexPath{
cel.subview_desc.isHidden = true
cel.subview_remarks.isHidden = true
cel.lblHearingTime.isHidden = true
}
else {
cel.subview_desc.isHidden = false
cel.subview_remarks.isHidden = false
cel.lblHearingTime.isHidden = false
}
return cel
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectIndex = true;
if(selectedInd == indexPath.row) {
selectedInd = -1
}
else{
let currentCell = tableView.cellForRow(at: indexPath)! as! CaseHearingTabTVC
cellUpdatedHeight = Float(currentCell.lblHearingTime.frame.origin.y + currentCell.lblHearingTime.frame.size.height) + 2;
selectedInd = -1
tblCaseHearing.reloadData()
selectedInd = indexPath.row
}
let previousPth = selctedIndexPath
if indexPath == selctedIndexPath{
selctedIndexPath = nil
}else{
selctedIndexPath = indexPath
}
var indexPaths : Array<IndexPath> = []
if let previous = previousPth{
indexPaths = [previous]
}
if let current = selctedIndexPath{
indexPaths = [current]
}
if indexPaths.count>0{
tblCaseHearing.reloadRows(at: indexPaths, with: UITableView.RowAnimation.automatic)
}
}
func tableView(_ tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowIndexPath indexPath:IndexPath) {
(cell as! CaseHearingTabTVC).watchFrameChanges()
}
func tableView(_ tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowIndexPath indexPath:IndexPath) {
(cell as! CaseHearingTabTVC).ignoreFrameChanges()
}
func tableView(_ TableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat{
if indexPath == selctedIndexPath{
return CGFloat(cellUpdatedHeight)
}else{
return CaseHearingTabTVC.defaultHeight
}
}
Best approach is to create two different cells for normal card and expanded card.
fileprivate var selectedIndex: Int?
func registerTableViewCells() {
tableView.register(UINib(nibName:Nib.CardCell , bundle: nil), forCellReuseIdentifier: "CardCell")
tableView.register(UINib(nibName:Nib.ExpandedCardCell , bundle: nil), forCellReuseIdentifier: "ExpandedCardCell")
}
override func viewDidLoad() {
super.viewDidLoad()
self.registerTableViewCells()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
guard let index = selectedIndex else {
return 115
}
if index == indexPath.row{
return 200
}
return 115
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let selected = selectedIndex, selected == indexPath.row{
let cell = tableView.dequeueReusableCell(withIdentifier: "ExpandedCardCell", for: indexPath) as! ExpandedCardCell
return cell
}
let cell = tableView.dequeueReusableCell(withIdentifier: "CardCell", for: indexPath) as! CardCell
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if selectedIndex == indexPath.row{
selectedIndex = nil
}
else{
selectedIndex = indexPath.row
}
UIView.performWithoutAnimation {
tableView.reloadData()
}
}
I have collectionView inside TableViewCell.
TableView has 1 section and 4 rows.
I want to figure out which row of tableviewcell is selected when collectionView is Scrolled Horizontally.
I tryed to figure out by putting tableView row in "var nowRow" variable like below code. But It does not work.
How can I find out which row of tableviewcell is selected?
class Home2ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UICollectionViewDataSource, UICollectionViewDelegate {
var posts = [Post]()
var nowRow = Int()
override func viewDidLoad() {
// get posts elements here
//posts.append(element).......
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count // 4counts
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// let cell = DetailMutiTableViewCell()
let cell = tableView.dequeueReusableCell(withIdentifier: "DetailMutiTableViewCell", for: indexPath) as! DetailMutiTableViewCell
nowRow = indexPath.row
cell.post = posts[nowRow]
cell.collectionView1.delegate = self
cell.collectionView1.dataSource = self
cell.collectionView1.reloadData()
return cell
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return posts[nowRow].imageUrls.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MultiImagesCollectionViewCell", for: indexPath) as! MultiImagesCollectionViewCell
let photoUrlString = posts[nowRow].imageUrls[indexPath.item] // ←error occured
let photoUrl = URL(string: photoUrlString)
cell.imageView1.sd_setImage(with: photoUrl)
return cell
}
}
editeditedit
As you have no doubt discovered, interacting with the collectionViews in your table rows does not trigger the tableView method tableView(_:didSelectRowAt:), and tableView.indexPathForSelectedRow is nil because no row has been selected. You need a way to map from the collectionView to the indexPath.row that contains it. This information is known at tableViewCell setup time.
Add a dictionary to your Home2ViewController that maps a UICollectionView to a row Int:
var collectionViewRow = [UICollectionView : Int]()
Add the entries in tableView(_:cellForRowAt:) where you know the row and collectionView:
collectionViewRow[cell.collectionView1] = indexPath.row
Then, anytime you have a collectionView, you can look up its row:
let row = collectionViewRow[collectionView]!
Here's the whole code:
class Home2ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UICollectionViewDataSource, UICollectionViewDelegate {
var posts = [Post]()
var collectionViewRow = [UICollectionView : Int]()
override func viewDidLoad() {
// get posts elements here
//posts.append(element).......
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count // 4counts
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// let cell = DetailMutiTableViewCell()
let cell = tableView.dequeueReusableCell(withIdentifier: "DetailMutiTableViewCell", for: indexPath) as! DetailMutiTableViewCell
collectionViewRow[cell.collectionView1] = indexPath.row
cell.post = posts[indexPath.row]
cell.collectionView1.delegate = self
cell.collectionView1.dataSource = self
cell.collectionView1.reloadData()
return cell
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
let row = collectionViewRow[collectionView]!
return posts[row].imageUrls.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MultiImagesCollectionViewCell", for: indexPath) as! MultiImagesCollectionViewCell
let row = collectionViewRow[collectionView]!
let photoUrlString = posts[row].imageUrls[indexPath.item] // ←error occured
let photoUrl = URL(string: photoUrlString)
cell.imageView1.sd_setImage(with: photoUrl)
return cell
}
}
Notes:
The force unwrap of the dictionary lookup won't fail because the collectionView will be in there. If you want to unwrap it with if let, you'll need to decide what to do when you don't get a row (which shouldn't happen).
This method could fail if your table allows editing (user can rearrange order of rows or delete rows). If you don't support editing, then this will work fine. To support editing, you could change the dictionary to [UICollectionView : UITableViewCell]. Then, given a UICollectionView, you could look up its cell, and then call let indexPath = tableView.indexPath(for: cell) to get the indexPath and your row is then just indexPath.row.
I have made a UICollectionView inside a UITableViewCell and it works pretty Fine. My only Problem is, that I can't perform a Segue on didSelectItemAt Method to another ViewController.
I know I have to perform it from the TableViewController,I made a segue on the Storyboard and I tried multiple possibilities but for some reasons it doesn't work.
Here my TableviewController:
import UIKit
import RealmSwift
import SwiftyJSON
class HomeVTwoTableViewController: UITableViewController {
let realm = try! Realm()
let headers = ["1","2","3"]
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
self.tableView.separatorStyle = .none
}
//MARK: Custom Tableview Headers
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return headers[section]
}
//MARK: DataSource Methods
override func numberOfSections(in tableView: UITableView) -> Int {
return headers.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
//Choosing the responsible PrototypCell for the Sections
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellBig", for: indexPath) as! HomeVTwoTableViewCell
cell.update()
return cell
} else {
return UITableViewCell()
}
}
// This on of my tries to perform a segue
func liveCellSelected() {
performSegue(withIdentifier: "showChat", sender: nil)
}
}
And here my TableViewCell with the embedded CollectionView:
import UIKit
import RealmSwift
class HomeVTwoTableViewCell: UITableViewCell{
var liveCommunities: Results<Community>?
#IBOutlet weak var collectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
collectionView.delegate = self
collectionView.dataSource = self
}
}
extension HomeVTwoTableViewCell:
UICollectionViewDataSource,UICollectionViewDelegate {
func numberOfSections(in collectionView: UICollectionView) -> Int
{
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return(liveCommunities?.count)!
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCellBig", for: indexPath) as? HomeVTwoCollectionViewCell else
{
fatalError("Cell has wrong type")
}
//removes the old image
cell.imageView.image = UIImage(named: "No Image")
cell.titleLbl.text = nil
//set url and Picture
url = (liveCommunities?[indexPath.row].pictureId)!
let name : String = (liveCommunities?[indexPath.row].communityName)!
let channelName : String = (liveCommunities?[indexPath.row].channelName)!
cell.titleLbl.text = name
cell.senderLbl.text = channelName
cell.imageView.downloadedFrom(link :"someSecretUrl")
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedCommunity = (liveCommunities?[indexPath.row].communityId)!
HomeVTwoTableViewController().liveCellSelected()
}
}
I found another question with a similar theme, but couldn't implement a delegate Protocol without creating problems with the already existing delegates.
Maybe it`s an obvious mistake but I can't see it.
Thanks in advance.
You're instantiating a new instacne of your home controller with this:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedCommunity = (liveCommunities?[indexPath.row].communityId)!
HomeVTwoTableViewController().liveCellSelected()
}
what you should do is to make it via a delegate, or you move your collectionview delegate to the main controller
protocol CellCollectionViewDelegate: class{
func didselect()
}
and you implement the delegate in cell and your home controller
May be you can create a variable to handle this. You can do optional also.
class HomeVTwoTableViewCell: UITableViewCell{
var liveCommunities: Results<Community>?
#IBOutlet weak var collectionView: UICollectionView!
var didSelectAction: () -> Void // add your action here
Here you can call to this function
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedCommunity = (liveCommunities?[indexPath.row].communityId)!
HomeVTwoTableViewController().liveCellSelected()
didSelectAction() // Invoque your action
}
//On the cell creator, add the navigation or logic when you want to tap the cell
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellBig", for: indexPath) as! HomeVTwoTableViewCell
cell.update()
cell.didSelectAction = {
// add here your navigation
}
return cell
} else {
return UITableViewCell()
}
}
Ok as it seems there are two Solutions to this Problem.
One is via a Variable and one via a delegate. As I know the delegate one is more common.
Solution 1 with Variable:
Here my TableviewController:
import UIKit
class TableViewController: UITableViewController {
let headers = ["1","2","3"]
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return headers.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellBig", for: indexPath) as! HomeVTwoTableViewCell
//Fill function, insert Navigation
cell.didSelectAction = {
self.performSegue(withIdentifier: "testSegue", sender: nil)
}
return cell
}
And here my TableViewCell with the embedded CollectionView:
import UIKit
class HomeVTwoTableViewCell: UITableViewCell{
var liveCommunities: Results<Community>?
//Instantiate function
var didSelectAction: () -> Void = {}
#IBOutlet weak var collectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
collectionView.delegate = self
collectionView.dataSource = self
}
}
extension HomeVTwoTableViewCell:
UICollectionViewDataSource,UICollectionViewDelegate {
func numberOfSections(in collectionView: UICollectionView) -> Int
{
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return(liveCommunities?.count)!
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCellBig", for: indexPath) as? HomeVTwoCollectionViewCell else
{
fatalError("Cell has wrong type")
}
//removes the old text
cell.titleLbl.text = nil
cell.senderLbl.text = nil
let name : String = (liveCommunities?[indexPath.row].communityName)!
let channelName : String = (liveCommunities?[indexPath.row].channelName)!
cell.titleLbl.text = name
cell.senderLbl.text = channelName
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedCommunity = (liveCommunities?[indexPath.row].communityId)!
// Invoque your action
didSelectAction()
}
}
Solution 2 with Delegate and Protocol:
Here my TableviewController:
import UIKit
class TableViewController: UITableViewController {
let headers = ["1","2","3"]
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return headers.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellBig", for: indexPath) as! HomeVTwoTableViewCell
//Add delegate
cell.delegate = self
return cell
}
//Add Extension with Navigation
extension HomeVTwoTableViewController: CellCollectionViewDelegate {
func didSelect() {
performSegue(withIdentifier: "showChat", sender: nil)
}
}
And here my TableViewCell with the embedded CollectionView:
import UIKit
//Create a delegate protocol
protocol CellCollectionViewDelegate: class{
func didSelect()
}
class HomeVTwoTableViewCell: UITableViewCell{
var liveCommunities: Results<Community>?
//Add a delegate property
weak var delegate: CellCollectionViewDelegate?
#IBOutlet weak var collectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
collectionView.delegate = self
collectionView.dataSource = self
}
}
//Adopt and implement the Delegate Protocol
extension HomeVTwoTableViewCell:
UICollectionViewDataSource,UICollectionViewDelegate {
func numberOfSections(in collectionView: UICollectionView) -> Int
{
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return(liveCommunities?.count)!
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCellBig", for: indexPath) as? HomeVTwoCollectionViewCell else
{
fatalError("Cell has wrong type")
}
//removes the old text
cell.titleLbl.text = nil
cell.senderLbl.text = nil
let name : String = (liveCommunities?[indexPath.row].communityName)!
let channelName : String = (liveCommunities?[indexPath.row].channelName)!
cell.titleLbl.text = name
cell.senderLbl.text = channelName
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedCommunity = (liveCommunities?[indexPath.row].communityId)!
//call delegate method
delegate?.didSelect()
}
}
I tried to sum up the Solutions from
Abdoelrhman Mohamed and Alexkater and write it out in detail.
Tell me if something is wrong or left out.
I have a TableView with two kind of Cells, both are filled with a CollectionView. In the TableViewController I let them them display with a simple if Statement.
My TableViewController:
import UIKit
import RealmSwift
import Alamofire
import SwiftyJSON
let myGroupLive = DispatchGroup()
let myGroupCommunity = DispatchGroup()
class HomeVTwoTableViewController: UITableViewController {
var headers = ["Live", "Channel1", "ChannelTwo", "Channel3", "Channel4", "Channel5", "Channel6"]
override func viewDidLoad() {
super.viewDidLoad()
DataController().fetchSomeDate(mode: "get")
DataController().fetchSomeOtherData(mode: "get")
}
//MARK: Custom Tableview Headers
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return headers[section]
}
override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int){
view.tintColor = UIColor.black
let header = view as! UITableViewHeaderFooterView
if section == 0 {
header.textLabel?.textColor = UIColor.black
view.tintColor = UIColor.white
}
else {
view.tintColor = UIColor.groupTableViewBackground
}
}
//MARK: DataSource Methods
override func numberOfSections(in tableView: UITableView) -> Int {
return headers.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
//Choosing the responsible PrototypCell for the Sections
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellBig", for: indexPath) as! HomeVTwoTableViewCell
return cell
}
else if indexPath.section == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellSmall", for: indexPath) as! HomeVTwoTableViewCellSmall
return cell
}
else {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellSmall", for: indexPath) as! HomeVTwoTableViewCellSmall
return cell
}
}
//Set custom cell height, has to match the CollectionView height
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0 {
return 225.0
}
else {
return 120.0
}
}
}
My TableViewCellSmall:
import UIKit
import RealmSwift
var communities: Results<Community>?
class HomeVTwoTableViewCellSmall: UITableViewCell{
#IBOutlet weak var collectionView: UICollectionView!
}
extension HomeVTwoTableViewCellSmall: UICollectionViewDataSource,UICollectionViewDelegate {
//MARK: Datasource Methods
func numberOfSections(in collectionView: UICollectionView) -> Int
{
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return (communities?.count)!
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCellSmall", for: indexPath) as? HomeVTwoCollectionViewCellSmall else
{
fatalError("Cell has wrong type")
}
//Here I want my Sorting Statement to make unique content per collection view
//normal approach if no section is asked
let url : String = (communities?[indexPath.row].pictureUri)!
let name :String = (communities?[indexPath.row].communityName)!
cell.titleLbl.text = name
cell.imageView.downloadedFrom(link :"somelink")
return cell
}
//MARK: Delegate Methods
override func layoutSubviews() {
myGroupCommunity.notify(queue: DispatchQueue.main, execute: {
let realm = try! Realm()
communities = realm.objects(Community.self)
self.collectionView.dataSource = self
self.collectionView.delegate = self
})
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
do something
}
}
My Problem is now, I want the "Channel Cells" to fill with customized and different data, in the CollectionView. That means I need some sort of key to get the right data in the right cell. My approach would be to take the SectionHeader Title, but for some reasons I cant access it from the TableViewCellSmall. So I have all the data in all the Cells and cant sort them without my Key.
Thanks in Advance.
from what I understand you need to fill the collectionview of each cell with different contents and for this needs to identify the cell?
If so, I used the method below that helped me, you can try.
If in doubt let me know so I can help, I hope I have helped :)
//TableViewCell Add
var didCollectionViewCellSelect: ((Int) -> Void)?
override func setSelected(_ selected: Bool, animated: Bool)
{
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
//TabelView Add
class myClass: UITableViewController
{
var storedOffsets = [Int: CGFloat]()
override func viewDidLoad()
{
super.viewDidLoad()
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
{
guard let tableViewCell = cell as? myTableViewCell else { return }
let secao = indexPath.section*1000 //Section
let linha = indexPath.row //Row
let posicao = secao+linha
tableViewCell.setCollectionViewDataSourceDelegate(self, forRow: posicao)
tableViewCell.collectionViewOffset = storedOffsets[posicao] ?? 0
}
override func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath)
{
guard let tableViewCell = cell as? myTableViewCell else { return }
let secao = indexPath.section*1000 //Section
let linha = indexPath.row //Row
let posicao = secao+linha
storedOffsets[posicao] = tableViewCell.collectionViewOffset
}
}
//CollectionView
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
let posicao = collectionView.tag
let secao = Int(collectionView.tag/1000) //Section
let linha = posicao-(secao*1000) //Row
var qtd = 0
if secao == 0 && arrStation.count > 0
{
qtd = arrStation.count
}
return qtd
}
I have made a CollectionView in a TableView for vertical and horizontal scrolling and customisable cells. This works so far. The problem is: I can't select an item of the CollectionView. I think the problem could be something with the delegate outlets but I could't find a solution.
I'm pretty new with Swift, so maybe I overlook something obvious.
My TableViewController:
import UIKit
class HomeVTwoTableViewController: UITableViewController {
var headers = ["Live", "Friends", "Last commented"]
#IBAction func cancelBtnPressed(_ sender: UIBarButtonItem) {
self.dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return headers[section]
}
override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int){
view.tintColor = UIColor.black
let header = view as! UITableViewHeaderFooterView
if section == 0 {
header.textLabel?.textColor = UIColor.black
view.tintColor = UIColor.white
}
else {
view.tintColor = UIColor.groupTableViewBackground
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
return headers.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellBig", for: indexPath) as! HomeVTwoTableViewCell
return cell
}
else if indexPath.section == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellSmall", for: indexPath) as! HomeVTwoTableViewCellSmall
return cell
}
else {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellSmall", for: indexPath) as! HomeVTwoTableViewCellSmall
return cell
}
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0 {
return 225.0
}
else {
return 120.0
}
}
}
My TableViewCell with the CollectionView:
import UIKit
class HomeVTwoTableViewCell: UITableViewCell, UICollectionViewDataSource, UICollectionViewDelegate {
#IBOutlet weak var collectionView: UICollectionView!
fileprivate var images = [UIImage]()
{
didSet
{
self.collectionView.reloadData()
}
}
func setup(for images: [UIImage])
{
self.images = images
}
override func layoutSubviews() {
collectionView.dataSource = self
}
func numberOfSections(in collectionView: UICollectionView) -> Int
{
return communityName.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return communityName.count
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("didSelect")
selectedCommunity = communityId[indexPath.row]
let home = HomeViewController()
home.showCommunityDetail()
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCellBig", for: indexPath) as? HomeVTwoCollectionViewCell else
{
fatalError("Cell has wrong type")
}
//cell.imageView.image = image
cell.titleLbl.text = communityName[indexPath.row]
cell.imageView.downloadedFrom(link :"deleted because privat")
return cell
}
}
My CollectionViewCell:
import UIKit
class HomeVTwoCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var titleLbl: UILabel!
}
You need to set delegate and dataSource like this
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
collectionView.dataSource = self
collectionView.delegate = self
}
I think you missed this line. Just add, it will work fine collectionView.delegate = self
You have not confirm delegate of collection view.
override func layoutSubviews() {
collectionView.dataSource = self
collectionView.delegate = self
}