CollectionView Inside TableView - swift

I have a CollectionView in TableViewController cell the tableViewcontains 3 sections each section is a different category. How I can pass different data in each section. Like Netflix app
In UICollectionViewController file
import UIKit
import Alamofire
class HomeViewController: UITableViewController, MovieDataDelegate {
let tableViewHeaderIdentifier = "FeaturedTableHeader"
var homePresenter : HomePresenter!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let headerNib = UINib(nibName: "FeaturedUITableViewHeaderView", bundle: nil)
tableView.register(headerNib, forHeaderFooterViewReuseIdentifier: tableViewHeaderIdentifier)
homePresenter = HomePresenter()
homePresenter.delegate = self
homePresenter.fetchData()
homePresenter.fetchImageData()
}
func arrayOfMoviesNames(names: [String]) {
//print(homePresenter.homeData.moviesNamesArray)
tableView.reloadData()
}
func arrayOfPosters(path: [String]) {
//print(homePresenter.homeData.posterPathsArray)
}
//MARK: - Home UI table
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: "featuredCell", for: indexPath) as! FeaturedTableViewCell
cell.homeCollectionView.dataSource = self
return cell
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: tableViewHeaderIdentifier) as! FeaturedUITableViewHeaderView
switch section {
case 0:
headerView.isHidden = true
case 1:
headerView.catagoryLabel.text = "Popular Movies"
case 2:
headerView.catagoryLabel.text = "Celebs"
default:
headerView.catagoryLabel.text = "" as String
}
return headerView
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if section == 0 {
return 0
}
return 35
}
override func tableView(_ tableView: UITableView, estimatedHeightForFooterInSection section: Int) -> CGFloat {
return 12
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard let tableViewCell = cell as? FeaturedTableViewCell else { return }
tableViewCell.setCollectionViewDataSourceDelegate(self, forRow: indexPath.row)
}
}
//MARK: - collectionView
extension HomeViewController : UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return homePresenter.homeData.moviesNamesArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "homeCollectionCell", for: indexPath) as! HomeCollectionViewCell
cell.posterImage.image = UIImage(named: "Aladdin")
cell.movieName.text = "coco"
return cell
}
}
In UITableViewCell file
import UIKit
class FeaturedTableViewCell: UITableViewCell {
#IBOutlet weak var homeCollectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
let collectionNib = UINib(nibName: "HomeCollectionViewCell", bundle: nil)
homeCollectionView.register(collectionNib, forCellWithReuseIdentifier: "homeCollectionCell")
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
extension FeaturedTableViewCell {
func setCollectionViewDataSourceDelegate<D: UICollectionViewDataSource & UICollectionViewDelegate>(_ dataSourceDelegate: D, forRow row: Int) {
homeCollectionView.delegate = dataSourceDelegate
homeCollectionView.dataSource = dataSourceDelegate
homeCollectionView.tag = row
homeCollectionView.reloadData()
}
}
screenshot of app
I want to show diffrent image and text for each section of tabelview

Create a struct Movie and create an array of tuple in the view controller. In tuple add a category title and an array of related movies. In table view data source methods use the main array and in collection view data source methods use the movies array from the corresponding tuple. Set the current tuple/section index as the collectionView tag. And get the appropriate movies array in the collection view data source methods.
//HomeViewController
class HomeViewController: UITableViewController {
struct Movie {
var name: String
var image: UIImage?
//other details
}
var movieDetails:[(title:String, movies:[Movie])] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(FeaturedCell.self, forCellReuseIdentifier: "FeaturedCell")
movieDetails = [(title: "MoviesDB", movies: [Movie(name: "a", image: UIImage(named: "a")),
Movie(name: "b", image: UIImage(named: "b")),
Movie(name: "c", image: UIImage(named: "c"))]),
(title: "Popular Movies", movies: [Movie(name: "d", image: UIImage(named: "d")),
Movie(name: "e", image: UIImage(named: "e")),
Movie(name: "f", image: UIImage(named: "f"))]),
(title: "Celebs", movies: [Movie(name: "g", image: UIImage(named: "g")),
Movie(name: "h", image: UIImage(named: "h")),
Movie(name: "i", image: UIImage(named: "i"))])]
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return movieDetails.count
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return movieDetails[section].title
}
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: "FeaturedCell") as? FeaturedCell ?? FeaturedCell(style: .default, reuseIdentifier: "FeaturedCell")
cell.collectionView.tag = indexPath.section
cell.collectionView.delegate = self
cell.collectionView.dataSource = self
return cell
}
}
extension HomeViewController: UICollectionViewDataSource, UICollectionViewDelegate {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return movieDetails[collectionView.tag].movies.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeCell", for: indexPath) as? HomeCell ?? HomeCell()
let movie = movieDetails[collectionView.tag].movies[indexPath.item]
cell.posterImage.image = movie.image
cell.movieName.text = movie.name
return cell
}
}
//FeaturedCell
class FeaturedCell: UITableViewCell {
var collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
func commonInit() {
if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
layout.scrollDirection = .horizontal
}
collectionView.register(HomeCell.self, forCellWithReuseIdentifier: "HomeCell")
collectionView.translatesAutoresizingMaskIntoConstraints = false
addSubview(collectionView)
collectionView.topAnchor.constraint(equalTo: topAnchor).isActive = true
collectionView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
collectionView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
collectionView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
}
}
//HomeCell
class HomeCell: UICollectionViewCell {
let posterImage = UIImageView()
let movieName = UILabel()
//...
}

