Present viewController after touchUp GIDSignInButton()! - swift

I make a Google Auth for my App, but I don't know how to present a new viewController after touchup GIDSignInButton!
Here how I make GIDSignInButton:
viewDidLoad (){
let googleBtn = GIDSignInButton()
googleBtn.frame = CGRect(x: 16, y: 500 + 66, width: view.frame.width - 32, height: 35)
view.addSubview(googleBtn)}

Here's a code example that will present a second, programmatically generated view controller using a standard UIButton. Obviously, you could do the same with your GIDSignInButton:
class MyViewController: UIViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
let button = UIButton(frame: CGRect(x: 10, y: 250, width: self.view.frame.width - 20, height: 35))
button.setTitle("Go to VC2", for: .normal)
button.backgroundColor = UIColor.blue
button.addTarget(self, action:#selector(self.buttonClicked), for: .touchUpInside)
self.view.addSubview(button)
}
func buttonClicked(sender: UIButton!)
{
let secondViewController = MySecondViewController()
present(secondViewController, animated: true, completion: {})
}
}
class MySecondViewController:UIViewController
{
override func viewDidLoad() {
self.view.backgroundColor = UIColor.darkGray
}
}
Note, however, that if you are presenting multiple views, you are advised to embed them in a Navigation Controller, as per Apple's Documentation

Related

swift can't find textfield in scope even when its in the same viewController

I need to print value of txtField after clicking the button, txtField is on the viewcotroller but xcode returns an error cannot find 'txtField' in scope but they are in the same view
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(frame: CGRect(x: 100, y: 100, width: 100, height: 50))
button.backgroundColor = .green
button.setTitle("Test Button", for: .normal)
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
self.view.addSubview(button)
var txtField: UITextField = UITextField()
txtField.frame = CGRect(x: 50, y: 70, width: 200, height: 30)
txtField.backgroundColor = UIColor.gray
self.view.addSubview(txtField)
}
#objc func buttonAction(sender: UIButton!) {
print(txtField.text)
}
Actually, no, it's not in scope. Your var txtField is inside the viewDidLoad function. No other function's code can see inside this function, so the variable is not in scope from within another function such as your buttonAction.
In general the rule that things inside a scope can see only things that at a higher level of scope. If var txtField appeared outside both viewDidLoad and buttonAction (i.e. an instance property), then code inside both would be able to see it.
It's an easy move to make:
var txtField: UITextField = UITextField()
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(frame: CGRect(x: 100, y: 100, width: 100, height: 50))
button.backgroundColor = .green
button.setTitle("Test Button", for: .normal)
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
self.view.addSubview(button)
txtField.frame = CGRect(x: 50, y: 70, width: 200, height: 30)
txtField.backgroundColor = UIColor.gray
self.view.addSubview(txtField)
}
#objc func buttonAction(sender: UIButton!) {
print(txtField.text)
}
The error is that are in 2 different function, override or #objc doesn't change this simple thing. So move the txtField initialization outside them so can be readed or written by both.
var txtField: UITextField = UITextField()
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(frame: CGRect(x: 100, y: 100, width: 100, height: 50))
button.backgroundColor = .green
button.setTitle("Test Button", for: .normal)
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
self.view.addSubview(button)
txtField.frame = CGRect(x: 50, y: 70, width: 200, height: 30)
txtField.backgroundColor = UIColor.gray
self.view.addSubview(txtField)
}
#objc func buttonAction(sender: UIButton!) {
print(txtField.text)
}
In your code txtField is declared in viewDidLoad on line
var txtField: UITextField = UITextField()
Therefore out of the scope of buttonAction.
To mitigate this place
txtField
out of scope as a instance variable

TabBarController: always jump to root NavigationController

