I am creating a simple app which set image as circle by calculate with frame of image.
Here is I declare image variable:
lazy var imageUserDetailProfileView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.layer.borderWidth = 1
imageView.image = UIImage(named: "profile-icon")
imageView.layer.borderColor = UIColor(red:0.00, green:0.50, blue:0.00, alpha:1.0).cgColor
imageView.clipsToBounds = true
return imageView
}()
Here is i made that frame width and height of image became circle
imageUserDetailProfileView.frame = CGRect(x: view.frame.midX, y: 20,width: 100, height: 100)
imageUserDetailProfileView.layer.cornerRadius = imageUserDetailProfileView.frame.height/2
Now i want image should stay in middle of screen like using NSLayoutConstraint which has method centerXAnchor.
How to solve this problem?
let midX = view.frame.size.width / 2
let midY = view.frame.size.height / 2
Try This Code.
Custom Method For Image Set In Center Of Any View. Just Call Method And Pass Image & View. Customize according to Use. Swift 4
func setImageInCenterOfView(image:UIImage,view:UIView) {
let imageWidth:CGFloat = 100
let myImageView = UIImageView.init(frame: CGRect.init(x: (view.frame.size.width/2)-imageWidth/2, y: (view.frame.size.height/2)-imageWidth/2, width: imageWidth, height: imageWidth))
myImageView.clipsToBounds = true
myImageView.layer.cornerRadius = myImageView.frame.size.height/2
myImageView.image = image
view.addSubview(myImageView)
view.layoutIfNeeded()
}
I currently have in image in a nav bar but it's overlapping the edge:
Here is the code I use in viewDidLoad:
let logo = UIImage(named: "holy-grail-pub-logo-header-logo")
let imageView = UIImageView(image:logo)
imageView.contentMode = .ScaleAspectFit
self.navigationItem.titleView = imageView
I've tried setting the position manually using CGRECT but it wasn't changing anything:
let imageView = UIImageView(frame: CGRect(x: 0, y: -30, width: 100, height: 60))
imageView.contentMode = .ScaleAspectFit
let logo = UIImage(named: "holy-grail-pub-logo-header-logo")
imageView.image = logo
self.navigationItem.titleView = imageView
Any help will be appreciated!
Basically I hope you need to adjust the edgeInsets for your imageView which we cannot do directly on UIImageView as of now.
Using the method given here:
I did convert it to Swift(for your ref):
extension UIImage {
class func imageWith(image: UIImage, scaledToSize: CGSize) -> UIImage {
//UIGraphicsBeginImageContext(newSize);
// In next line, pass 0.0 to use the current device's pixel scaling factor (and thus account for Retina resolution).
// Pass 1.0 to force exact pixel size.
UIGraphicsBeginImageContextWithOptions(scaledToSize, false, 0.0)
image.drawInRect(CGRectMake(0, 0, scaledToSize.width, scaledToSize.height))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
}
Using above method:
let image = UIImage.imageWith(UIImage(named: "holy-grail-pub-logo-header-logo")!, scaledToSize: CGSizeMake(80,80))
let imageView = UIImageView()
imageView.frame = CGRectMake(0, 0, 100, 100)
imageView.contentMode = .ScaleAspectFit
imageView.image = image
Now your insets become 100-80 i.e. 20. I guess this workaround would help you fixing your issue. Try this and let us know if it works.
I am setting up a UIImageView as a leftView on a UITextField like so:
UIImageView *envelopeView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.height*.1, self.height*.1)];
envelopeView.image = [UIImage imageNamed:#"envelope.png"];
envelopeView.contentMode = UIViewContentModeScaleAspectFit;
envelopeView.bounds = CGRectInset(envelopeView.frame, 15, 10);
self.emailAddress.leftView = envelopeView;
self.emailAddress.leftViewMode = UITextFieldViewModeAlways;
which gets me the following:
As you can see the left size of the image goes right up to the left edge of the button even though I tried to set an inset. How can I move this envelope in so that it's got padding on all sides?
Update: I tried the proposed answer of changing the UIImageView frame like so, but the envelope is still lined up on the left side at the border of the UITextField:
CGFloat padding = 20;
UIImageView *envelopeView = [[UIImageView alloc] initWithFrame:CGRectMake(3*padding, padding, self.height*.1-padding, self.height*.1-padding)];
For Swift 3 Users
Here is what worked for me:
extension UITextField {
/// set icon of 20x20 with left padding of 8px
func setLeftIcon(_ icon: UIImage) {
let padding = 8
let size = 20
let outerView = UIView(frame: CGRect(x: 0, y: 0, width: size+padding, height: size) )
let iconView = UIImageView(frame: CGRect(x: padding, y: 0, width: size, height: size))
iconView.image = icon
outerView.addSubview(iconView)
leftView = outerView
leftViewMode = .always
}
}
test:
txOrigin.setLeftIcon(icon_location)
result:
For Swift 4.2 +
You can use this extension:
extension UITextField {
func leftImage(_ image: UIImage?, imageWidth: CGFloat, padding: CGFloat) {
let imageView = UIImageView(image: image)
imageView.frame = CGRect(x: padding, y: 0, width: imageWidth, height: frame.height)
imageView.contentMode = .center
let containerView = UIView(frame: CGRect(x: 0, y: 0, width: imageWidth + 2 * padding, height: frame.height))
containerView.addSubview(imageView)
leftView = containerView
leftViewMode = .always
}
}
you can simply try this:
UIImageView *envelopeView = [[UIImageView alloc] initWithFrame:CGRectMake(20, 0, 30, 30)];
envelopeView.image = [UIImage imageNamed:#"comment-128.png"];
envelopeView.contentMode = UIViewContentModeScaleAspectFit;
UIView *test= [[UIView alloc]initWithFrame:CGRectMake(20, 0, 30, 30)];
[test addSubview:envelopeView];
[self.textField.leftView setFrame:envelopeView.frame];
self.textField.leftView =test;
self.textField.leftViewMode = UITextFieldViewModeAlways;
You can use this. Change your frame according to your need.
NSTextAttachment* placeholderImageTextAttachment = [[NSTextAttachment alloc] init];
placeholderImageTextAttachment.image = [UIImage imageNamed:#"Search"];
placeholderImageTextAttachment.bounds = CGRectMake(0, -2, 16, 16);
NSMutableAttributedString* placeholderImageString = [[NSAttributedString attributedStringWithAttachment:placeholderImageTextAttachment] mutableCopy];
NSMutableAttributedString* placeholderString = [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(#" Search", nil)];
[placeholderImageString appendAttributedString:placeholderString];
_txtFieldSearch.attributedPlaceholder = placeholderImageString;
_txtFieldSearch.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
Tweetbot and Kickstarter for iOS uses a cool feature on user profiles that have a banner image. If you pull down on the tableView the image zooms.
I have it partially working using the following, it changes the height of the image, but strangely, not the width:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
UIImageView *imageView = (UIImageView *)self.tableView.tableHeaderView;
CGFloat y = -scrollView.contentOffset.y;
imageView.frame = CGRectMake(0, scrollView.contentOffset.y, self.cachedImageViewSize.size.width+y, self.cachedImageViewSize.size.height+y);
NSLog(#"%#", NSStringFromCGRect(imageView.frame));
}
Does anyone know how to recreate this effect?
Ok, I figured it out. Here is what I did:
- (void)viewDidLoad {
[super viewDidLoad];
self.imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"church-welcome.png"]];
self.imageView.contentMode = UIViewContentModeScaleAspectFill;
self.cachedImageViewSize = self.imageView.frame;
[self.tableView addSubview:self.imageView];
[self.tableView sendSubviewToBack:self.imageView];
self.tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 170)];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat y = -scrollView.contentOffset.y;
if (y > 0) {
self.imageView.frame = CGRectMake(0, scrollView.contentOffset.y, self.cachedImageViewSize.size.width+y, self.cachedImageViewSize.size.height+y);
self.imageView.center = CGPointMake(self.view.center.x, self.imageView.center.y);
}
}
The above answer for Swift:
Variable Decelerations:
var imageView: UIImageView!
var cachedImageViewSize: CGRect!
viewDidLoad:
var imageView: UIImageView!
var cachedImageViewSize: CGRect!
override func viewDidLoad() {
super.viewDidLoad()
self.imageView = UIImageView(image: UIImage(named: "image-plane"))
imageView.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 170)
self.imageView.contentMode = .ScaleAspectFill
self.cachedImageViewSize = self.imageView.frame
self.tableView.addSubview(self.imageView)
self.imageView.center = CGPointMake(self.view.center.x, self.imageView.center.y)
self.tableView.sendSubviewToBack(self.imageView)
self.tableView.tableHeaderView = UIView(frame: CGRectMake(0, 0, self.view.frame.size.width, 170))
}
scrollViewDidScroll:
override func scrollViewDidScroll(scrollView: UIScrollView) {
let y: CGFloat = -scrollView.contentOffset.y
if y > 0 {
self.imageView.frame = CGRectMake(0, scrollView.contentOffset.y, self.cachedImageViewSize.size.width + y, self.cachedImageViewSize.size.height + y)
self.imageView.center = CGPointMake(self.view.center.x, self.imageView.center.y)
}
}
Swift 3.0 version of Nic Hubbard's answer:
override func viewDidLoad() {
self.imageView = UIImageView(image: UIImage(named: "header-image"))
imageView.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 170)
self.imageView.contentMode = .scaleAspectFill
self.cachedImageViewSize = self.imageView.frame
self.tableView.addSubview(self.imageView)
self.imageView.center = CGPoint(x: self.view.center.x, y:self.imageView.center.y)
self.tableView.sendSubview(toBack: self.imageView)
self.tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 170))
}
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
let y: CGFloat = -scrollView.contentOffset.y
if y > 0 {
self.imageView.frame = CGRect(x: 0, y: scrollView.contentOffset.y, width: self.cachedImageViewSize.size.width + y, height: self.cachedImageViewSize.size.height + y)
self.imageView.center = CGPoint(x: self.view.center.x, y: self.imageView.center.y)
}
}
I think it's simply resize the image view to fit the vertial space, while keeping the same aspect ratio.
Swift 2 version of Nic Hubbard's answer:
var imageView: UIImageView!
var cachedImageViewSize: CGRect!
override func viewDidLoad(){
super.viewDidLoad()
self.imageView = UIImageView(image: UIImage(named: "church-welcome.png"))
self.imageView.contentMode = .ScaleAspectFill
self.cachedImageViewSize = self.imageView.frame
self.tableView.addSubview(self.imageView)
self.tableView.sendSubviewToBack(self.imageView)
self.tableView.tableHeaderView = UIView(frame: CGRectMake(0, 0, self.view.frame.size.width, 170))
}
func scrollViewDidScroll(scrollView: UIScrollView) {
var y: CGFloat = -scrollView.contentOffset.y
if y > 0 {
self.imageView.frame = CGRectMake(0, scrollView.contentOffset.y, self.cachedImageViewSize.size.width + y, self.cachedImageViewSize.size.height + y)
self.imageView.center = CGPointMake(self.view.center.x, self.imageView.center.y)
}
}
The above mentioned solutions will actually not really provide the exact implementation of how it is in Tweetbot or Tinder [target's profile picture zooming].
I also had to solve this problem and the most perfect implementation I found is to use 2 main elements:
1) Tableview which has content inset
2) Imageview on top of that table view which has an outlet for top constraint and height constraint and which is on top of that empty space provided by the tableview content inset.
So first make sure to set the insets for the tableView and initial height constraint for the imageView. You can do this in viewDidLoad for example.
imageViewHeightConstraint.constant = view.frame.height * 0.3
tableView.contentInset = UIEdgeInsets(top: view.frame.height * 0.3, left: 0, bottom: 0, right: 0)
Then just listen to thew scrollViewDidScroll delegate method and modify the constraints accordingly.
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let contentOffset = scrollView.contentOffset.y
if -contentOffset >= view.frame.height * 0.3 {
//reset the top constraint
topConstraint.constant = 0
//make the imageview bigger by the additional content offset value
imageViewHeightConstraint.constant = -contentOffset
} else {
topConstraint.constant = -(view.frame.height * 0.3 + contentOffset)
}
}
You may need to inverse the signs according to how you've set your own constraints. And probably there's a way to optimize and not modify the constraints that often, but you get the idea.
Please also note that you need to:
imageView.contentMode = .scaleAspectFill
layer.masksToBounds = true
Otherwise the image will be drawn on top of your first tableView cells [dependent on the image size it may come to cover to whole table view] because it is drawn outside its "bounds".
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.