UIBarButtonItem created programmatically not Tapping and linked - ios

I created a view controller for a UIBarButtonItem, a toggle on the main controller. but the UIAction button is inactive
import UIKit
class SideMenuContentViewController: UIViewController {
//Manipulation for Dashboard Side Menu Hamburger
let profileButton = UIButton(type: .custom)
override func viewDidLoad() {
super.viewDidLoad()
profileButton.setImage(UIImage(named: "hamburger") , for: .normal)
profileButton.contentMode = .scaleAspectFit
profileButton.translatesAutoresizingMaskIntoConstraints = false
// function performed when the button is tapped
profileButton.addTarget(self, action: #selector(profileButtonTapped(_:)), for: .touchUpInside)
// Add the profile button as the left bar button of the navigation bar
let barbutton = UIBarButtonItem(customView: profileButton)
self.navigationItem.leftBarButtonItem = barbutton
// Set the width and height for the profile button
NSLayoutConstraint.activate([
profileButton.widthAnchor.constraint(equalToConstant: 35.0),
profileButton.heightAnchor.constraint(equalToConstant: 35.0)
])
// Make the profile button become circular
profileButton.layer.cornerRadius = 35.0 / 2
profileButton.clipsToBounds = true
}
#IBAction func profileButtonTapped(_ sender: Any){
}
}
import UIKit
class MainSideViewController: SideMenuContentViewController {
#IBOutlet weak var sideMenuContainer: UIView!
#IBOutlet weak var sideMenuViewLeadingConstraint: NSLayoutConstraint!
#IBOutlet weak var dashBoardViewLeadingConstraint: NSLayoutConstraint!
var sideMenuVisible = false
override func viewDidLoad() {
super.viewDidLoad()
sideMenuViewLeadingConstraint.constant = 0 - self.sideMenuContainer.frame.size.width
}
#objc func toggleSideMenu(fromViewController: SideMenuContentViewController) {
if(sideMenuVisible){
UIView.animate(withDuration: 0.5, animations: {
// hide the side menu to the left
self.sideMenuViewLeadingConstraint.constant = 0 - self.sideMenuContainer.frame.size.width
// move the content view (tab bar controller) to original position
self.dashBoardViewLeadingConstraint.constant = 0
self.view.layoutIfNeeded()
})
} else {
self.view.layoutIfNeeded()
UIView.animate(withDuration: 0.5, animations: {
// move the side menu to the right to show it
self.sideMenuViewLeadingConstraint.constant = 0
// move the content view (tab bar controller) to the right
self.dashBoardViewLeadingConstraint.constant = self.sideMenuContainer.frame.size.width
self.view.layoutIfNeeded()
})
}
sideMenuVisible = !sideMenuVisible
}
}
// THIS IS THE ACTION NOT WORKING
#IBAction override func profileButtonTapped(_ sender: Any){
if let mainVC = self.navigationController?.tabBarController?.parent as? MainSideViewController {
mainVC.toggleSideMenu(fromViewController: self)
}
}
}
I want the action to google in the side menu.

Related

How can I add a navigation button to a sceneView?