Use both UITableView data source and UICollectionView data source methods.
Set 3 sections in UITableView with only one cell for every section.
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Your cell with UICollectionView inside
let cell = tableView.dequeueReusableCell(withIdentifier: "YOUR_TABLE_VIEW_CELL_IDENTIFIER", for: indexPath)
// Set UICollectionViewDataSource, also add data source methods in your class, look at next code block
cell.collectionView.dataSource = self
return cell
}
// Header for each section,
func tableView(_ tableView: UITableView,
titleForHeaderInSection section: Int) -> String? {
if (section == 0) {
return nil
} else if (section == 1) {
return "Popular movies"
} else if (section == 2) {
return "Celebs"
}
}
// UICollectionViewDataSource methods
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1 // only one section for each UICOllectionView
}
override func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
// return here number of items in each UICollectionView
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YOUR_COLLECTION_CELL_IDENTIFIER", for: indexPath)
// set real data for each UICollectionCell here
cell.label = "COCO"
return cell
}
If you want to

Related

Swift - How to enable and generate horizontal scroll of UICollection View that is within a UITableViewCell?

I have a UICollectionView placed inside a UITableViewCell. The collection view has its scroll direction set to horizontal. However, when I swipe left or right on it to try and scroll, it doesn't work. Instead the table view cell is just pressed. It seems like the table view is eating up the gesture and not allowing the collection view to register it.
How can I make it so the collection view can scroll left and right with horizontal swipes, while still allowing the parent table view to scroll vertically?
Image that I want to the first cell to have a collection view of images horizontally and on the other cells rows of names for example .
you can see my project on this GitHub account : https://github.com/BenSeferidis/Nft-Assets/tree/version4 for better understanding .
the code is the following :
LobbyViewController (Main VC):
import UIKit
class LobbyViewController: UIViewController {
// MARK: - IBProperties
#IBOutlet weak var tableView: UITableView!
// MARK: - Properties
var data: [DataEnum] = []
var likes:[Int] = []
var numlikes: Int = 0
var nfts: [Nft] = []
let creators : [Creator] = []
var icons: [Icon] = []
var loadData = APICaller()
// MARK: - Life Cyrcle
override func viewDidLoad() {
super.viewDidLoad()
let nib = UINib(nibName: "AssetTableViewCell", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "AssetTableViewCell")
let nib2 = UINib(nibName: "CreatorsTableViewCell", bundle: nil)
tableView.register(nib2, forCellReuseIdentifier: "CreatorsTableViewCell")
tableView.dataSource = self //method to generate cells,header and footer before they are displaying
tableView.delegate = self //method to provide information about these cells, header and footer ....
downloadJSON {
self.tableView.reloadData()
print("success")
}
loadData.downloadData { (result) in
print(result)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? PresentViewController {
destination.nft = nfts[tableView.indexPathForSelectedRow!.row]
destination.delegate = self
}
}
// MARK: - Methods
func downloadJSON(completed: #escaping () -> ()) {
let url = URL(string: "https://public.arx.net/~chris2/nfts.json")
URLSession.shared.dataTask(with: url!) { [self] data, response, error in
if error == nil {
do {
self.nfts = try JSONDecoder().decode([Nft].self, from: data!)
nfts.forEach { nft in
let creators = nfts.map (\.creator)
self.data.append(.type1(creators: creators))
}
self.nfts.forEach { nft in
self.data.append(.type2(nft: nft))
}
DispatchQueue.main.async {
completed()
}
}
catch {
print("error fetching data from api")
}
}
}.resume()
}
}
// MARK: - Extensions
extension LobbyViewController : UITableViewDelegate , UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
indexPath.row == 0 ? 100 : UITableView.automaticDimension
}
//gemizo ta rows tou table
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch self.data[indexPath.item] {
case .type1(let creators):
let cell = tableView.dequeueReusableCell(withIdentifier: "CreatorsTableViewCell",
for: indexPath) as! CreatorsTableViewCell
//cell.creatorsCollectionView = self
return cell
case .type2(let nft):
let cell = tableView.dequeueReusableCell(withIdentifier: "AssetTableViewCell",
for: indexPath) as! AssetTableViewCell
cell.nameLabel?.text = nft.name
cell.nameLabel.layer.cornerRadius = cell.nameLabel.frame.height/2
cell.likesLabel?.text = "\((numlikes))"
let imgUrl = (nft.image_url)
print(imgUrl)
cell.iconView.downloaded(from: imgUrl)
cell.iconView.layer.cornerRadius = cell.iconView.frame.height/2
return cell
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "showDetails", sender: self)
}
}
extension LobbyViewController : TestDelegate{
func sendBackTheLikess(int: Int) {
numlikes = int
tableView.reloadData()
}
}
// MARK: - Enums
enum DataEnum {
case type1(creators: [Creator])
case type2(nft: Nft)
}
// MARK: - Struct
struct Constants {
static let url = "https://public.arx.net/~chris2/nfts.json"
}
Creators TableViewCell :
import UIKit
class CreatorsTableViewCell: UITableViewCell {
//MARK: - IBProtperties
#IBOutlet var creatorsCollectionView: UICollectionView!
#IBOutlet var creatorsLbl: UILabel!
//MARK: - Properties
var nft : Nft?
var creators : [Creator] = []
var users: User?
weak var delegate : CreatorsTableViewCellDelegate?
//MARK: - Life Cyrcle
override func awakeFromNib() {
super.awakeFromNib()
creatorsCollectionView.dataSource = self
creatorsCollectionView.delegate = self
let nibName = UINib(nibName: "CollectionViewCell", bundle: nil)
creatorsCollectionView.register(nibName, forCellWithReuseIdentifier: "CollectionViewCell")
creatorsCollectionView.horizontalScrollIndicatorInsets
}
//init
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.itemSize = CGSize(width: 10 , height: 10)
layout.sectionInset = UIEdgeInsets(top: 3, left: 3, bottom: 3, right: 3)
super.init(style: style, reuseIdentifier: reuseIdentifier)
creatorsCollectionView.showsHorizontalScrollIndicator = true
creatorsCollectionView.showsVerticalScrollIndicator = false
}
required init?(coder aDecoder : NSCoder) {
super.init(coder: aDecoder)
}
func setUpCollection(creators: Creator) {
creatorsLbl.text = creators.user.username
}
}
//MARK: - Extensions
extension CreatorsTableViewCell : UICollectionViewDelegate , UICollectionViewDataSource , UICollectionViewDelegateFlowLayout{
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return creators.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = creatorsCollectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell",
for: indexPath) as! CollectionViewCell
// cell.setUpCollectionViewCell((nft?.creator.profileImgURL[indexPath.row])!)
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.deselectItem(at: indexPath, animated:true)
}
}
//MARK: - Protocols
protocol CreatorsTableViewCellDelegate: AnyObject {
func didSelectPhoto(index: Int)
}
CollectionViewController :
import UIKit
private let reuseIdentifier = "Cell"
class CollectionViewController: UICollectionViewController , UICollectionViewDelegateFlowLayout {
let creatorsCellId = "creatorsCellId"
override func viewDidLoad() {
super.viewDidLoad()
setupCollectionView()
// self.collectionView!.register(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
func setupCollectionView() {
collectionView?.showsHorizontalScrollIndicator = false
collectionView?.backgroundColor = .lightGray
let nib = UINib(nibName: "CollectionViewCell", bundle: nil)
collectionView?.register(nib, forCellWithReuseIdentifier: creatorsCellId)
collectionView?.register(CollectionViewCell.self, forCellWithReuseIdentifier: "cellId")
}
}
}
extension CollectionViewController {
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 7
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: creatorsCellId, for: indexPath) as! CollectionViewCell
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 180, height: view.frame.height-60)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10)
}
}
CollcetionViewCell:
import UIKit
class CollectionViewCell: UICollectionViewCell {
//MARK: - IBProperties
#IBOutlet var creatorsImg: UIImageView!{
didSet {
creatorsImg.contentMode = .scaleAspectFit
}
}
//MARK: - Properties
var nft : Nft?
//MARK: - Life Cyrcle
override func awakeFromNib() {
super.awakeFromNib()
}
func setUpCollectionViewCell(_ nft: Nft) {
let imgUrl = (nft.creator.profileImgURL)
print(imgUrl)
creatorsImg.downloaded(from: imgUrl)
// creatorsImg.image = UIImage(named: (nft.creator.profileImgURL))
creatorsImg.layoutIfNeeded()
creatorsImg.layer.cornerRadius = creatorsImg.frame.height / 2
}
}
the results is this :

