titleEdgeInsets for UIButton make no sense - ios

I have an image and a title for a UIButton. I'm trying to get my image (15px in width) to be aligned left and my title to be aligned 5px left of that:
The button is 215 in width, but I had to set my titleEdgeInset right to -44. This doesn't make sense. What are the maths to get -44?

It's because the image and title of a button are centered together by default.
For example, here's a 300px wide button with an image and text, no insets:
Looks like I need the button contents shifted left by 60 pts, so -60 left inset and 60 right inset.
button.imageEdgeInsets = UIEdgeInsetsMake(0.0, -60.0, 0.0, 60.0)
button.titleEdgeInsets = UIEdgeInsetsMake(0.0, -60.0, 0.0, 60.0)
Edit:
These insets would also work for the above example.
button.imageEdgeInsets = UIEdgeInsetsMake(0.0, -120.0, 0.0, 0.0)
button.titleEdgeInsets = UIEdgeInsetsMake(0.0, -120.0, 0.0, 0.0)
The button is centering its contents, so if you say "there are 2 more pts on the left" the button will move its contents over by 1 pt to keep them centered.
The rule is
-leftInset+rightInset=leftMargin*2

UIButton is centered by default like the other answers stated, but you can change that to achieve a more intuitive inset behaviour.
Select left alignment in the attributes inspector.
Then set insets like this:
button.imageEdgeInsets = UIEdgeInsets.zero
button.titleEdgeInsets = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 0)