I have an app that has multiple views and one of them is a SceneView as you can see below. The SceneView is not the initial view. Users can open the SceneView by triggering a segue from another ViewController but when I want to add a nav bar to the SceneView, an error has occured.
So how can I add a navigation bar or a button to a sceneView? If there is no way, how can I manage to dismiss segue from the SceneView?
I couldn't find a way to add a navigationBar on top of a sceneView but I figured out how to add a button to a sceneView. If we create a button programmatically and add that button to the sceneView, we can navigate via that button.
Here's what we can do;
import UIKit
import SceneKit
class ViewController: UIViewController {
var scnView: SCNView?
var exampleScn = SCNScene(named: "ExampleScn")
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.scnView = SCNView(frame: self.view.frame)
self.scnView?.scene = exampleScn
self.view.addSubview(self.scnView!)
let button = UIButton(type: .system)
button.tintColor = UIColor.black
button.titleLabel?.font = UIFont(name: "Arial", size: 25)
button.setTitle("Back", for: .normal)
button.sizeToFit()
button.addTarget(self, action: #selector(didPressBack), for: .touchUpInside)
button.center.x = 50
button.frame.origin.y = 20
scnView.addSubview(button)
}
#objc func didPressBack (sender: UIButton!) {
dismiss(animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
if we do this, the result will look like this:

How can I completely override the navbar's back button action?

Basically my issue is that I'm trying to create a drawer since iOS/Swift doesn't seem to have a native object for this. For reasons I can't recall, I decided to go with a navigation controller for this, thinking I could just override the back button(s) and their actions to turn this nav bar into a drawer. While I've changed the image/text of the back button successfully to look like a "burger" (drawer icon), I can't figure out how to successfully stop the button from taking us back, and instead have it just open/close my drawer.
Any advice appreciated, including suggestions to take an entirely different approach to creating this.
The following is the controller for the page which has the back button i'm trying to override. You can see in viewDidLoad() I call prepareDrawerPage(), which is a helper I have in another file. This definition can also be seen below.
class CreateListingController: UIViewController {
let DRAWER_OPEN = CGFloat(0)
var DRAWER_CLOSED: CGFloat = 0 // -1 * width of drawer
#IBOutlet var navItem: UINavigationItem!
#IBOutlet var drawerView: UIView!
#IBOutlet var drawerViewLead: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
DRAWER_CLOSED = UIScreen.main.bounds.width * -1 * drawerViewLead.multiplier
drawerViewLead.constant = DRAWER_CLOSED
prepareDrawerPage(controller: self, title: "PBX - Create a Listing")
}
#IBAction func flipMenu(_ sender: UIBarButtonItem) {
if (drawerViewLead.constant == DRAWER_OPEN){
drawerViewLead.constant = DRAWER_CLOSED
UIView.animate(withDuration: 0.2, delay: 0.0, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
})
} else {
drawerViewLead.constant = DRAWER_OPEN
UIView.animate(withDuration: 0.2, delay: 0.0, options: .curveEaseIn, animations: {
self.view.layoutIfNeeded()
})
}
}
}
prepareDrawerPage():
func prepareDrawerPage(controller: UIViewController, title: String) {
let blank = UIImage()
controller.navigationController?.navigationBar.backIndicatorImage = blank
controller.navigationController?.navigationBar.backIndicatorTransitionMaskImage = blank
controller.title = title
}
The above approach works fine on the home page, where we haven't used the navigation bar yet. However, once we click to the create listing page, the button still takes us back home when clicked despite having linked an action between the BarButtonItem (back button) and CreateListingController (flipMenu function).
You can add a custom button on the navigation bar.
override func viewDidLoad() {
...
self.navigationItem.hidesBackButton = true
let newBackButton = UIBarButtonItem(image: YourImage, style: .plain, target: self, action: #selector(back(sender:)))
self.navigationItem.leftBarButtonItem = newBackButton
...
}
#objc func back(sender: UIBarButtonItem) {
// Perform your custom actions
// ...
// Go back to the previous ViewController
// self.navigationController?.popViewController(animated: true)
}

How to center custom tabbar item on iPhone X

