I made a StackView on top of my ScrollView. The bottom constraint of my StackView is constrained to the top constraint of the ScrollView. I use the ScrollView as a container to display my content. The StackView consists of 6 buttons and serves as a navigation. Hierarchy looks like this.
To add a new controller into my ScrollView I use the following code:
#IBAction func planAction(_ sender: UIButton) {
let newPlan = sender.frame.origin.x
scrollView.subviews.forEach{$0.removeFromSuperview()}
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let nextController = storyBoard.instantiateViewController(withIdentifier: "PlansViewController2") as! PlansViewController2
addChildView(viewController: nextController, in: scrollView)
self.movingView.frame.origin.x = newPlan
}
public func addChildView(viewController: UIViewController, in containerView: UIView) {
viewController.view.autoresizingMask = [.flexibleHeight, .flexibleWidth]
viewController.view.frame = containerView.bounds
addChildViewController(viewController)
containerView.addSubview(viewController.view)
viewController.didMove(toParentViewController: self)
}
In my PlansViewController I add a UIBarButtonItem programmatically but it is not displayed. Look here.
public override func viewDidLoad() {
self.navigationController?.setNavigationBarHidden(false, animated: false)
if let viewControllers = self.navigationController?.viewControllers {
if !viewControllers.contains(where: {
return $0 is StructureNavigationListViewController }) {
let filterBtn = UIBarButtonItem(title: "Kategorienliste", style: .plain, target: self, action: #selector(handleCategoryListTap(sender:)))
navigationItem.rightBarButtonItems = [filterBtn]
}
}
Is my hierarchy wrong or what´s going on here?
Related
Juts like clicking a button to show another view contoller, is there a way to do that with a label?
Call below function
NOTE: Please set identifier same which you are you in below code
class firstViewController: UIViewController {
#IBOutlet weak var yourlabel: UILabel
override func viewDidLoad() {
super.viewDidLoad()
self.addGesture()
}
func addGesture() {
let tap = UITapGestureRecognizer(target: self, action: #selector(self. labelTapped(_:)))
tap.numberOfTapsRequired = 1
self.yourlabel.isUserInteractionEnabled = true
self.yourlabel.addGestureRecognizer(tap)
}
#objc
func labelTapped(_ tap: UITapGestureRecognizer) {
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
let SecondVC = storyboard.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
self.navigationController?.pushViewController(SecondVC, animated: animated)
}
}
Second ViewController
class SecondViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}
I have created a button and I was wondering how do I programmatically code an action for the UIButton to take me to another view controller?
This is all I have so far:
let getStartedButton: UIButton = {
let getStartedButton = UIButton()
getStartedButton.backgroundColor = UIColor(red:0.24, green:0.51, blue:0.59, alpha:1.0)
getStartedButton.setTitle("Get Started", for: .normal)
getStartedButton.titleLabel?.font = UIFont(name: "Helvetica Bold", size: 18)
getStartedButton.translatesAutoresizingMaskIntoConstraints = false
getStartedButton.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
return getStartedButton
}()
#objc func buttonAction(sender: UIButton!) {
print("...")
}
If you want to make the transition to another ViewController after pressing the button, you can do this in 2 ways:
1) present(_:animated:completion:)
#objc func buttonAction(sender: UIButton!) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "Main") as! SecondViewController
self.present(vc, animated: true, completion: nil)
}
2) pushViewController(_:animated:)
#objc func buttonAction(sender: UIButton!) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "Main") as! SecondViewController
self.navigationController?.pushViewController(vc, animated: true)
}
There are 3 ways you can show a new View Controller:
Presenting View Controller:
#objc func buttonAction(sender: UIButton!) {
let destinationVC = self.storyboard?.instantiateViewController(withIdentifier: "DestinationViewController") as! DestinationViewController
self.present(destinationVC, animated: true, completion: nil)
}
Performing a Segue from Storyboard:
If you already have the View Controller you want to present in your Storyboard, and it has a segue from your origin VC to your destination VC, then you can add an identifier to the segue and do this...
#objc func buttonAction(sender: UIButton!) {
self.performSegue(withIdentifier: "MySegueIdentifier", sender: self)
}
Pushing View Controller onto Stack (this only works if your original VC is embedded in a Navigation Controller):
#objc func buttonAction(sender: UIButton!) {
let destinationVC = self.storyboard?.instantiateViewController(withIdentifier: "DestinationViewController") as! DestinationViewController
self.navigationController?.pushViewController(destinationVC, animated: true)
}
I have a button in UITableViewController. when I press this button, alert controller appears asks if the user wants to go to the cart page or stay in the same page, as follows,
if user?.uid != nil{
let title = "Item is added to your cart "
let alert = AlertController.instance(title: title)
present(alert, animated: true, completion: nil)
} else{
// Alert asks user to register..
}
AlertController is in different class and I created it with custom animation.
I want when user press (go to cart page) button, the cart page is displayed as if it was as (show,"push") segue.
This is how I pushed the view controller programmatically in alert controller class.
#IBAction func showCartButton(_ sender: Any) {
//---> go to cart page ...
print("cart button pressed")
//-----> this code is working fine with other UIviewcontrollers (however it is 'not working in UItableviewcontroller)
let storyBoard : UIStoryboard = UIStoryboard(name: "Cart", bundle:nil)
let CartViewController = storyBoard.instantiateViewController(withIdentifier: "CartPage")
navigationController?.pushViewController(CartViewController, animated: true)
//-----> this code shows the cart page without the navigation and tabs..
// let storyBoard : UIStoryboard = UIStoryboard(name: "Cart", bundle:nil)
// let CartViewController = storyBoard.instantiateViewController(withIdentifier: "CartPage")
// self.present(CartViewController, animated:true, completion:nil)
}
The push view controller is not working with Alert controller, I am not sure if it is because I used the navigation with the alert, and if so, is there a way I can push the view controller??
This is the whole AlertController Class I created in seperate storyboard and put it as initial view controller..
import UIKit
class AlertController: UIViewController{
#IBOutlet weak fileprivate var AddProductToCartLabel: UILabel!
#IBOutlet weak fileprivate var cartButton: UIButton!
#IBOutlet weak fileprivate var shoppingButton: UIButton!
#IBOutlet weak fileprivate var container: UIView!
var text = String()
override func viewDidLoad() {
setContainer()
setCartButton()
setShoppingButton()
}
override func viewDidLayoutSubviews() {
layoutContainer()
}
#IBAction func cancel(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
#IBAction func showCartButton(_ sender: Any) {
//---> go to cart page ...
print("cart button pressed")
let storyBoard : UIStoryboard = UIStoryboard(name: "Cart", bundle:nil)
let CartViewController = storyBoard.instantiateViewController(withIdentifier: "CartPage")
navigationController?.pushViewController(CartViewController, animated: true)
// let storyBoard : UIStoryboard = UIStoryboard(name: "Cart", bundle:nil)
// let CartViewController = storyBoard.instantiateViewController(withIdentifier: "CartPage")
// self.present(CartViewController, animated:true, completion:nil)
}
#IBAction func completeShopButton(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
}
fileprivate extension AlertController{
// to set the view above
func setContainer() {
let shape = CAShapeLayer()
shape.fillColor = UIColor.white.cgColor
container.backgroundColor = UIColor.clear
container.layer.insertSublayer(shape, at: 0)
}
func setCartButton(){
cartButton.clipsToBounds = true
//cartButton.layer.cornerRadius = 10
}
func setShoppingButton(){
shoppingButton.clipsToBounds = true
shoppingButton.layer.borderColor = UIColor.darkGray.cgColor
shoppingButton.layer.borderWidth = 1
//shoppingButton.layer.cornerRadius = 10
}
}
fileprivate extension AlertController{
// design the size of the container
func layoutContainer() {
let path = UIBezierPath(roundedRect: container.bounds, cornerRadius: 10)
let layer = container.layer.sublayers?.first as! CAShapeLayer
layer.path = path.cgPath
}
}
extension AlertController{
static func instance(title: String?) -> AlertController{
let storyboard = UIStoryboard(name: String(describing: self), bundle: Bundle(for: self))
let controller = storyboard.instantiateInitialViewController() as! AlertController
controller.text = title!
return controller
}
}
The problem is that when you try to push CartViewController, there is no navigation controller to push it on.
You present AlertController modally, and then try to do:
navigationController?.pushViewController(CartViewController, animated: true). If you put a breakpoint here and print out navigationController, I expect it is nil.
I suggest you have AlertController delegate back to your UITableViewController that is inside a navigation controller, and have the tableview controller push to the next screen. You could also present AlertController inside of a navigation view, but this seems unnecessary.
I have a TableViewController which I want to present modally and I need it to have a NavigationBar.
To get that navbar, I have an embedded UINavigationController and as far as I know, that UINavigationController is what I have to present modally, so that's what I've done.
Everything works just fine, but I can't manage to dismiss that controller properly. Here is what I've got so far:
func presentErrorMessages(errorMessages: [String]) {
let storyBoard: UIStoryboard = UIStoryboard(name: "Message", bundle: nil)
let infoMessagesNavigationViewController = storyBoard.instantiateViewController(withIdentifier: "InfoMessagesNavigation") as! ModalNavigationController
let infoMessagesTableViewController = infoMessagesNavigationViewController.viewControllers[0] as! InfoMessagesTableViewController
infoMessagesTableViewController.errorMessages = errorMessages
self.navigationController?.present(infoMessagesNavigationViewController, animated: true)
}
I use that to present ModalNavigationController, and this to dismiss it:
class ModalNavigationController: BaseNavigationController {
var backNavItem = UINavigationItem()
var okNavItem = UINavigationItem()
override func viewDidLoad() {
super.viewDidLoad()
let backButton = UIBarButtonItem(title: "Back", style: .plain, target: self, action: #selector(dismissModal))
backNavItem.leftBarButtonItem = backButton
...
var items = [UINavigationItem]()
items.append(backNavItem)
self.navigationBar.items = items
}
#objc func dismissModal() {
self.dismiss(animated: true)
}
}
When I press that back button, there is no change but the navbar which gets blank (with no title). I have the feeling that the application just 'forgets' what is the NavigationController used before the new one is presented.
How can I solve this?
Try something like this:
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Back", style: .done, target: self, action: #selector(dismissModal))
...
}
#objc func dismissModal() {
self.dismiss(animated: true, completion: nil)
}
I managed to solve the problem by placing and invoking the dismissfunction on my TableViewController rather than my NavigationController:
...
public func setBackButton(){
if self.navigationController != nil {
let item = UIBarButtonItem(title: "Back", style: .plain, target: self, action: #selector(dismissModal))
self.navigationItem.leftBarButtonItem = item
}
}
#objc func dismissModal() {
self.dismiss(animated: true)
}
I am trying to create a rightBarButtonItem that appears throughout my app. When this barItem is clicked I want to show a modal popup using UIPopoverPresentationController. I have been able to get the button to show up on the barItem on all the views. However when i click on the button the xib takes over the entire view (including nav bar, see image below). Please see the class below:
class MyAppsNavigationController: UINavigationController, UINavigationControllerDelegate, UIPopoverPresentationControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
self.navigationBar.barTintColor = Colors.Red01.color()
self.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName : UIColor.white]
}
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
viewController.navigationItem.rightBarButtonItem = UIBarButtonItem(image: #imageLiteral(resourceName: "Ellipsis"), style: .plain, target: self, action: #selector(displayMenu(sender:)))
}
func displayMenu(sender: UIBarButtonItem)
{
let filterVC = DropdownMenuController(nibName: "DropdownMenuController", bundle: nil)
let nav = UINavigationController(rootViewController: filterVC)
nav.modalPresentationStyle = UIModalPresentationStyle.popover
//nav.isNavigationBarHidden = true
nav.preferredContentSize = CGSize(width: 200, height: 300)
let popover = nav.popoverPresentationController! as UIPopoverPresentationController
popover.permittedArrowDirections = .up
popover.delegate = self
popover.barButtonItem = self.navigationItem.rightBarButtonItem
popover.sourceView = self.view;
var frame:CGRect = (sender.value(forKey: "view")! as AnyObject).frame
frame.origin.y = frame.origin.y+20
popover.sourceRect = frame
popover.delegate = self
self.present(nav, animated: true, completion: nil)
}
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
}
Result when clicked on the button:
When clicked the popup takes over entire view:
Any chance you're not using the right delegate method? I think this looks better:
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
Also, in this case sourceView and sourceRect is not needed: specifying a barButtonItem for the popover presentation controller is sufficient.
https://developer.apple.com/documentation/uikit/uipopoverpresentationcontroller/1622314-barbuttonitem