Dynamically resize UITableViewCell at runtime on tvOS - swift

I currently have a UIViewController with the following hierarchy:
UIViewController
-- UIView
---- UITableView
------ UITableViewCell
-------- UICollectionView
---------- UICollectionViewCell
-------- UIView
---------- UIStackView
------------ UILabel
------------ UILabel
So basically, I have a UITableViewCell, containing an UICollectionView and an UIView, with the following constraints defined in Interface Builder:
UICollectionView.leading = Superview.leading
UICollectionView.trailing = Superview.trailing
UICollectionView.top = Superview.top
UICollectionView.bottom = UIView.top
UIView.leading = Superview.leading
UIView.trailing = Superview.trailing
UIView.bottom = Superview.bottom
The UICollectionView is also set up with a horizontal flow layout.
In my ViewController, I have also overridden the heightForRowAtIndexPath datasource function for the UITableView.
The result is a vertically scrolling list of UITableViewCells, and each UITableViewCell will have a horizontally scrolling list of UIImageViews. The UIView and its two UILabels will display relevant information to the UIImageView when it is focused.
What I am trying to achieve is to hide the UIView containing the two UILabels when the focus moves to a different UITableViewCell. I am able to trap and detect the change in focus by overriding the didUpdateFocusInContext function. I am able to reduce the height of the previously-focused UITableViewCell in the UICollectionViewDelegate, however, the gap between the previously-focused and currently-focused UITableViewCells remain unchanged.
Attempts to set the UITableView.RowHeight to UITableViewAutomaticDimension, setting UITableView.EstimatedRowHeight to an arbitrary figure, removing the overridden heightForRowAtIndexPath function, causes the UICollectionViews to not load at all.
Does anyone have a good suggestion on what I could try?
Edit: Sample source code
ViewController
// ==== ViewController.swift ====
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
let cellIdentifier = "\(CVTableViewCell.self)"
override func viewDidLoad() {
super.viewDidLoad()
setupControls()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
setupControls()
}
func setupControls() {
setupTableView()
}
func setupTableView() {
tableView.dataSource = self
tableView.delegate = self
// causes collectionView in CVTableViewCell to not load
// tableView.rowHeight = UITableViewAutomaticDimension
// tableView.estimatedRowHeight = 200
tableView.register(UINib(nibName: cellIdentifier, bundle: nil),
forCellReuseIdentifier: cellIdentifier)
}
}
extension ViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 316.0 + 106.0 // 316.0 for image height, 106.0 for labelContainerView
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let dequeuedCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? CVTableViewCell else {
fatalError("Unable to dequeue cell")
}
return dequeuedCell
}
}
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, canFocusRowAt indexPath: IndexPath) -> Bool {
return false
}
}
CVTableViewCell
// ==== CVTableViewCell.swift ====
import Foundation
import UIKit
class CVTableViewCell: UITableViewCell {
#IBOutlet weak var collectionView: UICollectionView!
#IBOutlet weak var labelContainerView: UIView!
#IBOutlet weak var labelContainerStackView: UIStackView!
#IBOutlet weak var firstLabel: UILabel!
#IBOutlet weak var secondLabel: UILabel!
let cellIdentifier = "\(CVCollectionViewCell.self)"
override func awakeFromNib() {
super.awakeFromNib()
setupControls()
}
override func prepareForReuse() {
super.prepareForReuse()
setupControls()
}
func setupControls() {
setupTableViewCell()
setupCollectionView()
setupLabelContainerView()
setupLabelContainerStackView()
setupLabels()
}
func setupTableViewCell() {
contentView.backgroundColor = .clear
}
func setupCollectionView() {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.itemSize = CGSize(width: 316.0, height: 316.0)
layout.minimumInteritemSpacing = 0.0
layout.minimumLineSpacing = 50.0
collectionView.dataSource = self
collectionView.delegate = self
collectionView.backgroundColor = .clear
collectionView.clipsToBounds = false
collectionView.collectionViewLayout = layout
collectionView.register(UINib(nibName: cellIdentifier, bundle: nil),
forCellWithReuseIdentifier: cellIdentifier)
}
func setupLabelContainerView() {
labelContainerView.backgroundColor = .clear
}
func setupLabelContainerStackView() {
labelContainerStackView.backgroundColor = .clear
labelContainerStackView.distribution = .fillEqually
}
func setupLabels() {
firstLabel.text = "Look at me"
secondLabel.text = "I refuse to go away"
}
}
extension CVTableViewCell: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let dequeuedCell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath) as? CVCollectionViewCell else {
fatalError("Unable to dequeue cell")
}
dequeuedCell.imageView.adjustsImageWhenAncestorFocused = true
dequeuedCell.imageView.image = #imageLiteral(resourceName: "stackoverflow")
return dequeuedCell
}
}
extension CVTableViewCell: UICollectionViewDelegate {
override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
super.didUpdateFocus(in: context, with: coordinator)
// if next focused view is within current collectionview, show labelContainerView
// else hide
if let cell = context.nextFocusedView as? CVCollectionViewCell,
let _ = collectionView.indexPath(for: cell) {
labelContainerView.isHidden = false
} else {
labelContainerView.isHidden = true
}
}
}
CVCollectionViewCell
// ==== CVCollectionViewCell.swift ====
import Foundation
import UIKit
class CVCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imageView: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
setupControls()
}
override func prepareForReuse() {
super.prepareForReuse()
setupControls()
}
func setupControls() {
setupImageView()
}
func setupCollectionViewCell() {
backgroundColor = .clear
}
func setupImageView() {
imageView.image = nil
}
}

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 :

