Adding button to view created programatically - ios

I have a view that is created programatically as follows
let viewOne = UIView()
viewOne.contentMode = .scaleAspectFit
viewOne.backgroundColor = UIColor.blue
viewOne.layer.masksToBounds = true
viewOne.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(viewOne)
NSLayoutConstraint.activate([
viewOne.centerXAnchor.constraint(equalTo: view.centerXAnchor),
viewOne.centerYAnchor.constraint(equalTo: view.centerYAnchor),
viewOne.heightAnchor.constraint(equalToConstant:200),
viewOne.widthAnchor.constraint(equalToConstant:200)])
I have the following button that is created programmatically as follows,
let button = UIButton()
button.frame = CGRect(x: 125, y: 125, width: 100, height: 50)
button.backgroundColor = UIColor.green
button.setTitle("Ok", for: .normal)
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
viewOne.addSubview(button)
How do I add the button to the center of viewOne. Thanks in advance.

You can try
let viewOne = UIView()
viewOne.contentMode = .scaleAspectFit
viewOne.backgroundColor = UIColor.blue
viewOne.layer.masksToBounds = true
viewOne.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(viewOne)
let button = UIButton()
button.backgroundColor = UIColor.green
button.setTitle("Ok", for: .normal)
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
viewOne.addSubview(button)
NSLayoutConstraint.activate([
viewOne.centerXAnchor.constraint(equalTo: view.centerXAnchor),
viewOne.centerYAnchor.constraint(equalTo: view.centerYAnchor),
viewOne.heightAnchor.constraint(equalToConstant:200),
viewOne.widthAnchor.constraint(equalToConstant:200),
button.centerXAnchor.constraint(equalTo: viewOne.centerXAnchor),
button.centerYAnchor.constraint(equalTo: viewOne.centerYAnchor),
button.heightAnchor.constraint(equalToConstant:100),
button.widthAnchor.constraint(equalToConstant:50)
])
Tip:
you can optionally remove these 2 constraints as the button has intrinsic content size by default but if you need a fixed content leave them
button.heightAnchor.constraint(equalToConstant:100),
button.widthAnchor.constraint(equalToConstant:50)

Button it self has the width and height. So you do not have to fix it
button.centerXAnchor.constraint(equalTo: viewOne.centerXAnchor)
button.centerYAnchor.constraint(equalTo: viewOne.centerYAnchor)

You can either use autolayout, as shown below:
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.backgroundColor = UIColor.green
button.setTitle("Ok", for: .normal)
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
viewOne.addSubview(button)
NSLayoutConstraint.activate([
button.centerXAnchor.constraint(equalTo: viewOne.centerXAnchor),
button.centerYAnchor.constraint(equalTo: viewOne.centerYAnchor),
button.heightAnchor.constraint(equalToConstant:50),
button.widthAnchor.constraint(equalToConstant:100)])
Or place your button manually, after doing some calculation.
let button = UIButton(frame: CGRect(x: 50, y: 75, width: 100, height: 50))
viewOne.addSubview(button)
I obtained x and y as follows:
x = viewOne width/2 - button width/2 = 200/2 - 100/2 = 50
y = viewOne height/2 - button height/2 = 200/2 - 50/2 = 75

Related

Swift - UIView moves when changing tab controller tabs

