MMDrawerController can't close drawer - ios

I'm trying to use MMDrawerController in my application, but I can't get the side drawer to close with gestures on the center view. I've used MMDrawerController somewhere else in my app with great success, but can't figure out why its not working in this case.
The top-level View Controller is a UINavigationController, whose default view controller is the MasterViewController (source below). This class extends MMDrawerController and configures the view for what I want (center and right, close gestures, max width). The center view has a button that opens the drawer. Once the drawer is open I can't close it with gestures on the center view. I added a button to the drawer and it can close the drawer programmatically, but I need to be able to tab/pan on the center view.
class MasterViewController: MMDrawerController {
override func viewDidLoad() {
let centerView = storyboard!.instantiateViewControllerWithIdentifier("CenterControllerName") as? CenterControllerType
super.setCenterViewController(centerView, withCloseAnimation: false, completion: nil)
let drawer = storyboard!.instantiateViewControllerWithIdentifier("Drawer") as? DrawerType
super.rightDrawerViewController = drawer
super.setMaximumRightDrawerWidth(200, animated: true, completion: nil)
super.closeDrawerGestureModeMask = MMCloseDrawerGestureMode.PanningCenterView | MMCloseDrawerGestureMode.TapCenterView
}
}
The function to open the drawer:
#IBAction func drawerButtonPressed(sender: AnyObject) {
drawer?.openDrawerSide(MMDrawerSide.Right, animated: true, completion: nil)
}

I was able to work around this by placing a ContainerView as the only object in my view and then configuring the MMDrawerContainer from my ViewController. It doesn't seem like the right answer but everything looks and functions right from the user's perspective.

Ok so I run into the same issue, and I am almost sure that it comes from this:
Ok, the VC1 (with the star) is our application Home, the VC2 is the left drawer, and the VC3 is the DrawerController.
During a long time I tried to put gesture functions in the VC1 and VC2, but only opening in the VC1, and closing in the VC2 would work.
The functions I used in VC1:
let rightSwipe = UISwipeGestureRecognizer(target: self, action: Selector("showDrawer:"))
rightSwipe.direction = .Right
view.addGestureRecognizer(rightSwipe)
...
func showDrawer(sender: UISwipeGestureRecognizer) {
if let m = mmdc {
if !m.isLeftDrawerOpen() {
m.toggleDrawerSide(MMDrawerSide.Left, animated: true, completion: nil)
}
}
}
And the same one in VC2 but with the LeftSwipe and closeDrawer.
The solution is tu put both of these functions and gestures recognizer in the VC3 (DrawerController).
The problem is coming from the fact that your gestures are defined for a given VC, but when you open the drawer, it changes the current VC by a new one, and the previous VC is just displayed but can't be interactif with. By putting things in the parentVC of VC1/VC2 it solves the problem.

Related

Navigation bar not appearing after delegation setup

I have a UILabel in my ViewController that has a NavigationController (let's say view controller A) with a tap gesture recognizer attached to the label. When the label is tapped another view appears (let's call it B). The user picks some text in B and the view dismisses back to A with the label text updated with the selection. So I created a delegation between A and B to get the selection. The problem is that I do not see the NavigationBar when B appears. Is there a way to fix this?
ViewController A
#IBOutlet weak var sectionName: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let sectionLabelTap = UITapGestureRecognizer(target: self, action: #selector(labelTapped(_:)))
sectionName.isUserInteractionEnabled = true
sectionName.addGestureRecognizer(sectionLabelTap)
}
#objc func labelTapped(_ sender: UITapGestureRecognizer) {
let sectionNameVC = storyboard?.instantiateViewController(withIdentifier: "SectionName") as! SectionNameTableViewController
sectionNameVC.selectionNameDelegate = self
sectionNameVC.userData = userData
present(sectionNameVC, animated: true, completion: nil)
}
In order to display the Navigation bar the UIViewController needs to have a UINavigationController.
You can add that sectionNameVC ViewController into a UINavigationController to persevere the present animation.
In that case your code might look something like this:
#objc func labelTapped(_ sender: UITapGestureRecognizer) {
let sectionNameVC = storyboard?.instantiateViewController(withIdentifier: "SectionName") as! SectionNameTableViewController
sectionNameVC.selectionNameDelegate = self
sectionNameVC.userData = userData
let naviagtionController = UINavigationController(rootViewController: sectionNameVC)
present(naviagtionController, animated: true, completion: nil)
}
Or you can simply call pushViewController on the View Controller A's navigation Controller, like this:
self.navigationController?.pushViewController(sectionNameVC, animated: true)
This will add sectionNameVC into the View Controller A's navigation Controller stack. In this case the transition animation will be different, the sectionNameVC will come from your right.
You are missing the concept between "Presenting" View Controller & "Navigating" the View Controller. You will get the answer, once you understood the concept. Here, it is..
When you are presenting the ViewController, you are completely replacing the stack container to the new view controller.
STACK holds the addresses of the ViewControllers you push or pop via navigating.
e.g:
present(sectionNameVC, animated: true, completion: nil)
On the other hand, if you are navigating to other view controller by pushing it. In this case, you can go back to previous controller by simple popping the ViewController address from stack.
e.g:
self.navigationController?.pushViewController(sectionNameVC, animated: true)
self.navigationController?.popViewController(animated: true)
So, If you navigate then, only you will get navigation Bar.
Now, in your case, you are presenting the ViewController and hence, navigation bar is not showing.