I don't know what I have to do in order to make (2) work.. in swift

I want to make things like this.
(1). if I press one of that button(A) among 31. that number(A) turn red.
(2). then if I press another button(B) then (A) turn black again and then (B) turn red.
**
class ViewController: UICollectionViewController {
var collectionViewCell = CollectionViewCell()
let data = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]
override func viewDidLoad() {
super.viewDidLoad()
collectionView.register(UINib(nibName: "CollectionViewCell", bundle: nil), forCellWithReuseIdentifier : "MyCell")
}
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return data.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath) as! CollectionViewCell
cell.Label.text = String(data[indexPath.row])
return cell
}
}
class CollectionViewCell: UICollectionViewCell {
#IBOutlet weak var Label: UILabel!
#IBOutlet weak var button: UIButton!
#IBAction func buttonPressed(_ sender: UIButton) {
if Label.textColor == .red{
Label.textColor = .black
} else if Label.textColor == .black{
Label.textColor = .red
}
}
public override func awakeFromNib() {
super.awakeFromNib()
}
}
You have to use isSelected and func setSelected(_ selected: Bool, animated: Bool) {
But first you need to know that in Swift we use camelCase styling for variables.
Now we would have to change a little bit your cell implementation:
class CollectionViewCell: UICollectionViewCell {
#IBOutlet weak var label: UILabel!
#IBOutlet weak var button: UIButton!
public override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
if selected {
label.textColor = .red
} else {
label.textColor = .black
}
}
#IBAction func buttonPressed(_ sender: UIButton) {
self.isSelected = !self.isSelected
}
}
Also don't forget to update cell.Label.text = String(data[indexPath.row]) to cell.label.text = String(data[indexPath.row])
EDIT
As Leo Darbus pointed out it would be better to use isSelected.toggle() than self.isSelected = !self.isSelected, since it's already provided by system
You have to save the row number of the selected cell in the view controller.
Rather than modifying the color in the cell add a callback closure. In cellForRow handle the callback to set the current row to red and the previous row to black by reloading the row.
Something like this
class ViewController: UICollectionViewController {
var selectedRow : Int?
let data = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]
override func viewDidLoad() {
super.viewDidLoad()
collectionView.register(UINib(nibName: "CollectionViewCell", bundle: nil), forCellWithReuseIdentifier : "MyCell")
}
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return data.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath) as! CollectionViewCell
cell.Label.textColor = indexPath.item == selectedRow ? .red : .black
cell.callback = { [unowned self] in
if let row = self.selectedRow {
self.selectedRow = indexPath.item
collectionView.reloadItems(at: [IndexPath(item: row, section: 0)])
}
cell.Label.textColor = .red
}
cell.Label.text = String(data[indexPath.row])
return cell
}
}
class CollectionViewCell: UICollectionViewCell {
#IBOutlet weak var Label: UILabel!
#IBOutlet weak var button: UIButton!
var callback : (() -> Void)?
#IBAction func buttonPressed(_ sender: UIButton) {
callback?()
}
}