Inside the viewDidAppear I have a function that contains this code, in order to make a UIView:
let contentView = UIView()
func addSleepingView() {
contentView.backgroundColor = .systemYellow.withAlphaComponent(0.25)
view.addSubview(contentView)
contentView.translatesAutoresizingMaskIntoConstraints = false
contentView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
contentView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
// Anchor your view right above the tabBar
contentView.bottomAnchor.constraint(equalTo: (tabBarController?.tabBar.topAnchor)!).isActive = true
contentView.heightAnchor.constraint(equalToConstant: 50).isActive = true
let label = UILabel()
label.text = "Test"
label.frame = CGRect(x: 0, y: 0, width: 25, height: 34.0)
label.lineBreakMode = .byWordWrapping
label.numberOfLines = 0
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(label)
label.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
label.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
let button = UIButton()
button.setImage(UIImage(systemName: "arrow.clockwise", withConfiguration: UIImage.SymbolConfiguration(scale: .large)), for: UIControl.State.normal)
button.tintColor = .systemGray
button.frame = CGRect(x: self.view.bounds.width-42, y: 8, width: 34, height: 34.0)
button.isUserInteractionEnabled = true
button.addTarget(self, action: #selector(wakeupFunction), for: .touchUpInside)
contentView.addSubview(button)
let button2 = UIButton()
button2.setImage(UIImage(systemName: "exclamationmark.triangle", withConfiguration: UIImage.SymbolConfiguration(scale: .large)), for: UIControl.State.normal)
button2.tintColor = .label
button2.frame = CGRect(x: 8, y: 8, width: 34, height: 34.0)
button2.isUserInteractionEnabled = false
contentView.addSubview(button2)
contentView.bringSubviewToFront(button)
}
This is what it looks like:
Now this is exactly how I want it. The problem comes when I change tab. For example go to the last tab, and back to the first tab again. Then it looks like this:
What am I doing wrong here?
You can just add your code of activating constraints inside the DispatchQueue.main block
Updated Line you can change and it will start working as you're expectation.
// Anchor your view right above the tabBar
DispatchQueue.main.async
{
self.contentView.bottomAnchor.constraint(equalTo: (self.tabBarController?.tabBar.topAnchor)!).isActive = true
self.contentView.heightAnchor.constraint(equalToConstant: 50).isActive = true
}

Why is space added between UIButtons?

I have the following code
let mostRead = UIButton(frame: CGRect(x: 0, y: tableView.frame.origin.y + tableView.frame.height, width: self.view.bounds.size.width, height: 160))
mostRead.setImage(UIImage.init(named: "mostread"), for: .normal)
mostRead.addTarget(self, action:#selector(self.goToMostRead(sender:)), for: .touchUpInside)
innerView.addSubview(mostRead)
let videoTitles = UIButton(frame: CGRect(x: 0, y: mostRead.frame.maxY, width: self.view.bounds.size.width, height: 160))
videoTitles.setImage(UIImage.init(named: "videotitles"), for: .normal)
videoTitles.addTarget(self, action:#selector(self.goToVideoTitles(sender:)), for: .touchUpInside)
innerView.addSubview(videoTitles)
let audioTitles = UIButton(frame: CGRect(x: 0, y: videoTitles.frame.maxY, width: self.view.bounds.size.width, height: 160))
audioTitles.setImage(UIImage.init(named: "audiotitles"), for: .normal)
audioTitles.addTarget(self, action:#selector(self.goToAudioTitles(sender:)), for: .touchUpInside)
innerView.addSubview(audioTitles)
Space gets added between the UI Buttons. If you notice in the picture, there's a lot of space between each image even though I specified no space between images. Does anyone know why that's happening?
You try to add it with stackView and auto layout like this:
first set your object under your controller class:
let buttonmostRead: UIButton = {
let button = UIButton()
button.backgroundColor = .red
button.setBackgroundImage(UIImage(named: "mostRead"), for: .normal)
button.layer.cornerRadius = 8
button.clipsToBounds = true
return button
}()
let buttonvideoTitles: UIButton = {
let button = UIButton()
button.backgroundColor = .red
button.setBackgroundImage(UIImage(named: "videoTitles"), for: .normal)
button.layer.cornerRadius = 8
button.clipsToBounds = true
return button
}()
let buttonaudiotitles: UIButton = {
let button = UIButton()
button.backgroundColor = .red
button.setBackgroundImage(UIImage(named: "audiotitles"), for: .normal)
button.layer.cornerRadius = 8
button.clipsToBounds = true
return button
}()
after that in viewDiLoad set staclView an constraints:
let stackView = UIStackView(arrangedSubviews: [buttonmostRead, buttonvideoTitles, buttonaudiotitles])
stackView.axis = .vertical
stackView.distribution = .fillEqually
stackView.spacing = 8
stackView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stackView)
stackView.heightAnchor.constraint(equalToConstant: 466).isActive = true
stackView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -20).isActive = true
stackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 20).isActive = true
stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0).isActive = true
to set space between button, change stackView spacing...
and this is the result
I put stackView in the center of the view but you can place them wherever you want by changing the constraints...

Trying to make a UIButton a circle

