I am currently working on the iOS project.
My problem is that when I see the new screen, I don't see the old screen and I only see the new one.
I want a modal screen. What am I missing?
move ModalScreen
func callAlert(_ text: String!) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let myAlert = storyboard.instantiateViewController(withIdentifier: "ModalViewController") as! ModalViewController
myAlert.modalPresentationStyle = .overCurrentContext
myAlert.modalTransitionStyle = .crossDissolve
myAlert.text = text
self.present(myAlert, animated: false, completion: nil)
}
modalScreenController
class ModalViewController : UIViewController {
var text: String?
#IBOutlet weak var modalCustomAlert: UITextView!
#IBOutlet weak var okButton: UIButton!
#IBAction func okPress(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
modalCustomAlert.layer.cornerRadius = 8
self.modalCustomAlert.text = text
}
...
modalStoryBoard
You need to set a background color with alpha component in your viewcontroller's view.
class ModalViewController : UIViewController {
var text: String?
#IBOutlet weak var modalCustomAlert: UITextView!
#IBOutlet weak var okButton: UIButton!
#IBAction func okPress(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.black.withAlphaComponent(0.5) //Your desired color and alpha component
modalCustomAlert.layer.cornerRadius = 8
self.modalCustomAlert.text = text
}
Related
So I want to instantiate a view controller from storyboard and change its static variables.
This is "vc1" - the view controller to be instantiated:
import UIKit
class vc1: UIViewController {
#IBOutlet weak var lbl_title: UILabel!
static var title = "initial value"
override func viewDidLoad() {
super.viewDidLoad()
lbl_title.text = vc1.title
}
}
And this is my root vc.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var btn_go: UIButton!
#IBAction func btn_gogogo(_ sender: Any) {
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "vc1") as! vc1
vc.title = "bla"
self.present(vc, animated: true, completion: nil)
}
}
Here I'm trying to change the static variable of the view controller that I just instantiated,
with no effect. The variable ( in my case 'title' ) is always stuck to its initial value.
What is the problem here?
Best
Mark
Don't try to override the view controller's title property. Instead, create your own:
class vc1: UIViewController {
#IBOutlet weak var lbl_title: UILabel!
var myTitle = "initial value"
override func viewDidLoad() {
super.viewDidLoad()
lbl_title.text = myTitle
}
}
class ViewController: UIViewController {
#IBOutlet weak var btn_go: UIButton!
#IBAction func btn_gogogo(_ sender: Any) {
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "vc1") as! vc1
vc.myTitle = "bla"
self.present(vc, animated: true, completion: nil)
}
}
I have my main screen with only one button on it "Show next screen". When the second screen(VC) pops up it has 2 buttons (go back and toSelect button).
My goal is to when I show my second screen and select a button on it then go back to first. The button on my second screen will stay selected. How can I do that?
So basically I need to save my actions on the second screen so if I go back to it it will show everything I did.
What is the best way to do it?
Storyboard
The easiest way to achieve this using Delegate and protocol.
you should listen and save the changes of SecondViewController at FirstViewController using delegate methods.
And when you are presenting the secondViewController you will share the saved changes to secondViewController so that button can be selected on behalf of that information
Code -
class FirstViewController: UIViewController {
//secondViewController States
private var isButtonSelected = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func gotoSecondVCAction(_ sender: Any) {
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
guard let secondVC = storyBoard.instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController else { return }
secondVC.isButtonSelected = isButtonSelected
secondVC.delegate = self
self.present(secondVC, animated: true, completion: nil)
}
}
extension FirstViewController: ButtonSelectionProtocol {
func button(isSelected: Bool) {
isButtonSelected = isSelected
}
}
and for secondViewController
protocol ButtonSelectionProtocol {
func button(isSelected:Bool)
}
class SecondViewController: UIViewController {
var isButtonSelected : Bool = false
var delegate:ButtonSelectionProtocol?
#IBOutlet weak var selectButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
if isButtonSelected {
selectButton.tintColor = .red
selectButton.setTitle("Selected", for: .normal)
}else{
selectButton.tintColor = .green
selectButton.setTitle("Select Me", for: .normal)
}
}
#IBAction func gobackAction(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
#IBAction func selectAction(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
isButtonSelected.toggle()
delegate?.button(isSelected: isButtonSelected)
}
}
I have 2 UIViewControllers and I try to hide an UILabel from the second UIViewController using Notifications and Observer.
Is the first time when I use this design pattern and I'm a little bit confused. What I'm doing wrong ?
I want to specify that I'm getting the message from that print for the first time only when I click the back button from the second ViewController.
And after that I'm getting the message normal when I click Go Next but the UILabel is not hidden or colour changed.
Here is my code for first UIViewController:
class ReviewPhotosVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.post(name: Notification.Name("NotificationOfReviewMode"), object: nil)
}
#IBAction func goNextTapped(_ sender: UIButton) {
let fullscreenVC = storyboard?.instantiateViewController(withIdentifier: "FullscreenPhoto") as! FullscreenPhotoVC
self.present(fullscreenVC, animated: true, completion: nil)
}
}
Here is my code for second UIViewController:
class FullscreenPhotoVC: UIViewController {
#IBOutlet weak var customLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self,
selector: #selector(hideCustomLabel),
name: Notification.Name("NotificationOfReviewMode"),
object: nil)
}
#IBAction func goBackTapped(_ sender: UIButton) {
let reviewPhotosVC = storyboard?.instantiateViewController(withIdentifier: "ReviewPhotos") as! ReviewPhotosVC
self.present(reviewPhotosVC, animated: true, completion: nil)
}
#objc func hideCustomLabel(){
customLabel.isHidden = true
customLabel.textColor = .red
print("My func was executed.")
}
}
Here is my Storyboard:
Thanks if you read this.
The problem is that you are posting the notification before the next controller is initialised and has started observing. Also, there is no need for the notification you can do it directly. In this case I have used an extra variable shouldHideLabel as you cannot call the function hideCustomLabel() directly because this will lead to crash as the outlets are only initialised after view is loaded.
class ReviewPhotosVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//NotificationCenter.default.post(name: Notification.Name("NotificationOfReviewMode"), object: nil)
}
#IBAction func goNextTapped(_ sender: UIButton) {
let fullscreenVC = storyboard?.instantiateViewController(withIdentifier: "FullscreenPhoto") as! FullscreenPhotoVC
fullscreenVC.shouldHideLabel = true
self.present(fullscreenVC, animated: true, completion: nil)
}
}
class FullscreenPhotoVC: UIViewController {
var shouldHideLabel = false
#IBOutlet weak var customLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
if shouldHideLabel {
hideCustomLabel()
}
/*
NotificationCenter.default.addObserver(self,
selector: #selector(hideCustomLabel),
name: Notification.Name("NotificationOfReviewMode"),
object: nil)
*/
}
#IBAction func goBackTapped(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
#objc func hideCustomLabel() {
customLabel.isHidden = true
customLabel.textColor = .red
print("My func was executed.")
}
}
On my storyboard I have main ViewController, not TabBarViewController, which consist of TabBar on the bottom, view on the top and ContainerView on the middle. ContainerView have a NavigationController. I also have 4 ViewControllers, one of them - RootViewController of NavigationController. I wish to show one of ViewControllers when I selecting TabBarItem, and in future I will add slide menu, which also will show selected ViewController.
I have next code, which only shows initial ViewController inside ContainerView, and when I selecting TabBarItems, new ViewControllers don't showing and I see only first View Controller. What goes wrong?
class ViewController: UIViewController {
#IBOutlet weak var container: UIView!
#IBOutlet weak var first: UITabBarItem!
#IBOutlet weak var second: UITabBarItem!
#IBOutlet weak var third: UITabBarItem!
#IBOutlet weak var fours: UITabBarItem!
#IBOutlet weak var tabBar: UITabBar!
var firstVC: FirstViewController?
var secondVC: SecondViewController?
var thirdVC: ThirdViewController?
var foursVC: FoursViewController?
var navi: UINavigationController?
override func viewDidLoad() {
super.viewDidLoad()
tabBar.delegate = self
initialSetup()
}
func initialSetup() {
tabBar.selectedItem = tabBar.items?.first
navi = self.storyboard?.instantiateViewController(withIdentifier: "containerNavi") as? UINavigationController
firstVC = self.storyboard?.instantiateViewController(withIdentifier: "FirstViewController") as? FirstViewController
secondVC = self.storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController
thirdVC = self.storyboard?.instantiateViewController(withIdentifier: "ThirdViewController") as? ThirdViewController
foursVC = self.storyboard?.instantiateViewController(withIdentifier: "FoursViewController") as? FoursViewController
}
func showVC(number: Int) {
switch number {
case 0:
navi?.popToRootViewController(animated: true)
print("0")
case 1:
if let second = secondVC {
navi?.pushViewController(second, animated: true)
}
print("1")
case 2:
if let third = thirdVC {
navi?.pushViewController(third, animated: true)
}
print("2")
case 3:
if let fours = foursVC {
navi?.pushViewController(fours, animated: true)
}
print("3")
default:
return
}
}
}
extension ViewController: UITabBarDelegate {
func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
showVC(number: item.tag)
}
}
Storyboard screenshot:
You can try to use this extesion to add/remove any of the 4 to containerView
extension UIViewController {
func add(_ child: UIViewController, frame: CGRect? = nil) {
addChildViewController(child)
if let frame = frame {
child.view.frame = frame
}
view.addSubview(child.view)
child.didMove(toParentViewController: self)
}
func remove() {
willMove(toParentViewController: nil)
view.removeFromSuperview()
removeFromParentViewController()
}
}
// use it like this
let vc = self.storyboard?.instantiateViewController(withIdentifier: "first")
self.add(vc, frame: self.containerView.frame)
to remove
vc.remove()
I am having troubles showing the Game Center leaderboard when the user presses a button on my SecondViewController (game over screen with score/top score). The UIbutton is ShowLeaderboard which you'll see below.
The error I get is:
Warning: Attempt to present <GKGameCenterViewController: 0x7fb1c88044a0> on <UIViewController: 0x7fb1c2624e90> whose view is not in the window hierarchy!
I have tried dismissing the view first but no matter what I do I can't just get the leaderboard view to show. Below is my SecondViewController code:
import UIKit
import GameKit
class SecondViewController: UIViewController, GKGameCenterControllerDelegate {
#IBOutlet var scoreLabel: UILabel!
#IBOutlet var HighScoreLabel: UILabel!
var receivedString: String = ""
var receivedHighScore: String = ""
override func viewDidLoad() {
super.viewDidLoad()
scoreLabel.text = receivedString
HighScoreLabel.text = receivedHighScore
}
#IBAction func ShowLeaderboard(sender: UIButton) {
dismissViewControllerAnimated(true, completion:nil)
showLeader()
}
func showLeader() {
var vc = self.view?.window?.rootViewController
var gc = GKGameCenterViewController()
gc.gameCenterDelegate = self
vc?.presentViewController(gc, animated: true, completion: nil)
}
func gameCenterViewControllerDidFinish(gameCenterViewController: GKGameCenterViewController!)
{
gameCenterViewController.dismissViewControllerAnimated(true, completion: nil)
}
override func prefersStatusBarHidden() -> Bool {
return true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func retryButton(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil)
}
}
EDIT Got it working! All I had to do was change
var vc = self.view?.window?.rootViewController
to
var vc = self
You are probably seeing this warning because you are displaying the Leaderboard before dismissViewControllerAnimated has finished the animation. You should place the showLeader() inside the completion argument of dismissViewControllerAnimated.
Here is my Code. Hope it helps!
if (self.levelGameAttemptCount == 3)
{
self.canRestart = false
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = mainStoryboard.instantiateViewControllerWithIdentifier("gameOverControllerID") as! GameOverController
self.view!.window!.rootViewController!.dismissViewControllerAnimated(false, completion: nil)
UIApplication.sharedApplication().keyWindow!.rootViewController!.presentViewController(vc, animated: true, completion: nil)
}
else
{
self.canRestart = true
}