Center alignment UIButton xCODE programmatically - ios

I’m trying to center the text of UIButton programmatically.
This is what I want the UIButton to look like (I used the interface builder):
UIbutton
This is what the UIButton looks like after I set it programmatically:
UIbutton
And this is what the UIButton looks like after I set it programmatically and tried to center the text like in the first picture:
UIButton
This is the code that I used to try to center it:
previousPageButton.titleLabel?.numberOfLines = 0
previousPageButton.titleLabel?.textAlignment = .center

The problem was I had set up "attributed" to the title in interface builder. I just had to set it to "plain" and it's working now.

Do it with new button configuration, set your button:
let myButton: UIButton = {
let b = UIButton()
b.configuration = UIButton.Configuration.filled()
b.configuration?.title = "CLICK TO GO TO\n PREVIOUS PAGE"
b.titleLabel?.textAlignment = .center
b.configuration?.baseForegroundColor = .white // text color
b.configuration?.baseBackgroundColor = .black // background color
b.configuration?.cornerStyle = .small // corner radius
b.translatesAutoresizingMaskIntoConstraints = false
return b
}()
in viewDidLoad set constraints:
view.addSubview(myButton)
myButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
myButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
myButton.heightAnchor.constraint(equalToConstant: 80).isActive = true // set eight of button
myButton.widthAnchor.constraint(equalToConstant: 200).isActive = true // set width of button
This is the result:

Related

How to mask a UIButton in Swift?

