I have used the following code to try and change the layout of a UIAlertController using a nib however the dialog just shows up and looks the same each time regardless of the nib specified, it looks like a translucent grey box, at the bottom of my screen.
class AlertDialogViewController: UIViewController {
var message: String = ""
override init() {
super.init(nibName: "SignUpViewController", bundle: nil)
//Below two lines are important for custom transitions.
transitioningDelegate = self
modalPresentationStyle = .Custom
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
//Other code for your dialog controller
// .
// .
// .
}
extension AlertDialogViewController : UIViewControllerAnimatedTransitioning {
func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
return 0.5 //Add your own duration here
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
//Add presentation and dismiss animation transition here.
}
}
extension AlertDialogViewController : UIViewControllerTransitioningDelegate {
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return self
}
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return self
}
}
extension UIViewController {
func showAleartWithMessage(message: String) {
var ad = AlertDialogViewController()
ad.message = message
presentViewController(ad, animated: true, completion: nil)
}
}
You can't
The UIAlertController class is intended to be used as-is and does not
support subclassing. The view hierarchy for this class is private and
must not be modified.
Edit: Relevant code to what I said in comment is added
Imagine you want a dialog box with a UILable and two UIButtons instance
class CustomView : UIView {
var commentLabel: UILable!
var okayButton: UIButton!
var cancelButton: UIButton!
init(frame: CGRect) {
super.init(frame: frame)
commentLabel = UILabel()
okayButton = UIButton.buttonWithType(.Custom)
cancelButton = UIButton.buttonWithType(.Custom)
// TODO: Configuration such target, action, titleLable, etc. left to the user
[commentLabel, okayButton, cancelButton].map { self.addSubview($0) }
}
#IBAction func okayButtonAction(sender: AnyObject) {
// TODO: Complete implementation
}
#IBAction func okayButtonAction(sender: AnyObject) {
// TODO: Complete implementation
}
}
class CustomAlertDialogViewCongroller : UIViewController {
override func loadView() {
self.view = CustomView(frame: CGRect(x: 0, y: 0, width: 200, height: 100))
}
}
// In the view controller that you want to present that alert dialog. Let's call it viewController
let customAlertDialogViewController = CustomAlertDialogViewCongroller()
customAlertDialogViewController.modalPresentationStyle = .UIModalPresentationFormSheet
customAlertDialogViewController.modalTransitionStyle = .CoverVertical
viewController.presentViewController(customAlertDialogViewController, animated: true, completion: nil)
Related
There are two view controllers, MainViewController and ChildViewController, I want to add ChildViewController to MainViewController and this is my code:
MainViewController.swift
class MainViewController: UIViewController {
#IBOutlet weak var containerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
self.add(ChildViewController(), in: containerView)
}
}
ChildViewController.swift
class ChildViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("ChildViewController is loaded")
}
}
UIViewController+Ext.swift
extension UIViewController {
func add(_ child: UIViewController, in container: UIView) {
addChild(child)
container.addSubview(child.view)
child.view.frame = container.bounds
child.didMove(toParent: self)
}
func add(_ child: UIViewController) {
add(child, in: view)
}
func remove(from view: UIView) {
guard parent != nil else {
return
}
willMove(toParent: nil)
removeFromParent()
view.removeFromSuperview()
}
func remove() {
remove(from: view)
}
}
Storyboard
Output:
"ChildViewController is loaded" appears in the terminal but the UI components are not loaded.
self.add(ChildViewController(), in: containerView)
You are creating a ChildViewController instance programatically instead of getting it from the storyboard.
if let childViewController = self.storyboard?.instantiateViewController(withIdentifier: "ChildViewController") {
self.add(ChildViewController(), in: containerView)
}
I want to trigger Navigation controller to some other screen when i press the button in UIView class. How can i do this?
//Code for UIView Class in Which Button Iboutlet is created
import UIKit
protocol ButtonDelegate: class {
func buttonTapped()
}
class SlidesVC: UIView {
var delegate: ButtonDelegate?
#IBAction func onClickFinish(_ sender: UIButton) {
delegate?.buttonTapped()
}
#IBOutlet weak var imgProfile: UIImageView!
}
//ViewController Class code in Which Button Protocol will be entertained
class SwipingMenuVC: BaseVC, UIScrollViewDelegate {
var slidesVC = SlidesVC()
override func viewDidLoad() {
super.viewDidLoad()
slidesVC = SlidesVC()
// add as subview, setup constraints etc
slidesVC.delegate = self
}
extension BaseVC: ButtonDelegate {
func buttonTapped() {
self.navigationController?.pushViewController(SettingsVC.settingsVC(),
animated: true)
}
}
A more easy way is to use typealias. You have to write code in 2 places. 1. your viewClass and 2. in your View Controller.
in your SlidesView class add a typealias and define param type if you need otherwise leave it empty.
class SlidesView: UIView {
typealias OnTapInviteContact = () -> Void
var onTapinviteContact: OnTapInviteContact?
#IBAction func buttonWasTapped(_ sender: UIButton) {
if self.onTapinviteContact != nil {
self.onTapinviteContact()
}
}
}
class SwipingMenuVC: BaseVC, UIScrollViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let slidesView = SlidesView()
slidesView.onTapinviteContact = { () in
// do whatever you want to do on button tap
}
}
You can use the delegate pattern to tell the containing ViewController that the button was pressed and let it handle whatever is needed to do next, The view doesn't really need to know what happens.
A basic example:
protocol ButtonDelegate: class {
func buttonTapped()
}
class SomeView: UIView {
var delegate: ButtonDelegate?
#IBAction func buttonWasTapped(_ sender: UIButton) {
delegate?.buttonTapped()
}
}
class ViewController: UIViewController {
var someView: SomeView
override func viewDidLoad() {
someView = SomeView()
// add as subview, setup constraints etc
someView.delegate = self
}
}
extension ViewController: ButtonDelegate {
func buttonTapped() {
self.showSomeOtherViewController()
// or
let vc = NewViewController()
present(vc, animated: true)
}
}
I have several viewcontrollers embedded in a UINavigationController. I would like to customize the appearance of the Navigation Bar title for each viewController. What is the best method where to call setCustomTitleInNavBar. If it is called in viewDidLoad, self is not yet initialized and the app will crash. In ViewWillAppear title is not yet displayed when view is shown to user. Please advise alternative implementation if this is not the correct way to do it.
class CustomMethods {
func setCustomTitleInNavBar(textValue:String, VC:UIViewController) -> UIView {
let titleLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 40, height: 40))
titleLabel.text = textValue
titleLabel.adjustsFontSizeToFitWidth = true
titleLabel.textAlignment = NSTextAlignment.center
VC.navigationItem.titleView = titleLabel
return VC.navigationItem.titleView!
}
}
//call method on the current view controller to modify the nav bar title
class someViewController: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
setCustomTitleInNavBar(textValue: "Where to come?", VC: self)
}
}
Here is a way to implement it through protocol :
// Protocol
protocol NavigationBarSetUpProtocol: class {
// Add more param if needed
func setupNavigationBar(with title: String)
}
// Default implemention
extension NavigationBarSetUpProtocol where Self: UIViewController {
// Default implementation
func setupNavigationBar(with title: String) {
// configure you VC navigation item with : self.navigationItem.titleView = ...
}
}
// VC A
class ViewControllerA: UIViewController, NavigationBarSetUpProtocol {
override func viewDidLoad() {
super.viewDidLoad()
setupNavigationBar(with: "HOME")
}
}
// VC B
class ViewControllerB: UIViewController, NavigationBarSetUpProtocol {
override func viewDidLoad() {
super.viewDidLoad()
setupNavigationBar(with: "PROFILE")
}
}
You can call
navigationItem.title = "Your title"
in viewDidLoad.
I have a CenterViewController which contains a Game Controller. I want to add/remove a RulesViewController that the user can easily refer to as they play.
The RulesViewController appears and is dismissed fine. But the delegate.continueGame method is never called. I've added the protocol to RulesViewController. I've added a class extension to CenterViewController to handle the delegate. What am I missing?? Any help much appreciated...
Class CenterViewController: UIViewController {
private var controller: GameController
required init(coder aDecoder: NSCoder){
controller = GameController()
}
override func viewDidLoad() {
// add all the views here
let gameView = UIView(frame: CGRectMake(0,0, ScreenWidth, ScreenHeight))
self.view.addSubview(gameView)
controller.gameView = gameView
}
// method called when rules button on the gameView is pressed
func showRulesForLevel () {
let rulesViewController = storyboard!.instantiateViewControllerWithIdentifier("RulesViewController") as! RulesViewController
presentViewController(rulesViewController, animated: true, completion: nil)
// extension to the Class to handle the delegate
extension CenterViewController: RulesViewControllerDelegate {
//func to continue the game
func continueGame() {
controller.gameView.userInteractionEnabled = true
}
}
In the RulesViewController I have:
protocol RulesViewControllerDelegate {
func continueGame()
}
class RulesViewController: UIViewController {
var delegate: RulesViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// code to add a continue button which when pressed calls continueGameAction method
}
func continueGameAction() {
// dismiss the UIViewController so game can continue
self.dismissViewControllerAnimated(true, completion: nil)
// continue the game in CenterViewController
delegate?.continueGame()
}
}
BUT delegate?.continueGame() is never called.
Ok so you need to set the delegate in showRulesForLevel method like this:
rulesViewController.delegate = self
:)
I am trying to create a custom UIView and display it as a pop up in my main View using Swift.
My Custom UIView code is
class DatePopUpView: UIView {
var uiView:UIView?
override init() {
super.init()
self.uiView = NSBundle.mainBundle().loadNibNamed("DatePopUpView", owner: self, options: nil)[0] as? UIView
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
required override init(frame: CGRect) {
super.init(frame: frame)
}
}
And I am Calling it in my main view as:
#IBAction func date_button_pressed (sender : AnyObject?) {
var popUpView = DatePopUpView()
var centre : CGPoint = CGPoint(x: self.view.center.x, y: self.view.center.y)
popUpView.center = centre
popUpView.layer.cornerRadius = 10.0
let trans = CGAffineTransformScale(popUpView.transform, 0.01, 0.01)
popUpView.transform = trans
self.view .addSubview(popUpView)
UIView .animateWithDuration(0.5, delay: 0.0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {
popUpView.transform = CGAffineTransformScale(popUpView.transform, 100.0, 100.0)
}, completion: {
(value: Bool) in
})
}
But popUp is not Coming. I used breakpoint and noticed that value is getting assigned to my popUpView but still it is not displayed on my main View. Please Help
Please Note: I am using StoryBoard for my mainView and custom View i have made using xib.
Without additional description on what you are attempting to do, may I suggest something like the code below? Basically, you can use .hidden feature of a view (or any other control) to show/hide the view. You can set the size and positioning of the view to be popped by using the layout editor.
import UIKit
class ViewController: UIViewController {
var popped = false
var popupBtnTitle = "Show Popup"
#IBAction func popupButton(sender: UIButton) {
popped = !popped
anotherView.hidden = !popped
popupBtnTitle = popped ? "Hide Popup" : "Show Popup"
popupButtonOutlet.setTitle(popupBtnTitle, forState: UIControlState.Normal)
}
#IBOutlet weak var popupButtonOutlet: UIButton!
#IBOutlet weak var anotherView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
popped = false
anotherView.hidden = !popped
popupButtonOutlet.setTitle(popupBtnTitle, forState: UIControlState.Normal)
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}