How to navigate to another view controller from datasource class

I have a UIViewController with a UITableView. I have separate class for UITableViewDataSource and UITableViewDelegate. How can I navigate to another view controller when a cell is selected?
class ViewController: UIViewController {
let tableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = TableViewDataSource()
}
}
class TableViewDataSource: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//How to push SecondVC from Viewcontroller?
}
}
class TableViewDataSource: UITableViewDataSource, UITableViewDelegate {
var parentViewController : UIViewController?
func init(parentController : UIViewController){
self.parentViewController = parentController
}
// rest of your code
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//How to push SecondVC from Viewcontroller?
let storyboard = UIStoryboard(name: "Stroybaordname", bundle: nil)
let secondVC = storyboard.instantiateViewController(withIdentifier: "ViewControllerName")
parentViewController.present(secondVC, animated: true, completion: nil)
}
}
Try this way
If I had to do this I would do it using a separate delegate method. If I am missing the context pardon me.
class ViewController: UIViewController, TableViewDataSourceDelegate {
let tableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
let customTableDataSource = TableViewDataSource()
customTableDataSource.delegate = self
// Setting the custom delegate
tableView.delegate = customTableDataSource
}
func cellSelected(at: IndexPath) {
// Navigate from here.
}
}
/// Protocol helps to communicate with the TableViewDataSource to the user of it.
protocol TableViewDataSourceDelegate {
func cellSelected(at: IndexPath)
}
class TableViewDataSource: UITableViewDataSource, UITableViewDelegate {
var delegate: TableViewDataSourceDelegate?
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return UITableViewCell()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
delegate?.cellSelected(at: indexPath)
}
}
You can create a blocks to access it in your ViewController class.
//MARK:- MODULES
import UIKit
//MARK:- TYPEALIAS
typealias ListCellConfigureBlock = (_ cell : AnyObject? , _ item : AnyObject? , _ indexpath: IndexPath?) -> ()
typealias DidSelectedRow = (_ indexPath : IndexPath) -> ()
typealias ScrollViewDidScroll = (_ scrollView : UIScrollView) -> ()
typealias ViewForHeaderInSection = (_ section : Int) -> UIView?
typealias DidDeselectedRow = (_ indexPath : IndexPath) -> ()
typealias CanEditRowAt = (_ indexPath : IndexPath) -> Bool
typealias CommitEditingStyle = (_ commiteditingStyle: UITableViewCellEditingStyle, _ indexPath : IndexPath) -> ()
typealias HeightForRowAt = (_ indexPath : IndexPath) -> CGFloat
//MARK:- CLASS
class TableViewDataSource: NSObject {
//MARK:- PROPERTIES
var _section: [String]?
var sectionCount: Array<AnyObject>?
var rowCount : Array<AnyObject>?
var cellIdentifier : String?
var tableView : UITableView?
var configureCellBlock : ListCellConfigureBlock?
var aRowSelectedListener : DidSelectedRow?
var ScrollViewListener : ScrollViewDidScroll?
var viewforHeaderInSection : ViewForHeaderInSection?
var headerHeight : CGFloat?
var aRowDeselectedListener : DidDeselectedRow?
var aRowEditListener : CanEditRowAt?
var aRowCommitListener : CommitEditingStyle?
var aRowHeightListener : HeightForRowAt?
init (tableView : UITableView?, cellIdentifier : String?, sectionCount: Array<AnyObject>?, rowCount : Array<AnyObject>? , height : HeightForRowAt? , configureCellBlock : ListCellConfigureBlock? , aRowSelectedListener : #escaping DidSelectedRow,aRowDeselectedListener: #escaping DidDeselectedRow ,aRowCommitListener: #escaping CommitEditingStyle, DidScrollListener : ScrollViewDidScroll?) {
self.tableView = tableView
self.sectionCount = sectionCount
self.rowCount = rowCount
self.cellIdentifier = cellIdentifier
self.aRowHeightListener = height
self.configureCellBlock = configureCellBlock
self.aRowSelectedListener = aRowSelectedListener
self.aRowDeselectedListener = aRowDeselectedListener
self.aRowCommitListener = aRowCommitListener
self.ScrollViewListener = DidScrollListener
}
override init() {
super.init()
}
}
//MARK:- DELEGATE, DATASOURCE
extension TableViewDataSource : UITableViewDelegate , UITableViewDataSource{
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let identifier = cellIdentifier else { fatalError("Cell identifier not provided") }
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: identifier , for: indexPath) as UITableViewCell
cell.selectionStyle = UITableViewCellSelectionStyle.none
if let block = self.configureCellBlock , let item: AnyObject = self.rowCount?[(indexPath as NSIndexPath).row]{
block(cell , item , indexPath as IndexPath?)
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let block = self.aRowSelectedListener{
block(indexPath)
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.rowCount?.count ?? 0
}
func numberOfSections(in tableView: UITableView) -> Int {
return self.sectionCount?.count ?? 0
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
guard let block = self.aRowHeightListener else { return 0.0 }
return block(indexPath)
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
guard let block = viewforHeaderInSection else { return nil }
return block(section)
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self._section?[section]
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return headerHeight ?? 0.0
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if let block = self.ScrollViewListener{
block(scrollView)
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let block = self.aRowDeselectedListener {
block(indexPath)
}
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
guard let block = self.aRowEditListener else { return false }
return block(indexPath)
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if let block = self.aRowCommitListener{
block(editingStyle, indexPath)
}
}
}
You can use it like:
//Create a variable:
var dataSource = TableViewDataSource()
fileprivate func setUpDataSource() throws {
DispatchQueue.main.async { [weak self] in
dataSource = TableViewDataSource.init(tableView: tblView, cellIdentifier: CellId.chatUserTVCell.rV, sectionCount: arrSection as Array<AnyObject>, rowCount: arrSearchChatListing , height: { (indexPath) -> CGFloat in
return 80.0
}, configureCellBlock: { (cell, item, indexPath) in
guard let _cell = cell as? ChatUserTableCell, let _item = item as? ChatListing, let row = indexPath?.row else { return }
_cell.chatListing = _item
try? self?.shouldRequestPaging(row: row)
}, aRowSelectedListener: { (indexPath) in
let vc = StoryboardScene.Home.instantiateChatTextController()
try? self?.pushVC(vc)
}, aRowDeselectedListener: { (indexPath) in
debugPrint("Deselected")
}, aRowCommitListener: { (editingStyle, indexPath) in
debugPrint("aRowCommitListener")
}, DidScrollListener: { (scrollView) in
debugPrint("DidScrollListener")
})
tblView.delegate = dataSource
tblView.dataSource = dataSource
tblView.reloadData()
}
}
Hope it helps :)