I have the following hierarchy in my app:
there is a TabBarController (X)
each of its items points to a NavigationController (A, B, C...)
each of those NavigationControllers starts a hierarchy (e.g. A1, A2, A3,...) of TableViewControllers
Now when the user is, say, in A3, they can press another TabBar item and jump to another hierarchy (say, the one of B). However, when they press the item for A, they will jump back to A3.
What I do want to happen, is for them to jump to A1 instead, which is essentially the "parent" UIView in the A hierarchy. Similarly, if they press B, they should jump to B1, not to wherever they were in the B hierarchy. I do not want to force the user to go back to e.g. A1 manually by hiding the bottom bar (the one from the TabBarController).
What is the best way to achieve this?
For visualisation:
/- A - A1 - A2 - A3
X ---- B - B1 - ...
\- C - ...
Programmatically, I currently have custom classes for X (TabBarController, TabBarControllerDelegate) and the TableViewControllers A1,...,B1,... . When the user presses an item, I can by debugging see that the target VC for the segue would be A/B/... and not A1/B1/... so I cannot control the process this way.
EDIT: check storyboard image below.
I'm not sure if I understood you correctly, but the bottomline is whenever the user taps on the tab bar you want the user to be able to see the root controller of each of the UINavigationController, correct?
You mentioned that you already have a custom TabBarController so have you tried the shouldSelect method?:
class CustomTabBarController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
(viewController as? UINavigationController)?.popToRootViewController(animated: true)
return true
}
}
This seems to be working when I tried it on my playground.
Here's the full code I tried it with:
import PlaygroundSupport
import UIKit
class A: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.title = "A"
let label = UILabel(frame: CGRect(origin: .init(x: 100, y: 100), size: .init(width: 200, height: 100)))
label.text = "A"
self.view.addSubview(label)
let button = UIButton(frame: CGRect(origin: .init(x: 100, y: 200), size: .init(width: 200, height: 100)))
button.setTitle("Button", for: .normal)
button.addTarget(self, action: #selector(pressed), for: .touchUpInside)
button.backgroundColor = .black
self.view.addSubview(button)
}
#objc func pressed(_ sender: UIButton) {
let a1 = A1()
self.navigationController?.pushViewController(a1, animated: true)
}
}
class A1: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let label = UILabel(frame: CGRect(origin: .init(x: 100, y: 100), size: .init(width: 200, height: 100)))
label.text = "A1"
self.view.addSubview(label)
}
}
class B: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.title = "B"
let label = UILabel(frame: CGRect(origin: .init(x: 100, y: 100), size: .init(width: 200, height: 100)))
label.text = "B"
self.view.addSubview(label)
let button = UIButton(frame: CGRect(origin: .init(x: 100, y: 200), size: .init(width: 200, height: 100)))
button.setTitle("Button", for: .normal)
button.addTarget(self, action: #selector(pressed), for: .touchUpInside)
button.backgroundColor = .black
self.view.addSubview(button)
}
#objc func pressed(_ sender: UIButton) {
let b1 = B1()
self.navigationController?.pushViewController(b1, animated: true)
}
}
class B1: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let label = UILabel(frame: CGRect(origin: .init(x: 100, y: 100), size: .init(width: 200, height: 100)))
label.text = "B1"
self.view.addSubview(label)
}
}
class CustomTabBarController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
(viewController as? UINavigationController)?.popToRootViewController(animated: true)
return true
}
}
let nav1 = UINavigationController(rootViewController: A())
let nav2 = UINavigationController(rootViewController: B())
let tabbarVC = CustomTabBarController()
tabbarVC.view.frame = CGRect(origin: .zero, size: CGSize(width: 500, height: 500))
tabbarVC.addChild(nav1)
tabbarVC.addChild(nav2)
PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = tabbarVC

How to add another button to a button?

