I have a collection view and when a cell is selected it presents a popover view showing more information about that cell.
I would like to allow the user to click another cell and then have the popover view change to showing that cell's information without having to close the popover. If the user were to click somewhere on the parent view that isn't a cell then the popover should close. But, I would like the user to still be able to scroll the collection view without closing the popover.
How can that be done?
According to Apple :
When a popover is active, interactions with other views are normally disabled until the popover is dismissed. Assigning an array of views to this property allows taps outside of the popover to be handled by the corresponding views.
Then you can use the passthroughViews
in the following way :
CollectionViewController
import UIKit
let reuseIdentifier = "Cell"
class CollectionViewController: UICollectionViewController {
var popoverViewController : PopoverViewController?
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
//#warning Incomplete method implementation -- Return the number of sections
return 1
}
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//#warning Incomplete method implementation -- Return the number of items in the section
return 15
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! CollectionViewCell
cell.labelInfo.text = "Cell \(indexPath.row)"
return cell
}
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
println("tapped")
if let popover = self.popoverViewController {
var cell = self.collectionView!.cellForItemAtIndexPath(indexPath) as! CollectionViewCell
popover.labelPop.text = cell.labelInfo.text
}
else {
self.popoverViewController = self.storyboard?.instantiateViewControllerWithIdentifier("PopoverViewController") as? PopoverViewController
var cell = self.collectionView!.cellForItemAtIndexPath(indexPath) as! CollectionViewCell
var t = self.popoverViewController!.view
self.popoverViewController!.labelPop.text = cell.labelInfo.text
self.popoverViewController!.modalPresentationStyle = .Popover
var popover = self.popoverViewController!.popoverPresentationController
popover?.passthroughViews = [self.view]
popover?.sourceRect = CGRect(x: 250, y: 500, width: 0, height: 0)
self.popoverViewController!.preferredContentSize = CGSizeMake(250, 419)
popover!.sourceView = self.view
self.presentViewController(self.popoverViewController!, animated: true, completion: nil)
}
}
}
The above code is the CollectionViewController
to handle the UICollectionViewController
and all its delegates.
CollectionViewCell
class CollectionViewCell: UICollectionViewCell {
@IBOutlet weak var labelInfo: UILabel!
}
The custom cell with just a UILabel
inside.
PopoverViewController
class PopoverViewController: UIViewController {
@IBOutlet var labelPop: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
And finally the PopoverViewController
to show in form of .Popover
.
There are some observations in answer I would like to point out :
I set a reference to the class PopoverViewController
to keep it through the life cycle and pass it data when it remains open yet.
The line var t = self.popoverViewController!.view
it's necessary because if not the @IBOutlet
inside the PopoverViewController
was not init until it's presented, there could be other ways to do it.
I present the popover in the middle of the screen to handle the tap in several cell and test it the scroll too, you can display it in any position you want.
In the views to allow when the popover is opened , I set the self.view
, but in this way you need to dismiss it for you own, because it never is dismissed when you make taps in the view, you can put any view you want instead.
Any trouble you have with the solution I can share it the project on Github.
I hope this help you
What you are looking for is the passthroughViews property of the popover.
However, if you open the popover as a result of tapping a cell, I don't see how scrolling the collectionView will make sense. Don't you open the popover with the arrow pointing to your cell? Scrolling the view will make the presenting cell to move away...
You can use property of UIViewController 'modalInPopover' to enable touches outside the popover boundary. Just write the line given below in your view controller which you are presenting using popover controller.
self.modalInPopover = false;
where self is kind of UIViewController.
I have attached a screenshot for the same.
In swift the line will remain same
self.modalInPopover = false
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With