I have a tabbed application with three tabs and I want to make the transition between them with a Swipe Gesture Recogniser.
I dragged and dropped one Swipe Gesture Recogniser from the Object Library to the first View and one to the third View. I added two on the second View so I can swipe both left and right.
I changed the Swipe to the Attribute Inspector so it will swipe right or left as needed
Using the Assistant editor I used Control+Drag to create Actions to the proper ViewController.swift files.
What else should I do so the swiping should work?
All of the guides I found online are in Objective-C. Does anyone know how to complete these Events in Swift?
You have to apply custom view controller transitions. Otherwise your tab transition will be neither animated (by default tab switches are without animation) nor interactive (you cannot control the speed with your gesture).
A good starting point is Colin Eberhardt's VC Transitions Library. It's in Objective-C but you can use it from Swift.
Just a warning: Custom view controller transitions are an immature part of iOS 7 or 8. If another view transition is initiated while a custom one is still running, the UI will more or less lock up. And it easily happens: user presses yet another tab before the transitions ends, your code switches tab and pushes a view controller at the same time, user manages to press a button during transition that opens another view controller etc.
EDIT: I have added a sample project to github and it fully works. Feel free to copy it or wok on it.
You don't need to add them in the story board. First add this code to your initializer (in most cases viewDidLoad):
var swipeGesture = UISwipeGestureRecognizer(target: self, action: "SwipeToNextViewController:")
swipeGesture.direction = UISwipeGestureRecognizerDirection.Left
view.addGestureRecognizer(swipeGesture)
var swipeGestureReverse = UISwipeGestureRecognizer(target: self, action: "SwipeToPreviousViewController:")
swipeGestureReverse.direction = UISwipeGestureRecognizerDirection.Right
view.addGestureRecognizer(swipeGestureReverse)
Now that your viewController has the gesture, SwipeToNextViewController() will be called if you swipe left, and SwipeToPreviousViewController() will be called when swiped Right.
Write the code for the two functions associated with the gestures:
func SwipeToNextViewController(gestureRecognizer:UISwipeGestureRecognizer)
{
performSegueWithIdentifier("next", sender: self)
}
func SwipeToPreviousViewController(gestureRecognizer:UISwipeGestureRecognizer)
{
performSegueWithIdentifier("previous", sender: self)
}
These two functions will be called when view has been swiped left or right. Add your code in it (in this case performSegue) and you can segue to another viewController.
Hope it helps :)
Related
I'm developing a SpriteKit game with two different scenes (MainMenu.sks and Settings.sks). I also have a UIViewController.
From the MainMenu the user can tap "Settings" which causes the app to load the Settings.sks scene and present it.
It's done using this code:
// Move to Settings.sks
let transition = SKTransition.flipVertical(withDuration: 1.0)
let loadScene = SettingsScene(fileNamed: "SettingsScene")
loadScene?.scaleMode = self.scaleMode
self.view?.presentScene(loadScene!, transition: transition)
From the Settings.sks scene the user can tap on the SKLabelNode "Change username" which causes the app to load the UIViewController by performing a segue.
The UIViewController contains a UITextField and a UIButton. The UIButton takes the user back to MainMenu.sks.
However, when I'm doing so the it's like a new scene of MainMenu is placed upon the other causing the app to sort of "freeze" and not responding to any touch gestures. I can see from the nodeCount that the nodes are doubled.
A workaround is loading the UIViewController directly from the MainMenu.sks (also via a segue). By doing so, the app works just fine.
I'm suspecting the problem to be the way I load Settings.sks.
What am I missing? Maybe unloading the entire SKView before exiting?
Performing a segue will present a new view on top of the stack. By using a segue to return to the main menu, the app will create a new main menu on top of the UIViewController. I can't say for certain why your app freezes. But I would guess that there are some properties or functions that don't work properly when a new main menu is created and presented from your UIViewController.
I recommend unwinding the segue used to reach the UIViewController instead. This way you can return to the previous view and conserve memory.
You'll need to write an IBAction in your destination view, the main menu in this case:
#IBAction func unwindToMainMenu(segue: UIStoryboardSegue) {
}
Then ctrl-drag from your button in the UIViewController to the exit icon in storyboard. You should see an option to use the IBAction unwindToMainMenu that you just wrote. This will create an unwind segue.
A complete guide to unwind segues and multiple examples can be found in this answer: What are Unwind segues for and how do you use them?
I have the following setup:
A UIPageviewController that has two child-ViewControllers.
ViewController 1 contains a UITableView, ViewController 2 holds a camera setup (AVCaptureSession, etc). It's basically a Snapchat like setup.
Swiping between the two works perfectly - swipe left, UITableView is showing, swipe right and the camera shows up again. So far so good.
Now I want to implement a button that turns the page to get to the controller that hold the UITableView programatically. Here's how I do it:
let startingViewController = self.viewControllerAtIndex(0)
let viewControllers: [UIViewController] = [startingViewController!]
pageViewController!.setViewControllers(viewControllers, direction: .Reverse, animated: true, completion: nil)
This works for the most part, as it slides out the UIViewController holding the camera instance and slides in the one holding the UITableView. However, it seems like the view controller that holds the camera session is deallocated, so when I swipe right again, the camera has to be fired up again. Is there any way to turn the page differently, without having the camera session deallocated?
I have tried adding the camera to the PageViewcontroller and adding an "invisible" overlay, but this is not the solution I am looking for. Can someone help out here?
The correct way to do this is using a UIScrollView with multiple subviews and paging enabled. When you press the button, you do not "turn the page", you manipulate/animate the content of the scroll view.
For further reference:
https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/UIScrollView_pg/ScrollViewPagingMode/ScrollViewPagingMode.html
There are couple for segues in the storyboard, all with identifier. Is it possible to access them through code and change its anchor?
Something like this:
mySegue1.anchor = someOtherView
try this
self.performSegueWithIdentifier("YourSegueIdentifier", sender: self)
I think you may chnage anchor's view controller with the following codes, as I wrote in above comments, I believe you can create a Segue programmatically and the following code will create a new Segue for you not just change an old already drawn Segue's anchor programmatically.
Most of the good programmers think that you can not create a Segue by code, thats why changing a Segue anchor is not believed to be a performable job. But it is
It is an 'Objective C' version but you may easily convert it to 'Swift' if you like.
UIViewController *toViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"OtherViewControllerId"];
MySegue *segue = [[MySegue alloc] initWithIdentifier:#"" source:self destination:toViewController];
[self prepareForSegue:segue sender:sender];
[segue perform];
However if you need to create a popover menu using a gesture recognizer, then just create a gesture recognizer and activate your pop over in gesture's action func ( handleTap() )
take a look at the following link, you may create your popover in storyboard and then write the rest of the code or completely do it by code, both are fully covered here.
http://gracefullycoded.com/display-a-popover-in-swift/
as I understood which I hope I get it right, you are about to create a pop over on your view controller which has a tab gesture defined on it. and you succeed to do the job but the pop over menu is mislocated. if this is the case You dont need to use a segue or a storyboard, all parts can be done by code easily.
What you can do is making an invisible anchor frame (ie a label ) and using that as anchor for the segue. I had som buttons and use this approach and it works fine. If you replace my buttons with you dynamically created objects.
#IBAction func rearHubActionUIButton(sender: UIButton) {
invisibleAncherLabel.frame = sender.frame
performSegueWithIdentifier("PopSelection", sender: sender)
}
The popover will then appear with your object as anchor.
I currently have a segue that presents a VC modally in PresentationStyle.PageSheet. I have done this both programmatically and with just the storyboard. I get the same result with both approaches, the modal pop over presents itself but does not show any content inside the UIView from the VC. It will only show the background color of the view and that is all. I also want to point out that everything is displayed if I do a default modal segue (full screen) but fails with page sheet presentation style or with using UIPopoverController. Here are some screen shots that show what I am talking about.
This is what it looks like in the storyboard:
This is what it looks like in the simulator and on an actual ipad:
Here is what my coding approach looked like:
#IBAction func addPickUp(){
var addPickupVC = self.storyboard?.instantiateViewControllerWithIdentifier("pickup") as AddPickupViewController
addPickupVC.modalPresentationStyle = UIModalPresentationStyle.PageSheet
self.presentViewController(addPickupVC, animated: true, completion: nil)
}
This written in swift for ipad ios8.
What am I missing here? Any constructive feed back is appreciated!
EDIT: Here is the document outline of the VC that is to presented modally.
Your code for presenting popover is correct.
Probably there is problem with AutoLayout constraints.
As you can see your popover is presented but label is missing.
Remove your AutoLayout (they will be auto generated) and see if the label will be visible now
Try to add new label. Drag and drop it, and don't specify any constraints
Debug your view
Click "Debug view hierarchy" button at the debug panel
Now you can see your view hearty. Select your label, if it's present and see it's constraints.
Check your AutoLayout constraints and Label is present in correct Size Classes
Size classes is shown bellow UI designer. In my case it's (Any Any).
It means that it's for all sizes and all devices.
Also check that your constrains is not removes at runtime.
You can see it on inspector in right side.
In the storyboard, you can simply control drag a connection from your button to your presented Viewcontroller. There's no reason to have a #IBAction for this. If you use the InterfaceBuilder approach you can optionally set the presentation style on the segue to PageSheet.
I'm working on trying to figure out storyboards and it all seems pretty cool but I'm having problems with moving from one screen with a few buttons to another screen no matter which button is pressed. Obviously I can control drag from each button but then I have segues all over the place on the story board and I feel like there has to be a better way to do it. I've tried highlighting all the buttons and control-dragging to the next screen but that only caused the one I dragged from to work.
Here's an illustration of what I have that works right now...
If I have to stick with this then so be it but I'm going to end up with 6 buttons on one page and 8 on another. That's alot of segues. Basically each button signifies a choice for the user. That choice will cause different things to happen behind the scenes but no matter which button they choose they move to the next screen.
What I've Tried:
Highlighting all the buttons and then dragging to the next view controller.
This failed because it only connected the segue to the button I clicked on when I control-dragged
Dragging out one segue then dragging from the second button to the circle part of the segue.
This caused nothing at all to happen.
I'm unaware of a way to give a single segue multiple triggers in a storyboard, however you could create a single segue with a particular identifier, and then have all of the buttons respond to a single IBAction that calls [self performSegueWithIdentifier:...];
Check out generic segues, which are tied to the source view controller instead of an IBAction:
https://stackoverflow.com/a/8868096/295130