Everything works fine, but when I try to call the createSecondContainer () method from configureAddButton() it doesn't work. That is, pressing the button itself does not work.
override func viewDidLoad() {
super.viewDidLoad()
configureMainContainer()
}
func configureMainContainer(){
view.addSubview(mainContainer)
let frame = CGRect(x: view.bounds.midX - 60, y: view.bounds.midY, width: 120, height: 40)
mainContainer.frame = frame
mainContainer.addTarget(self, action: #selector(showAlert), for: .touchUpInside)
configureAddButton()
}
func configureAddButton(){
mainContainer.addSubview(addButton)
let frame = CGRect(x: mainContainer.bounds.maxX + 5, y: mainContainer.bounds.midY / 2, width: 20, height: 20)
addButton.frame = frame
addButton.addTarget(self, action: #selector(createSecondContainer), for: .touchUpInside)
}
#objc func createSecondContainer(){
print("something to complete")
}
You can use this Code working fine
import UIKit
class ViewController: UIViewController {
let mainContainer = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
configureMainContainer()
}
func configureMainContainer(){
let frame = CGRect(x: view.bounds.midX - 60, y: view.bounds.midY, width: 120, height: 40)
mainContainer.frame = frame
mainContainer.addTarget(self, action: #selector(showAlert), for: .touchUpInside)
mainContainer.backgroundColor = UIColor.red
self.view.addSubview(mainContainer)
configureAddButton()
}
#objc func showAlert() {
// Your Alert Code here
}
func configureAddButton(){
let addButton = UIButton()
let frame = CGRect(x: mainContainer.bounds.midX, y: mainContainer.bounds.midY / 2, width: 20, height: 20)
addButton.frame = frame
addButton.addTarget(self, action: #selector(createSecondContainer), for: .touchUpInside)
addButton.backgroundColor = UIColor.blue
mainContainer.addSubview(addButton)
}
#objc func createSecondContainer(){
print("something to complete")
}
}

How to add UIImageView to navigation bar in swift?

