Active UI navigation on the view under popover - ios

I have an UI where the SCNView is in the background, and a WKWebView is in the foreground presented as a .popover. Views are controlled by separate view controllers. The WKWebView appears when user presses the bell button (see the attached screen). SCNView has standard camera control enabled.
Currently when the WKWebView popover appears the SCNView becomes unresponsive. Tap gesture outside the WKWebView closes it, other gestures are ignored, so user cannot control SCNView camera while WKWebView popover is visible. How can I make the SCNView responsive while WKWebVIew popover is present? How can I dismiss the WKWebView only when the bell button is pressed?
Code used below:
class MainVC: UIViewController, UIPopoverPresentationControllerDelegate {
#IBOutlet weak var scnView: SCNView!
#IBOutlet weak var bellBtn: UIButton!
var myWebViewVC: MyWebViewVC!
override func viewDidLoad() {
super.viewDidLoad()
let scene = SCNScene(named: "art.scnassets/DemoScene.scn")!
let scnView = sceneView
scnView!.scene = scene
scnView!.allowsCameraControl = true
}
#IBAction func onBellBtnPressed(_ sender: UIButton) {
myWebViewVC.modalPresentationStyle = .popover
myWebViewVC.popoverPresentationController?.delegate = self
present(myWebViewVC, animated: true, completion: nil)
myWebViewVC.popoverPresentationController?.sourceView = sender
myWebViewVC.popoverPresentationController?.sourceRect = sender.bounds
}
}
The MyWebViewVC takes care only of the size of the view. No additional custom modifications are implemented in the file.

Ok. So the solution is mainly connected with the popoverPresentationController parameter of the view controller. Here is documentation. To enable control on the view beneath the view presented as a .popover you need to inform it about the views which are going to be responsive when popover is present. The order of the passing is top to bottom. The code below and the passThrough array make it work.
class MainVC: UIViewController, UIPopoverPresentationControllerDelegate {
#IBOutlet weak var scnView: SCNView!
#IBOutlet weak var bellBtn: UIButton!
#IBOutlet weak var dotBtn: UIButton!
var myWebViewVC: MyWebViewVC!
override func viewDidLoad() {
super.viewDidLoad()
let scene = SCNScene(named: "art.scnassets/DemoScene.scn")!
scnView!.scene = scene
scnView!.allowsCameraControl = true
}
#IBAction func onBellBtnPressed(_ sender: UIButton) {
activeUiNavigationUnderPopover()
}
func activeUiNavigationUnderPopover () {
myWebViewVC.modalPresentationStyle = .popover
myWebViewVC.popoverPresentationController?.delegate = self
if let pop = myWebViewVC.popoverPresentationController {
var passthroughViews: [AnyObject]?
passthroughViews = [dotBtn, scnView]
pop.passthroughViews = NSMutableArray(array: passthroughViews!) as? [UIView]
pop.permittedArrowDirections = .any
pop.delegate = self
}
present(myWebViewVC, animated: true, completion: nil)
myWebViewVC.popoverPresentationController?.sourceView = sender
myWebViewVC.popoverPresentationController?.sourceRect = sender.bounds
}
}

Related

Get UIActivityViewController (share) to show on iPad in the way it shows on iPhone?

I have a share button. When the share button is tapped, the view controller runs code like this:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBOutlet weak var popOverView: UIView!
#IBOutlet weak var shareButton: UIButton!
#IBAction func share()
{
let text = "Sharing."
if let url = URL(string: "https://www.apple.com")
{
let items = [text,url] as [Any]
let activityViewController = UIActivityViewController(activityItems: items, applicationActivities: nil)
if let popoverViewController = activityViewController.popoverPresentationController
{
popoverViewController.sourceView = popOverView
// popoverViewController.sourceRect = popOverView.frame
}
present(activityViewController, animated: true, completion: nil)
print(activityViewController.popoverPresentationController?.sourceView)
}
}
}
This works, but produces this:
when I want something like this, because the content to be shared won't be on this view controller:
How do I get the screen that I want?
I think you need to do this:
sharingViewController.modalPresentationStyle = .popover
before you set the sharingViewController.popoverPresentationController?.sourceView property. sharingViewController.popoverPresentationController is nil until you do this.
Unfortunately that is not possible on iPad.
Sorry for the bad news!
If you truly, truly wanted that look, you'd have to make a completely custom view controller that sits down there (ie, no connection to UIActivityViewController), of course that would be an unrealistic amount of work.

subview not clickable in UIViewController

