I am Having a tableView and Cell, on Cell i have a collectionView and Displaying Some Content On it .
I want to send a link on selection of indexPath.
I want to push/present My View from Custom CollectionViewCell which is on TableViewCell.
class secondTopicTableViewCell: UITableViewCell {
#IBOutlet weak var relatedCustom: UICollectionView!
var relArray = NSArray()
func loadArray(arr: NSArray) {
self.relArray = arr
self.relatedCustom.reloadData()
}
}
extension secondTopicTableViewCell : UICollectionViewDataSource {
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return relArray.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("collection", forIndexPath: indexPath) as! relatedCollectionViewCell
let info = self.relArray.objectAtIndex(indexPath.row) as! specificTopicInfo
cell.showInfo(info)
return cell
}
}
extension secondTopicTableViewCell : UICollectionViewDelegate {
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let relatedTopic = self.relArray.objectAtIndex(indexPath.row) as! specificTopicInfo
let str = relatedTopic.relatedLink!
print(str)
}
}
class relatedCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var relatedLabel: UILabel!
func showInfo(info: specificTopicInfo) {
relatedLabel.backgroundColor = UIColor.grayColor()
relatedLabel.text = info.relatedTitle
}
}
You just need to navigate using didSelectItemAtIndexPath same as Tableview control.
Write your Navigation code to didSelectItemAtIndexPath of Collectionview
If you are nesting a collection view inside a table view cell and want to trigger an action from the table view displaying this 1st cell, you can do two things.
First
You can use the UICollectionViewDelegate protocol to catch the user interaction with your collection view cell.
Don't forget to set your table view cell as the delegate of its collection view.
Second
You can create your own protocol (useful when a cell have multiple buttons).
Then, each button will have its own “didTap” method, instead of the “didSelect” method from the original collection view delegate.
Related
I have a UICollectionViewController, which scrolls vertically(like a tableview). I created a custom UICollectionViewCell. Inside of a custom cell, there are checkmarks. I need some kind of event to click when the user clicks on a checkmark.
What I tried, was overriding:
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("clicked")
}
but that only executes when the use clicks on a cell. But, asI stated above, the cell contains checkmarks...I need to find out when each individual check mark is clicked.
Is this possible?
You can add an IBAction to the UICollectionViewCell class and handle the tap from that IBAction, if you need it to change something on the Parent view controller you have a couple of options, you can use a delegate or pass the controller to the cell.
On the parent view controller :
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! CustomCollectionViewCell
cell.controller = self
return cell
}
On the UICollectionViewCell class:
var controller: ParentViewController?
#IBAction func checkmarkPressed(sender: UIButton) {
print("checkmarkPressed")
controller.someFunction()
}
Having UICollectionView as a child of UITableView row. UICollectionView contains images, but whenever I scroll tableview down and up the collection view images got vanished randomly. I am attaching images for my problem reference. Please suggest me how to stop this.
I want my tableview to be like this. And its items should not change on scrolling.
----------------------------------------------------------------------------------------------------------------------------------------------
The collectionview images got vanish on scrolling tableview. It looks like this after scrolling up.
Code Is as follow:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell:PartOfLookTableViewCell = self.looksListTable.dequeueReusableCell(withIdentifier: "cell") as! PartOfLookTableViewCell
let oneRecord = looksArray[indexPath.row]
cell.myCollectionView.loadInitial(_dataArray: oneRecord.imagesArray, isLooks: 1)
return cell
}
Code for loading data to CollectionView:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: looksReuseIdentifier, for: indexPath) as! CustomCollectionViewCell
let oneRecord = inputArray[indexPath.row]
cell.productImage.sd_setImage(with: URL.init(string: oneRecord.thumb_url)){ (image, error, cacheType, url) in
DispatchQueue.main.async {
cell.productImage.image = image
}
}
}
}
}
#Sourabh Bissa :
UITableView reuses the cell using method CellForRowAtIndexPath whenever your new cell gets visible your this method reuse the data source.
The very important thing here is to maintain the data source:
In your case cell for the row at index path giving the updated value to the collection view method but you are not reloading in main Queue. Try to do it immediately after you get the data source.
Your Cell for the row at index path will look like this :
guard let cell = self.tableview.dequeueReusableCell(withIdentifier: "cell") as! PartOfLookTableViewCell else {
return UITableViewCell()
}
let oneRecord = looksArray[indexPath.row]
cell.configureCell(for record : oneRecord with looks : 1)
return cell
and Now in the cell, you will have collection view outlet, where you will implement a collection view data source method and there you download your images asynchronously.
Cell Class will look like this :
class PartOfLookTableViewCell: UITableViewCell {
#IBOutlet weak var collectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
collectionView.delegate = self
collectionView.dataSource = self
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func configureCell(for record : Record , with looks : Int) {
// Here reload your collection view
// This collection view will be specific to the cell.
collectionView.reloadData()
}
}
extension PartOfLookTableViewCell : UICollectionViewDelegate , UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//return array
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// Asyncronously download images
}
}
This is how you can achieve your requirements without using any tags. Please let me know if you have any Queries in it.
I have a collectionView used for scrolling between pages, inside of one of these full page cells I have another collectionView with cells. How do I perform a segue when one of the cells inside of the inner most collectionView is tapped.
You will need a delegate on the cells with collection view, that will need to be notified when a particular cell is selected:
protocol CollectionCellDelegate: class {
func selectedItem()
}
class CollectionCell: UITableViewCell {
weak var delegate: CollectionCellDelegate?
// ...
func collectionView(_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath) {
self.delegate?.selectedItem()
}
}
And in the TableViewController you will have to implement that delegate to perform segue from it (you have to perform segue from UIViewController subclass, but the UITableViewCell is not subclassing it, that's why you need the delegate pattern).
class TableViewController: UITableViewController, CollectionCellDelegate {
// ...
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CollectionCell", for: indexPath) as! CollectionCell
// set its delegate to self
cell.delegate = self
return cell
}
func selectedItem() {
// here you can perform segue
performSegue(withIdentifier: "mySegue", sender: self)
}
}
I haven't passed any argument to the delegate, but you can of course use arguments to pass any information that you need for the segue (e.g., the id of the collection cell that was selected, etc.).
When you tap on an item in collectionView, the following delegate method will be called (if you wired up everything properly) func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)... notice that the first param is collectionView itself.
Depending on how you set it up...
if you have two collectionViews within one UIViewController then you can do..
func collectionView(_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath) {
if collectionView == self.innerCollectionView {
// performSegue...
}
}
if you have two view controllers, one for outer and another for inner.. then you can create use delegate pattern to let the outer know which item got selected, and segue using that info.
I have one UICollectionView and a custom cell for it. The custom cell contains one UIImageView and a UILabel.
I want to change the background color of the UIImageView, when I tap that corresponding cell ( In didSelectItemAt indexPath method I want to access the custom cell properties). Is there any way to achieve this? Or should I need some alternate way?
Another problem I am getting that when I tap any item from that UICollectionView, multiple selection is happening. Means the reusable cells are also getting selected as well.
Can anybody help me?
Try This:
1. Custom UICollectionViewCell class:
import UIKit
class CustomCollectionViewCell: UICollectionViewCell
{
//MARK: Outlets
#IBOutlet weak var testImageView: UIImageView!
#IBOutlet weak var testLabel: UILabel!
//MARK: Lifecycle Methods
override func awakeFromNib()
{
self.testImageView.image = nil
self.testLabel.text = nil
}
override var isSelected: Bool{
willSet{
super.isSelected = newValue
if newValue
{
self.backgroundColor = UIColor.lightGray
}
else
{
self.backgroundColor = UIColor.groupTableViewBackground
}
}
}
}
2. Implement UICollectionViewDelegate Method as:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
{
collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .centeredVertically)
}
You can change the cell selection and default colors according to your requirement.
For your first problem
Refer to this link as it contains the explanation on how to access the cell and its properties. (It is for UITableView but the same thing can be done for a UICollectionView)
For your second problem
You will have to update your model on didSelectRow and in cellForRowAtIndexPath you will have to set the color of the cell based on that model.
Another solution for your second point would be to store the selected indexPath in an
array and in your cellForRowAtIndexPath check if that indexPath
is present in that array and set its color appropriately. Example:
var array = [Int]()
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
//update model or
array.append(indexPath.item)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//check model or
if(array.contains(indexPath.item)){
}else{
}
}
I have two collection views. They both use identical cell layouts but for other reasons they must be separate controllers. Currently when I make updates to cellForItemAtIndexPath: in one, I have to copy and paste the change to the other.
Is there a way for me to separate out this one method so I can make changes in one place and have them reflected in both controllers? One of the controllers is a UIViewController subclass. The other is a subclass of a custom UIViewController subclass.
You can make a Separate Data Source class then you can just link the collectionview data source to it.
Your data source will be like this
class CollectionViewDataSource: NSObject, UICollectionViewDataSource {
var dataArray:[YourObjects]?
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataArray!.count ?? 0
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("YourCellIdentifier", forIndexPath: indexPath) as! UICollectionViewCell
return cell
}
}
And you can cell it in your controller like this
lazy var collectionViewDataSource: CollectionViewDataSource = {
return CollectionViewDataSource()
}()
#IBOutlet weak var collectionView: UICollectionView! {
didSet{
collectionViewDataSource.dataArray = //Your array
collectionView.dataSource = collectionViewDataSource
}
You can achieve this
Suppose there are 2 viewcontroller vc1 and vc2 and 2 collectionview cv1 and cv2
Make a separate class
CollectionDelegate cD
now set datasource of both collectionview to this newly made CollectionDelegate
like
cv1.dataSource = cD
cv2.datasource = cD
Implement you cellForItemAtIndexPatha and other data source method in CollectionDelegate class