I have this code that adds a rounded border around a UIImage using UIImageView and I've used UITapGestureRecognizer to let the user tap on the button:
var profilePicture = UIImageView()
func setupUserProfileButton() {
let defaultPicture = UIImage(named: "profilePictureSmall")
profilePicture = UIImageView(image: defaultPicture)
profilePicture.layer.cornerRadius = profilePicture.frame.width / 2
profilePicture.clipsToBounds = true
profilePicture.layer.borderColor = UIColor.black.cgColor
profilePicture.layer.borderWidth = 1
// Letting users click on the image
profilePicture.isUserInteractionEnabled = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(profilePictureTapped))
profilePicture.addGestureRecognizer(tapGesture)
}
How can I add this to the left side of a navigation bar? Is it possible? And I don't think the tap gesture is needed if I can add the ImageView to the navigation bar as a barButtonItem, so you can ignore that. I kinda found some similar questions but they were in objective C and none of what I tried worked.
Here is what I came up with based on an answer:
import UIKit
import Firebase
class CreateStoryPage: BaseAndExtensions {
let userProfileButton = UIButton(type: .custom)
override func viewDidLoad() {
super.viewDidLoad()
// Call all the elements
setupUserProfileButton()
}
// MARK:- Setups
// Setup the user profile button
func setupUserProfileButton() {
userProfileButton.setImage(#imageLiteral(resourceName: "profilePictureSmall.png"), for: .normal)
userProfileButton.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
userProfileButton.addTarget(self, action: #selector(profilePictureTapped), for: .touchUpInside)
let userProfileView = UIView(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
userProfileView.layer.cornerRadius = 14
userProfileView.backgroundColor = .red
userProfileView.addSubview(userProfileButton)
let leftNavBarItem = UIBarButtonItem(customView: userProfileView)
self.navigationItem.setLeftBarButton(leftNavBarItem, animated: true)
}
// if user taps on profile picture
#objc func profilePictureTapped() {
let userProfilePage = UserProfilePage()
present(userProfilePage, animated: true, completion: nil)
}
}
Try this;
private func setupRightItem() {
let userProfileButton = UIButton(type: .custom)
userProfileButton.imageView?.contentMode = .scaleAspectFill
userProfileButton.clipsToBounds = true
userProfileButton.addTarget(self, action: #selector(profilePictureTapped), for: .touchUpInside)
userProfileButton.setImage(#imageLiteral(resourceName: "profilePictureSmall.png"), for: .normal)
userProfileButton.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: userProfileButton)
userProfileButton.widthAnchor.constraint(equalToConstant: 30).isActive = true
userProfileButton.heightAnchor.constraint(equalToConstant: 30).isActive = true
}
#objc private func goProfile() {
/// -> Action
}
let navBtn = UIButton(type: .custom)
navBtn.setImage("yourImage", for: .normal)
navBtn.frame = CGRect(x: 0, y: 0, width: 28, height: 28)
navBtn.addTarget(self, action: #selector(self.openProfile(_:)), for: .touchUpInside)
let view = UIView(frame: CGRect(x: 0, y: 0, width: 28, height: 28))
view.cornerRadius = 14
view.backgroundColor = Global.colorBlue
view.addSubview(navBtn)
let leftNavBarItem = UIBarButtonItem(customView: view)
self.navigationItem.setLeftBarButton(leftNavBarItem, animated: true)
#objc
func openProfile(_ sender: UIButton) {
}

how do I make another button appear if I pressed one button in swift

I am trying to make a game where if I press a button it can spawn another button in another area so you can click and keep doing that, every time you press the button you should get a point. I don't know how to spawn another button when I pressed one button.
// this is the code
var monkeyPosition : Int = 1
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(white: 0.25, alpha: 1.0)
view.backgroundColor = UIColor(white: 0.25, alpha: 1.0)
view.addSubview(makeButtonSpawn())
view.addSubview(makeButtonSpawn2())
}
#IBAction func monkeyPlayer(_ sender: UIButton) {
if sender.tag == 1 && (monkeyPosition == 1) {
makeButtonSpawn2().isHidden = false
}
}
func makeButtonSpawn() -> UIButton {
let monkey = UIButton(type: UIButton.ButtonType.system)
//Set a frame for the button. Ignored in AutoLayout/ Stack Views
monkey.frame = CGRect(x: 30, y: 30, width: 90, height: 90)
monkey.backgroundColor = UIColor.blue
makeButtonSpawn().isHidden = true
return monkey
}
func makeButtonSpawn2() -> UIButton {
let monkey = UIButton(type: UIButton.ButtonType.system)
//Set a frame for the button. Ignored in AutoLayout/ Stack Views
monkey.frame = CGRect(x: 80, y: 80, width: 90, height: 90)
monkey.backgroundColor = UIColor.blue
makeButtonSpawn2().isHidden = true
return monkey
}
Create instance variables for your buttons, then you will be able to access them from places in your class. Also you can set its properties inside variable closure instead of declaring method
class ViewController: UIViewController {
var button1: UIButton = {
let button = UIButton()
button.frame = CGRect(x: 30, y: 30, width: 90, height: 90)
button.backgroundColor = .blue
return button
}()
var button2: UIButton = {
let button = UIButton()
button.frame = CGRect(x: 80, y: 80, width: 90, height: 90)
button.backgroundColor = .blue
button.isHidden = true
return button
}()
}
Next, you need to add your buttons as subviews to main view and you need to add target for them
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(white: 0.25, alpha: 1.0)
view.backgroundColor = UIColor(white: 0.25, alpha: 1.0)
view.addSubview(button1)
view.addSubview(button2)
button1.addTarget(self, action: #selector(button1Pressed(_:)), for: .touchUpInside)
button2.addTarget(self, action: #selector(button2Pressed(_:)), for: .touchUpInside)
}
#objc func button1Pressed(_ sender: UIButton) {
}
#objc func button2Pressed(_ sender: UIButton) {
}
Finally, you can unhide second button when first button is pressed
#objc func button1Pressed(_ sender: UIButton) {
if monkeyPosition == 1 {
button2.isHidden = false
}
}