I have an app where I created a custom tabbar item in a UITabbarController, that someone can press to take a picture, and it looks like it does below.
That is exactly what I want, the problem is that when I test it on an iPhone X, the tabbar item for the camera looks lower then I would like, for example:
I have tried a couple of things to fix this, such as fixing the height of the tabbar in the viewDidLayoutSubviews(), but it messed with the tabbar on the iPhone 8. I also made sure that the "Use Safe Area Layout Guides" is selected, but it still doesn't work.
I also tried to change the frame of the tabbar item, but that doesn't work either.
This is the code that I used for the custom tabbar Controller:
import UIKit
class OtherTabController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
setupBtn()
// Do any additional setup after loading the view.
}
func setupBtn() {
let centerBtn = UIButton(frame: CGRect(x: 0, y: 10, width: 45, height: 45))
var centerBtnFrame = centerBtn.frame
centerBtnFrame.origin.y = (view.bounds.height - centerBtnFrame.height) - 2
centerBtnFrame.origin.x = view.bounds.width/2 - centerBtnFrame.size.width/2
centerBtn.frame = centerBtnFrame
centerBtn.layer.cornerRadius = 35
view.addSubview(centerBtn)
let centerImg = UIImage(named: "Other")
centerBtn.setBackgroundImage(centerImg, for: .normal)
centerBtn.addTarget(self, action: #selector(centerBtnAction(sender:)), for: .touchUpInside)
view.layoutIfNeeded()
}
#objc private func centerBtnAction(sender: UIButton) {
print("Camera")
cameraAction()
}
func cameraAction() {
let alertController = UIAlertController.init(title: nil, message: nil, preferredStyle: .actionSheet)
let takePhotoAction = UIAlertAction(title: "Take a Photo", style: .default, handler: nil)
alertController.addAction(takePhotoAction)
let selectFromAlbumAction = UIAlertAction(title: "Select from Album", style: .default, handler: nil)
alertController.addAction(selectFromAlbumAction)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion: nil)
//OtherTabController?.present(alertController, animated: true, completion: nil)
}
}
If there is anything else I could help with, please ask. Thank you
EDIT:
I tried to make the y view the same as the super view but all it did was move the button to the top of the screen.
var centerBtnFrame = centerBtn.frame
centerBtnFrame.origin.y = view.bounds.minY //Make centerBtn' top equal to that of view's
centerBtnFrame.origin.x = view.bounds.width/2 - centerBtnFrame.size.width/2
centerBtn.frame = centerBtnFrame
If you need any more info, please ask. Thank you
Edit:
With the help of #Revanth Kausikan, I decided to create a custom tabbar with a view and a few buttons. It works very well in my opinion. It looks a little rough around the edges, but this is just a test for now.
Here is the code for the view:
import UIKit
class ItemScene: UIViewController {
#IBOutlet var customTab: UIView!
#IBOutlet weak var cameraBtn: UIButton!
#IBOutlet weak var twoBtn: UIButton!
#IBOutlet weak var oneBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func cameraBtnPressed(_ sender: Any) {
print("Camera")
}
#IBAction func twoBtnPressed(_ sender: Any) {
self.performSegue(withIdentifier: "segue", sender: nil)
print("Two")
}
#IBAction func oneBtnPressed(_ sender: Any) {
print("One")
}
}
this is the code for the second ViewController:
import UIKit
class TestingViewController: UIViewController {
#IBOutlet weak var cameraBtn: UIButton!
#IBOutlet weak var oneBtn: UIButton!
#IBOutlet weak var twoBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func cameraBtnPressed(_ sender: Any) {
print("Camera")
}
#IBAction func twoBtnPressed(_ sender: Any) {
print("Two")
}
#IBAction func oneBtnPressed(_ sender: Any) {
performSegueToReturnBack()
print("One")
}
}
extension UIViewController {
func performSegueToReturnBack() {
if let nav = self.navigationController {
nav.popViewController(animated: true)
} else {
self.dismiss(animated: true, completion: nil)
}
}
}
If anyone has anything else to add it would be greatly appreciated. Thank you
The Y point of button frame must be the same as that of it's super view (i.e. tab bar here).
If you've not created an outlet for the tab bar, first do so.
Ctrl (or right) click and drag from your tab bar in the storyboard to its associated view controller, to create an outlet. (assume that I'm naming it as tabBar)
now try this:
var centerBtnFrame = centerBtn.frame
let tabBarFrame = self.convert(tabBar.frame, to: view)
centerBtnFrame.origin.y = tabBarFrame.minY //Make centerBtn' top equal to that of tabBar's
centerBtnFrame.origin.x = view.bounds.width/2 - centerBtnFrame.size.width/2
centerBtn.frame = centerBtnFrame
Alternatively, you can try this:
var centerBtnFrame = centerBtn.frame
centerBtnFrame.origin.y = view.height - tabBar.height //This is the same logic as you've used for fixing x value of centerBtnFrame.
centerBtnFrame.origin.x = view.bounds.width/2 - centerBtnFrame.size.width/2
centerBtn.frame = centerBtnFrame
Yet another approach is to go back to the constraints, and make sure the elements and the base view are within the safe area.
If my guess is right (since you've not provided details about the constraints in the question), you've set the base view (the view that is in the bottom/base, holding all other elements on it) to fit itself with the entire view are of the view controller. Consider changing it to fit itself within the safe area.
Let me know the results.
EDIT
My opinion on your new attempt: It's really good, and I see that you are now able to customize it a lot more.
To improve it, you can try these:
Here, there are three views that are clickable in nature. we can use this to increase the interactive area as per our wish, to provide a natural experience for the user.
Here are it's constraints:
Other than these suggestions, I don't think I need to provide any. Your method is self sufficient for your implementation idea.
:)
Try this code working 100% ...
Declare the button
var menuButton = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
setupMiddleButton()
}
//create the method
func setupMiddleButton(flag:String) {
menuButton = UIButton(frame: CGRect(x: 0, y: 0, width: 60, height: 60))
var menuButtonFrame = menuButton.frame
menuButtonFrame.origin.y = tabBar.bounds.height - menuButtonFrame.height
menuButtonFrame.origin.x = tabBar.bounds.width/2 - menuButtonFrame.size.width/2
menuButton.frame = menuButtonFrame
menuButton.backgroundColor = UIColor.red
menuButton.layer.borderColor = UIColor.black.cgColor
menuButton.layer.borderWidth = 1
tabBar.addSubview(menuButton)
menuButton.layer.cornerRadius = menuButtonFrame.height/2
menuButton.setImage(UIImage(named: "Homenormal"), for: .normal)
menuButton.addTarget(self, action: #selector(menuButtonAction(sender:)), for: .touchUpInside)
}
//button methods inside add background colour
#objc private func menuButtonAction(sender: UIButton) {
menuButton.backgroundColor = UIColor.red
selectedIndex = 2
print("menuButtonActio=\(sender.tag)")
}
//next Tabbar didselect
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
let Selected_index = tabBar.items?.lastIndex(of: item)
print("selectedIndex123=\(Selected_index)")
if Selected_index == 0 {
menuButton.backgroundColor = UIColor.darkGray
menuButton.layer.borderColor = UIColor.black.cgColor
}
else if Selected_index == 1 {
menuButton.backgroundColor = UIColor.darkGray
menuButton.layer.borderColor = UIColor.black.cgColor
}
else if Selected_index == 2 {
menuButton.backgroundColor = UIColor.red
menuButton.layer.borderColor = UIColor.black.cgColor
}
else if Selected_index == 3 {
menuButton.backgroundColor = UIColor.darkGray
menuButton.layer.borderColor = UIColor.black.cgColor
}
else if Selected_index == 4 {
menuButton.backgroundColor = UIColor.darkGray
menuButton.layer.borderColor = UIColor.black.cgColor
}
}