Collection View inside table view delegate

I have a table view with collection view inside table rows.
structure is next:
MainViewController.swift:
class MainViewController: UIViewController {
#IBOutlet weak var customTable: UITableView!
func callSegue() {
performSegue(withIdentifier: "customSegue", sender: self)
}
override func viewDidLoad() {
customTable(UINib(nibName: "CustomTableCell", bundle: nil), forCellReuseIdentifier: "TipsTableCell")
}
}
extension MainViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableCell", for: indexPath) as! CustomTableCell
//Fill cell with my data
return cell
}
}
CustomTableCell.swift
class CustomTableCell.swift: UITableViewCell {
#IBOutlet var collectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
self.collectionView.dataSource = self
self.collectionView.delegate = self
self.collectionView.register(UINib.init(nibName: "CustomTableCell", bundle: nil), forCellWithReuseIdentifier: "CustomTableCell")
}
}
extension CustomTableCell: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomTableCell", for: indexPath) as! CustomTableCell
cell.label1.text = dataArray[indexPath.item]
return cell
and my CustomCollectionvCell.swift
class CustomCollectionvCell: UICollectionViewCell {
#IBOutlet weak var label1: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
I need something like this:
I need to call "callSegue" func in MainViewController when I tapped at cell where label1.text == "Something".
Use closures to solve that.
Add a closure in CustomTableCell and call it when the collectionViewCell is tapped in collectionView(_:didSelectItemAt:) method, i.e.
class CustomTableCell: UITableViewCell {
var handler: (()->())?
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.handler?()
}
}
In MainViewController, set the closure while dequeuing CustomTableCell in tableView(_:cellForRowAt:) method, i.e.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableCell", for: indexPath) as! CustomTableCell
cell.handler = {[weak self] in
self.callSegue() //here.....
}
return cell
}
Also cross-check if you have a segue with identifier customSegue in your storyboard.
In your case, you have to implement delegate from CustomTableCell.swift and use in MainViewController.swift
// MainViewController.swift:
class MainViewController: UIViewController {
#IBOutlet weak var customTable: UITableView!
func callSegue() {
performSegue(withIdentifier: "customSegue", sender: self)
}
override func viewDidLoad() {
customTable(UINib(nibName: "CustomTableCell", bundle: nil), forCellReuseIdentifier: "TipsTableCell")
}
}
extension MainViewController: UITableViewDataSource, collectionViewCellTapped {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableCell", for: indexPath) as! CustomTableCell
//Fill cell with my data
return cell
}
func cellTapped(_ text: String) {
if let text = dataArray[indexPath.item], text == "Something" {
callSegue()
}
}
}
// CustomTableCell.swift
protocol collectionViewCellTapped {
func cellTapped(_ text: String)
}
class CustomTableCell : UITableViewCell {
#IBOutlet var collectionView: UICollectionView!
var delegate: collectionViewCellTapped!
override func awakeFromNib() {
super.awakeFromNib()
self.collectionView.dataSource = self
self.collectionView.delegate = self
self.collectionView.register(UINib.init(nibName: "CustomTableCell", bundle: nil), forCellWithReuseIdentifier: "CustomTableCell")
}
}
extension CustomTableCell: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomTableCell", for: indexPath) as! CustomTableCell
cell.label1.text = dataArray[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let delegate = self.delegate {
delegate.cellTapped(text)
}
}
}