It's easy to do:
In swift:
let button: UIButton = UIButton(frame: CGRect(x: 44, y: 64, width: 100, height: 40))
button.backgroundColor = UIColor.clear
button.setImage(UIImage(named: "img"), for: .normal)
button.setTitle("hello", for: .normal)
button.layer.borderWidth = 1
button.layer.borderColor = UIColor.blue.cgColor
button.layer.cornerRadius = 4
// set edge inset
button.imageEdgeInsets = UIEdgeInsets(top: 0, left: -40, bottom: 0, right: 0)
button.titleEdgeInsets = UIEdgeInsets(top: 0, left: -20, bottom: 0, right: 0)
view.addSubview(button)
In objective-c:
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(44, 64, 100, 40);
button.backgroundColor = [UIColor clearColor];
[button setImage:[UIImage imageNamed:#"img"] forState:UIControlStateNormal];
[button setTitle:#"hello" forState:UIControlStateNormal];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
button.layer.cornerRadius = 4;
button.layer.borderColor = [UIColor blueColor].CGColor;
button.layer.borderWidth = 1;
// set edge inset
button.imageEdgeInsets = UIEdgeInsetsMake(0, -40, 0, 0);
button.titleEdgeInsets = UIEdgeInsetsMake(0, -20, 0, 0);
[self.view addSubview:button];
[![The result][1]][1]
[1]: https://i.stack.imgur.com/FyzqB.png

Related

CALayer's contentsCenter not working in swift

I want to increase an image button's touch area, and as I searched, I found a way to use contentsCenter property of CALayer.
https://developer.apple.com/documentation/quartzcore/calayer/1410740-contentscenter
The example of the document above shows an image centered inside the layer that can be resized as the size of layer changes, while maintaining the ratio defined in contentsCenter property.
But when I used contentsCenter property, it just stretches the image's center - (0.5, 0.5).
So I added contentsGravity property to .center, but it results in contentsCenter property not working.
button.frame = CGRect(x: 0, y: 0, width: 300, height: 300)
button.center = view.center
button.backgroundColor = .clear
let image = UIImage(named: "profileImage")
button.layer.contents = image?.cgImage
button.layer.contentsCenter = CGRect(x: 0.25, y: 0.25, width: 0.5, height: 0.5)
button.layer.contentsGravity = .center
//button.layer.contentsScale = image?.scale
button.layer.borderColor = UIColor.black.cgColor
button.layer.borderWidth = 2
button.layer.cornerRadius = 5
button.layer.masksToBounds = true
How can I make the image center inside a button with insets maintaining ratio?
You can increase the UIButton Size using the below Code
button.contentEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)

How to increase the UIButton Image size in Swift3?

I am using the default UIImage property of the UIButton to set the back image . I have successfully done it but it seems that the image is appearing small. How to increase the size of the image in UIButton?
let viewForNavigation = UIView(frame: CGRect(x: 0, y: 0, width: 320, height: 40))
viewForNavigation.backgroundColor = UIColor.clear
let backbutton = UIButton(frame: CGRect(x: 0, y: 8, width: 320, height: 20))
backbutton.setImage(UIImage(named: "back_button"), for: UIControlState.normal)
backbutton.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right:10)
backbutton.contentHorizontalAlignment = .left
backbutton.titleEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 0)
backbutton.titleLabel!.font = UIFont().robotoMedium(withFontSize: 20)
backbutton.setTitle(title, for: .normal)
backbutton.setTitleColor(UIColor.black, for: UIControlState.normal)
backbutton.addTarget(self, action: #selector(exitViewController), for: UIControlEvents.touchUpInside)
viewForNavigation.addSubview(backbutton)
let rightBarButton = UIBarButtonItem(customView: viewForNavigation)
self.navigationItem.leftBarButtonItem = rightBarButton
I think you have choose wrong size back button image, please use below image for back button:
Output

How to change the selection area of a UIBarButtonItem?

I'm trying to change the selection area of a UIBarButtonItem within the navigation controller. Basically I'm trying to change the allowable area that will make that UIBarButtonItem selectable. Right now, the size of my UIBarButtonItem is 40x40, but I can easily select it even if my finger is not touching the button at all.
Here's to illustrate what I mean:
The green represents the size of the UIBarButtonItem. The red represents the allowable area that makes the UIBarButtonItem selectable.
How can I change the width of the red area?
Here's a snippet of code if helpful:
changeMuscleMap = UIButton(frame: CGRect(x: 0, y: 0, width: 40, height: 40) )
changeMuscleMap.setImage(UIImage(named: "change"), forState: .Normal)
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: changeMuscleMap)
Thanks!
If you want larger click area than required, try the below code, then making a UIBarButtonItem With custom button:
#implementation CustomButton
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event
{
UIEdgeInsets extendTouchInsets = UIEdgeInsetsMake(20, 0, 20, 0);
CGRect bounds = self.bounds;
bounds.origin.x -= extendTouchInsets.left;
bounds.origin.y -= extendTouchInsets.top;
bounds.size.width += extendTouchInsets.left + extendTouchInsets.right;
bounds.size.height += extendTouchInsets.top + extendTouchInsets.bottom;
return CGRectContainsPoint(bounds, point);
}
#end
You can use the following code to increase or decrease UIBarButtonItem button width.
changeMuscleMap = UIButton(frame: CGRect(x: 0, y: 0, width: 120, height: 40) )
changeMuscleMap.setImage(UIImage(named: "change"), forState: .Normal)
changeMuscleMap.contentHorizontalAlignment = .left
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: changeMuscleMap)
It can be achieved by making a UIBarButtonItem with custom item as UIImageView instead of UIButton. Try the below code. I hope this will solve it now.
changeMuscleMap = UIImageView(image:UIImage(named: "change"))
imageView.frame = CGRectMake(0, 0, 40, 40)
let leftBarBtn = UIBarButtonItem(customView: imageView)
self.navigationItem.leftBarButtonItem = leftBarBtn
I was able to achieve what I wanted by using #Damien Romito's provided answer here:
UINavigationBar UIBarButtonItems much larger click area than required
Updated for Swift 3.0:
let buttonContainer: UIView = UIView(frame: CGRect(x: 0, y: 0, width: 27, height: 30) )
let barButton: UIButton = UIButton(frame: CGRect(x: 0, y: 0, width: 30, height: 30) )
buttonContainer.addSubview(barButton)
barButton = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
barButton(#imageLiteral(resourceName: "image"), for: UIControlState.normal)
self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: buttonContainer)
barButton(self, action: #selector(ViewController.doSomething), for: UIControlEvents.touchUpInside)

How to remove specific border on an UIButton and an UIView?

I have an UIButton and an UIView where i want to remove bottom border for the button and top border for the view. The image below show an UIButton. When I press this UIButton the UIView will be added as subview (like a dropdown menu), But I want the button and the view merge with each other so it will look like on "box".
I know how to set border width and color:
self.layer.borderWidth = 1
self.layer.borderColor = UIColor(CGColor: "#616366".CGColor).CGColor
But I don't know if it is possible to remove on border line. Hope you guys can help - Thank you
The easiest way is going to be to change your layout a little bit so that rather than adding the UIView as a subview of the UIButton you add them both as siblings to a container view, and draw the border on the container view.
Kind of like this:
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 44))
button.setTitle("Button", forState: .Normal)
button.titleLabel?.textColor = UIColor.blackColor()
let container = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 44))
container.addSubview(button)
container.frame = button.frame
container.backgroundColor = UIColor.whiteColor()
container.layer.borderWidth = 5
container.layer.borderColor = UIColor.blackColor().CGColor
let added = UIView(frame:CGRect(x: 0, y: 44, width: 100, height: 200))
added.backgroundColor = UIColor.blueColor()
container.addSubview(added)
container.frame.size.height += added.frame.size.height
XCPlaygroundPage.currentPage.liveView = container

