I have a UIToolbar installed on my Viewcontroller on the bottom via Storyboard. I also added a bottom in the Storyboard and now I want to give this bottom a greater height than the toolbar itself.
It should be something like that, but it cannot be a Tabbar but needs to be a Toolbar, as the items on it are purely contextual actions and not top level navigation items (see Apple guidelines here and here):
I tried the following code in my Viewcontroller without success (as mentioned here):
class MyVC: UIViewController {
#IBOutlet var ibOutletForButton: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
let menuBtn = UIButton(type: .custom)
menuBtn.frame = CGRect(x: 0.0, y: 0.0, width: 20, height: 120)
menuBtn.setImage(UIImage(named:"iconImage"), for: .normal)
menuBtn.addTarget(self, action: #selector(onMenuButtonPressed(_:)), for: UIControlEvents.touchUpInside)
let menuBarItem = UIBarButtonItem(customView: menuBtn)
let currWidth = menuBarItem.customView?.widthAnchor.constraint(equalToConstant: 24)
currWidth?.isActive = true
let currHeight = menuBarItem.customView?.heightAnchor.constraint(equalToConstant: 124)
currHeight?.isActive = true
ibOutletForButton = menuBarItem
}
}
How could I get the button bigger and moved up that it looks like on the image?
One way you could do this is to add the button directly to the UIViewController instead of to the UIToolbar. You have then complete freedom of positioning and sizing.
As you don't use a UITabBar, you will stay within your UIViewController and it should be no problem
You can create 4 BarbuttonItem after first 2, give some flexible space between items and add your 'plus' button to toolbar directly in that space.
#IBOutlet weak var myToolBar: UIToolbar!
let menuBtn = UIButton(type: .custom)
override func viewDidLoad() {
super.viewDidLoad()
let menuBtn = UIButton(type: .custom)
menuBtn.frame = CGRect(x: myToolBar.center.x-10, y: -60, width: 20, height: 120)
menuBtn.setImage(UIImage(named:"iconImage"), for: .normal)
menuBtn.addTarget(self, action: #selector(onMenuButtonPressed(_:)), for: UIControlEvents.touchUpInside)
let spacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let items = myToolBar.items!
myToolBar.setItems([items[0],items[1],spacer,items[2],items[3]], animated: false)
myToolBar.addSubview(menuBtn)
}
Related
I created a UICollectionViewController to simulate a Feed app and I wanted to configure the top navigation bar similar to the Twitter one, with custom buttons that trigger actions, here's mine
The problem I'm facing is that when I click on the black profile icon, the action is not triggered.
Here's my code:
import UIKit
class HomeViewController: UICollectionViewController {
//MARK: - Properties
private lazy var profileButton: UIButton = {
let button = UIButton(type: .system)
button.setImage(UIImage(systemName: "person.fill"), for: .normal)
button.tintColor = UIColor(rgb: 0x79CBBF)
button.addTarget(self, action: #selector(didTapProfile), for: .touchUpInside)
return button
}()
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setupNavBar()
}
// MARK: - Helpers
func setupNavBar() {
let width = view.frame.width
let titleView = UIView()
titleView.backgroundColor = .clear
titleView.frame = .init(x: 0, y: 0, width: width, height: 50)
titleView.addSubview(profileButton)
profileButton.tintColor = .black
profileButton.centerY(inView: titleView, leftAnchor: titleView.leftAnchor, paddingLeft: 0)
titleView.addSubview(filterButton)
filterButton.centerY(inView: titleView, leftAnchor: profileButton.rightAnchor, paddingLeft: view.frame.width - 60 - 16)
navigationItem.titleView = titleView
}
// MARK: - Actions
#objc func didTapProfile() {
print("did tap profile")
}
As said below, I added a .addTarget to the button but the #selector(didTapProfile) function does not get triggered when the button is inside the navigation bar.
Any hints on how to do this?
Instead of creating a title view and measuring its size and stuff... there are a load of convenience functions for doing this...
Take a look here... https://www.hackingwithswift.com/example-code/uikit/how-to-add-a-bar-button-to-a-navigation-bar
You can do something like...
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(didTapProfile))
There are different ways to create UIBarButtonItem with images and text also...
https://developer.apple.com/documentation/uikit/uibarbuttonitem
I am trying to center a Button onto the bottom of a view but it never appears. The only time it appears is when I uncomment takePhotoButton.frame. What is the proper way to do this?
import UIKit
import AVFoundation
class InputViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let photoPreviewImageView = UIImageView()
photoPreviewImageView.frame = view.bounds
photoPreviewImageView.backgroundColor = UIColor.green
view.addSubview(photoPreviewImageView)
let imageOfPhotoButton = UIImage(named: "smallcircle.circle.fill") as UIImage?
let takePhotoButton = UIButton(type: .custom) as UIButton
takePhotoButton.setImage(imageOfPhotoButton, for: .normal)
//takePhotoButton.frame = CGRect(x: 10, y: 10, width: 60, height: 60) // It will appear with this code however i took it away because im trying to center it at the bottom of the screen
takePhotoButton.center = view.center
photoPreviewImageView.addSubview(takePhotoButton)
}
}
Use constraint anchors. After you add the takePhotoButton set them the following way:
takePhotoButton.bottomAnchor.constraint(equalTo: photoPreviewImageView.bottomAnchor).isActive = true
takePhotoButton.centerXAnchor.constraint(equalTo: photoPreviewImageView.centerXAnchor).isActive = true
This will set make your button have the same bottom and center as it's container.
Good day,
you have to add constraint.
import UIKit
class ViewController: UIViewController {
var loginButton : UIButton = {
let button = UIButton(type: .system)
button.setTitle("Login", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
button.backgroundColor = .red
button.tintColor = .white
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
constraintsInit()
}
func constraintsInit(){
view.addSubview(loginButton)
NSLayoutConstraint.activate([
loginButton.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),
loginButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
loginButton.heightAnchor.constraint(equalToConstant: 30),
loginButton.leadingAnchor.constraint(equalTo: self.view.leadingAnchor,constant: 30),
loginButton.trailingAnchor.constraint(equalTo: self.view.trailingAnchor,constant: -30),
])
}
}
on youtube you can find several people that explain how create the views, using only code.
I am trying to write an extension fo UIBarButtonItem. I would like to use auto layout so that the UIBarButtonItem's width and height is 70% of the height of the UINavigationBar. When I implement this extension, i am getting the following auto layout errors:
import UIKit
extension UIBarButtonItem {
static func menuButton(target: Any?, action: Selector, imageName: String, navigationBar: UINavigationBar) -> UIBarButtonItem{
let button = UIButton.init(type: .system)
let image = UIImage.init(named: imageName)
button.setBackgroundImage(image, for: .normal)
button.addTarget(target, action: action, for: .touchUpInside)
let menuButton = UIBarButtonItem.init(customView: button)
menuButton.customView?.translatesAutoresizingMaskIntoConstraints = false
menuButton.customView?.widthAnchor.constraint(equalTo: navigationBar.heightAnchor, multiplier: 0.7).isActive = true
menuButton.customView?.heightAnchor.constraint(equalTo: navigationBar.heightAnchor, multiplier: 0.7).isActive = true
return menuButton
}
}
Implementation:
let rightButton = UIBarButtonItem.menuButton(target: self, action: #selector(editCells), imageName: "expand", navigationBar: navigationController!.navigationBar)
navigationItem.rightBarButtonItem = rightButton
Error message in console:
Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to activate constraint with anchors <NSLayoutDimension:0x600001be1180 "UIButton:0x7ff5d6d16b80.width"> and <NSLayoutDimension:0x600001be25c0 "UINavigationBar:0x7ff5d911a2f0.height"> because they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies? That's illegal.'
You can create custom view for your navigationBar custom button and set properties for whatever you want like this:
func addRightButton() {
let barButtonView = UIView(frame: CGRect(origin: .zero, size: CGSize(width: 180, height: 40)))
barButtonView.backgroundColor = UIColor.red
let navigationBarHeightWithRatio = (navigationController?.navigationBar.frame.height ?? 100) * 0.7
let customBarButton = UIButton(frame: CGRect(x: 0, y: 8, width: navigationBarHeightWithRatio, height: navigationBarHeightWithRatio))
customBarButton.setImage(UIImage(named: "your_image_name"), for: .normal)
customBarButton.setTitle("title", for: .normal)
customBarButton.addTarget(self, action: #selector("<your_action_function>"), for: .touchUpInside)
barButtonView.addSubview(customBarButton)
let rightBarButton = UIBarButtonItem(customView: barButtonView)
navigationItem.rightBarButtonItem = rightBarButton
}
Note:
You can customize width different width, height values and x, y positions.
I hope it is works.
Enjoy.
The error message is clear. When you say:
let rightButton = UIBarButtonItem.menuButton(
target: self, action: #selector(editCells),
imageName: "expand",
navigationBar: navigationController!.navigationBar)
... and the menuButton method runs, at that moment, you are trying to form a constraint relationship between the button and the navigation bar at a time when the button is not in the navigation bar. That, as the error message tells you, is illegal.
(I doubt that the goal you have outlined is possible at all, but that's another story. I'm just explaining the error message.)
I create and display uiview in live view windows, when i create the button and add to the uiview , the program fail with nonstop looping which continuously load addbutton . Did somebody meet this problem and please tell me why :-)
import UIKit
import PlaygroundSupport
class MyViewController : UIViewController {
var label1 : UILabel?
override func loadView() {
let view = UIView()
view.backgroundColor = .white
print("code run here ")
let label = UILabel()
label.frame = CGRect(x: 150, y: 200, width: 200, height: 20)
label.text = "Hello World!"
label.textColor = .black
label1 = label
view.addSubview(label)
let k1:UIButton = addnewbutton() as! UIButton
//view.addSubview(k1)
self.view = view
}
#objc func buttonPressed(sender: UIButton!) {
var alertController = UIAlertController(title: "title", message: "message", preferredStyle: UIAlertControllerStyle.alert)
self.present(alertController, animated: true, completion: nil)
}
func addnewbutton() -> UIView{
var btn : UIButton
btn = UIButton()
btn.frame = CGRect(x:200,y:300,width:100,height:25)
btn.setTitle("clickme",for: UIControlState.normal)
//btn.titleLabel?.text = "clickme"
btn.backgroundColor = UIColor.black
btn.titleLabel?.textColor = UIColor.white
btn.titleColor(for: UIControlState.normal)
btn.addTarget(self, action: #selector(buttonPressed), for: UIControlEvents.touchUpInside)
view.addSubview(btn)
return btn
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()
You add the button here
view.addSubview(btn)
inside addnewbutton
which recursively searches for the parent view of the VC and it's not yet setted inside loadView so control calls it again and the problem happens to infinite loop , so comment that line and uncomment this
view.addSubview(k1) // which is inside loadView
BTW make the return of addnewbutton to UIButton directly instead of a cast
I need to create Toolbar and add buttons programmatically. I will have different sets of buttons for diferent screens.
That's easy.
Also, I need to center those buttons. They should have equal space between them.
And also I need that all those buttons separate screen width only between themselfs. Like, I have 5 buttons, total screen width is 300, so each button will have width 60. I am not sure how to do that, i tried dirrenrt things but they wasn't centered or hadn't such width. Any ideas how to do that?
class OptionsView: UIView {
#IBOutlet weak var toolbar: UIToolbar!
var width: CGFloat {
return 0//UIScreen.main.bounds.width/5 //was trying to calculate width , but it did not work
}
override func awakeFromNib() {
super.awakeFromNib()
toolbar.isTranslucent = true
toolbar.setBackgroundImage(UIImage(), forToolbarPosition: UIBarPosition.any, barMetrics: UIBarMetrics.default)
toolbar.setShadowImage(UIImage(), forToolbarPosition: UIBarPosition.any)
toolbar.barTintColor = .white
backgroundColor = .clear
}
func addAirPlay(target: Any?, action: Selector) {
let normalImage = UIImage(named: "player-airplay")
let button = UIButton(type: .custom)
button.frame = CGRect(x: 0, y: 0, width: width, height: 100)
button.setImage(normalImage, for: UIControlState())
button.addTarget(target, action: action, for: .touchUpInside)
let item = UIBarButtonItem(customView: button)
//item.width = width //was trying to play with that
var items = toolbar.items
items?.append(item)
toolbar.items = items
toolbar.reload()
}
func addOrientation(target: Any?, action: Selector) {
let button = UIButton(type: .custom)
button.tag = orientationTag
button.frame = CGRect(x: 0, y: 0, width: width, height: 100)
button.addTarget(target, action: action, for: .touchUpInside)
let item = UIBarButtonItem(customView: button)
//item.width = width
var items = toolbar.items
items?.append(item)
toolbar.items = items
toolbar.reload()
reloadOrientation()
}
func addFlexibleSpace() {
let item = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
var items = toolbar.items
items?.append(item)
toolbar.items = items
toolbar.reload()
}
Creating:
optionsView = OptionsView.loadFromNib()
playerView.addSubview(optionsView)
optionsView.snp.makeConstraints { (make) in
make.leading.trailing.top.bottom.equalTo(self.optionsPlaceholderView)
}
// optionsView.addFlexibleSpace() //was trying that as well
optionsView.addAirPlay(target: self, action: #selector(airplayButtonAction(_:)))
optionsView.addFlexibleSpace()
optionsView.addOrientation(target: self, action: #selector(orientationButtonAction(_:)))
optionsView.addFlexibleSpace()
optionsView.addFave(target: self, action: #selector(faveButtonAction(_:)))
optionsView.addFlexibleSpace()
optionsView.addExtra(target: self, action: #selector(showExtraButtonAction(_:)))
optionsView.addFlexibleSpace()
optionsView.addScenes(target: self, action: #selector(sceneButtonAction(_:)))
// optionsView.addFlexibleSpace()