#UITabBarController
Explore tagged Tumblr posts
Text
How to Create a Custom Tab Bar Controller in Swift for iOS
Creating a Custom Tab Bar Controller in Swift for iOS Introduction A custom tab bar controller is a fundamental component in iOS applications that allows users to navigate between different sections of the app seamlessly. While Apple provides a built-in UITabBarController class, there are scenarios where developers need to create a custom implementation. This could be due to specific design…
0 notes
Link
original source : https://www.innofied.com/know-how-to-customize-tab-bar-controller/
tab bar의 기본, 구조(약간언급), tab bar를 이용 다른 view controller로 이동할때 나오는 animation을(transition) 수정하는 내용을 설명한다.
내가 주는 점수 7/10
A mobile app user wants to see the most useful features of an app at the home page. But we can’t put all of the features on it for the obvious reason of space. To solve this issue and to make it easy for a user to browse through the pages in no time, UITabBarController is a one stop solution in iOS. In this blog, I’ll focus on view transition among the view controllers of the tab controller. If you know how to integrate a tab bar controller programmatically for a custom iphone app development, you can skip to the following paragraph.
A Brief Introduction to UITabBarController ::
It is a bunch of buttons, which can be found at the bottom of an iPhone screen and forms a great part of custom iPhone app development. When you click on any of it, specific view controller will be displayed. Let’s dive into implementation.
Implement Custom UITabBarController ::
You can implement it using both interface builder and programming. But here I am going to implement it programmatically. Please download this starter project .
Now, build and run the project.
Wow! You didn’t find anything in it. Sorry! It is empty. Now create a new file of type /Source/Cocoa Touch Class. Give a name to it and inherit “UITabBarController” class.
Now, we will implement the TabBarController and proceed for other steps to custom iPhone app development. As you see we need a few icons and view controllers to display. So, we need to create an array of images, titles & view controllers. You may worry about the images and number of view controllers. Just don’t, your starter project contains all the required images. Here, we will use a single view controller and create multiple instances of it. Now add this method at the bottom of AppDelegate.
func getArrayOfViewController() -> [ViewController] { var arrayOfVC = [ViewController]() let storyboard = UIStoryboard.init(name: "Main", bundle: NSBundle.mainBundle()) // Append View Controllers return arrayOfVC }
This method will be used to create an array of view controllers. There is a ViewController class in this project. It has a scene / interface in Main.storyboard. We will need an instance of Main storyboard to instantiate the view controller. We will take five view controllers. So add the following code in place of “//Append View Controllers”.
for i in 0..<5 { let vc = storyboard.instantiateViewControllerWithIdentifier("ViewController") as! ViewController // customise controllers arrayOfVC.append(vc) }
To identify these view controllers, we need to customize them. We will change the background colour and title of the view controller. To do that add following codes in “// customise controllers”
vc.textForTitle = arrayOfImages[i] vc.view.backgroundColor = arrayOfColors[i]
Add following codes just after the declaration of class AppDelegate.
let arrayOfImages = [ "Home", "Chats", "Contacts", "Settings", "Search"] let arrayOfColors = [ UIColor.orangeColor(), UIColor.brownColor(), UIColor.greenColor(), UIColor.redColor(), UIColor.blueColor()]
Now, we will create an instance of TCTabBarController in application:didFinishLaunchingWithOptions before return true. And assign all view controllers which we created in the previous method.
let tabBar = TCTabBarController() tabBar.viewControllers = self.getArrayOfViewController() // set tabBar as root
We want to set tabBar controller appears after launch screen. So, rootViewController of the window will be assigned with tabBar and call makeKeyAndVisible(). Replace “//set tabBar as root” with following code at the bottom of the method.
self.window?.rootViewController = tabBar self.window?.makeKeyAndVisible()
Now, it’s time to see what we did so far. Let’s run the project.
Wow! View controller has improved from the previous one. But, can’t find the tab bar. Just randomly click on the bottom of the view controller. Oh yeah!! View controllers are changing, but what about icons?
Well, we will customize the tab bar now. UITabBarController has a property, called “tabBar”. It is the bar, which is visible at the bottom of the view controller. It has a property, called “items”. It contains UITabBarItem. We need to customize these BarItems. We will set image and title to them.
func customiseTabItems(tabBar: UITabBar) { for item in tabBar.items! { item.image = UIImage(named: arrayOfImages[tabBar.items!.indexOf(item)!]) item.title = arrayOfImages[tabBar.items!.indexOf(item)!] } }
Call this method from application:didFinishLaunchingWithOptions after assigning the array of view controllers.
self.customiseTabItems(tabBar.tabBar)
Now Run the app and see.
Wow!! We did it.
You can download complete code here.
Behind the View Transition:
In this section, we will change the default view transition animation to a customized one. Let us move to the second stage of iOS development with UITabBar. Before going to implementation, we need to know how this transition works.
After any TabBarItem getting pressed, UITabBarControllerDelegate call tabBarController(: animationControllerForTransitionFromViewController:toViewController:) -> UIViewControllerAnimatedTransitioning? delegate method. If we want any custom transition animation we have created a class inheriting UIViewControllerAnimatedTransitioning class and return instance through this delegate call.
If any UIViewControllerAnimatedTransitioning type instance return to the delegate, it will call transitionDuration() and animateTransition() of the UIViewControllerAnimatedTransitioning instance. When transitionDuration() method will be called, we need to return the duration for animating two views. Whole work of animation will be performed inside animateTransition().
Implement the View Transition:
We will create an animator class to handle the animation between two view controller in this custom iphone app development. So, click File/ New / File and choose the template iOSSourceCocoa Touch Class. Write the name of this class as “SwapAnimator” and inherit NSObject.
Open SwapAnimator.swift and update the class definition to “SwapAnimator : NSObject, UIViewControllerAnimatedTransitioning “.
Don’t worry about the error. When you will implement transitionDuration and animateTransition, these errors will go away.
Now add following property to SwapAnimator
let animationDuration = 1.0 weak var storedContext: UIViewControllerContextTransitioning?
It is time to implement transitionDuration. Return animaitonDuration from this method.
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { return animationDuration }
Now, we will implement animateTransition. All errors go away, don’t they?
Add a property of SwapAnimator to TCTabBarController.
let swapAnimator = SwapAnimator()
Now we will implement UITabBarControllerDelegate in TCTabBarController and tabBarController(:_ animationControllerForTransitionFromViewController: toViewController:) -> UIViewControllerAnimatedTransitioning? Method.
extension TCTabBarController : UITabBarControllerDelegate { func tabBarController(tabBarController: UITabBarController, animationControllerForTransitionFromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { return swapAnimator } }
Don’t forget to assign delegate of UITabBarController to self within viewDidLoad().
self.delegate = self
Run the app and see if there are any new changes in the view. Oh! No!! Nothing has changed!
Wait, we have to write code for animation. Now, create instance for the view to show next and the view to remove from containView inside animateTransition() method. And also add toView to containerView of transitionContext.
storedContext = transitionContext let toView = transitionContext.viewForKey(UITransitionContextToViewKey) let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey) transitionContext.containerView()?.addSubview(toView!)
We will define an animation to animate the fromView.
let animation = CABasicAnimation(keyPath: "transform") animation.fromValue = NSValue(CATransform3D: CATransform3DIdentity) animation.toValue = NSValue(CATransform3D: CATransform3DConcat( CATransform3DMakeTranslation(0.0, -10.0, 0.0), CATransform3DMakeScale(150.0, 150.0, 1.0) ) )
Now, we will refine the animation and add it to fromVIew.layer.
animation.duration = animationDuration animation.delegate = self animation.fillMode = kCAFillModeForwards animation.removedOnCompletion = false animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn) fromView?.layer.addAnimation(animation, forKey: nil)
Run the app and see. Still, nothing has changed.
The animation on fromView isn’t working because is hidden by toView. As we add toView to containerView before the starting of the animation, so the toView overrides the fromView. So, we will set initial alpha zero to toView and put an animation to make it 1.0 .
let fadeIn = CABasicAnimation(keyPath: "opacity") fadeIn.fromValue = 0.0 fadeIn.toValue = 1.0 fadeIn.duration = animationDuration toView!.layer.addAnimation(fadeIn, forKey: nil)
Now, run it and see. The animation is working but the whole bar gets disabled after the first click. We didn’t call animation completion method and property storedContext was not released. Along with them, we have to release all animation from fromView.layer. Add the following method at the bottom of animateTransition method.
override func animationDidStop(anim: CAAnimation, finished flag: Bool) { if let context = storedContext { context.completeTransition(!context.transitionWasCancelled()) let fromView = context.viewForKey(UITransitionContextFromViewKey) fromView?.layer.removeAllAnimations() } storedContext = nil }
Now, run and see it. Not bad!
We will make it even better. Open ViewController.swift and look into viewDidLoad(). You definitely find the circleLayer which has not been added to the layer. So, uncomment the line of code.
view.layer.addSublayer(circle)
Now, run it and see. Wow!
You can download complete code here.
Why does the white spot appear over all the views? It is nothing but the circleLayer. I want you to rectify it as an assignment.
What’s Next?
Hope now you have an idea of view transition that forms an important part in any custom iphone app development. This similar idea works in changes view transition in Navigation Control, Modal segue etc. Here, we did animation without letting a user interact with the screen. It is also possible to give an awesome experience to the user by this tutorial of interactive view transition .
1 note
·
View note
Text
How to Build a Login Screen in SwiftUI
In WWDC 2019 Apple announced a completely new user interface development framework called SwiftUI. SwiftUI is a user interface toolkit that lets us design apps in a declarative way. There was lots of talk about whether we should use Storyboard or build UI programmatically. SwiftUI is the answer to all these questions. You can now develop the app's UI with a declarative Swift syntax.
No more storyboard, Interface Builder and Auto-layout
Earlier we used to develop user interfaces with storyboards, xib's and auto layout. But with SwiftUI, storyboard and auto-layout are completely out of the picture. Now the code editor is available with a preview canvas.
Migrating from UIKit to SwiftUI
If you've used UIKit before then you need to understand what's the UIKit component equivalent in SwiftUI. Many of the classes you know just by removing prefix UI but few have been renamed. Let's have a look at the list.
1. UIViewController: View
2. UITableViewController: List
3. UITabbarController: TabView
4. UINavigationController: NavigationView
5. UIAlertController: Alert
6. UIAlertController with style .actionSheet: ActionSheet
7. UILabel: Text
8. UITextField: TextField
9. UITextField with secure entry: SecureField
10. UISwitch: Toggle
11. UISlider: Slider
12. UIButton: Button
13. UIStackView with horizontal axis: HStack
14. UIStackView with vertical axis: VStack
15. UIImageView: Image
16. UISegmentedControl: SegmentedControl
17. UIStepper: Stepper
18. UIDatePicker: DatePicker
19. UIPickerView: Picker
20. UITabbar: TabView
21. UINavigationBar: NavigationView
22. UIScrollView: ScrollView
Creating Project:
Step 1 - Creating a new project with SwiftUI
Step 2 - Add the VStack in the View. It will act as Vertical StackView
Step 3 - Add title text as Login in the View and can set style to the Text.
Step 4 - Adding Image to the top of the Screen to show that its user's login and adding frame of width and height as shown below.
Fig 1 - Adding Image and Text
Step 5 - Adding Text Field for Phone Number and password with TestField and SecureField inside the VStack and Alignment to leading.
Step 6 - Adding placeholder to the textfield , Add Text and Value will be saved in the Variable.
Step 7 - Give Divider() for allowing space between two textfield and add style as required for the textfield to be displayed.
Step 8 - Adding padding to bottom and given 15.
Step 9 - Adding Button of forgot password inside the HStack to align the right corner of the screen with the Text as shown below.
Fig 2 - Adding Textfield and SecureField with Forget Password
Step 10 - Add a button with the title “Login” for clicking the login functionality inside the VStack.
Step 11 - In this button Action will be added inside the action closure function and can add text to the button (i.e Title) and Style the button as shown.
Fig 3 - Adding Button with Action and Text
Step 12 - Add a button which will have an action to move to SignUp Screen inside the HStack with spacing. Where the SignUp text will be clickable which we implement using Attribute text Similarly in SwiftUI it is implemented in Simple Way.
Fig 4 - "Don't have an Account ? Sign Up"
Final Result - Login Screen with PhoneNumber and Password using SwiftUI
Conclusion
SwiftUI is new to everyone and might take time to get stable as a framework. But SwiftUI is the future of iOS development. There are a lot of things to learn in SwiftUI.
0 notes
Text
HackingWithSwift Day 33/34/35 - Project 7
Here introduce to UITabBarController
“Swift has built-in support for working with JSON using a protocol called Codable. When you say “my data conforms to Codable”, Swift will allow you to convert freely between that data and JSON using only a little code.”
Definition by the author, let’s see how powerful is this.
So it’s quite convenient to parse the json data into swift native support data type, instead of self declare and unwrap it layer by layer.
Only 1 thing is the window code to add a new tab, I think it’s time to update it using SceneDelegate since window is omitted from AppDelegate with the latest Xcode.
Seems like Codable usage is very wide, might need more research on this
0 notes
Video
tumblr
Course Preview - Navigation Setup - UITabBarController & UINavigationController https://www.youtube.com/watch?v=VI3HaNWTYVg
0 notes
Link
iOS Notes App - Advanced Core Data, Navigation, & TableViews ##freetutorials ##udemycoupon #Advanced #app #Core #Data #iOS #Navigation #notes #TableViews iOS Notes App - Advanced Core Data, Navigation, & TableViews Finish Your iOS Apps Once and For All. Whether you are working on your own apps, a client's, or the company's you are working for, by building the iOS notes app with an emphasis on Core Data, you will be able to implement various features and capabilities into the iOS applications you are developing and plan to develop. Core Freaking Data Boi. After completing this course you WILL be able to utilize top Core Data features such as deleting, creating, and updating documents, NSPersistentContainer, ViewContext, NSFetchRequest and more. Fill in more gaps! You will also be able to implement various features around iOS development like UIAlertController, UITabBarController, Programmatic Auto Layout and more! Watchu waiting for? Start learning iOS Development and Core Data today. 👉 Activate Udemy Coupon 👈 Free Tutorials Udemy Review Real Discount Udemy Free Courses Udemy Coupon Udemy Francais Coupon Udemy gratuit Coursera and Edx ELearningFree Course Free Online Training Udemy Udemy Free Coupons Udemy Free Discount Coupons Udemy Online Course Udemy Online Training 100% FREE Udemy Discount Coupons https://www.couponudemy.com/blog/ios-notes-app-advanced-core-data-navigation-tableviews/
0 notes
Video
youtube
Customisation of UITabbarController Xcode 11 | Swift 5.2 No Third party required ! A Step by step tutorial about Customization of UITabBarController using Swift5.2 to build the App. We can customise theme colour, shape, border and change font and size based on application.
0 notes
Link
1. Introduction IOS7 introduces new classes to facilitate developers the possibility of making transitions to our liking, both in the presentation of screens in modal form as in the UINavigationsControllers and the UITabBarControllers, so the limit is our imagination, we begin to see a bit of theory, the classes that play in this role are …
0 notes
Link
0 notes
Text
How to Create a Custom Tab Bar Controller in Swift for iOS Development
Creating a Custom Tab Bar Controller in Swift for iOS 1. Introduction 1.1 Brief Explanation A tab bar controller is a fundamental component in iOS app development, providing users with a way to navigate between different sections of an app. While UIKit’s UITabBarController is a commonly used solution, there are scenarios where a custom implementation is more appropriate—such as when you need…
0 notes
Video
youtube
Swift: Create Facebook's Tab Menu system with UITabBarController
my review point is 9/10
https://youtu.be/1Sg7HjR_k2c?t=2m30s UITabBarController 만들어 사용하기
https://youtu.be/1Sg7HjR_k2c?t=4m3s UITabBarController에 있는 viewControllers 프로퍼티를 다른 view controller로 채운다. 하단의 텝에 나오는 tab bar styling은 UINavigationController obj를 이용한다. title, tabBarItem 속성을 이용한다.
https://youtu.be/1Sg7HjR_k2c?t=16m43s tab bar가 투명하게 하는 것을 막는 작업 (UINavigationController 내의 tabBar.translucent = false )
https://youtu.be/1Sg7HjR_k2c?t=18m tab bar top border 바꾸기
https://youtu.be/1Sg7HjR_k2c?t=21m35s 기본적으로 텝이 선택되고 안 선택되고에 따라 버튼의 색이 ios 에 의해 지정되는데 이를 수정하는 작업 ( AppDelegate에서 UITabBar.appearance().tintColor 를 수정한다. )
#ios#brian#facebook feed#facebook#UITabBarController#tab#bar#viewController#tabBarItem#UINavigationController#navigation#transparent#tabBar#translucent#border#UITabBar#tintColor#color
0 notes
Text
Tab Bar Controller iOS Tutorial
The UITabBarController class implements a specialized view controller that manages a radio-style selection interface. This tab bar interface displays tabs at the bottom of the window for selecting different views. In this Tutorial a Tab Bar Controller will be created and by default two Tab Bar Items will be included. The third Tab Bar Item will be added using the Storyboard. This tutorial is made with Xcode 10 and built for iOS 12.
Open Xcode and create a new Tapped App.
For product name, use IOS12TabBarControllerTutorial and then fill out the Organization Name and Organization Identifier with your customary values. Enter Swift as Language and choose Next.
For the Tab Bar items some custom images will be used. Download the images, unzip them and add the images to the Assets Library. Go to the Storyboard. In the Document Outline select the First Bar button Item in the First Scene and go to the Attribute Inspector. In the Bar Items section change the title to "Red" and select the book image.
Repeat this step for the Second Bar Item of the Second View Controller. Name it "Blue" and select the clock image.
Select to the Red View and change the Background to red using the Attributes Inspector. In the blue view change the Background to blue. Also remove the Labels inside the view.
The Storyboard should now look like this.
Build and Run the project, and change views by clicking the Tab Bar Items.
Next, we will add another Tab Bar Item inside the Storyboard. Drag a View Controller from the Object Library to the Scene. Select the View Controller and go to the Attribute Inspector. Change the Background color to Green. Next Ctrl and Drag from inside the Tab Bar Controller to the newly created View Controller and select "view controllers" in the Relationship Segue section.
In the Document Outline select the Tab Bar Item in the Item Scene and Go to The Attribute Inspector. In the Bar Items section change the title to "Green" and select the crown image.
Build and Run the project, the 3 Tab Bar Items will be visible. By clicking the Icons the Views will change.
You can download the source code of the IOS12TabBarControllerTutorial at the ioscreator repository on Github.
0 notes
Text
How to Build a Login Screen in SwiftUI
What is SwiftUI ?
In WWDC 2019 Apple announced a completely new user interface development framework called SwiftUI. SwiftUI is a user interface toolkit that lets us design apps in a declarative way. There was lots of talk about whether we should use Storyboard or build UI programmatically. SwiftUI is the answer to all these questions. You can now develop the app's UI with a declarative Swift syntax.
No more storyboard, Interface Builder and Auto-layout
Earlier we used to develop user interfaces with storyboards, xib's and auto layout. But with SwiftUI, storyboard and auto-layout are completely out of the picture. Now the code editor is available with a preview canvas.
Migrating from UIKit to SwiftUI
If you've used UIKit before then you need to understand what's the UIKit component equivalent in SwiftUI. Many of the classes you know just by removing prefix UI but few have been renamed. Let's have a look at the list.
1. UIViewController: View
2. UITableViewController: List
3. UITabbarController: TabView
4. UINavigationController: NavigationView
5. UIAlertController: Alert
6. UIAlertController with style .actionSheet: ActionSheet
7. UILabel: Text
8. UITextField: TextField
9. UITextField with secure entry: SecureField
10. UISwitch: Toggle
11. UISlider: Slider
12. UIButton: Button
13. UIStackView with horizontal axis: HStack
14. UIStackView with vertical axis: VStack
15. UIImageView: Image
16. UISegmentedControl: SegmentedControl
17. UIStepper: Stepper
18. UIDatePicker: DatePicker
19. UIPickerView: Picker
20. UITabbar: TabView
21. UINavigationBar: NavigationView
22. UIScrollView: ScrollView
Creating Project:
Step 1 - Creating a new project with SwiftUI
Step 2 - Add the VStack in the View. It will act as Vertical StackView
Step 3 - Add title text as Login in the View and can set style to the Text.
Step 4 - Adding Image to the top of the Screen to show that its user's login and adding frame of width and height as shown below. Read more..
0 notes
Text
How to Create Your Own Slide-Out Navigation Panel in Swift
Update Note: This tutorial has been updated for iOS 11, Xcode 9, and Swift 4 by Nick Sakaimbo. The original tutorial was written by Tammy Coron.
This tutorial will show you how to build a slide-out navigation panel, which is a popular alternative to using a UINavigationController or a UITabBarController that allows users to slide content on or off screen.
The slide-out navigation panel design pattern lets developers add permanent navigation to their apps without taking up valuable screen real estate. The user can choose to reveal the navigation at any time, while still seeing their current context.
In this tutorial you’ll take a less-is-more approach so you can apply the slide-out navigation panel technique to your own applications with relative ease.
Getting Started
You’re going to build a slide-out navigation panel into a cute kitten and puppy photo browser. To get started, download the starter project for this tutorial. It’s a zip file, so save it to a convenient location and then extract it to get the project.
Next open the project in Xcode and take a look at how it’s organized. The Assets folder contains a couple of asset catalogs of all of the kitten and puppy images that’ll be displayed in the app. Notice too there’s three main view controllers. When the time comes to adapt this tutorial to your own projects, here’s what you should keep in mind:
ContainerViewController: This is where the magic happens! This contains the views of the left, center, and right view controllers and handles things like animations and swiping. In this project, it’s created and added to the window in application(_:didFinishLaunchingWithOptions:) in AppDelegate.swift
CenterViewController: The center panel. You can replace it with your own view controller (make sure you copy the button actions).
SidePanelViewController: Used for the left and right side panels. This could be replaced with your own view controller.
The views for the center, left, and right view controllers are all defined within Main.storyboard, so feel free to take a quick look to get an idea of how the app will look.
Now you’re familiar with the structure of the project, it’s time to start at square one: the center panel.
Finding Your Center
In this section, you’re going to place the CenterViewController inside the ContainerViewController, as a child view controller.
Note: This section uses a concept called View Controller Containment introduced in iOS 5. If you’re new to this concept, check out Chapter 22 in iOS 5 by Tutorials, “UIViewController Containment.”
Open ContainerViewController.swift. At the bottom of the file there’s a small extension for UIStoryboard. It adds a few static methods which make it a bit more concise to load specific view controllers from the app’s storyboard. You’ll make use of these methods soon.
Add a couple of properties to ContainerViewController for the CenterViewController and for a UINavigationController, above viewDidLoad():
var centerNavigationController: UINavigationController! var centerViewController: CenterViewController!
Note: These are implicitly-unwrapped optionals (as denoted by the !). They have to be optional because their values won’t be initialized until after init() has been called, but they can be automatically unwrapped because once they’re created you know they will always have values.
Next, add the following block of code to viewDidLoad(), beneath the call to super:
centerViewController = UIStoryboard.centerViewController() centerViewController.delegate = self // wrap the centerViewController in a navigation controller, so we can push views to it // and display bar button items in the navigation bar centerNavigationController = UINavigationController(rootViewController: centerViewController) view.addSubview(centerNavigationController.view) addChildViewController(centerNavigationController) centerNavigationController.didMove(toParentViewController: self)
The code above creates a new CenterViewController and assigns it to the centerViewController property you just created. It also creates a UINavigationController to contain the center view controller. It then adds the navigation controller’s view to ContainerViewController‘s view and sets up the parent-child relationship using addSubview(_:), addChildViewContoller(_:) and didMove(toParentViewController:).
It also sets the current view controller as the center view controller’s delegate. This will be used by the center view controller to tell its container when to show and hide the left and right side panels.
If you try to build now, you’ll see an error when the code assigns the delegate. You need to modify this class so it implements the CenterViewControllerDelegate protocol. You’ll add an extension to ContainerViewController to implement it. Add the following code above the UIStoryboard extension near the bottom of the file (this also includes a number of empty methods which you’ll fill out later):
// MARK: CenterViewController delegate extension ContainerViewController: CenterViewControllerDelegate { func toggleLeftPanel() { } func toggleRightPanel() { } func addLeftPanelViewController() { } func addRightPanelViewController() { } func animateLeftPanel(shouldExpand: Bool) { } func animateRightPanel(shouldExpand: Bool) { } }
Now is a good time to check your progress. Build and run the project. If all went well, you should see something similar to the screen below:
Yes, those buttons at the top will eventually bring you kitties and puppies. What better reason could there be for creating sliding navigation panels? But to get your cuteness fix, you’ve got to start sliding. First, to the left!
Kittens to the Left of Me…
You’ve created your center panel, but adding the left view controller requires a different set of steps. There’s quite a bit of set up to get through here, so bear with it. Think of the kittens!
To expand the left menu, the user will tap on the Kitties button in the navigation bar. So head on over to CenterViewController.swift.
In the interests of keeping this tutorial focused on the important stuff, the IBActions and IBOutlets are pre-connected for you in the storyboard. However, to implement your DIY slide-out navigation panel, you need to understand how the buttons are configured.
Notice there’s already two IBAction methods, one for each of the buttons. Find kittiesTapped(_:) and add the following implementation to it:
delegate?.toggleLeftPanel?()
As previously mentioned, the method is already hooked up to the Kitties button.
This uses optional chaining to only call toggleLeftPanel() if delegate has a value and it has implemented the method.
You can see the definition of the delegate protocol in CenterViewControllerDelegate.swift. As you’ll see, there’s optional methods toggleLeftPanel() and toggleRightPanel(). If you remember, when you set up the center view controller instance earlier, you set its delegate as the container view controller. Time to go and implement toggleLeftPanel().
Note: For more information on delegate methods and how to implement them, please refer to Apple’s Developer Documentation.
Open ContainerViewController.swift. First add an enum to the ContainerViewController class, right below the class name:
class ContainerViewController: UIViewController { enum SlideOutState { case bothCollapsed case leftPanelExpanded case rightPanelExpanded } // ...
This will let you keep track of the current state of the side panels, so you can tell whether neither panel is visible, or one of the left or right panels are visible.
Next, add two more properties below your existing centerViewController property:
var currentState: SlideOutState = .bothCollapsed var leftViewController: SidePanelViewController?
These will hold the current state, and the left side panel view controller itself:
The current state is initialized to be .bothCollapsed – that is, neither of the side panels are visible when the app first loads. The leftViewController property is an optional, because you’ll be adding and removing the view controller at various times, so it might not always have a value.
Next, add the implementation for the toggleLeftPanel() delegate method:
let notAlreadyExpanded = (currentState != .leftPanelExpanded) if notAlreadyExpanded { addLeftPanelViewController() } animateLeftPanel(shouldExpand: notAlreadyExpanded)
First, this method checks whether the left side panel is already expanded or not. If it’s not already visible, then it adds the panel to the view hierarchy and animates it to its ‘open’ position. If the panel is already visible, then it animates the panel to its ‘closed’ position.
Next, you’ll include the code to add the left panel to the view hierarchy. Locate addLeftPanelViewController(), and add the following code inside it:
guard leftViewController == nil else { return } if let vc = UIStoryboard.leftViewController() { vc.animals = Animal.allCats() addChildSidePanelController(vc) leftViewController = vc }
The code above first checks to see if the leftViewController property is nil. If it is, then creates a new SidePanelViewController, and sets its list of animals to display – in this case, cats!
Next, add the implementation for addChildSidePanelController(_:) below addLeftPanelViewController():
func addChildSidePanelController(_ sidePanelController: SidePanelViewController) { view.insertSubview(sidePanelController.view, at: 0) addChildViewController(sidePanelController) sidePanelController.didMove(toParentViewController: self) }
This method inserts the child view into the container view controller. This is much the same as adding the center view controller earlier. It simply inserts its view (in this case it’s inserted at z-index 0, which means it will be below the center view controller) and adds it as a child view controller.
It’s almost time to try the project out again, but there’s one more thing to do: add some animation! It won’t take long!
And sliiiiiiide!
First, add a constant below your other properties in ContainerViewController.swift:
let centerPanelExpandedOffset: CGFloat = 60
This value is the width, in points, of the center view controller left visible once it has animated offscreen. 60 points should do it.
Next, locate the method stub for animateLeftPanel(shouldExpand:) and add the following block of code to it:
if shouldExpand { currentState = .leftPanelExpanded animateCenterPanelXPosition( targetPosition: centerNavigationController.view.frame.width - centerPanelExpandedOffset) } else { animateCenterPanelXPosition(targetPosition: 0) { finished in self.currentState = .bothCollapsed self.leftViewController?.view.removeFromSuperview() self.leftViewController = nil } }
This method simply checks whether it’s been told to expand or collapse the side panel. If it should expand, then it sets the current state to indicate the left panel is expanded, and then animates the center panel so it’s open. Otherwise, it animates the center panel closed and then removes its view and sets the current state to indicate it’s closed.
Finally, add animateCenterPanelXPosition(targetPosition:completion:) underneath animatedLeftPanel(shouldExpand:):
func animateCenterPanelXPosition(targetPosition: CGFloat, completion: ((Bool) -> Void)? = nil) { UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0, options: .curveEaseInOut, animations: { self.centerNavigationController.view.frame.origin.x = targetPosition }, completion: completion) }
This is where the actual animation happens. The center view controller’s view is animated to the specified position, with a nice spring animation. The method also takes an optional completion closure, which it passes on to the UIView animation. You can try tweaking the duration and spring damping parameters if you want to change the appearance of the animation.
OK… It’s taken a little while to get everything in place, but now is a great time to build and run the project. So do it!
When you’ve run the project, try tapping on the Kitties button in the navigation bar. The center view controller should slide over – whoosh! – and reveal the Kitties menu underneath. D’aww, look how cute they all are.
But too much cuteness can be a dangerous thing! Tap the Kitties button again to hide them!
Me and my shadow
When the left panel is open, notice how it’s right up against the center view controller. It would be nice if there were a bit more of a distinction between them. How about adding a shadow?
Still in ContainerViewController.swift, add the following method below your animation methods:
func showShadowForCenterViewController(_ shouldShowShadow: Bool) { if shouldShowShadow { centerNavigationController.view.layer.shadowOpacity = 0.8 } else { centerNavigationController.view.layer.shadowOpacity = 0.0 } }
This adjusts the opacity of the navigation controller’s shadow to make it visible or hidden. You can implement a didSet observer to add or remove the shadow whenever the currentState property changes.
Next, scroll to the top of ContainerViewController.swift and change the currentState declaration to:
var currentState: SlideOutState = .bothCollapsed { didSet { let shouldShowShadow = currentState != .bothCollapsed showShadowForCenterViewController(shouldShowShadow) } }
The didSet closure will be called whenever the property’s value changes. If either of the panels are expanded, then it shows the shadow.
Build and run the project again. This time when you tap the kitties button, check out the sweet new shadow! Looks better, huh?
Up next, adding the same functionality but for the right side, which means… puppies!
Puppies to the Right…
To add the right panel view controller, simply repeat the steps for adding the left view controller.
Open ContainerViewController.swift, and add the following property below the leftViewController property:
var rightViewController: SidePanelViewController?
Next, locate toggleRightPanel(), and add the following implementation:
let notAlreadyExpanded = (currentState != .rightPanelExpanded) if notAlreadyExpanded { addRightPanelViewController() } animateRightPanel(shouldExpand: notAlreadyExpanded)
Next, replace the implementations for addRightPanelViewController() and animateRightPanel(shouldExpand:) with the following:
func addRightPanelViewController() { guard rightViewController == nil else { return } if let vc = UIStoryboard.rightViewController() { vc.animals = Animal.allDogs() addChildSidePanelController(vc) rightViewController = vc } } func animateRightPanel(shouldExpand: Bool) { if shouldExpand { currentState = .rightPanelExpanded animateCenterPanelXPosition( targetPosition: -centerNavigationController.view.frame.width + centerPanelExpandedOffset) } else { animateCenterPanelXPosition(targetPosition: 0) { _ in self.currentState = .bothCollapsed self.rightViewController?.view.removeFromSuperview() self.rightViewController = nil } } }
The code above is almost an exact duplicate of the code for the left panel, except of course for the differences in method and property names and the direction. If you have any questions about it, review the explanation from the previous section.
Just as before, the IBActions and IBOutlets have been connected in the storyboard for you. Similar to the Kitties button, the Puppies button is hooked up to an IBAction method named puppiesTapped(_:). This button controls the sliding of the center panel to reveal the right-side panel.
Finally, switch to CenterViewController.swift and add the following snippet to puppiesTapped(_:):
delegate?.toggleRightPanel?()
Again, this is the same as kittiesTapped(_:), except it’s toggling the right panel instead of the left.
Time to see some puppies!
Build and run the program again to make sure everything is working. Tap on the Puppies button. Your screen should look like this:
Looking good, right? But remember, you don’t want to expose yourself to the cuteness of puppies for too long, so tap that button again to hide them away.
You can now view both kitties and puppies, but it would be great to be able to view a bigger picture of each one, wouldn’t it? MORE CUTENESS :]
Pick An Animal, Any Animal
The kitties and puppies are listed within the left and right panels. These are both instances of SidePanelViewController, which essentially just contain table views.
Head over to SidePanelViewControllerDelegate.swift to take a look at the SidePanelViewController delegate method. A side panel’s delegate can be notified via this method whenever an animal is tapped. Let’s use it!
In SidePanelViewController.swift, first add an optional delegate property at the top of the class, underneath the table view IBOutlet:
var delegate: SidePanelViewControllerDelegate?
Then fill in the implementation for tableView(_:didSelectRowAt:) within the UITableViewDelegate extension:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let animal = animals[indexPath.row] delegate?.didSelectAnimal(animal) }
If there’s a delegate set, this will tell it an animal has been selected. Currently there’s no delegate yet! It would make sense for CenterViewController to be the side panel’s delegate, as it can then display the selected animal photo and title.
Open up CenterViewController.swift to implement the delegate protocol. Add the following extension to the bottom of the file, beneath the existing class definition:
extension CenterViewController: SidePanelViewControllerDelegate { func didSelectAnimal(_ animal: Animal) { imageView.image = animal.image titleLabel.text = animal.title creatorLabel.text = animal.creator delegate?.collapseSidePanels?() } }
This method simply populates the image view and labels in the center view controller with the animal’s image, title, and creator. Then, if the center view controller has a delegate of its own, you can tell it to collapse the side panel away so you can focus on the selected item.
collapseSidePanels() is not implemented yet. Open, ContainerViewController.swift and add the following method below toggleRightPanel():
func collapseSidePanels() { switch currentState { case .rightPanelExpanded: toggleRightPanel() case .leftPanelExpanded: toggleLeftPanel() default: break } }
The switch statement in this method simply checks the current state of the side panels, and collapses whichever one is open (if any!).
Finally, update addChildSidePanelViewController(_:) to the following implementation:
func addChildSidePanelController(_ sidePanelController: SidePanelViewController) { sidePanelController.delegate = centerViewController view.insertSubview(sidePanelController.view, at: 0) addChildViewController(sidePanelController) sidePanelController.didMove(toParentViewController: self) }
In addition to what it was doing previously, the method will now set the center view controller as the side panels’ delegate.
That should do it! Build and run the project again. View kitties or puppies, and tap on one of the cute little critters. The side panel should collapse itself again and you should see the details of the animal you chose.
Move Your Hands Back and Forth
The navigation bar buttons are great, but most apps also allow you to “swipe” to open the side panels. Adding gestures to your app is surprisingly simple. Don’t be intimated; you’ll do fine!
Open ContainerViewController.swift and locate viewDidLoad(). Add the following to the end of the method:
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(_:))) centerNavigationController.view.addGestureRecognizer(panGestureRecognizer)
The above code defines a UIPanGestureRecognizer and assigns handlePanGesture(_:) to it to handle any detected pan gestures. (You will write the code for that method in a moment.)
By default, a pan gesture recognizer detects a single touch with a single finger, so it doesn’t need any extra configuration. You just need to add the newly created gesture recognizer to centerNavigationController view.
Note: Refer to our Using UIGestureRecognizer with Swift Tutorial for more information about gesture recognizers in iOS.
Next make this class a UIGestureRecognizerDelegate by adding the following extension at the bottom of the file, above the UIStoryboard extension:
// MARK: Gesture recognizer extension ContainerViewController: UIGestureRecognizerDelegate { @objc func handlePanGesture(_ recognizer: UIPanGestureRecognizer) { } }
Didn’t I tell you it’d be simple? There’s only one move remaining in your slide-out navigation panel routine.
Now Move That View!
The gesture recognizer calls handlePanGesture(_:) when it detects a gesture. So your last task for this tutorial is to implement the method.
Add the following block of code to the method stub you just added above (it’s a big one!):
let gestureIsDraggingFromLeftToRight = (recognizer.velocity(in: view).x > 0) switch recognizer.state { case .began: if currentState == .bothCollapsed { if gestureIsDraggingFromLeftToRight { addLeftPanelViewController() } else { addRightPanelViewController() } showShadowForCenterViewController(true) } case .changed: if let rview = recognizer.view { rview.center.x = rview.center.x + recognizer.translation(in: view).x recognizer.setTranslation(CGPoint.zero, in: view) } case .ended: if let _ = leftViewController, let rview = recognizer.view { // animate the side panel open or closed based on whether the view // has moved more or less than halfway let hasMovedGreaterThanHalfway = rview.center.x > view.bounds.size.width animateLeftPanel(shouldExpand: hasMovedGreaterThanHalfway) } else if let _ = rightViewController, let rview = recognizer.view { let hasMovedGreaterThanHalfway = rview.center.x < 0 animateRightPanel(shouldExpand: hasMovedGreaterThanHalfway) } default: break }
The pan gesture recognizer detects pans in any direction, but you're only interested in horizontal movement. First, you set up the gestureIsDraggingFromLeftToRight Boolean to check for this using the x component of the gesture velocity.
There's three states that need to be tracked: UIGestureRecognizerState.began, UIGestureRecognizerState.changed, and UIGestureRecognizerState.ended:
.began: If the user starts panning, and neither panel is visible then shows the correct panel based on the pan direction and makes the shadow visible.
.changed: If the user is already panning, moves the center view controller's view by the amount the user has panned
.ended: When the pan ends, check whether the left or right view controller is visible. Depending on which one is visible and how far the pan has gone, perform the animation.
You can move the center view around, and show and hide the left and right views using a combination of these three states, as well as the location and velocity / direction of the pan gesture.
For example, if the gesture direction is right, then show the left panel. If the direction is left, then show the right panel.
Build and run the program again. At this point, you should be able to slide the center panel left and right, revealing the panels underneath. If everything is working... you're good to go!
Where to Go from Here?
Congratulations! If you made it all the way through, you're a slide-out navigation panel ninja!
I hope you enjoyed this tutorial. Feel free to download the completed project file. I'm sure you'll enjoy being stuck in the middle of kitties and puppies!
If you want to try a pre-built library over the DIY solution, be sure to check out SideMenu. For an in-depth discussion of the origins of this UI control (and a trip down memory lane), check out iOS developer and designer Ken Yarmosh's post New iOS Design Pattern: Slide-Out Navigation. He does a great job of explaining the benefits of using this design pattern and showing common uses in the wild.
Leave a comment in the forums below to share your slide-out moves and grooves!
The post How to Create Your Own Slide-Out Navigation Panel in Swift appeared first on Ray Wenderlich.
How to Create Your Own Slide-Out Navigation Panel in Swift published first on http://ift.tt/2fA8nUr
0 notes
Text
Storyboards Tutorial for iOS: Part 1
Storyboards, Scenes and View Controllers
Update note: This tutorial has been updated for Xcode 9, iOS 11, and Swift 4 by Nicholas Sakaimbo. The original tutorial was written by Matthijs Hollemans.
Storyboards are an exciting feature first introduced in iOS 5 that save time building user interfaces for your apps. Storyboards allow you to prototype and design multiple view controller views within one file.
Before Storyboards you had to use XIB files and you could only use one XIB file per view (UITableViewCell, UITableView or other supported UIView types).
The following image shows you what a storyboard looks like, and it’s similar to the storyboard you’ll build during this tutorial:
You may not know what the app does but you can see its scenes and how they’re related.
Storyboards have a number of advantages:
You can visually lay out all your view controllers in “scenes” and describe the connections between them. With a storyboard you’ve a better conceptual overview of all the scenes in your app.
Describe the transitions between the various scenes. These transitions are called “segues” and you create them by connecting your view controllers in the storyboard. Thanks to segues you need less code to take care of your UI.
Make working with table views a lot easier with prototype and static cells features. You can design your table views almost completely in the storyboard editor, cutting down the amount of code you have to write.
Make it easier to use Auto Layout, a feature that allows you to define mathematical relationships between elements defining their position and sizing. This powerful feature makes it easier to handle devices of varying screen sizes and dimensions. In this tutorial you’ll use Auto Layout a little, but it’s outside the scope of this tutorial. You can read more in our Auto Layout Tutorial or watch the video series.
In this tutorial you’re going to build a sample app to create a list of players and show you the games they play and their skill rating. In the process, you’ll learn common tasks which can be accomplished using in storyboards.
Getting Started
Open Xcode and create a new project. Use the Single View Application template as the starting point.
Fill in the template options as follows, click Next and then Create:
Product Name: Ratings
Organization Name: fill this in however you like
Organization Identifier: the identifier you use for your apps
Language: Swift
Make sure Use Core Data, Include Unit Tests and UI Tests are unchecked
Once created, the main Xcode window should look like the following:
The new project consists of three files, AppDelegate.swift, ViewController.swift, and the star of this tutorial: Main.storyboard.
Under Deployment Info > Device Orientation in the General project settings, set Devices to iPhone. Since this is a portrait-only app, uncheck the Landscape Left and Landscape Right options.
Open Main.storyboard in the project navigator to view it in the Interface Builder editor:
The official storyboard terminology for a view controller is “scene”, but you can use the terms interchangeably. A scene represents a view controller in the storyboard.
Here you see a single view controller containing an empty view. The arrow pointing to the view controller from the left indicates it’s the initial view controller to be displayed for this storyboard.
Designing a layout in the storyboard editor is done by dragging controls from the Object Library (see bottom-right corner) into your view controller.
You’ll notice the default scene size is for a 4.7-inch screen. Xcode enables Auto Layout and Size Classes by default for storyboards. Auto Layout and Size Classes allow you to make flexible user interfaces that can easily resize, which is useful for supporting the various sizes of iPhones and iPads. To change the scene size to another device, click the button at the bottom left of the storyboard. You’ll then be able to select from the full range of supported device sizes, ranging from the iPad Pro (12.9-inch) to the iPhone 4S (3.5-inch), in both portrait and landscape orientations.
For this tutorial, we’ll leave the default scene size – iPhone 7 – unchanged, so make sure to switch it back if you’ve toggled through a couple of different device sizes. Xcode will automatically re-size existing and new scenes added to the storyboard for the currently-selected device size.
To get a feel for how the storyboard editor works, drag some controls from the Object Library into the blank view controller:
As you drag controls in, they should show up in the Document Outline on the left:
The storyboard shows the contents of all your scenes. Currently there’s only one scene in your storyboard, but over the course of this tutorial you’ll add several others.
There’s a miniature version of this Document Outline above the scene called the Dock:
The Dock shows the top-level objects in the scene. Each scene has at least a View Controller object, a First Responder object, and an Exit object. It can potentially have other top-level objects as well. The Dock is convenient for making connections to outlets and actions. If you need to connect something to the scene, you can simply drag to its icon in the Dock.
Note: You probably won’t use the First Responder very much. This is a proxy object referring to whatever object has first responder status at any given time. As an example, you can hook up the Touch Up Inside event from a button to First Responder’s cut: selector. If at some point a text field has input focus then you can press that button to make the text field, which is now the first responder, cut its text to the pasteboard.
Build and run the app, it should look exactly like what you designed in the editor (yours may look different than the screenshot below):
The single view controller you defined was set as the Initial View Controller – but how did the app load it? Open AppDelegate.swift to find the answer:
import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true }
The @UIApplicationMain attribute at the top of the file designates the AppDelegate class as the entry point for the module. It’s a requirement for using storyboards your application delegate inherits from UIResponder and has a UIWindow property. All the methods are practically empty. Even application(_:didFinishLaunchingWithOptions:) simply returns true.
The secret’s in the Info.plist file. Open Info.plist in the Project Navigator and you’ll see the following:
Storyboard apps use the UIMainStoryboardFile key, also known as “Main storyboard file base name”, to specify the name of the storyboard to load when the app starts. When this setting is present, UIApplication will load the named storyboard file, automatically instantiate the “Initial View Controller”, and put that controller’s view into a new UIWindow object.
You can also see this in the Project Settings under the General tab and Deployment Info section:
Now to create the real Ratings app with several view controllers.
Just Add It To My Tab
The Ratings app you’re about to build has a tabbed interface with two scenes. With a storyboard it’s easy to create tabs.
Open Main.storyboard and delete the scene you worked with earlier. This can be done by clicking on View Controller in the Document Outline and pressing the delete key.
Drag a Tab Bar Controller from the Object Library into the canvas. You may want to maximize your Xcode window first, because the Tab Bar Controller comes with two view controllers attached and you’ll need some room to maneuver. You can zoom in and out by double-clicking the canvas, or set the zoom scale by ctrl-clicking the canvas and selecting the zoom level.
The new Tab Bar Controller comes pre-configured with two additional view controllers – one for each tab. UITabBarController is a so-called container view controller because it contains one or more other view controllers. Two other common containers are Navigation Controller and Split View Controller (you’ll use the Navigation Controller later).
The container Relationship is represented by the arrows between the Tab Bar Controller and the view controllers it contains. An embed Relationship in particular is signified by the icon seen below in the middle of the arrow body.
Note: If you want to move the Tab Bar Controller and its attached view controllers as a group, zoom out, then ⌘-click or click and drag to select multiple scenes. This makes it possible to move them around together. (Selected scenes have a thin blue outline.)
Drag a label into the first view controller (currently titled “Item 1”), double click it, and give it the text “First Tab”. Next, drag a label into the second view controller (“Item 2”) and give it the text “Second Tab”. This allows you to see something happen when you switch between the tabs.
Build and run the app. You’ll see something similar to this in the console:
Ratings[18955:1293100] Failed to instantiate the default view controller for UIMainStoryboardFile 'Main' - perhaps the designated entry point is not set?
Fortunately, the error is pretty clear here – you never set an entry point, meaning you didn’t set the Initial View Controller after you deleted the previous scene. To fix this, select the Tab Bar Controller, go to the Attributes Inspector and check Is Initial View Controller.
In the canvas, an arrow now points at the Tab Bar Controller:
Now when you run the app, UIApplication will make the Tab Bar Controller the main screen. Build and run the app. Now you can see a tab bar and can switch between the two view controllers:
Note: To change the initial view controller, you can also drag the arrow between view controllers.
Xcode comes with a template for building a tabbed app (called the Tabbed Application template). You could have used it, but it’s good to know how this works so you can create a Tab Bar Controller by hand if you have to.
Note: If you connect more than five scenes to the Tab Bar Controller, it automatically gets a More… tab when you run the app. Pretty neat!
Adding a Table View Controller
The two scenes currently attached to the Tab Bar Controller are both UIViewController instances. You’re going to replace first tab scene with a UITableViewController instead.
Click on the first view controller in the Document Outline to select it, then delete it. Drag a new Table View Controller into the canvas where the previous scene used to be:
Next, you want to place the Table View Controller inside a navigation controller. First, select the Table View Controller. Next, choose Editor\Embed In\Navigation Controller from Xcode’s menubar. This adds another controller to the canvas:
You could have dragged in a Navigation Controller from the Object Library and embedded the table view, but this Embed In command is a nice time saver for a common action.
Since the Navigation Controller is also a container view controller (just like the Tab Bar Controller), it has a relationship arrow pointing to the Table View Controller. You can also see these relationships in the Document Outline:
Notice embedding the Table View Controller gave it a navigation bar. Interface Builder automatically put it there because this scene will now be displayed inside the Navigation Controller’s frame. It’s not a real UINavigationBar object, but a simulated one. Simulated Metrics will infer the context around the scene and show a navigation bar when it’s inside a Navigation Controller, a tab bar when it’s inside a Tab Bar Controller, and so on.
To connect these two new scenes to the Tab Bar Controller, ctrl-drag from the Tab Bar Controller to the Navigation Controller. When you let go, a small popup menu appears. Choose the Relationship Segue – view controllers option:
This creates a new relationship arrow between the two scenes. This is also an embed Relationship as you saw with the other controllers contained by the Tab Bar Controller.
The Tab Bar Controller has two embed relationships, one for each tab. The Navigation Controller itself has an embed Relationship with the Table View Controller.
When you made this new connection, a new tab was added to the Tab Bar Controller, simply named “Item”. For this app, you want this new scene to be the first tab, so drag the tabs around to change their order:
Build and run the app to try it out. The first tab now contains a table view inside a navigation controller.
Before you put some actual functionality into this app, you need to clean up the storyboard a little. You’ll name the first tab “Players” and the second “Gestures”. You don’t change this on the Tab Bar Controller itself, but in the view controllers connected to these tabs.
As soon as you connect a view controller to a Tab Bar Controller, it’s given a Tab Bar Item object which you can see in the Document Outline or the bottom of the scene. Use this Tab Bar Item to configure the tab’s title and image seen on the Tab Bar Controller.
Select the Tab Bar Item inside the Navigation Controller, and in the Attributes inspector set its Title to Players:
Next, rename the Tab Bar Item for the second tab to Gestures the same way you did above.
A well-designed app should also put icons on these tabs. The resources for this tutorial contains a subfolder named Images. Drag that folder into the Assets.xcassets subfolder in the project.
Open Main.storyboard, in the Attributes inspector for the Players Tab Bar Item, choose the Players image.
Next, give the Gestures Tab Bar Item the image Gestures.
A view controller embedded inside a Navigation Controller has a Navigation Item used to configure the navigation bar. Select the Navigation Item for the Table View Controller in the Document Outline and change its title in the Attributes inspector to Players. .
Notice the Scene title in the Document Outline now changes to Players
Note: Alternatively, you can double-click the navigation bar and change the title there. You should double-click the simulated navigation bar in the Table View Controller, not the actual Navigation Bar object in the Navigation Controller.
Build and run the app. Now marvel at your pretty tab bar, created without writing a single line of code!
Prototype Cells
Prototype cells allow you to easily design a custom layout for your table view cells directly within the storyboard editor.
The Table View Controller comes with a blank prototype cell. Click the cell to select it and in the Attributes inspector set the Style option to Subtitle. This immediately changes the appearance of the cell to include two labels.
Note: With so much stackable content on a storyboard, it can sometimes be difficult to click on exactly what you want. If you have trouble, there’s several options. One is you can select the item in the Document Outline to the left of the canvas. The second is a handy hotkey: hold control + shift and click on the area you’re interested in. A popup will appear allowing you to select any element directly under your cursor.
If you’ve used table views before and created your own cells by hand, you may recognize this as the UITableViewCellStyle.Subtitle style. With prototype cells you can pick one of the built-in cell styles as you just did, or create your own custom design (which you’ll do shortly).
Set the Accessory attribute to Disclosure Indicator and the Identifier to PlayerCell. All prototype cells must have a reuse identifier so you can refer to them in code. In addition, set the cell’s Selection to None.
Note: The cell’s Selection attribute is set to None to prevent the user from editing an existing item by tapping the PlayerCell. Although you won’t be adding this functionality in this tutorial, you will have enough knowledge by the end of Part 2 to implement this feature into the sample project for additional practice.
Build and run the app, nothing has changed. That’s not so strange: you still have to make a data source for the table so it knows which rows to display. You’re going to do that next.
Add a new file to the project. Choose the Cocoa Touch Class template under iOS/Source. Name the class PlayersViewController and make it a subclass of UITableViewController. Uncheck Also create XIB file. Choose the Swift language and hit Next followed by Create.
Open Main.storyboard and select the Table View Controller (make sure you select the actual view controller and not one of its views). In the Identity inspector, set its Class to PlayersViewController. This is an essential step for hooking up a scene from the storyboard with your custom view controller subclass. Don’t forget this or your class won’t be used!
Now when you run the app the table view controller from the storyboard is an instance of the PlayersViewController class.
The table view should display a list of players, so now you’ll create the main data model for the app – an array containing Player objects. Add a new file to the project using the Swift File template under iOS/Source and name the file Player.
Replace the code in Player.swift with the following:
import Foundation struct Player { // MARK: - Properties var name: String? var game: String? var rating: Int }
There’s nothing special going on here. Player is simply a container object for these three properties: the name of the player, the game they’re playing, and a rating of 1 to 5 stars. Note because you didn’t define a custom initializer, the struct will automatically receive a default memberwise initializer which can be used to set all of its properties.
Next, create a new file using the Swift File template named SampleData. Replace the contents of SampleData.swift with the following:
import Foundation final class SampleData { static func generatePlayersData() -> [Player] { return [ Player(name: "Bill Evans", game: "Tic-Tac-Toe", rating: 4), Player(name: "Oscar Peterson", game: "Spin the Bottle", rating: 5), Player(name: "Dave Brubeck", game: "Texas Hold 'em Poker", rating: 2) ] } }
Here you’ve defined a static method on SampleData to generate an array of hard coded Player objects.
Next, open PlayersViewController.swift and replace the contents of the file with the following:
import UIKit class PlayersViewController: UITableViewController { // MARK: - Properties var players = SampleData.generatePlayersData() }
You could have set up the sample data in PlayersViewController when defining the players variable. But this data might be provided from a plist or other outside source, hence it’s wise to handle loading the data outside of the view controller.
Now you’ve an array full of Player objects, continue hooking up the data source in PlayersViewController. Still in PlayersViewController.swift, add the following extension to the end of the file:
// MARK: - UITableViewDataSource extension PlayersViewController { override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return players.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "PlayerCell", for: indexPath) let player = players[indexPath.row] cell.textLabel?.text = player.name cell.detailTextLabel?.text = player.game return cell } }
The method dequeueReusableCell(withIdentifier:for:) will check to see if there’s an existing cell that can be recycled. If not, it will automatically allocate a prototype cell and return it to you. All you need to do is supply the re-use identifier you set on the prototype cell in the storyboard editor – in this case PlayerCell. Don’t forget to set the identifier, or this little scheme won’t work!
Build and run the app, the table view has players in it!
It takes just a few lines of code to use these prototype cells. I think that’s just great!
Note: In this app you’re using only one prototype cell. If your table needs to display different kinds of cells you can add additional prototype cells to the storyboard. Make sure to give each cell its own re-use identifier!
Designing Your Own Prototype Cells
Using a standard cell style is fine for most apps, but for this app you want to add an image on the right-hand side of the cell showing the player’s rating. Having an image view in that spot is not supported by the standard cell styles, so you’ll have to make a custom design.
Open Main.storyboard, select the prototype cell in the table view, and in Attributes inspector, set its Style attribute to Custom. The default labels now disappear.
First make the cell a little taller. Either change the Row Height value in the Size inspector (after checking Custom) or drag the handle at the bottom of the cell. Make the cell 60 points high.
Drag two Label objects from the Objects Library into the cell and place them roughly where the standard labels were previously. Just play with the font and colors in the Attributes Inspector and pick something you like. Set the text of the top label to Name and the bottom label to Game.
Select both the Name and Game labels in the Document Outline using Command+click, and choose Editor\Embed In\Stack View.
Note: Stack views were introduced in in iOS 9 and are brilliant for easily laying out collections of views. You can find out more about stack views in our UIStackView Tutorial.
Drag an Image View into the cell and place it on the right, next to the disclosure indicator. In the Size Inspector, make it 81 points wide and 35 points high. Set its Content Mode to Center (under View in the Attributes inspector) so whatever image you put into this view is not stretched.
Command + click the Stack View and Image View in the Document Outline to select both of them. Choose Editor\Embed in\Stack View. Xcode will create a new horizontal stack view containing these two controls.
Select this new horizontal stack view, and in the Attributes Inspector, change the Alignment to Center and the Distribution to Equal Spacing.
Now for some simple auto layout for this control. At the bottom right of the storyboard, click the Pin icon:
Change the top constraints to Top: 0, Right: 20, Bottom: 0 and Left: 20. Make sure the four red pointers to the values are highlighted as in the picture. Click Add 4 Constraints at the bottom of the popover window.
If your stack view has orange constraints, it is misplaced. To fix this, select the horizontal stack view and choose Editor\Resolve Auto Layout Issues\Update Frames (in the Selected Views section of the menu). The stack view should position itself correctly and the orange constraint errors go away.
To position the image view within the stack view, select the image view in the Document Outline and choose Editor\Resolve Auto Layout Issues\Add Missing Constraints (in the Selected Views section of the menu).
You may see a small arrow highlighted in red in the Document Outline indicating unresolved layout issues with the stack view. Click on this arrow and click on the red circle to view Xcode’s suggested auto-fix. Selecting Change Priority for either the Name or Game labels’ hugging priority should silence this warning.
The final design for the prototype cell looks something like this:
Because this is a custom designed cell, you can no longer use UITableViewCell’s textLabel and detailTextLabel properties to put text into the labels. These properties refer to labels that aren’t on this cell anymore; they’re only valid for the standard cell types. Instead, you’ll subclass UITableViewCell to provide the functionality.
Note: You could use Tags in this situation, however tags do not provide the type of object which the compiler can check at runtime hence you have to use type casting and checking during runtime which you should avoid if at all possible. For this reason, tags were no longer considered prudent to teach in this situation.
Using a Subclass for the Cell
Add a new file to the project, with the Cocoa Touch Class template. Name it PlayerCell and make it a subclass of UITableViewCell. Don’t check the option to create a XIB, as you already have the cell in your storyboard.
Next, add the following to the PlayerCell class, just below the class definition:
// MARK: - IBOutlets @IBOutlet weak var gameLabel: UILabel! @IBOutlet weak var nameLabel: UILabel! @IBOutlet weak var ratingImageView: UIImageView!
These IBOutlets can be connected to your scene using the storyboard.
Next, add the following property below the IBOutlets:
// MARK: - Properties var player: Player? { didSet { guard let player = player else { return } gameLabel.text = player.game nameLabel.text = player.name ratingImageView.image = image(forRating: player.rating) } }
Whenever the player property is set, it’ll verify there’s a value and if so, update the IBOutlets with the correct information.
Next, add the following method below player:
func image(forRating rating: Int) -> UIImage? { let imageName = "\(rating)Stars" return UIImage(named: imageName) }
This returns a different star image depending on the provided rating.
Next, open Main.storyboard, select the prototype cell PlayerCell and change its class to PlayerCell in the Identity inspector. Now whenever you ask the table view for a new cell with dequeueReusableCell(withIdentifier:for:), it’ll return a PlayerCell instance instead of a regular UITableViewCell.
Note: You gave this class the same name as the reuse identifier – they’re both called PlayerCell – but that’s only because I like to keep things consistent. The class name and reuse identifier have nothing to do with each other, so you can name them differently if you wish.
Finally, connect the labels and the image view to these outlets. Navigate to the Connections Inspector in the storyboard and then select the Player Cell from either the canvas or Document Outline. Drag from the nameLabel Outlet in the Connections inspector to the Name label object in either the Document Outline, or the canvas. Repeat for gameLabel and ratingImageView.
Note: You should hook up the controls to the table view cell, not to the view controller! You see, whenever your data source asks the table view for a new cell with dequeueReusableCell, the table view doesn’t give you the actual prototype cell but a copy (or one of the previous cells is recycled if possible).
This means there will be more than one instance of PlayerCell at any given time. If you were to connect a label from the cell to an outlet on the view controller, then several copies of the label will try to use the same outlet. That’s just asking for trouble. (On the other hand, connecting the prototype cell to actions on the view controller is perfectly fine. You would do that if you’ve custom buttons or other UIControls on your cell.)
Now you’ve hooked up the properties, you can simplify the data source code a bit. Open PlayersViewController.swift, and change tableView(_:cellForRowAt:) to the following:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "PlayerCell", for: indexPath) as! PlayerCell let player = players[indexPath.row] cell.player = player return cell }
That’s more like it. You now cast the object you receive from dequeueReusableCell to a PlayerCell, and pass the correct player to the cell. Setting the player variable in PlayerCell will automatically propagate the values into the labels and image view. Isn’t it great how using prototype cells makes table views a whole lot less messy?
Build and run the app.
Hmm, that doesn’t look quite right – the cells appear to be squished. You did change the height of the prototype cell, but the table view doesn’t take that into consideration. There’s two ways to fix it: you can change the table view’s Row Height attribute, or implement the tableView(_:heightForRowAt:) method. The former is fine in this case because we only have one type of cell and we know the height in advance.
Note: You would use tableView(_:heightForRowAt:) if you didn’t know the height of your cells in advance, or if different rows can have different heights.
Open Main.storyboard, in the Size inspector of the Table View, set Row Height to 60:
Build an run the app.
That’s much better isn’t it!
Note: If you changed the cell height by dragging its handle rather than typing in the value, the table view’s Row Height property was automatically changed too. So it may have worked correctly for you the first time around.
Where To Go From Here?
Click here to download the full source code for the project up to this point.
Check out part two of this tutorial, where we’ll cover segues, static table view cells, the Add Player scene, a game picker scene, and the full downloadable example project for this tutorial!
If you felt lost at any point during this tutorial, you also might want to brush up on the basics with our iOS Apprentice series. In that series, you’ll learn the foundational knowledge you need as an iOS developer from the ground up — perfect for complete beginners, or those looking to fill in some gaps.
If you have any questions or comments on this tutorial or on storyboards, please join the forum discussion below!
The post Storyboards Tutorial for iOS: Part 1 appeared first on Ray Wenderlich.
Storyboards Tutorial for iOS: Part 1 syndicated from http://ift.tt/2uHrXAJ
0 notes
Text
swift3初心者が集めた勉強に役立つリンク集
ASHISH KAKKAD iOSスライドメニュー、プッシュ通知などいろいろ実用できるサンプルがあります。 リンク: ASHISH KAKKAD UITabBarControllerをコードから使ってみる Xcode 7.1(swift2) iOS 9.1(Simulator) リンク: UITabBarControllerをコードから使ってみる _ha1f 2015年11月03日に投稿 【Swift 3】UITabBarを使って下部メニューを作成してみた【UITabBar】 リンク: 【Swift 3】UITabBarを使って下部メニューを作成してみた【UITabBar】 2016年12月03日 iOSでプッシュ通知を実装する(PHP,Swift3) リンク: iOSでプッシュ通知を実装する(PHP,Swift3) 2016年11月5日 iOSのメニュー周りライブラリ集 リンク:…
View On WordPress
0 notes