Retrieving the tag from a cell in row in a section [duplicate]

This question already has answers here:
Cannot assign a value of type '[(String)]' to a value of type 'String!'?
(2 answers)
Closed 4 years ago.
enter image description hereI have a tableView with a custom cell. I have added a button to this cell (I have created a UITableViewCell subclass for this cell).
My data is distributed in 3 sections and rows. I want to be able to press the button at any row and pass that row content to the next page. I was able to do all this when I did not have any sections. Here is my code:
import UIKit
class ViewController: UIViewController,UITableViewDataSource {
var menu = ["a", "b", "c"]
#IBOutlet weak var tblview: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// print(menu[section].count)
return menu.count
}
func numberOfSections(in tableView: UITableView) -> Int {
//print(menu.count)
return menu.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! AddItemClassCell
cell.textLabel?.text = menu[indexPath.row]
cell.addBtn.tag = indexPath.row
cell.addBtn.addTarget(self, action: #selector(BtnClicked), for: .touchUpInside)
return cell
}
#objc private func BtnClicked(sender: UIButton) {
let vc = self.storyboard!.instantiateViewController(withIdentifier: "NextVC") as! NextVC
vc.loadViewIfNeeded()
//vc.lb.text = menu[sender.indexPath.section][sender.indexPath.row]
vc.lb.text = menu[sender.tag]
self.navigationController?.pushViewController(vc, animated: true)
}
}
Here is the cell class:
import UIKit
class AddItemClassCell: UITableViewCell {
#IBOutlet weak var addBtn: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Cannot assign value of type '[String]' to type 'String?'
If your are using a button on a cell you can use
import UIKit
struct Menu {
let title: String
let innerMenu: [String]
}
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var myTV: UITableView!
let menuArr = [
Menu(title: "1", innerMenu: ["a", "b", "c"]),
Menu(title: "2", innerMenu: ["d", "e", "f"]),
Menu(title: "3", innerMenu: ["g", "h", "i"]),
]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
myTV.delegate = self
myTV.dataSource = self
myTV.reloadData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return menuArr.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return menuArr[section].innerMenu.count
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let title = UILabel()
title.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: 50)
title.text = menuArr[section].title
return title
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 40
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : MyCell! = tableView.dequeueReusableCell( withIdentifier: "MyCell") as? MyCell
cell.lbl_Title.text = menuArr[indexPath.section].innerMenu[indexPath.row]
cell.btn_Click.addTarget(self, action: #selector(BtnClicked), for: .touchUpInside)
return cell as MyCell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
#objc func BtnClicked(sender:UIButton!){
let view = sender.superview!
let cell = view.superview as! MyCell
let indexPath = myTV.indexPath(for: cell)
print("\(indexPath?.section) - \(indexPath?.row)")
}
}

How to make label or image dynamic in tableviewcell?

I want to make tableview cell have dynamic label or image in it. I don't want to loop add subview to content view of tableview cell because it will run slow when you scroll. So can anyone help me please? Like this image:
My code is;
Without knowing the context of your code, something like this can work:
NOTE This will work on iOS <= 8
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var TableVC: UITableView!
let elements = ["item1 item2 item3","item1 item2", "item1"]
override func viewDidLoad() {
super.viewDidLoad()
self.TableVC.delegate = self
self.TableVC.dataSource = self
self.TableVC.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return elements.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.numberOfLines = 0
cell.textLabel?.attributedText = addTextToAttribute(text: elements[indexPath.item])
return cell
}
func addTextToAttribute(text : String) -> NSMutableAttributedString {
let mutString = NSMutableAttributedString()
let s = text.components(separatedBy: .whitespaces)
let attr: [String: AnyObject] = [NSFontAttributeName: UIFont.boldSystemFont(ofSize: 20)]
for text in s {
mutString.append(NSAttributedString(string: "-" + text + "\n", attributes: attr))
}
return mutString
}
}