I have a complicated Stack view that has many arranged labels and buttons. When I have attempted to mask the whole stack view in order to enforce a corner radius, the buttons within the stack view no longer worked (action selectors not triggered upon touch inside). I have decided to simplify the problem first to one button and one mask like so:
let mask = UIView()
mask.translatesAutoresizingMaskIntoConstraints = false
mask.backgroundColor = .green
mask.layer.cornerRadius = 50
view.addSubview(mask)
mask.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
mask.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
mask.widthAnchor.constraint(equalToConstant: 200).isActive = true
mask.heightAnchor.constraint(equalToConstant: 100).isActive = true
btn = UIButton()
btn.backgroundColor = .red
btn.translatesAutoresizingMaskIntoConstraints = false
btn.setTitle("More info", for: .normal)
btn.tintColor = .black
btn.addTarget(self, action: #selector(moreInfoTapped), for: .touchUpInside)
view.addSubview(btn)
btn.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
btn.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
btn.widthAnchor.constraint(equalToConstant: 200).isActive = true
btn.heightAnchor.constraint(equalToConstant: 100).isActive = true
view.layoutSubviews()
view.setNeedsLayout()
btn.mask = mask
This masks the button correctly but unfortunately the mask is placed in front of the button and thus taps on the button are never registered.
This is the view hierarchy:
Am I missing something?
I dont know why you are masking for achieving round corners if you guide me i can suggest you better solution .. but for your current case if you turn off user interaction of mask view .. your button will start responding
mask.isUserInteractionEnabled = false
I'll use the button example you specified above, as I don't know what you want to do with the stackview.
You'll style the mask as you want with the corner radius. And then you'll add the button to the mask but with a transparent background and make it fill the parent i.e. mask
let maskView = UIView()
view.addSubview(maskView)
maskView.setCornerRadius() // implement this
maskView.setupConstraints() // implement this
let button = UIButton()
button.backgroundColor = .clear
maskView.addSubview(button)
button.fillParent() // implement this
The same logic will apply for the stackview. You just need to style the container view or mask view.
Alternatively, you can include both the button and mask view in a container view:
the mask beneath the button
the button to be clear
the container view to be clear
style the mask view
have both mask and button fill the container view (or size them as would work best for you

Adding buttons programmatically to stackView in Swift

I've tried to add buttons dynamically/programmatically in UIStackView that I've built with interface builder but they failed to show up when I run the application. The number of buttons that's supposed to be added ranging normally from 4-6. Can you guys tell me what's wrong with the code
#Nowonder I just recreate what you are trying to achieve. The following are the steps.
Add a UIStackView in viewController from Interface Builder and add required constraints.
Add the following code.
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton()
button.setTitle("btn 1", for: .normal)
button.backgroundColor = UIColor.red
button.translatesAutoresizingMaskIntoConstraints = false
let button2 = UIButton()
button2.setTitle("btn 2", for: .normal)
button2.backgroundColor = UIColor.gray
button2.translatesAutoresizingMaskIntoConstraints = false
let button3 = UIButton()
button3.setTitle("btn 3", for: .normal)
button3.backgroundColor = UIColor.brown
button3.translatesAutoresizingMaskIntoConstraints = false
buttonStackView.alignment = .fill
buttonStackView.distribution = .fillEqually
buttonStackView.spacing = 8.0
buttonStackView.addArrangedSubview(button)
buttonStackView.addArrangedSubview(button2)
buttonStackView.addArrangedSubview(button3)
}
Following is the outcome.
Hope it helps.
I think you need to do few more steps before the button will start showing up.
Add the stack view to current view's subviews
view.addSubview(buttonStackView)
Now each of these views buttons, as well as the stackView, needs to set the translatesAutoresizingMaskIntoConstraints to false.
button1.translatesAutoresizingMaskIntoConstraints = false
button2.translatesAutoresizingMaskIntoConstraints = false
buttonStackView.translatesAutoresizingMaskIntoConstraints = false
Now set the stackView contraints
NSLayoutConstraint.activate([
buttonStackView.topAnchor.constraint(equalTo: view.topAnchor),
buttonStackView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
buttonStackView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
buttonStackView.trailingAnchor.constraint(equalTo: view.trailingAnchor)])
You will need to provide the constraints, or can override the intrinsic size of stackView.
override func intrinsicContentSize() -> CGSize
{
return CGSizeMake(200, 40)
}
As UILabel have the intrinsic size and so, the button will show, if not you will have to set the constraints for them also to be safe.
SOLVED!
The button showed up when I set the type of the button with the instance method init(type:)

Swift UITapGesture on view in a titleView not working

I have a UINavigationItem and I set it's titleView to a UIView which has a UILabel and UIImageView embedded. I'm attempting to add a UITapGestureRecognizer to the view but it doesn't seem to work. Any solutions? Also, adding a gestureRecognizer to the whole navigationBar isn't an option as I have a rightBarButtonItem and want to make use of the back button.
Here is my code:
func configureTitleView() {
guard let profile = profile else {
// Pop navController
return
}
let titleView = UIView()
titleView.frame = CGRect(x: 0, y: 0, width: 100, height: 40)
let containerView = UIView()
containerView.translatesAutoresizingMaskIntoConstraints = false
titleView.addSubview(containerView)
let profileImageView = UIImageView()
profileImageView.translatesAutoresizingMaskIntoConstraints = false
profileImageView.contentMode = .scaleAspectFill
profileImageView.clipsToBounds = true
let imageURL = URL(string: profile!.firstProfilePicture!)
profileImageView.sd_setImage(with: imageURL)
containerView.addSubview(profileImageView)
profileImageView.leftAnchor.constraint(equalTo: containerView.leftAnchor).isActive = true
profileImageView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true
profileImageView.widthAnchor.constraint(equalToConstant: 36).isActive = true
profileImageView.heightAnchor.constraint(equalToConstant: 36).isActive = true
profileImageView.layer.cornerRadius = 36 / 2
let nameLabel = UILabel()
containerView.addSubview(nameLabel)
nameLabel.text = profile!.displayName!
nameLabel.textColor = .white
nameLabel.translatesAutoresizingMaskIntoConstraints = false
nameLabel.leftAnchor.constraint(equalTo: profileImageView.rightAnchor, constant: 8).isActive = true
nameLabel.centerYAnchor.constraint(equalTo: profileImageView.centerYAnchor).isActive = true
nameLabel.rightAnchor.constraint(equalTo: containerView.rightAnchor).isActive = true
nameLabel.heightAnchor.constraint(equalTo: profileImageView.heightAnchor).isActive = true
containerView.centerXAnchor.constraint(equalTo: titleView.centerXAnchor).isActive = true
containerView.centerYAnchor.constraint(equalTo: titleView.centerYAnchor).isActive = true
self.navigationItem.titleView = titleView
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.openProfile))
tapGesture.numberOfTapsRequired = 1
titleView.addGestureRecognizer(tapGesture)
titleView.isUserInteractionEnabled = true
}
Beginning with iOS 11, views added to toolbars as UIBarButtonItem using UIBarButtonItem(customView:) are now laid out using auto layout. This includes title views added to a UINavigationBar through the navigationItem.titleView property of a UIViewController. You should add sizing constraints on your titleView. For example:
titleView.widthAnchor.constraint(equalToConstant: 100).isActive = true
titleView.heightAnchor.constraint(equalToConstant: 40.0).isActive = true
Otherwise, auto layout will use the intrinsic content size of your title view which is CGSize.zero. Gestures are masked to the bounds of the view they are attached to even if the sub views of that view are not. Because the bounds of titleView without constraints is CGRect.zero it will never fire. Add constraints and it works as expected.
For more information see the WWDC 2017 session Updating your app for iOS 11.
You do not need to add explicit height and width constant constraint to custom view.
Just add subviews to custom view, add width and height anchor.
let customView = UIView()
let button = UIButton(type: .custom)
button.translatesAutoresizingMaskIntoConstraints = false
customView.addSubview(button)
[
button.widthAnchor.constraint(equalTo: customView.widthAnchor),
button.heightAnchor.constraint(equalTo: customView.heightAnchor),
].forEach({$0.isActive = true})
navigationItem.titleView = customView

