CustomView UIBarButtonItem works for all phones other than iPhone 6 - ios

I created a UIBarButtonItem with a custom view using the following code (I specify the size of the profileImageButton frame to have dimensions 40x40).
let profileImageButton = UIButton(type: .custom)
profileImageButton.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
profileImageButton.setImage(imageCache.getProfileImage(), for: .normal)
profileImageButton.layer.cornerRadius = 20
profileImageButton.layer.masksToBounds = true
profileImageButton.addTarget(self, action: #selector(self.openSettings), for: .touchUpInside)
let settingsButton = UIBarButtonItem(customView: profileImageButton)
On most devices, the view has a 40x40 frame. However, when I run it on the iPhone 6s, it looks a bit rectangular. So I printed out its frame in the debug hierarchy feature of Xcode. The result I get is: frame = (0 0; 50 44), which I assume means that the frame has dimensions 50x44. Therefore, my question is why doesn't the iPhone 6s keep the specified 40x40 size?

In iOS 11, the size of a UIBarButtonItem with a custom view is determined by the internal constraints of the custom view. You have not provided any internal constraints, so all bets are off; you have not put yourself in charge of the bar button item's size. To do so, give profileImageButton a width constraint and a height constraint.

Adding onto matt's answer, I needed to also add these three lines of code for use in iOS 11:
profileImageButton.translatesAutoresizingMaskIntoConstraints = false
profileImageButton.heightAnchor.constraint(equalToConstant: 40).isActive = true
profileImageButton.widthAnchor.constraint(equalToConstant: 40).isActive = true

Related

Changing UILabel title in custom UIButton without positional change

I have a UIButton with the label on the left side and UIImageView on the right side. The button is used to open a UIPicker. When a value is picked in the picker the same value is shown in button title. When the title changes (or, more accurately, when to uilabel has a width that screws the UI up) the title and icon is moved and the UI does not look good.
When a title with too long text is used the word is clipped and when it's too short the alignment is messed up.
I've tried changing the label frame so it can be constant, whatever the text, and left aligning the text so the jumping stops. I added adjustsFontSizeToFitWidth = true which kind of works, but with a longer title the text will get too small. I've also tried recreating/rerendering the button when the title changes but all attempts fail.
lazy var sortButton = { () -> UIButton in
let btn = UIButton()
btn.addTarget(self, action: #selector(sortButtonPressed), for: .touchUpInside)
btn.setTitle(NSLocalizedString("Sortera", comment: ""), for: .normal)
btn.titleLabel?.text = btn.titleLabel?.text?.uppercased()
btn.setImage(UIImage(named: "ios-down"), for: .normal)
btn.translatesAutoresizingMaskIntoConstraints = false
btn.setTitleColor(Colors.FILTER_BUTTON_TEXT_COLOR, for: .normal)
btn.titleLabel?.adjustsFontSizeToFitWidth = true
btn.titleLabel?.font = UIFont(name: Fonts.AkzidenzGroteskProMd, size: 16)
btn.backgroundColor = Colors.BUTTON_BACKGROUND_GRAY
btn.imageView?.contentMode = .scaleAspectFit
btn.imageEdgeInsets = UIEdgeInsets(top: 16, left: (btn.titleLabel?.frame.size.width)! - buttonInsideOffset/2, bottom: 16, right: -(btn.titleLabel?.frame.size.width)! + buttonInsideOffset/2)
btn.titleEdgeInsets = UIEdgeInsets(top: 0, left: -(btn.titleLabel?.frame.size.width)! + buttonInsideOffset, bottom: 0, right: (btn.titleLabel?.frame.size.width)! - buttonInsideOffset)
return btn
}()
I want all button to like like this, whatever the title text:
However, when the text is too small it looks like this:
or when it's too long:
You can do it in many way but the simplest way :
Take a UIView and then others two-element (a label a imageView) set in this View and make it look like button then set constraint as you want. Then addTarget to label and do all functionality to that that target selector method.
If you dont want button image to be shifted to the right or left then you have to constraint independent of the button's title label
btn.imageView?.frame = CGRect(x: 0, y: 0, width: 20, height: 20) // Or any size you want
// NB: I ommited left insets intentionally
btn.imageEdgeInsets.top = 16
btn.imageEdgeInsets.bottom = 16
btn.imageEdgeInsets.right = 16
Then constraint your label dependent to the imageView position, that way only label size will change without affecting the position of image.
btn.titleEdgeInsets = UIEdgeInsets(top: 0, left: -(btn.titleLabel?.frame.size.width)! + buttonInsideOffset, bottom: 0, right: btn.imageView?.frame.width + 10)
Lastly, Since the frame is fixed size, I think you need to limit the font scaling factor to the min size you want and truncate the tail when that size is reached. If you don't want to truncate tail then you have to enable multiline titleLabel (Which I think you don't want this).
btn.titleLabel?.minimumScaleFactor = 0.5 // Or whatever minimum scale you wish
btn.titleLabel?.lineBreakMode = NSLineBreakMode.byTruncatingTail // Since button size is fixed and you want to limit font size then the best option is to truncate tail

Adjust the MenuBar under Navigation Controller

When I tried to run on different devices, the menuBar on Iphone 8 seems lower than Iphone X, how would I adjust those programmatically for every screen?
This is my code I have for the menuBar
customCollectionView = MenuBar(frame: CGRect(x: 0, y:(navigationController?.navigationBar.frame.height)!, width: view.frame.width, height: 50))
customCollectionView.translatesAutoresizingMaskIntoConstraints = true
customCollectionView.collectionView.isScrollEnabled = false
customCollectionView.collectionView.delegate = self
view.addSubview(customCollectionView)
menubarViewConstraints()
function for menuBar constraints
func menubarViewConstraints(){
customCollectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
customCollectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
customCollectionView.topAnchor.constraint(equalTo: (navigationController?.navigationBar.bottomAnchor)!).isActive = true
}
Switch form portrait mode to landscape mode:
The problem here is the safe area on the iPhone X (any potentially future iOS devices).
If you change the y position of your init frame call to be the following it should work.
y:((navigationController?.navigationBar.frame.height)!) + (navigationController?.navigationBar.frame.origin.y) + 30
Basically that will take the height of the navigation bar and add the Y origin position and finally add 30 to it.
There might be a better way to achieve this using the devices safe area, but this is the method that came to mind first that seems like it'll work.

Why do my objects get placed and sized so perfectly when I add them to a UIKitView?

So I have the following UIKit elements I am adding to my UIViewController to control the simulation that appears. I expected to have to write a lot of placement code but instead everything appears perfectly no-mater what device... my question is why?
let menuButton = UIButton()
let statusLabel = UILabel()
let segmentedLabel = UISegmentedControl(items: ["None", "Glow", "Cloud"])
func initializeUI() {
//The menu button that opens up the options for the simulations
menuButton.layer.borderColor = UIColor.lightGray.cgColor
menuButton.layer.borderWidth = 1
menuButton.layer.cornerRadius = 5
menuButton.layer.backgroundColor = UIColor.darkGray.cgColor
menuButton.showsTouchWhenHighlighted = true
menuButton.imageView?.contentMode = UIViewContentMode.scaleAspectFit
menuButton.setImage(UIImage(named: "hamburger.png"), for: UIControlState.normal)
menuButton.addTarget(self, action: #selector(menuPress), for: UIControlEvents.touchDown)
view.addSubview(menuButton)
//Will display the status of the simulation
statusLabel.text = "Particle Simulation"
statusLabel.textColor = UIColor.darkGray
view.addSubview(statusLabel)
//Will display visual options
view.addSubview(segmentedLabel)
}
The size of each of the elements is perfect and they dont overlap. The label is in the bottom left corner the button is in the bottom right and the segmented view is in the top left corner (of my landscape app).
An additional question I have is if I wanted to start placing these objects programmatically how would I do so? The elements don't have an attribute position that I can work with and if I do something like menuButton.frame.size.height *= 20 that does not make the menu button super tall.
The reason this works is that all of your UI items in your example have an “intrinsic” content size so they are able to create their own frame. Add a standard UIView the same way and you will be out of luck. Also the views are creating their own constraints based on initial frames using Auto Resizing Masks(Also known as Springs and Struts).
Finally to place items you would set the frame directly. Just math. Good luck.
Super important to understand intrinsic content size. Some frame changes might require you to turn off automatic constraints but this is usually not the case but could be the problem with your button
UIView.translatesAutoresizingMaskIntoConstraints = false

UIButton titleLabel make as a circle

Hello I want to make UIButton title label as a circle. So I did in this way.
btnAttachments.setTitle(strcount, for: .normal)
btnAttachments.setTitleColor(UIColor.white, for: .normal)
btnAttachments.titleLabel?.backgroundColor=com.getRedcolor()
btnAttachments.titleLabel?.font=UIFont.init(name: "Bariol", size: 15)
btnAttachments.titleLabel?.layer.cornerRadius=(btnAttachments.titleLabel?.frame.width)!/2
But it doesn't make it as a circle. It looks like this code doen't affect on the titleLabel
UPDATE
This is what I want to make
Please help me
Thanks
well first you have to verify that the uibutton has its clipsToBounds true, but incase that s already set and the problem still there, then you probably trying to achieve this in the viewDidLoad which "should" work, but for some reason in some of the xcode 8 versions in the viewDidLoad the layout are still aint final (objects doesnt have their true dimensions set yet) you can verify this by logging the uibutton frame right before you assign the corner radius if you find some incoherent that this is probably the issue , incase this is the issue then you just need to move your code to viewWillAppear
You are missing to set MasToBounds
btnAttachments.titleLabel?.layer.masksToBounds = true;
add this you code will work fine ,
You should set corner redius in viewDidLayoutSubViews or drawRect(usually in UIView class)
i hope this will help u
Use the following code to get desired result:
let btnAttachments = UIButton(type: .custom)
btnAttachments.setTitle(strcount, for: .normal).setTitleColor(UIColor.white, for: .normal)
btnAttachments.frame = CGRect(x: 160, y: 100, width: 50, height: 50)
btnAttachments.titleLabel?.backgroundColor=com.getRedcolor()
btnAttachments.titleLabel?.font=UIFont.init(name: "Bariol", size: 15)
btnAttachments.layer.cornerRadius = 0.5 * button.bounds.size.width
btnAttachments.clipsToBounds = true

How to remove right padding/margin/space from a custom bar button item which has an image?

I've been trying to find a solution to this problem for the past two days and still nothing I have tried works for me. Some solutions I have tried either stretch or completely mess up my custom image but nothing removes the right padding. Here is my code below as well as the result. Notice how the right bar button has a bigger space than the left system one.
var saveButton: UIButton = UIButton(frame: CGRectMake(0, 0, 32, 32))
saveButton.addTarget(self, action: "saveAction:", forControlEvents: .TouchUpInside)
let img = UIImage(named: "save")
saveButton.setBackgroundImage(img, forState: .Normal)
var saveBarButton: UIBarButtonItem = UIBarButtonItem(customView: saveButton)
self.navigationItem.setRightBarButtonItem(saveBarButton, animated: false)
Alright guys, I've found a solution that works pretty well for me. Instead of creating and setting the bar button item in code I added one in storyboard and set it's left margin in size inspector to -6 (or whatever value you like) and it's right margin to 6 (again whatever value you prefer note that the two values must be the same values but one is positive and the other is negative). Then I set it's image to the image I desired in the attributes inspector. If for some reason you want to change the image in code you can do so like this:
barButtonOutlet.image = UIIMage(named: "yourImage") as UIImage?
Hope this helps some of you out.
This is my solution. Try..
rightBtn.imageInsets = UIEdgeInsets(top: 0, left: -13.0, bottom: 0, right: 13.0)
self.navigationItem.rightBarButtonItem = rightBtn

Resources