Swift - Connect Delegate to Custom Xib Cell

[SOLVED]
Solution
When created a Xib File , I hadn't deleted the start UIView. Whereas I had to delete this view and after add new CollectionViewCell in this xib.
Reference: IBAction inside UITableViewCell not called in iOS 9
I use this structure so many times.When I write this delegate with using StoryBoard , it works properly but now it's not. Where is my mistake when use the xib files?
print(indexpath) doesn't work!
import UIKit
class SearchVC: UIViewController {
var searchUid:String?
var comingPage:String?
var searchElements = [ProductElement]()
var collection:UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
if comingPage == "ProductVC" {
print(searchUid!)
}
let searchView : SearchListView = UIView.fromNib()
searchView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(searchView)
searchView.topAnchor.constraint(equalTo: view.safeTopAnchor, constant: 0).isActive = true
searchView.bottomAnchor.constraint(equalTo: view.safeBottomAnchor, constant: 0).isActive = true
searchView.rightAnchor.constraint(equalTo: view.safeRightAnchor, constant: 0).isActive = true
searchView.leftAnchor.constraint(equalTo: view.safeLeftAnchor, constant: 0).isActive = true
searchView.backgroundColor = UIColor.white
collection = searchView.collectionView
collection.translatesAutoresizingMaskIntoConstraints = false
collection.delegate = self
collection.dataSource = self
collection.register(UINib(nibName: "SearchCollectionCell", bundle: nil), forCellWithReuseIdentifier: "SearchCollectionCell")
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 10
collection.collectionViewLayout = layout
GetElements().search(keywords: ["\(searchUid!)"], contentTypes: ["contenttype_article"]) { (elements) in
self.searchElements = elements
self.collection.reloadData()
}
}
}
extension SearchVC: UICollectionViewDelegate, UICollectionViewDataSource , UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return searchElements.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
var cell: SearchCollectionCell! = collectionView.dequeueReusableCell(withReuseIdentifier: "SearchCollectionCell", for: indexPath) as? SearchCollectionCell
if cell == nil {
collectionView.register(UINib(nibName: "SearchCollectionCell", bundle: nil), forCellWithReuseIdentifier: "SearchCollectionCell")
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SearchCollectionCell", for: indexPath) as? SearchCollectionCell
}
let url = URL(string: "\(String(describing: Config.fileServiceWFileUid!))\(String(describing: searchElements[indexPath.row].oneImage!))")
cell.searchImage.kf.setImage(with: url)
cell.productName.text = searchElements[indexPath.row].title
cell.productCompany.text = searchElements[indexPath.row].description
cell.delegate = self
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.bounds.size.width / 2 - 5 , height: 175)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// print(indexPath.row)
}
}
extension SearchVC : SearchCollectionCellDelegate {
func searchCellShareButton(sender: SearchCollectionCell) {
print("AA")
if let indexpath = collection.indexPath(for: sender) {
print(indexpath)
}
}
}
//
protocol SearchCollectionCellDelegate{
func searchCellShareButton(sender:SearchCollectionCell)
}
class SearchCollectionCell: UICollectionViewCell {
#IBOutlet var searchImage: UIImageView!
#IBOutlet var productName: UILabel!
#IBOutlet var productCompany: UILabel!
var delegate:SearchCollectionCellDelegate?
override func layoutSubviews() {
searchImage.layer.cornerRadius = 4
}
#IBAction func cellShareButtonAction(_ sender: Any) {
if delegate != nil {
delegate?.searchCellShareButton(sender: self)
}
}
}
[EDIT]
I added didSelectItemAt func. When I try to press "..." button for calling protocol, didSelectItemAt works. I think also this is another mistake.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print(indexPath.row)
}
[EDIT 2]
AddTarget Action didn't work. Where is my mistake? Please help me!!!
#IBOutlet var shareButton: UIButton!
weak var delegate:SearchCollectionCellDelegate?
override func awakeFromNib() {
shareButton.addTarget(self, action: #selector(asd), for: .touchUpInside)
}
#objc func asd(){
print("asd")
}
Used the same code of your's and it is working perfectly fine. Can't figure out why it is not working at your end.
If you are not getting the solution try Closures :
class SecondCollectionViewCell: UICollectionViewCell {
var callbackOnButton : (()->())?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
#IBAction func methodButton(_ sender: Any) {
self.callbackOnButton?()
}
}
and in cellForRowAtIndex add :
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SecondCollectionViewCell", for: indexPath) as! SecondCollectionViewCell
cell.callbackOnButton = {
print("Button Clicked")
}
return cell
}
try this
in viewDidLoad
override func viewDidLoad() {
collectionView.register(UINib(nibName: "SearchCollectionCell", bundle: nil), forCellWithReuseIdentifier: "SearchCollectionCell")
}
in your cell class
protocol SearchCollectionCellDelegate:class{
func searchCellShareButton(sender:SearchCollectionCell)
}
class SearchCollectionCell: UICollectionViewCell {
#IBOutlet var searchImage: UIImageView!
#IBOutlet var productName: UILabel!
#IBOutlet var productCompany: UILabel!
weak var delegate:SearchCollectionCellDelegate?
override func layoutSubviews() {
searchImage.layer.cornerRadius = 4
}
#IBAction func cellShareButtonAction(_ sender: Any) {
delegate?.searchCellShareButton(sender: self)
}
}
now go to your controller conform protocol
class yourViewController:UIVIewController, SearchCollectionCellDelegate{
}
in you data source method
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell: SearchCollectionCell! =
collectionView.dequeueReusableCell(withReuseIdentifier:
"SearchCollectionCell",
for: indexPath) as? SearchCollectionCell else{return UICollectionViewCell() }
cell.delegate = self
return cell
}
Have you registered CollectionViewCell Class with proper identifier in your view controller...
if not try to register it in viewDidLoad Method.