I'm trying to embed a custom view in UIViewController. But when displayed, it's not clickable since it's out of the UIView frame.
viewDidLoad:
#IBOutlet var theVC_InVC_Test: UIView!
#IBOutlet var TableView: UITableView!
override func viewDidLoad() {
TableView.delegate = self
TableView.dataSource = self
func embed(_ viewController:UIViewController, inView view:UIView){
viewController.willMove(toParent: self)
viewController.view.frame = view.bounds
view.addSubview(viewController.view)
self.addChild(viewController)
viewController.didMove(toParent: self)
}
embed(sidemenutest1(), inView: theVC_InVC_Test)
}
sidemenutest1 UIViewController:
func popItOver(){
let PopOverVC = UIStoryboard(name:"Main",bundle: nil).instantiateViewController(withIdentifier: "CoinsPopUp") as! CoinsPopUpViewController
self.addChild(PopOverVC)
PopOverVC.view.frame = UIScreen.main.bounds
self.view.addSubview(PopOverVC.view)
PopOverVC.didMove(toParent: self)
}
#IBAction func storeAction(_ sender: Any) {
popItOver()
}
It's displayed fine, but it's not clickable... When I tried to click the subview buttons, the TableView is clicked and not the subview.
You shouldn't add the popover menu as a container view controller. It should be presented from the controller as a modal view controller instead and set its background view color to be the translucent gray color.

how to go back root view controller from recursive view controller(fourth)

class FourthViewController : UIViewController {
#IBOutlet weak var previousLabel: UILabel!
#IBOutlet weak var backButton: UIButton!
var delegate: FourthToFirst?
var label = ""
// MARK: - Lifecycle method
override func viewDidLoad() {
super.viewDidLoad()
previousLabel.text = label
let fourthViewController = storyboard?.instantiateViewController(withIdentifier: "FourthViewController") as? FourthViewController
navigationController?.pushViewController(fourthViewController!, animated: true)
}
// MARK: - IBAction
#IBAction func backToFirst(_ sender: Any) {
navigationController?.popToRootViewController(animated: true)
}
Actually I am in fourthviewController it was going recursively(i.e pushing the fourthViewcontroller again and again, nonstop)
if I pressed back button in the controller I have to go back(i.e firstviewcontroller)
problem is:
In my code it was going (i.e non stop)
I can't press the back button to go back(i.e firstviewcontroller)
navigationController?.popViewController(animated: true) instead of navigationController?.popToRootViewController(animated: true) could be what's you need mate. (Based on what's you just edited)

Cannot switch to another child view controller in container view