How to hide navigation bar when image is tapped

How would I hide the navigation bar once my imageView is tapped, the navigation bar messes up the view of the full screen image once my imageView is tapped and I would like it hidden when the image is tapped and to reappear once the image is dismissed. Here is my code for my image being tapped.
//expandImage
#IBAction func expand(_ sender: UITapGestureRecognizer) {
let imageView = sender.view as! UIImageView
let newImageView = UIImageView(image: imageView.image)
newImageView.frame = self.view.frame
newImageView.backgroundColor = .black
newImageView.contentMode = .scaleAspectFit
newImageView.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector(dismissFullscreen))
newImageView.addGestureRecognizer(tap)
self.view.addSubview(newImageView)
}
func dismissFullscreen(_ sender: UITapGestureRecognizer) {
sender.view?.removeFromSuperview()
}
Add this to your expand() method:
self.navigationController?.setNavigationBarHidden(true, animated: true)
And in dismissFullscreen() method:
self.navigationController?.setNavigationBarHidden(false, animated: true)
Or you can create new ViewController, pass image to it (with segue e.g) and add this to viewDidLoad() of new ViewController:
self.navigationController?.hidesBarsOnTap = true
So here is how you can do that:
class ViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
let tapImageScrollView = UITapGestureRecognizer(target: self, action: #selector(imageTapped(_:)))
imageView.isUserInteractionEnabled = true
imageView.addGestureRecognizer(tapImageScrollView)
}
func imageTapped(_ sender: UIGestureRecognizer) {
if self.navigationController?.navigationBar.isHidden == false {
self.navigationController?.navigationBar.isHidden = true
} else {
self.navigationController?.navigationBar.isHidden = false
}
}
}
So basically add a UITapGestureRecognizer to your imageView and in the imageTapped function you check if the navigationBar is not hidden then you want to show the image and hide the navigationBar and if you click on the imageView again you want to show the navigationBar again.
So simply add the logic in imageTapped to your dismissFullscreen function.

Can't hide UIButton?