How to recognize which cell was tapped once and which was tapped twice

there! I would like to get to know which cell is tapped once and which is tapped twice. I have two classes, one for TableViewController and the other one for TableViewCell. I would like to manipulate cells regarding the touch but I cannot get their indexPath.
TableViewController:
import UIKit
var elements: [[Int16]] = Array(repeating:Array(repeating:0, count:2), count:10)
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource
{
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) as! TableViewCell
if(elements[indexPath.row][1] == 1) //if red
{
cell.Label.text = String(elements[indexPath.row][0] * 3)
cell.Circle.backgroundColor = UIColor.red
}
else //if blue
{
cell.Label.text = String(elements[indexPath.row][0])
cell.Circle.backgroundColor = UIColor.blue
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return UIScreen.main.bounds.height/10
}
override func viewWillAppear(_ animated: Bool)
{
for i in 0..<elements.count
{
elements[i][0] = Int16(Int(arc4random_uniform(10)))
elements[i][1] = Int16(Int(arc4random_uniform(2)))
}
Memory().save(entity: elements)
}
override func viewDidLoad()
{
super.viewDidLoad()
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
}
TableViewCell:
import UIKit
class TableViewCell: UITableViewCell
{
override func awakeFromNib()
{
super.awakeFromNib()
Circle.layer.cornerRadius = Circle.frame.width / 2
let singleTap = UITapGestureRecognizer(target: self, action: #selector(tappedOnce))
singleTap.numberOfTapsRequired = 1
addGestureRecognizer(singleTap)
let doubleTap = UITapGestureRecognizer(target: self, action: #selector(tappedTwice))
doubleTap.numberOfTapsRequired = 2
addGestureRecognizer(doubleTap)
singleTap.require(toFail: doubleTap)
singleTap.delaysTouchesBegan = true
doubleTap.delaysTouchesBegan = true
}
override func setSelected(_ selected: Bool, animated: Bool)
{
super.setSelected(selected, animated: animated)
}
#objc func tappedOnce(sender: AnyObject?)
{
print("1111111")
//Memory().reload(reload: x, I: x)
}
#objc func tappedTwice()
{
print("2222222")
}
#IBOutlet weak var Label: UILabel!
#IBOutlet weak var Circle: UIView!
}
Inside the cells I have a label storing a random number (label) from 0 to 10 next to which there is a circle - blue or red (they are also random at start). If the circle is red, then the number (label) shows the number multiplied by three. All this is there.
Now... I want to change the number by touching on the cell once and make it 0 by touching on it twice
TableViewController:
var elements: [[Int16]] = Array(repeating: Array(repeating:0, count:2), count:10)
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
//MARK: - UIViewController LifeCycle
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
for i in 0..<elements.count {
elements[i][0] = Int16(Int(arc4random_uniform(10)))
elements[i][1] = Int16(Int(arc4random_uniform(2)))
}
Memory().save(entity: elements)
}
//MARK: - UITableView Delegate & DataSource
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) as! TableViewCell
if elements[indexPath.row][1] == 1 {
cell.Label.text = String(elements[indexPath.row][0] * 3)
cell.Circle.backgroundColor = UIColor.red
}
else {
cell.Label.text = String(elements[indexPath.row][0])
cell.Circle.backgroundColor = UIColor.blue
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UIScreen.main.bounds.height/10
}
}
TableViewCell:
class TableViewCell: UITableViewCell {
#IBOutlet weak var Label: UILabel!
#IBOutlet weak var Circle: UIView!
private var tapCounter = 0
override func awakeFromNib() {
super.awakeFromNib()
Circle.layer.cornerRadius = Circle.frame.width / 2
let tap = UITapGestureRecognizer(target: self, action: #selector(tapAction))
addGestureRecognizer(tap)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
#objc func tapAction() {
if tapCounter == 0 {
DispatchQueue.global(qos: .background).async {
usleep(250000)
if self.tapCounter > 1 {
self.tappedTwice()
}
else {
self.tappedOnce()
}
self.tapCounter = 0
}
}
tapCounter += 1
}
func tappedOnce() {
print("1111111")
}
func tappedTwice() {
print("2222222")
}
}
Take reference from here
Single and double taps on UITableViewCell in Swift 3

How can I get an array of Strings i.e.. [String] to show up in the custom collection view cell using storyboard

In the Storyboard:
The datasource and delegate are connected from the LFCollectionView to the LFCollectionViewController. The reuseIdentifier is set to LFCell in the CollectionViewCell. The label inside the CollectionViewCell is named cellLabel and has an outlet to my custom LFCollectionViewCell. I want the outlet cellLabel to display the elements in my array of strings lFContainerLabel within each cell container in the collection. I am missing something, or going about this all wrong. I do not have a nib. I don't know how to use those. Is a nib a must in this scenario?
import UIKit
var lFContainerLabel: [String] = []
private let reuseIdentifier = "LFCell"
class LFCollectionView: UICollectionView { }
class LFNavigationController: UINavigationController { }
class LFCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var cellLabel: UILabel!
}
class LFCollectionViewController: UICollectionViewController,UICollectionViewDelegateFlowLayout {
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView!.register(LFCollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSections(in LFCollectionViewController: UICollectionView) -> Int {
return 1
}
override func collectionView(_ LFCollectionViewController: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return lFContainerLabel.count
}
override func collectionView(_ LFCollectionViewController: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let lFCell = LFCollectionViewController.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as UICollectionViewCell!
var myIndex: Int = 0
lFCell?.backgroundColor = UIColor.black
lFCell?.accessibilityElements = lFContainerLabel
myIndex = indexPath.item
lFCell?.cellLabel?.text = lFContainerLabel[myIndex]
return lFCell!
}
}