Swipe right gesture with 'finger control'

I'm currently learning the very basics of Swift, having just finished the iOS Application Development Tutorial from the Apple Developer website.
I am wanting to create a swipe gesture that's very similar to most popular applications that are out at the moment. Swipe right to reveal the content from another view from the left, essentially a 'back' button but with a gesture instead.
Here is an image I found of the gesture I want to create:
The tutorial from Apple explains how the cancel button works in the navigation controller:
//MARK: Navigation
#IBAction func cancel(_ sender: UIBarButtonItem) {
// Depending on style of presentation (modal or push presentation), this view controller needs to be dismissed in two different ways.
let isPresentingInAddMealMode = presentingViewController is UINavigationController
if isPresentingInAddMealMode {
dismiss(animated: true, completion: nil)
}
else if let owningNavigationController = navigationController {
owningNavigationController.popViewController(animated: true)
}
else {
fatalError("The MealViewController is not inside a navigation controller.")
}
}
And so (referencing the tutorial from Apple) I placed a Swipe Gesture Recogniser object on the 'New Meal' controller and created my own 'rightSwipe' function that does the exact same thing:
#IBAction func rightSwipe(_ sender: UISwipeGestureRecognizer) {
// Depending on style of presentation (modal or push presentation), this view controller needs to be dismissed in two different ways.
let isPresentingInAddMealMode = presentingViewController is UINavigationController
if isPresentingInAddMealMode {
dismiss(animated: true, completion: nil)
}
else if let owningNavigationController = navigationController {
owningNavigationController.popViewController(animated: true)
}
else {
fatalError("The MealViewController is not inside a navigation controller.")
}
}
This works great, the application at the moment is clever enough to recognise your 'entry' to the view (whether it's via tapping on an existing item on the list or via the 'create a new item' view).
Is it now possible to control the animation with your finger instead of executing the entire thing as soon as the screen has been swiped to the right? This is a little difficult to explain...
As soon as I swipe right, the animation gets executed and the current view is dismissed. I have no control over the animation until it is over. I'm not able to animate the 'dismissal' with my finger as I drag it across the screen.
The scenario I want to explain is very similar to how switching pages on the home screen of iOS works.
I want to be able to 'hold' the screen on the left, be able to drag it to the right, while holding down, and should be able to see the previous view as I do it, then execute the actual transition of views as soon as I let go. I hope you understand what I mean?
How can this be achieved? Is there anything currently built in that allows me to do this? Would anyone be able to show me how this can be done?
I'm currently working with Swift 3 and using the Xcode9-beta IDE

Back button hidden in navigation bar (but still works)

I have read about similar problems where the problem was caused by having multiple navigation controllers, but I only have one. This is my navigation flow.
VC = UIViewController, NC = UINavigationController
VC1 -modal-> NC -root-> VC2 -show-> VC3
VC1 is not embedded in a navigation controller, I'm starting that modal segue using performSegueWithIdentifier:sender:.
VC2 then is using a show segue to present VC3, which is the one where the back button is not visible. It still works though. But, it does appear if I exit to the home screen and then enters the app again, as shown here:
https://gfycat.com/VelvetyThisHamster.
Any ideas why this is happening?
edit: To make things clear: I want the button both visible and functioning (it's not that it's working that's the problem, but that it's hidden)
EDIT 2:
If I change my navigation flow to this
NC -root-> VC2 -show-> VC3
then the back button works as intended. So the question is, how can I add a regular view controller without a navigation controller before the first navigation controller? I want it before because VC1 should not have a navigation bar and VC2 should be presented modally.
try this
Hidden
override func viewWillAppear(animated: Bool)
{
super.viewWillAppear(animated)
//use this
self.navigationItem.setHidesBackButton(true, animated: false)
//else use this
self.navigationItem.leftBarButtonItem = nil
}
Show
override func viewWillAppear(animated: Bool)
{
super.viewWillAppear(animated)
//use this
self.navigationItem.setHidesBackButton(false, animated: false)
//else
self.navigationController.navigationItem.backBarButtonItem.enabled = TRUE
}
Update
override func viewWillAppear(animated: Bool)
{
super.viewWillAppear(animated)
//use this
self.navigationItem.setHidesBackButton(false, animated: false)
//else
let backButton = UIBarButtonItem(title: "leftbutton", style: UIBarButtonItemStyle.Plain, target: self, action: "buttonMethod")
self.navigationItem.leftBarButtonItem = backButton
}
func buttonMethod() {
print("Perform action")
}
I think I found the source of the problem, so I'll post it here in case someone else runs into the same problem.
The modal presentation between VC1 and NC was made from a background queue (by calling performSegueWithIdentifier:sender: in the completion handler of an NSURLSessionDataTask to be precise). By dispatching that line of code to the main queue the problem seems to disappear.
Turn out, I had NavigationBar tint color set to "Clear". Once I changed it, the back button appeared.

Transition from Modal View to Next VC in a TabBar and NavBar

I'm using Swift 2 and xcode 7.1.1.
My app is a tabbar + navigationbar based application.
What I'd like to do:
From my first viewcontroller (CollectionVC) I have a collectionview of images(tabbar at bottom and navbar at top). When you select an image, I transition programmatically to a modalviewcontroller (ImageZoomVC) that allows them to zoom on the image (no tabbar or navbar). From the ImageZoomVC I want to transition programmatically to the UserProfileVC. The UserProfileVC should have the tabbar and navbar like the first view. The navbars back button should also take us back to the ImageZoomVC.
This workflow is similar to facebook. When you select an image, you go to a black screen with just that image and some more info. You can click on anyone tagged in the image and it will push their profile onscreen with the tabbar and navbar back in place.
The Problem:
Once in the ImageZoomVC, I can't transition to the UserProfileVC without losing the tabbar and navbar. I've been able to add a navbar programmatically but there is no back button, and setting a back button hasn't worked. Also, there is no tabbar.
Code:
From my CollectionVC, I transition to the ImageZoomVC from my collectioncell like this:
#IBAction func PhotoButtonPressed(sender: UIButton) {
let imageZoom = ImageZoomVC()
imageZoom.showFrom(self.parentView!)
}
Here is the showFrom function that presents the ImageZoomVC modally. This code is inside the ImageZoomVC:
public func showFrom(viewController: UIViewController) {
//Some stuff here, edited for length
viewController.presentViewController(self, animated: false) {
UIView.animateWithDuration(ImageZoomVC.TransitionAnimationDuration,
delay: 0,
options: [.BeginFromCurrentState, .CurveEaseInOut],
animations: {
[weak self] in
self?.collectionView.alpha = 1
self?.collectionView.transform = CGAffineTransformIdentity
},
completion: {
[weak self] finished in
self?.view.userInteractionEnabled = finished
}
)
}
}
This is the code I'm attempting to use to transition to the UserProfileVC with navbar and tabbar. This doesn't work. It will present the VC, but there is no tabbar or back button.
func userSelected (sender: UIButton) {
let vc = self.presentingViewController?.storyboard?.instantiateViewControllerWithIdentifier("User Profile") as! UserProfileVC
let newNav = UINavigationController(rootViewController: vc)
newNav.navigationBar.barTintColor = UIColor().specialPurple()
newNav.navigationBar.translucent = false
self.presentViewController(newNav, animated: true, completion: nil)
}
A couple notes: The ImageZoomVC doesn't exist in storyboard. It is called and instantiated programmatically.
The ImageZoomVC is based off Agrume from Github found here:
https://github.com/JanGorman/Agrume
I'd like to push the UserProfileVC like facebook does. This current code presents it from the bottom. The code pushViewController is not recognized here in xCode.
Let me know what you think. All thoughts are welcome. Thanks.