Im currently trying to make a button into a circle shape and here is my code:
var raffleButton:UIButton = {
var button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.titleLabel?.font = UIFont(name: "AvenirNext-Bold", size: 19)
button.setTitle("Tap To Enter Raffle!", for: .normal)
button.setTitleColor(UIColor.red, for: .normal)
button.backgroundColor = .white
button.layer.masksToBounds = true
button.frame = CGRect(x: 1600, y: 160, width: 160, height: 160)
button.layer.cornerRadius = button.frame.width/2
return button
}()
However when I run the code the button is disfigured and looks like the following... round and football like.
Is there any reason why the button looks like it does instead of being a circle?
You have some confusion as to whether you are using autolayout or not.
You have set translatesAutoresizingMaskIntoConstraints to false, but then you are trying to manipulate the frame.
If you add constraints to set the width & height, you will get a result closer to what you are after, but you will still need to adjust your label or font to get it to fit:
var raffleButton:UIButton = {
var button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.titleLabel?.font = UIFont(name: "AvenirNext-Bold", size: 19)
button.setTitle("Tap To Enter Raffle!!", for: .normal)
button.setTitleColor(UIColor.red, for: .normal)
button.backgroundColor = .white
button.layer.masksToBounds = true
button.heightAnchor.constraint(equalToConstant: 160).isActive = true
button.widthAnchor.constraint(equalToConstant: 160).isActive = true
button.layer.cornerRadius = 80
return button
}()
Since you set button.translatesAutoresizingMaskIntoConstraints = false, this code won't work button.frame = CGRect(x: 1600, y: 160, width: 160, height: 160). The button's size will be changed during the layout process(won't be (160, 160) anymore). Therefore, it's not a circle.
you can either change button.translatesAutoresizingMaskIntoConstraints = false or try setting button's cornerRadius in viewDidLayoutSubviews method.
your button Height same as button width and then set this code..
anyButton.backgroundColor = .clear
anyButton.layer.cornerRadius = anyButton.frame.height / 2
anyButton.layer.borderWidth = 1
anyButton.layer.borderColor = UIColor.black.cgColor
One semi-obvious thing to note, is if the button frame's height and width is not equal, it will not be a circle :).

Round UIBarButtonItems in Swift

I am trying to make round (sort of notification counter which you see on most of the apps) UIBarButtonItem in Swift. I know how to do it but the thing is it is actually being round only when I am setting the width as 34 and height as 24. Are these magic numbers for UIBarButtonItems ? If I set the width or height (same , my desired frame is 30 x 30) for something else and calculate the cornerRadius based on the width then it is not perfect circle rather rounded rectangle. What is I am doing wrong ? My code is below :
let button = UIButton(type: .custom)
button.frame = CGRect(x: 0, y: 0, width: 34, height: 24)
button.backgroundColor = DarkModeUtil.isDarkMode() ? UIColor.white : UIColor.black
button.setTitle("\(self.pickedAppActions.count > 9 ? "9+" : "\(self.pickedAppActions.count)")", for: .normal)
button.setTitleColor(DarkModeUtil.isDarkMode() ? .black : UIColor.white, for: .normal)
button.contentHorizontalAlignment = .center
button.titleLabel?.fitSize()
button.layer.cornerRadius = button.bounds.size.width / 2
button.clipsToBounds = true
button.addTarget(self, action: #selector(counterTapped(_:)), for: [.touchUpInside])
let doneItem = UIBarButtonItem(image: UIImage(named: "done")?.withRenderingMode(.alwaysTemplate), style: .plain, target: self, action: #selector(doneButtonClicked(_:)))
doneItem.tintColor = DarkModeUtil.isDarkMode() ? .white : .black
let counterButton = UIBarButtonItem(customView: button)
let buttons:[UIBarButtonItem] = [doneItem,counterButton]
self.navigationItem.rightBarButtonItems = buttons
If I set same width and height for example 30 x 30 I get button like this:
make height and width 34 work for me. here is a code. also no need to change button.frame.size.width / 2.
let button = UIButton(type: .custom)
button.frame = CGRect(x: 0, y: 0, width: 34, height: 34)
button.backgroundColor = DarkModeUtil.isDarkMode() ? UIColor.white : UIColor.black
button.setTitle("\(self.pickedAppActions.count > 9 ? "9+" : "\(self.pickedAppActions.count)")", for: .normal)
button.setTitleColor(DarkModeUtil.isDarkMode() ? .black : UIColor.white, for: .normal)
button.contentHorizontalAlignment = .center
button.titleLabel?.fitSize()
button.layer.cornerRadius = button.bounds.size.width / 2
button.clipsToBounds = true
button.addTarget(self, action: #selector(counterTapped(_:)), for: [.touchUpInside])
let doneItem = UIBarButtonItem(image: UIImage(named: "done")?.withRenderingMode(.alwaysTemplate), style: .plain, target: self, action: #selector(doneButtonClicked(_:)))
doneItem.tintColor = DarkModeUtil.isDarkMode() ? .white : .black
let counterButton = UIBarButtonItem(customView: button)
let buttons:[UIBarButtonItem] = [doneItem,counterButton]
self.navigationItem.rightBarButtonItems = buttons
You can set corner radius of the Button using
button.frame = CGRect(x: 0, y: 0, width: 84, height: 40)
button.layer.cornerRadius = button.bounds.size.height / 2
Note: Button Maximum height: 44 and Minimum height: 34 in UINavigationBar as checked from view hierarchy.
Please try with this code :
For Round button you need to make height and width same value :
let button = UIButton(type: .custom)
button.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
button.backgroundColor = UIColor.black
button.setTitle("999", for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 12.0)
button.titleLabel?.minimumScaleFactor = 0.5
button.titleLabel?.numberOfLines = 0
button.titleLabel?.adjustsFontSizeToFitWidth = true
button.layer.cornerRadius = button.frame.size.height/2
button.clipsToBounds = true
let counterButton = UIBarButtonItem(customView: button)
let buttons:[UIBarButtonItem] = [counterButton]
self.navigationItem.rightBarButtonItems = buttons

Text and Image inside UIButton

I am stuck in UIButton. I want to add to UIButton text and then next to text add an image, like this:
I want to center it.
when I type this:
let button = UIButton(type: .custom)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Přidat za: \(priceForCategory)", for: .normal)
button.setImage(UIImage(named: "Coin"), for: .normal)
button.imageEdgeInsets = UIEdgeInsets(top: 6, left: -100, bottom: 6, right: 6)
button.titleLabel?.textAlignment = .right
button.alignImageRight()
button.imageView?.contentMode = .scaleAspectFit
button.backgroundColor = UIColor.custom.orange
button.addTarget(self, action: #selector(handleAddCategory), for: .touchUpInside)
button.tintColor = .white
button.titleLabel?.font = UIFont(name: ".SFUIText-Bold", size: 20)
It shows me:
My height breaks and still it doesn't work.
button.alignImageRight()
Means
func alignImageRight() {
if UIApplication.shared.userInterfaceLayoutDirection == .leftToRight {
semanticContentAttribute = .forceRightToLeft
}
else {
semanticContentAttribute = .forceLeftToRight
}
}
Thanks for every answer.
Create func for adding UIButton
func addRoundedButton() {
let button = UIButton(type: .custom)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Add for: 100", for: .normal)
button.setImage(UIImage(named: "Coin"), for: .normal)
button.alignImageRight()
//Add this line for rounded corner
button.layer.cornerRadius = 20 // set cornerRadius = height/2
button.backgroundColor = UIColor.orange
button.tintColor = .white
button.titleLabel?.font = UIFont(name: ".SFUIText-Bold", size: 20)
view.addSubview(button)
[button.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -15),
button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
button.heightAnchor.constraint(equalToConstant: 40),
button.widthAnchor.constraint(equalToConstant: 300)].forEach{ $0.isActive = true }
}
Create extension for UIButton (as you already created). but add UIEdgeInsets in extension.
extension UIButton {
func alignImageRight() {
if UIApplication.shared.userInterfaceLayoutDirection == .leftToRight {
semanticContentAttribute = .forceRightToLeft
imageEdgeInsets = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 0)
} else {
semanticContentAttribute = .forceLeftToRight
imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 15)
}
}
}
Output
TIP
For auto adjust width depend on Text and Image, use this extension

Resources