I'm trying to have a custom UIButton become hidden once it's pressed a certain number of times...but I'm at a loss.
Having exhausted my limited knowledge and consulting the Apple's documentation as well as the internet for the better part of 3 hours, I've finally made my way here. I've been learning Swift for a short while now and am making an effort to become more familiar with it. This is my first object-oriented language and it's testing me to say the least. Any help with this more likely than not ridiculously simple problem is very much appreciated.
import UIKit
class ViewController: UIViewController{
#IBOutlet weak var buttonMessageDisplay: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
buttonPressed()
}
var tapcount = 0
let buttonMessage : [String] = [/* long array of strings */]
func buttonPressed() {
let button = UIButton(type:.Custom) as UIButton
button.frame = CGRectMake(0, 0, 100, 100)
button.center = CGPointMake(self.view.frame.size.width/2, self.view.frame.size.height/2);
button.backgroundColor = UIColor.redColor()
button.layer.borderColor = UIColor.blackColor().CGColor
button.layer.borderWidth = 3
button.layer.cornerRadius = 0.5 * button.bounds.size.width
button.setTitle("", forState: UIControlState.Normal)
button.addTarget(self, action: "buttonPressed", forControlEvents: .TouchUpInside)
view.addSubview(button)
switch tapcount {
case 19...23:
//Hides the button
button.hidden = true
buttonMessageDisplay.text = buttonMessage[tapcount]
case 24...31:
//Unhides the button
button.hidden = false
buttonMessageDisplay.text = buttonMessage[tapcount]
default:
buttonMessageDisplay.text = buttonMessage[tapcount]
}
print("Tap Count: \(tapcount)")
++tapcount
}
Updated with Gesture Recognizer:
import UIKit
class ViewController: UIViewController{
#IBOutlet weak var buttonMessageDisplay: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
buttonMessageDisplay.text = ""
let button = UIButton(type:.Custom) as UIButton
button.frame = CGRectMake(0, 0, 100, 100)
button.center = CGPointMake(self.view.frame.size.width/2, self.view.frame.size.height/2);
button.backgroundColor = UIColor.redColor()
button.layer.borderColor = UIColor.blackColor().CGColor
button.layer.borderWidth = 3
button.layer.cornerRadius = 0.5 * button.bounds.size.width
button.setTitle("", forState: UIControlState.Normal)
button.addTarget(self, action: "buttonPressed", forControlEvents: .TouchUpInside)
self.view.addSubview(button)
}
var tapcount : Int = 0
let buttonMessage : [String] = [/* array of strings */]
#IBAction func userTap(sender: UITapGestureRecognizer) {
print("Tap Received")
if case 19...23 = tapcount {
buttonPressed()
}
}
func buttonPressed() {
switch tapcount {
case 0...18:
buttonMessageDisplay.text = buttonMessage[tapcount]
case 19...23:
//Hides the button
button.hidden = true
buttonMessageDisplay.text = buttonMessage[tapcount]
case 24...32:
//Unhides the button
button.hidden = false
buttonMessageDisplay.text = buttonMessage[tapcount]
case 33...100:
buttonMessageDisplay.text = buttonMessage[tapcount]
default:
print("There are no more messages or an error has been encountered")
}
print("Tap Count: \(tapcount)")
++tapcount
}
}
Your code makes no sense. As #formal says in his answer, you're creating a new button on every tap, which is wrong.
You want to define your button in your Storyboard.
Then you want an IBAction method, which takes the button as a parameter:
#IBAction func buttonPressed(sender: UIButton)
{
++tapcount
if tapcount < 19
{
sender.hidden = true
}
}
Note that if the button you're hiding is the same one the user is tapping, once it is hidden, you're done. The user can't tap a hidden button, so there's no way to un-hide it. (And thus no point in your switch statement)
Your main issue is that you are creating a new button every time you call button pressed. Create an #IBOutlet for your button and just set its hidden property in butPressed (which can be set as an action of the button).
Something like:
class ViewController: UIViewController {
#IBOutlet weak var button: UIButton!
#IBOutlet weak var buttonMessageDisplay: UILabel!
var tapcount = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func butPressed(sender: AnyObject) {
switch tapcount {
case 19...23:
//Hides the button
button.hidden = true
case 24...31:
//Unhides the button
button.hidden = false
default: break
}
print("Tap Count: \(tapcount)")
buttonMessageDisplay.text = "Tap: \(tapcount)"
++tapcount
}
}
The method buttonPressed() creates a new button each time it is called. You should define button as a property similar to buttonMessageDisplay and place the code to initialise it within viewDidLoad().
You should give space between range in case condition:
For example:
(IBAction)buttonTapped:(id)sender {
self.count++;
switch (self.count) {
case 5 ... 23 :
self.button.titleLabel.text = #"disable";
self.button.hidden = true;
break;
default:
break;
}
}

Resources