how to add gesture recognizer to ViewController and to its Children?

I am making app like in Euro Sport. My rootviewController is pageViewController which has 3 VCs. Swiping left and right you can change the VC. Next, I added sidebarmenu. I want to add gesture recognizer to the whole rootViewController. This is how I am adding gesture:
self.exitPanGesture = UIPanGestureRecognizer()
self.exitPanGesture.addTarget(self, action:"handleOffstagePan:")
self.sourceViewController.view.addGestureRecognizer(self.exitPanGesture)
self.sourceViewController.navigationController?.view.addGestureRecognizer(self.exitPanGesture)
When I drag rootviewController tapping on navigation bar it works. But the other parts like segmentcontrol, and pageContent doesnt work.
I am setting sourceViewController here:
func resetToMainPage(index: Int!) {
/* Getting the page View controller */
mainPageViewController = self.storyboard?.instantiateViewControllerWithIdentifier("MainPageViewController") as UIPageViewController
self.mainPageViewController.dataSource = self
self.mainPageViewController.delegate = self
pageContentViewController = self.viewControllerAtIndex(index)
// self.transtionManger.sourceViewController = pageContentViewController // adding swipe to the pageContentViewControlle in order to close menu
self.transtionManger.sourceViewController = mainPageViewController
self.mainPageViewController.setViewControllers([pageContentViewController!], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: nil)
self.mainPageViewController.view.frame = CGRectMake(0, 102, self.view.frame.width, self.view.frame.height)
self.addChildViewController(mainPageViewController)
self.view.addSubview(mainPageViewController.view)
self.mainPageViewController.didMoveToParentViewController(self)
}
So, My question is how to add gesture recognizer to the whole rootViewController, including navbar, segmentcontrol, pageviewcontrol?
A gesture recognizer can only be attached to one view. So the lines below mean that only navigationController?.view is getting the gesture added.
self.sourceViewController.view.addGestureRecognizer(self.exitPanGesture)
self.sourceViewController.navigationController?.view.addGestureRecognizer(self.exitPanGesture)
You can just duplicate the gesture recognizer for each view you want to have it on and then add them all that way.
self.exitPanGesture1 = UIPanGestureRecognizer()
self.exitPanGesture1.addTarget(self, action:"handleOffstagePan:")
self.sourceViewController.view.addGestureRecognizer(self.exitPanGesture1)
self.exitPanGesture2 = UIPanGestureRecognizer()
self.exitPanGesture2.addTarget(self, action:"handleOffstagePan:")
self.sourceViewController.navigationController?.view.addGestureRecognizer(self.exitPanGesture2)
guys, I solved my problem but I got another one. In my case , I created exitGestureRecognizer. I wanted to add this to whole viewcontroller views. So, here is my code:
for singleView in self.sourceViewController.view.subviews {
singleView.addGestureRecognizer(exitPanGesture)
singleView.navigationController??.view.addGestureRecognizer(exitPanGesture)
}
For some reason, recognizer on navBar.view doesnt work. If I write code in this way:
for singleView in self.sourceViewController.view.subviews {
singleView.addGestureRecognizer(exitPanGesture)
singleView.navigationController??.view.addGestureRecognizer(exitPanGesture)
}
self.sourceViewController.navigationController?.view.addGestureRecognizer(self.exitPanGesture)
Only nav bar gestures work and subview gestures dont work. If I change the order of this code. Nav bar gestures dont work but subviews gestures work. How can I add gestures to both views?

Resources