Set X and Y values of UILabel using NSLayout

I am adding a UI Label and I am trying out programmatic UI code. I set up my label using this code:
let titleLabel: UILabel = {
let lb = UILabel()
lb.translatesAutoresizingMaskIntoConstraints = false
lb.textAlignment = .center
lb.numberOfLines = 1
lb.textColor = UIColor.black
lb.font=UIFont.systemFont(ofSize: 22)
lb.backgroundColor = UIColor.white
return lb
and then added constraints using this code:
func setupTitleLabel() {
titleLabel.translatesAutoresizingMaskIntoConstraints = false
titleLabel.heightAnchor.constraint(equalToConstant: 100).isActive = true
titleLabel.widthAnchor.constraint(equalToConstant: 200).isActive = true
titleLabel.centerXAnchor.constraint(equalTo: titleLabel.superview!.centerXAnchor).isActive = true
titleLabel.centerYAnchor.constraint(equalTo: titleLabel.superview!.centerYAnchor).isActive = true
}
I call this function later on. However, I am not sure how to change to X and Y values. Currently, it is set to the middle of the page for both X and Y, but how would I move it up to the top.
As I said in my comment, you are using titleLabel.superview!.centerYAnchor wrongly if you need pin your label to top of your label superview you need use titleLabel.superview!.topAnchor instead
replace this
titleLabel.centerYAnchor.constraint(equalTo: titleLabel.superview!.centerYAnchor).isActive = true
by this
titleLabel.centerYAnchor.constraint(equalTo: titleLabel.superview!.topAnchor).isActive = true
What I understand the case is that the label is in the centerX and centerY, and you want it to be at the top of the superView later.If so,I think you can use var centerYAnchor: NSLayoutConstraint?
centerYAnchor = titleLabel.centerYAnchor.constraint(equalTo: titleLabel.superview!.centerYAnchor)
centerYAnchor.isActive = true
And when you want to change the label at the top later,you can set centerYAnchor.isActive = false and set the label's topAnchor.
titleLabel.topAnchor.constraint(equalTo: titleLabel.superview!.topAnchor).isActive = true

Center label in UIView which has y offset of height of status bar

I am quite new to swift and trying to center a label and an image in a UIView which is located at the top of the screen. Currently the label is centered vertically and horizontally since this is the only thing I am able to do right now. As you can see I set autoresizing mask into constraints to false and used centerXAnchor and -YAnchor.
However I actually do not want the label to be in the center of the PostView but rather centered with a y offset of the height of the status bar. So it is centered but with no y offset of the height of the statusbar. Consequently, it looks kind of cramped(?): It is very close to the status bar... It looks like this:
But I would like to have the label (and later also an image) vertically centered in the red box:
This is the code I have right now (PostView class):
override init(frame: CGRect){
super.init(frame: frame)
//add subview containing name (and image)
infosContainerView.frame = frame
addSubview(infosContainerView)
//add sub view containing label to former UIView (infosContainerView)
infosContainerView.addSubview(infoNameView)
infoNameView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
infoNameView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
}
//this UIView shall contain the infoNameView and infoImageView
let infosContainerView: UIView = {
//set properties of controls container view
let entireInfoView = UIView()
entireInfoView.backgroundColor = .white
return entireInfoView
}()
//label and properties of label with name (autoresizingmaskinto constraint set to false)
let infoNameView: UILabel = {
//set properties of controls container view
let nameView = UILabel()
nameView.translatesAutoresizingMaskIntoConstraints = false
nameView.backgroundColor = .white
nameView.font = UIFont(name: "HelveticaNeue", size: 20)
nameView.text = "Name"
nameView.textColor = .black
nameView.textAlignment = .center
return nameView
}()
EDIT:
Jože Ws was close to solving the problem, instead of dividing by 2 one has to divide by 4 although I do not know why...:
let statusBarHeight = UIApplication.shared.statusBarFrame.height
infosContainerView.addSubview(infoNameView)
infoNameView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
infoNameView.centerYAnchor.constraint(equalTo: centerYAnchor, constant: statusBarHeight/4).isActive = true
Screenshot:
Replace centerYAnchor constraint init with
// infoNameView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
let statusBarHeight = UIApplication.shared.statusBarFrame.height
infoNameView.centerYAnchor.constraint(equalTo: centerYAnchor, constant: statusBarHeight/2).isActive = true
This will add an offset to centerYAnchor equal to the value of the statusBarHeight

Resources