When going to a secondary page, I'm trying to slide the back button in from the left over a period of 0.33 seconds. Right now the animation doesn't appear to be doing that, even after slowing duration down to 2 seconds for visual clarification. Was wondering if anyone could tell me what I've done wrong in my code and how to correct it?
Going to come out and say that I likely am just misunderstanding how some aspect of animation works.
func addBackButton() {
let backButton = UIButton(type: .custom)
backButton.setImage(#imageLiteral(resourceName: "backArrow"), for: .normal)
backButton.setTitle("", for: .normal)
backButton.setTitleColor(backButton.tintColor, for: .normal)
backButton.addTarget(self, action: #selector(backAction), for: .touchUpInside)
let backBarButtonItem = UIBarButtonItem(customView: backButton)
backBarButtonItem.customView?.transform = CGAffineTransform(translationX: -backButton.frame.width, y: 0)
navigationItem.leftBarButtonItems?.insert(backBarButtonItem, at: 0)
UIView.animate(withDuration: 2, delay: 0.5, animations: {
backBarButtonItem.customView?.transform = CGAffineTransform(translationX: 2 * backButton.frame.width, y: 0)
})
}
You just need to put this custom button inside a containerView and set that containerView as the UIBarButtonItem's custom view. Your setup will look like this,
let containerFrame = CGRect(origin: .zero, size: CGSize(width: 44.0, height: 44.0))
let container = UIView(frame: containerFrame)
let buttonFrame = CGRect(origin: CGPoint(x: -100, y: 0), size: CGSize(width: 44, height: 44))
let backButton = UIButton(frame: buttonFrame)
backButton.setImage(#imageLiteral(resourceName: "backArrow"), for: .normal)
backButton.setTitle("", for: .normal)
backButton.setTitleColor(backButton.tintColor, for: .normal)
backButton.addTarget(self, action: #selector(backAction), for: .touchUpInside)
container.addSubview(backButton)
let backBarButtonItem = UIBarButtonItem(customView: container)
UIView.animate(withDuration: 2, delay: 0.5, animations: {
backButton.transform = CGAffineTransform(translationX: 2 * backButton.frame.width, y: 0)
})
You can check why you need to wrap your custom button inside another UIView here.
UIBarButtonItem is not a UIView subclass for a reason. If this is the effect you want (platform consistency says you should use UINavigationItem.setLeftBarButtonItems(_:animated:)) then you should instead add the backButton to your view hierarchy, animate it in, then set it as the leftBarButtonItem in the completion block.
Keep in mind you will have to likely add it to the navigation bar view hierarchy so it appears on top of it. This approach also means you are basically duplicating layout code of the navigation bar and you'll have to figure out where it's supposed to end up.
navigationController?.navigationBar.addSubview(backButton)
// layout back button in it's final spot here, either via constraints or frame math
backButton.transform = CGAffineTransform(translationX: -(button.bounds.width + leadingSpacing), translationY: 0.0)
UIView.animate(duration: 0.3, animations: {
backButton.transform = .identity
} { completed in
self.navigationItem.leftBarButtonItem = UIBarButtonItem
}
Related
actually I don't know the correct way how to make an image inside the navigation bar like this, either using navigation controller or by using custom view by myself
I need to insert these 2 image as bar button and image title
so I tried to use navigation controller and insert an image in viewDidLoad like the code below:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// insert image title
let aspectRatio : CGFloat = 0.25
let widthOfImageHeader = view.frame.width * 0.5
let heightOfImageHeader = widthOfImageHeader * aspectRatio
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: widthOfImageHeader, height: heightOfImageHeader))
imageView.contentMode = .scaleAspectFit
let image = UIImage(named: "testImage2")
imageView.image = image
navigationItem.titleView = imageView
// set bar button image
//create a new button
let button = UIButton(type: .custom)
//set image for button
button.setImage(UIImage(named: "hamburgerIcon"), for: .normal)
//set frame
button.frame = CGRect(x: 0, y: 0, width: 53, height: 51)
let barButton = UIBarButtonItem(customView: button)
//assign button to navigationbar
self.navigationItem.leftBarButtonItem = barButton
}
}
but the result is like the image below:
the position of image title is not exactly in the center for iPhone 5s and bar button seems a little bit off in the right.
and if I assign the image right bar button, using
/
/create a left button
let button = UIButton(type: .custom)
//set image for button
button.setImage(UIImage(named: "hamburgerIcon"), for: .normal)
//set frame
button.frame = CGRect(x: 0, y: 0, width: 53, height: 51)
let barButton = UIBarButtonItem(customView: button)
//assign button to navigationbar
self.navigationItem.leftBarButtonItem = barButton
//create a right button
let button2 = UIButton(type: .custom)
//set image for button
button2.setImage(UIImage(named: "backButton"), for: .normal)
//set frame
button2.frame = CGRect(x: 0, y: 0, width: 53, height: 51)
let barRightButton = UIBarButtonItem(customView: button)
//assign button to navigationbar
self.navigationItem.rightBarButtonItem = barRightButton
the result is even weirder
one of the button dissapears, the hamburger icon that should be on the left, now in the right
it will be far easier if I use custom view, but...is it weird if I use custom view that use like navigation bar? I am new in iOS Developer. Thanks in advance
Okay so here's what I usually do in a project with such kind of requirements (image at the navBar's title, and custom bar button items).
To answer first your question, you can actually do whatever you want.
Have indeed a custom view while having your viewController embedded inside a UINavigationController. But be sure to hide the navBar.
Have a visible navBar and viewContorller embedded in UINavigationController.
The ideal way for me is the latter.
The sample project below was made using my own old framework: https://github.com/glennposadas/gpkit-ios
You can copy any pieces of codes from that framework, modify/rename everything on it, and put in your production project.
If you want the result below, here's how I do it:
import GPKit
import UIKit
class ViewController: UIViewController {
// MARK: - Properties
internal lazy var button_Close: UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "ham"), for: .normal)
button.imageEdgeInsets = UIEdgeInsets.init(top: 0, left: -30, bottom: 0, right: 0)
//button.addTarget(self, action: #selector(hamburger(_:)), for: .touchUpInside)
return button
}()
// MARK: - Functions
// MARK: Overrides
override func viewDidLoad() {
super.viewDidLoad()
GPLog(classSender: self, log: "viewDidLoad!")
// Title View Test: -
let navBarImage = UIImage(named: "ic_logo_navbar")!
self.setNavBarTitleWithFeedback(image: navBarImage, navBarTintColor: .white)
self.makeNavBarColor(color: UIColor.colorWithRGBHex(0x332F39), itemsTintColor: .white)
// Barbutton
let barButton = UIBarButtonItem(customView: self.button_Close)
self.button_Close.frame = CGRect(x: 0, y: 0, width: 55.0, height: 44.0)
let negativeSpacer = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.fixedSpace, target: nil, action: nil)
if #available(iOS 11.0, *) {
negativeSpacer.width = -30
}
self.navigationItem.leftBarButtonItems = [negativeSpacer, barButton]
}
}
extension ViewController: GPTitleViewDelegate {
func gpTitleView(userDidTapTitleView gpTitleView: GPTitleView) {
GPLog(classSender: self, log: "userDidTapTitleView🌈")
}
func gpTitleView(userDidFinishLongPress gpTitleView: GPTitleView) {
GPLog(classSender: self, log: "userDidFinishLongPress🌺")
}
}
Result:
I don't have your hex color, so it looks ugly.
I hope thish elps.
let SearchView = UIView()
SearchView.backgroundColor = UIColor.clear
SearchView.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
let Searchbutton = UIButton(type: .system)
Searchbutton.setImage(UIImage (named: "SEARCH"), for: .normal)
Searchbutton.backgroundColor = .clear
Searchbutton.frame = CGRect(x: -17, y: -20, width: 30, height: 30)
Searchbutton.contentMode = .scaleAspectFit
let WidthConstraint = Searchbutton.widthAnchor.constraint(equalToConstant: 30)
let HeightConstraint = Searchbutton.heightAnchor.constraint(equalToConstant: 30)
WidthConstraint.isActive = true
HeightConstraint.isActive = true
let barButtonItem = UIBarButtonItem(customView: SearchView)
self.navigationItem.rightBarButtonItem = barButtonItem
SearchView.addSubview(Searchbutton)
Searchbutton.addTarget(self, action: #selector(viewanewcontroller(button:)), for: .touchUpInside)
//right search button
After making a button, I wanted to move it little bit to the right. So, i made UI View to move the button inside the view. But, then, after this, the button does not work anymore. Can anyone tell me the solution?
Your code is working fine but need to clarify some points.
Reason Your button not working is below 4 lines
let WidthConstraint = Searchbutton.widthAnchor.constraint(equalToConstant: 30)
let HeightConstraint = Searchbutton.heightAnchor.constraint(equalToConstant: 30)
WidthConstraint.isActive = true
HeightConstraint.isActive = true
As you already set UIButton frame then no need to use of above lines of code.
Yellow color view is your SearchView and green color is your UIButton.
If you use Searchbutton frame like Searchbutton.frame = CGRect(x: -17, y: -20, width: 30, height: 30) then it happens something like below image.
You added UIButton as subview of UIView and when you click on green button which is inside yellow View will work but the area which is outside Yellow area doesn't work.
You need to start UIButton frame from 0,0,30,30
Searchbutton.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
or you can directly set UIButton frame same as UIView frame then it looks like below image.
Searchbutton.frame = SearchView.frame
Below is your Working Code.
let SearchView = UIView()
SearchView.backgroundColor = UIColor.clear
SearchView.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
let Searchbutton = UIButton(type: .system)
Searchbutton.setImage(UIImage (named: "SEARCH"), for: .normal)
Searchbutton.backgroundColor = .clear
Searchbutton.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
Searchbutton.contentMode = .scaleAspectFit
let barButtonItem = UIBarButtonItem(customView: SearchView)
self.navigationItem.rightBarButtonItem = barButtonItem
SearchView.addSubview(Searchbutton)
Searchbutton.addTarget(self, action: #selector(viewanewcontroller(button:)), for: .touchUpInside)
//right search button
You're doing a lot of unnecessary things here. Firstly, you don't need to put your Button in a container view to put it as the right bar button item.
You also don't need to add constraints to your searchbutton, since you have given it a fixed frame.
let Searchbutton = UIButton(type: .system)
Searchbutton.setImage(UIImage (named: "SEARCH"), for: .normal)
Searchbutton.backgroundColor = .clear
Searchbutton.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
Searchbutton.contentMode = .scaleAspectFit
let barButtonItem = UIBarButtonItem(customView: Searchbutton)
self.navigationItem.rightBarButtonItem = barButtonItem
Searchbutton.addTarget(self, action: #selector(viewanewcontroller(button:)), for: .touchUpInside)
Also as Pratik's comment said, you're meant to use lower camel case. so SearchView should be searchView and SearchButton as searchButton
As for moving it to the right, it seems like that isn't possible anymore without either subclassing the UINavigationBar and changing the implementation, or by making UIViews look exactly like the standard Navigation Bar.
Get rid of the space on the right side of a UINavigationBar
I am having some difficulties creating a bar button that are leaving me pretty stumped. Im using the following code to create a right bar button:
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 22, height: 22))
button.setBackgroundImage(UIImage(named: "tune"), for: .normal)
button.addTarget(self, action:#selector(viewController.settingsBtnPressed), for:.touchUpInside)
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: button)
No matter what I set the width or height as the button size does not change. The VC is in a navigation controller. Does anyone have any insight or next steps I can take? Any help would be appreciated
Click on your ViewController in StoryBoard. Go to "Editor" -> "Embed In" -> Click on "Navigation Controller".After that paste the code in your ViewDidLoad method where you want to see the BarButton.
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 22, height: 22))
button.setBackgroundImage(UIImage(named: "tune"), for: .normal)
button.addTarget(self, action:#selector(ViewController.settingsBtnPressed), for:.touchUpInside)
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: button)
}
// The height and minimum value of this button will be affected by the rightBarButtonItem
Button height is 100000
Button height is 0
[ You can this ]
// Provide a vew to button
let tView = UIView(frame: CGRect(x: 0, y: 0, width: 30, height: 40));
tView.backgroundColor = UIColor.darkGray
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 20, height: 22))
//button.setBackgroundImage(UIImage(named: "tune"), for: .normal)
button.backgroundColor = UIColor.green;
button.addTarget(self, action:#selector(ViewController.settingsBtnPressed), for:.touchUpInside)
// add btton to tView
tView.addSubview(button)
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: tView)
Turns out that the problem arises due to how bar buttons are handled in iOS 11. UIBarButtonItemnow uses autolayout instead of frames. As a result, the following code allows you to adjust the size of the button:
button.widthAnchor.constraint(equalToConstant: 22.0).isActive = true
button.heightAnchor.constraint(equalToConstant: 22.0).isActive = true
I am new to swift coding, when I am trying to add a button by code, it does not show up in the Simulator.
I changed the dimension of the View in main.storyboard to 375*1114
there are scroll view and view inside with the same dimension as well.
there are also 5 collection views too.
These are all setup by the storyboard.
The code I used:
let fullScreenSize = UIScreen.main.bounds.size
let plusButton = UIButton(type: .custom)
plusButton.frame = CGRect(x: 300, y: 600, width: 50, height: 50)
plusButton.layer.cornerRadius = 0.5 * plusButton.bounds.size.width
plusButton.clipsToBounds = true
plusButton.setImage(UIImage(named: "plus.png"), for: .normal)
plusButton.center = CGPoint(x: fullScreenSize.width * 0.9, y: fullScreenSize.height * 0.9)
plusButton.addTarget(self, action: #selector(plusButtonPressed), for: .touchUpInside)
self.view.addSubview(plusButton)
I was trying to let the button to stay at the right bottom corner of the simulator all the time. How can I do that? Thanks.
your code is fine and correct add the background color and check once the button will be visibile else check your plusButton.setImage(UIImage(named: "plus.png"), for: .normal) plus.png is correct or not
plusButton.backgroundColor = UIColor.red
for full code
let fullScreenSize = UIScreen.main.bounds.size
let plusButton = UIButton(type: .custom)
plusButton.frame = CGRect(x: 300, y: 600, width: 50, height: 50)
plusButton.layer.cornerRadius = 0.5 * plusButton.bounds.size.width
plusButton.clipsToBounds = true
plusButton.setImage(UIImage(named: "normal.jpg"), for: .normal)
plusButton.backgroundColor = UIColor.red
plusButton.center = CGPoint(x: fullScreenSize.width * 0.9, y: fullScreenSize.height * 0.9)
// plusButton.addTarget(self, action: #selector(plusButtonPressed), for: .touchUpInside)
self.view.addSubview(plusButton)
output
I think you have to take an Outlet of UIView inside UIScrollview you already have in you UIViewController and add that button as a subView of that UIView. That's why your button is hiding, why don't you check it by looking at the View Hierarchy!
I have a problem.
I use show(vc) to present a view controller.
vc1 --> vc2 --> vc3
I want to redirect user from vc1 when user clicks on back button on vc3, to achieve that I am using the below mentioned code.
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.hidesBackButton = true
let newBackButton = UIBarButtonItem(title: "<", style: UIBarButtonItemStyle.plain, target: self, action: #selector(backToRoot(sender:)))
self.navigationItem.leftBarButtonItem = newBackButton
}
func backToRoot(sender: UIBarButtonItem) {
_ = self.navigationController?.popToRootViewController(animated: true)
}
I want the default image of back button, not customized button.
Is there a way I can do that?
I just made this today. I found no way to change action of system back button. In order to look like the system style, I draw a same picture(snapshot the simulator, and change in photo shop). The code is as followed:
let button: UIButton = UIButton(type: .system)
the default size of height is 30, width is whatever you set
button.frame = CGRect(x: 0, y: 0, width: 80, height: 30)
button.setImage(UIImage(named: "BackButton"), for: .normal)
the default font is the following:
button.setTitle("Back", for: .normal)
button.titleLabel?.font = UIFont(name: "AvenirNext", size: 15)
This is the trick, you need find out the same position with the system's, the following is my result, I had adjusted many times. I hope you could use, but I think you need find your own size
button.imageEdgeInsets = UIEdgeInsetsMake(0, -43, 0, 0)
button.titleEdgeInsets = UIEdgeInsetsMake(0, -33, 0, 0)
button.addTarget(target, action: action, for: .touchUpInside)
let barButton = UIBarButtonItem(customView: button)