I have a main view controller, a container view and 2 child view controllers and i would like to be able to switch between the children (for example: when the application loads for the first time, i would like that the controller containing the MapView to be loaded and when i press the Search Bar found in the main view, the controller with the table to be loaded).
Here is my storyboard: https://i.stack.imgur.com/rDPMe.png
MainScreen.swift
class MainScreen: UIViewController {
#IBOutlet private weak var searchBar: UISearchBar!
#IBOutlet private weak var ContainerView: UIView!
//private var openSearchBar: Bool?
private var openMapView: Bool = true
private var openPlacesList: Bool = false
private var containerView: ContainerViewController!
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//let containerView = segue.destination as? ContainerViewController
if containerView == nil{
containerView = segue.destination as? ContainerViewController
}
if openMapView == true{
containerView!.moveToMapView()
}
else if openPlacesList == true{
containerView!.MoveToOpenPlaces()
}
}
}
//search bar delegate functions
extension MainScreen: UISearchBarDelegate{
//detects when text is entered
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
openPlacesList = true
openMapView = false
containerView!.MoveToOpenPlaces()
}
}
ContainerViewController.swift:
class ContainerViewController: UIViewController {
private var childViewController: UIViewController!
private var first: UIViewController?
private var sec: UIViewController?
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "MainToMap"{
first = segue.destination as! MapViewController
self.addChild(first!)
self.view.addSubview(first!.view)
self.didMove(toParent: self)
}else{
sec = segue.destination as! PlacesListController
}
if(first != nil && sec != nil){
interchange(first!,sec!)
}
}
func interchange(_ oldVc: UIViewController,_ newVc: UIViewController ){
oldVc.willMove(toParent: nil)
self.addChild(newVc)
self.view.addSubview(newVc.view)
self.transition(from: oldVc, to: newVc, duration: 2, options: UIView.AnimationOptions.transitionCrossDissolve, animations: {
newVc.view.alpha = 1
oldVc.view.alpha = 0
}, completion: { (complete) in
oldVc.view.removeFromSuperview()
oldVc.removeFromParent()
newVc.willMove(toParent: self)
})
}
func moveToMapView(){
performSegue(withIdentifier: "MainToMap", sender: nil)
}
func MoveToOpenPlaces(){
performSegue(withIdentifier: "MainToSearches", sender: nil)
}
}
The problem is that when I press the search bar, it calls the method interchange and then it just gives a SIGABRT 1 error. I tried this tutorial: https://developer.apple.com/library/archive/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html#//apple_ref/doc/uid/TP40007457-CH11-SW1 and many more but so far no luck. I am stucked here and don't know how i can solve this problem.
Stack: https://i.stack.imgur.com/Zqpm1.png
SIGABR 1 Error: https://i.stack.imgur.com/NBgEN.png
You appear to be trying to manually transition between child view controllers, but at the same time using segues (which do their own transitioning for you). Eliminate the segues (other than the initial embed segue, if you're using a storyboard with a "container view"), and just manually instantiate the child view controllers using their storyboard IDs. But don't use segues and then try to replace the child view controllers in prepare(for:sender:).
Also, when you use transition(from:to:duration:options:animations:completion:), you should not add the views the the view hierarchy yourself. That method does that for you (unless you use the showHideTransitionViews option, which tells the method that you're taking this over, something we don't need to do here). Likewise, when you use the transitionCrossDissolve option, you don't need to mess with alphas, either.
Thus, using the code snippet from that article you reference, you can do:
class FirstViewController: UIViewController {
#IBOutlet weak var containerView: UIView! // the view for the storyboard's "container view"
#IBOutlet weak var redButton: UIButton! // a button to transition to the "red" child view controller
#IBOutlet weak var blueButton: UIButton! // a button to transition to the "blue" child view controller
// tapped on "transition to red child view controller" button
#IBAction func didTapRedButton(_ sender: UIButton) {
redButton.isEnabled = false
blueButton.isEnabled = true
let oldVC = children.first!
let newVC = storyboard!.instantiateViewController(withIdentifier: "RedStoryboardID")
cycle(from: oldVC, to: newVC)
}
// tapped on "transition to blue child view controller" button
#IBAction func didTapBlueButton(_ sender: UIButton) {
blueButton.isEnabled = false
redButton.isEnabled = true
let oldVC = children.first!
let newVC = storyboard!.instantiateViewController(withIdentifier: "BlueStoryboardID")
cycle(from: oldVC, to: newVC)
}
func cycle(from oldVC: UIViewController, to newVC: UIViewController) {
// Prepare the two view controllers for the change.
oldVC.willMove(toParent: nil)
addChild(newVC)
// Get the final frame of the new view controller.
newVC.view.frame = containerView.bounds
// Queue up the transition animation.
transition(from: oldVC, to: newVC, duration: 0.25, options: .transitionCrossDissolve, animations: {
// this is intentionally blank; transitionCrossDissolve will do the work for us
}, completion: { finished in
oldVC.removeFromParent()
newVC.didMove(toParent: self)
})
}
func display(_ child: UIViewController) {
addChild(child)
child.view.frame = containerView.bounds
containerView.addSubview(child.view)
child.didMove(toParent: self)
}
func hide(_ child: UIViewController) {
child.willMove(toParent: nil)
child.view.removeFromSuperview()
child.removeFromParent()
}
}
That yields:

Custom View Label Won't Change

My view contain a button which bring a custom view which contain a ContainerView and it has a label. When I bring the custom view to the front I get the label text empty. So please where would be my issue?
View Controller Code:
#IBAction func PushAlert(sender: UIButton) {
let alert = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("alertViewController") as! AlertViewController
var alertText = AlertTextViewController()
alertText.lblText = "DONE"
alert.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
alert.modalTransitionStyle = UIModalTransitionStyle.CrossDissolve
self.presentViewController(alert, animated: true, completion: nil)
}
class AlertTextViewController: UIViewController {
#IBOutlet weak var lblAlertText: UILabel!
var lblText = ""
override func viewDidLoad() {
super.viewDidLoad()
lblAlertText.text = lblText
}
}
I have created a link for the source code which will be much easier to understand source code
What about var lblText: String? in your AlertTextViewController.
Maybe it's overriden by your declaration (for some reason I wouldn't be able to explain)?
Or wait, I'm confused by
var alertText = AlertTextViewController()
as you are presenting creating and presenting the ViewController alert. How is alertText and alert related?
Edit:
class AlertViewController: UIViewController {
#IBOutlet weak var container: UIView!
override func viewDidLoad() {
super.viewDidLoad()
var alertText: AlertTextViewController = self.childViewControllers[0] as! AlertTextViewController
alertText.lblAlertText.text = "Test"
// Do any additional setup after loading the view.
}
Do this in your AlertViewController, and it works. I don't know what your final purpose is though, and this might not be the most elegant solution. I've created an outlet, the containerView to your class.
I think you may have a order of events problem. Try setting lblAlertText.text in viewWillAppear instead of viewDidLoad.

Resources