Hi I have a popover view that is showing an array. I am wondering if there is a way that I could somehow segue back which item's in the array are selected.
#IBAction func popOverButton(_ sender: UIButton)
{
let controller = TableViewController()
//This is just a regular tableViewController nothing special
controller.modalPresentationStyle = .popover
// configure the Popover presentation controller
let popController: UIPopoverPresentationController? = controller.popoverPresentationController
popController?.permittedArrowDirections = [.down]
popController?.delegate = self
popController?.sourceView = sender
popController?.sourceRect = sender.bounds
popController?.backgroundColor = .white
self.parent?.present(controller, animated: true, completion: { })
}
Here is what it looks like
Any help is appreciated thanks
Easiest way is to create a delegate and when a cell is selected pass the selection back to the presenting view controller. Then setting up the UITableViewDelegate method didSelectRowAtIndexPath to call the delegate method. Something like this:
#protocol PopoverOptionSelectionDelegate {
func itemSelected(item:String);
}
Implement the method in your presenting VC
class PresnetingViewController, PopoverOptionSelectionDelegate {
#IBAction func popOverButton(_ sender: UIButton) {
let controller = TableViewController()
controller.delegate = self //----Important---//
//This is just a regular tableViewController nothing special
controller.modalPresentationStyle = .popover
// configure the Popover presentation controller
let popController: UIPopoverPresentationController? =
controller.popoverPresentationController
popController?.permittedArrowDirections = [.down]
popController?.delegate = self
popController?.sourceView = sender
popController?.sourceRect = sender.bounds
popController?.backgroundColor = .white
self.parent?.present(controller, animated: true, completion: { })
}
func itemSelected(item:String) {
//DISMISS YOUR POPOVER MAYBE AND DO SOMETHING WITH "ITEM" HERE
}
}
class TableViewController,UITableViewDelegate {
weak var delegate:PopoverOptionSelectionDelegate?
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
delegate?.itemSelected(self.itemsArray[indexPath.row])
}
}
Related
I have a form the user is filling out, and I present a modal with images for them to choose from. I am attempting to set a UIImage in the original controller from the modal, but the problem is it's nil.
What is the best way to set it? The viewDidLoad doesn't seem to trigger on dismissal of a modal, which is how I'm getting rid of it, and neither does the viewWillAppear. When can I set the image?
My Code right now:
//Collection view choosing deal background
#IBOutlet var collectionView: UICollectionView!
var chosenNumber: Int?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
if(self.restorationIdentifier == "NewDeal") {
if(chosenNumber != nil) {
newDealBackgroundImage.image = UIImage(named: "food_\(chosenNumber!)")
}
}
}
extension BusinessOwnerVC: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.deselectItem(at: indexPath, animated: true)
//self.newDealBackgroundImage.image = UIImage(named: "food_\(indexPath.row + 1)")!
chosenNumber = indexPath.row + 1
self.dismiss(animated: true, completion: nil)
}
}
If your presentation style is fullScreen … then your willAppear will be called
navigationController.modalPresentationStyle = .fullScreen
but if you dont want full screen presentation Make yourself the presentation controller's delegate and override presentationControllerDidDismiss(_:).
class ViewController: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("viewWillAppear")
}
#IBAction func show(_ sender: Any) {
let newViewController = NewViewController()
//set delegate of UIAdaptivePresentationControllerDelegate to self
newViewController.presentationController?.delegate = self
present(newViewController, animated: true, completion: nil)
}
}
extension UIViewController: UIAdaptivePresentationControllerDelegate {
public func presentationControllerDidDismiss( _ presentationController: UIPresentationController) {
if #available(iOS 13, *) {
//Call viewWillAppear only in iOS 13
viewWillAppear(true)
}
}
}
After much experimentation, here's what I found works for me. All I wanted was to access and update a view controller (of the same kind) under a modal I am presenting. Turns out my previous VC was still active, so all I had to do was pass a reference to that VC into the modal, and then I could change its properties.
let modal = UIStoryboard.init(name: "BusinessOwner", bundle: nil).instantiateViewController(withIdentifier: "DealBackgroundSelection") as! BusinessOwnerVC
modal.newDealView = self // This is a weak var of BusinessOwnerVC? declared in the view controller itself
present(modal, animated: true, completion: nil)
And then when I was ready to dismiss that modal:
self.newDealView!.updateDealImage(number: indexPath.row + 1)
updateDealImage was just a function I created to handle all the update. And that works for me.
I'm trying to do something like this:
This is what I have now:
How I'm doing this now:
I have MainViewController with input field: NSTextField.
Using controlTextDidChange I'm checking if input field contains # character.
If yes - I'm opening popover using PopoverViewController.
In the PopoverViewController I have NSTableView that displays a list of available tags.
By clicking on the row it should add selected tag to the input fields and close the popover.
So here I even have to implement 2 way of communication between 2 view controllers.
Questions:
I feel that I'm doing something wrong. The logic of this tags-popover looks too complicated for me. Maybe an easier solution exists, but I just don't know how to do this.
What the best way to display the list of available tags in NSTextField? Should I use a popover with another view controller?
How to communicate best in this case between 2 different view controllers? (I have to send InputField value to PopoverViewController, filter results there and display them. Then, I have to send back to MainViewController selected tag)
My code:
Here is some parts of my code if you want to see it in more details:
MainViewController:
class ViewController: NSViewController, NSTextFieldDelegate {
#IBOutlet weak var InputField: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
table.delegate = self
table.dataSource = self
InputField.delegate = self
}
func controlTextDidChange(_ sender: Notification) {
if InputField.stringValue.contains("#") {
let controller = ToolTipVC.Controller()
let popover = NSPopover()
popover.contentViewController = controller
popover.behavior = .transient
popover.animates = true
popover.show(relativeTo: InputField.bounds, of: InputField!, preferredEdge: NSRectEdge.maxY)
}
}
ToolTipViewController:
import Cocoa
import EventKit
class ToolTipVC: NSViewController, NSTableViewDataSource, NSTableViewDelegate {
#IBOutlet weak var ToolTipTable: NSTableView!
override func viewDidLoad() {
super.viewDidLoad()
ToolTipTable.delegate = self
ToolTipTable.dataSource = self
}
func numberOfRows(in tableView: NSTableView) -> Int {
return ReminderLists.count
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
guard let cell = tableView.makeView(withIdentifier: tableColumn!.identifier, owner: self) as? NSTableCellView else { return nil }
cell.textField?.stringValue = "Row #\(row): " + ReminderLists[row].title
return cell
}
}
extension ToolTipVC {
static func Controller() -> ToolTipVC {
let storyboard = NSStoryboard(name: "Main", bundle: nil)
let identifier = NSStoryboard.SceneIdentifier("ToolTipId")
guard let viewcontroller = storyboard.instantiateController(withIdentifier: identifier) as? ToolTipVC else {
fatalError("Why cant i find viewcontroller? - Check Main.storyboard")
}
return viewcontroller
}
}
I appreciate your feedback and advises.
Thank you in advance!
P.S.: I'm not a developer, I'm a Product Manager. This is my pet-project, so I know that my code is awful and has a lot of mistakes.
Please, don't judge me hard :)
At first glance it looks like when you call this line:
popover.show(relativeTo: InputField.bounds, of: InputField!, preferredEdge: NSRectEdge.maxY)
preferredEdge is set to NSRectEdge.maxY
Try changing this from Y to X
popover.show(relativeTo: InputField.bounds, of: InputField!, preferredEdge: NSRectEdge.maxX)
Is there a reason you are usin NSPopover?
If that doesnt work try this:
let controller = MyPopViewController()
controller.modalPresentationStyle = UIModalPresentationStyle.popover
let popController = controller.popoverPresentationController
popController?.permittedArrowDirections = .any
popController?.delegate = self
popController?.sourceRect = //set the frame here
popController?.sourceView = //set the source view here
self.present(controller, animated: true, completion: nil)
Here is another approach, this will centre the pop over over a button. Which is what you are trying to do i am assuming with no up arrow? Is that correct?
So you can hit the filters button on the right side whihc you have and this pop over will appear centred.
#IBAction func buttonTap(sender: UIButton) {
// get a reference to the view controller for the popover
let popController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "popoverId")
// set the presentation style
popController.modalPresentationStyle = UIModalPresentationStyle.popover
// set up the popover presentation controller
popController.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection.up
popController.popoverPresentationController?.delegate = self
popController.popoverPresentationController?.sourceView = sender // button
popController.popoverPresentationController?.sourceRect = sender.bounds
// present the popover
self.present(popController, animated: true, completion: nil)
}
I have this strange problem with iOS 13 and its new sheet cards style modal presentation.
From ViewController1 I modal present ViewController2 embedded in a NavigationController, and everything works fine.
From ViewController2, I then modal present ViewController3 embedded in a NavigationController, and I get the Right Bar Button offset.
Here is a video of the problem: does anybody have a fix?
Main View Controller
import UIKit
let vc1identifier = "vc1identifier"
let vc2identifier = "vc2identifier"
class ViewController: UIViewController {
#IBAction func tap1(_ sender: UIButton) {
if let navigation = self.storyboard?.instantiateViewController(withIdentifier: vc1identifier) as? UINavigationController,
let nextVC = navigation.contentViewController as? UnoViewController {
//self.navigationController?.pushViewController(nextVC, animated: true)
self.present(navigation, animated: true, completion: nil)
}
}
}
extension UIViewController {
var contentViewController: UIViewController {
if let navcon = self as? UINavigationController {
return navcon.visibleViewController!
} else {
return self
}
}
}
Second View Controller
import UIKit
class UnoViewController: UIViewController {
#IBOutlet weak var barButton: UIBarButtonItem!
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
barButton.title = "GotoVC2"
}
#IBAction func pressThis(_ sender: UIBarButtonItem) {
if let navigation = self.storyboard?.instantiateViewController(withIdentifier: vc2identifier) as? UINavigationController,
let nextVC = navigation.contentViewController as? DueViewController {
self.present(navigation, animated: true, completion: nil)
}
}
}
I came across the same issue.
Solution is easy, you just need to tell navigationbar it needs layout like this
override public func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if #available(iOS 13.0, *) {
navigationController?.navigationBar.setNeedsLayout()
}
}
I am having a little trouble presenting the UIImagePicker from a collectionViewCell. I know collectionViewCells do not act as the picker delegate by default so I did try to call a method from the UIViewController class operating the cell holding the imageView tapped. There are no errors showing in my console, but when I run the app and try to present the UIImagePickerController nothing happens and I receive the "Warning: Attempt to present on whose view is not in the window hierarchy!". I would like to present the UIImagePickerController when user taps on the profileImageView. Thanks in advance for help!
// LoginCell class holding the imageView to call the UIImagePickerController method from LoginController class
lazy var profileImageView: UIImageView = {
let imageView = UIImageView()
imageView.addGestureRecognizer(UITapGestureRecognizer(target:self, action: #selector(handleSelectProfileImage)))
imageView.isUserInteractionEnabled = true
return imageView
}()
var loginController: LoginController?
func handleSelectProfileImage() {
let loginController = LoginController()
loginController.showImagePicker(sendingVC: loginController)
}
// LoginController class as UIImagePickerController delegate
func showImagePicker(sendingVC: LoginController) {
let picker = UIImagePickerController()
picker.delegate = self
picker.allowsEditing = true
present(picker, animated: true, completion: nil)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let loginCell = collectionView.dequeueReusableCell(withReuseIdentifier: loginCellId, for: indexPath) as! LoginCell
loginCell.delegate = self
return loginCell
}
try this, in your cell:
func handleSelectProfileImage() {
guard let loginController = delegate as? LoginViewController else {
return
}
loginController.showImagePicker()
}
in your LoginController
func showImagePicker() {
let picker = UIImagePickerController()
picker.delegate = self
picker.allowsEditing = true
present(picker, animated: true, completion: nil)
}
For presenting popover I am following the below code.
func showPopOver() {
let secondStoryboard = UIStoryboard(name: "Second", bundle: nil)
viewObj = secondStoryboard.instantiateViewControllerWithIdentifier("ViewController") as! ViewController
viewObj.modalPresentationStyle = UIModalPresentationStyle.Popover
viewObj.preferredContentSize = CGSizeMake(400,500)
let popoverPresentationController = viewObj.popoverPresentationController
popoverPresentationController?.delegate = self
popoverPresentationController?.sourceView = self.view //walletButton
popoverPresentationController?.sourceRect = CGRectMake(0, button.frame.origin.y+100, 0, 0)
presentViewController(viewObj, animated: true, completion: nil)
}
//MARK:- UIPopoverPresentationControllerDelegate methods... starts
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle{
return UIModalPresentationStyle.None
}
func prepareForPopoverPresentation(popoverPresentationController: UIPopoverPresentationController) {
print("prepare for presentation")
}
func popoverPresentationControllerDidDismissPopover(popoverPresentationController: UIPopoverPresentationController) {
print("did dismiss")
}
func popoverPresentationControllerShouldDismissPopover(popoverPresentationController: UIPopoverPresentationController) -> Bool {
print("should dismiss")
return false
}
its working fine in normal view controller, but i need to show a popover view in custom tableview cell.
class flow like
|-UITableViewController
|-CustomCell:UITableViewCell
|-UIButton: button action-> here we need to show a popover with 3/4 frame value of the tableview frame.
whenever user tapped out of the popover view then dismiss the popover view.