How to adjust an UIButton's imageSize?

How can I adjust the image size of the UIButton? I am setting the image like this:
[myLikesButton setImage:[UIImage imageNamed:#"icon-heart.png"] forState:UIControlStateNormal];
However this fills up the image to the full button, how do I make the image smaller?
Historic note:
For this now 10+ yr old question, you now typically just set the point size using setPreferredSymbolConfiguration
If I understand correctly what you're trying to do, you need to play with the buttons image edge inset. Something like:
myLikesButton.imageEdgeInsets = UIEdgeInsets(top: 30, left: 30, bottom: 30, right: 30)
Tim's answer is correct, however I wanted to add another suggestion, because in my case there was a simpler solution altogether.
I was looking to set the UIButton image insets because I didn't realize that I could set the content mode on the button's UIImageView, which would have prevented the need to use UIEdgeInsets and hard-coded values altogether. Simply access the underlying imageview on the button and set the content mode:
myButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
See UIButton doesn't listen to content mode setting?
Swift 3
myButton.imageView?.contentMode = .scaleAspectFit
Swift 3:
button.setImage(UIImage(named: "checkmark_white"), for: .normal)
button.contentVerticalAlignment = .fill
button.contentHorizontalAlignment = .fill
button.imageEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10)
Here is the other solution to scale an imageView of UIButton.
button.imageView?.layer.transform = CATransform3DMakeScale(0.8, 0.8, 0.8)
You can also do that from inteface builder like this.
I think it's helpful.
If your image is too large (and you can't/don't want to just made the image smaller), a combination of the first two answers works great.
addButton.imageView?.contentMode = .scaleAspectFit
addButton.imageEdgeInsets = UIEdgeInsetsMake(15.0, 15.0, 15.0, 5.0)
Unless you get the image insets just right, the image will be skewed without changing the contentMode.
you can use imageEdgeInsets property
The inset or outset margins for the rectangle around the button’s image.
[self.btn setImageEdgeInsets:UIEdgeInsetsMake(6, 6, 6, 6)];
A positive value shrinks, or insets, that edge—moving. A negative value expands, or outsets, that edge.
Heres the Swift version:
myButton.imageEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
Swift 4
You would need to use these two lines of code, in this specific order. All you need is to change the top and bottom value of the edge insets.
addButton.imageView?.contentMode = .scaleAspectFit
addButton.imageEdgeInsets = UIEdgeInsetsMake(10.0, 0.0, 10.0, 0.0)
Insetting the image works for me, but I also needed the button Type to be Custom and the button Style to be Default. The defaults for a button added in Xcode 13 are System for Type and Plain for Style.
self.imageEdgeInsets = UIEdgeInsets(top: 3.0, left: 3.0, bottom: 3.0, right: 3.0)
If you are using symbolic images for the button, then this solution is better:
button.setPreferredSymbolConfiguration(UIImage.SymbolConfiguration(pointSize: 48), forImageIn: .normal)
With the help of Tim C's answer, I was able to create an extension on UIButton using Swift that allows you to specify the image frame by using the .setImage() function with an extra frame parameter
extension UIButton{
func setImage(image: UIImage?, inFrame frame: CGRect?, forState state: UIControlState){
self.setImage(image, forState: state)
if let frame = frame{
self.imageEdgeInsets = UIEdgeInsets(
top: frame.minY - self.frame.minY,
left: frame.minX - self.frame.minX,
bottom: self.frame.maxY - frame.maxY,
right: self.frame.maxX - frame.maxX
)
}
}
}
Using this, if you wanted to set the frame of a UIButton to CGRectMake(0, 0, 64, 64), and set the image of it to myImage with a frame of CGRectMake(8, 8, 48, 48), you could use
let button: UIButton = UIButton(frame: CGRectMake(0, 0, 64, 64))
button.setImage(
myImage,
inFrame: CGRectMake(8, 8, 48, 48),
forState: UIControlState.Normal
)
When changing icon size with
UIEdgeInsetsMake(top, left, bottom, right), keep in mind button dimensions and the ability of UIEdgeInsetsMake to work with negative values as if they are positive.
Example: Two buttons with height 100 and aspect 1:1.
left.imageEdgeInsets = UIEdgeInsetsMake(40, 0, 40, 0)
right.imageEdgeInsets = UIEdgeInsetsMake(40, 0, 40, 0)
left.imageEdgeInsets = UIEdgeInsetsMake(40, 0, 40, 0)
right.imageEdgeInsets = UIEdgeInsetsMake(45, 0, 45, 0)
left.imageEdgeInsets = UIEdgeInsetsMake(40, 0, 40, 0)
right.imageEdgeInsets = UIEdgeInsetsMake(60, 0, 60, 0)
Examples 1 and 3 are identical since ABS(100 - (40 + 40)) = ABS(100 - (60 + 60))
Updated for Swift > 5
set the size:
button.frame = CGRect(x: 0, y: 0, width: 44, height: 44)
set margins:
button.imageEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
One approach is to resize the UIImage in code like the following. Note: this code only scales by height, but you can easily adjust the function to scale by width as well.
let targetHeight = CGFloat(28)
let newImage = resizeImage(image: UIImage(named: "Image.png")!, targetHeight: targetHeight)
button.setImage(newImage, for: .normal)
fileprivate func resizeImage(image: UIImage, targetHeight: CGFloat) -> UIImage {
// Get current image size
let size = image.size
// Compute scaled, new size
let heightRatio = targetHeight / size.height
let newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
// Create new image
UIGraphicsBeginImageContextWithOptions(newSize, false, 0)
image.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
// Return new image
return newImage!
}
Swift 3
I set myButton width and height to 40 and my padding from EdgeInsetsMake is 15 all sides. I suggest to add a background color to your button to see the actual padding.
myButton.backgroundColor = UIColor.gray // sample color to check padding
myButton.imageView?.contentMode = .scaleAspectFit
myButton.imageEdgeInsets = UIEdgeInsetsMake(15, 15, 15, 15)
Updated for Swift 3
yourButtonName.imageEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10)
If you don't want to play around with image insets and you are using auto layout (which I assume you do), another solution is to add size constraints to the image view. Make sure the constraints have a priority of 999, otherwise auto layout will complain.
guard let imageView = button.imageView else { return }
let size = CGSize(width: 20, height: 20)
let sizeConstraints = [
imageView.widthAnchor.constraint(equalToConstant: size.width),
imageView.heightAnchor.constraint(equalToConstant: size.height)
]
imageView.translatesAutoresizingMaskIntoConstraints = false
sizeConstraints.forEach { $0.priority = UILayoutPriority(rawValue: priority) }
NSLayoutConstraint.activate(sizeConstraints)
imageView.contentMode = .scaleAspectFit
i think, your image size is also same as button size then you put image in background of the button like :
[myLikesButton setBackgroundImage:[UIImage imageNamed:#"icon-heart.png"] forState:UIControlStateNormal];
you mast have same size of image and button.i hope you understand my point.

Resources