I am trying to add a button to a screen and edit it programmatically, but most of the edits don't respond.
This is the button code:
#IBOutlet weak var buttonTest: UIButton!
let screen = UIScreen.mainScreen().bounds
let buttonImg = ResizeImage(UIImage(named: "Blokker")!, targetSize: CGSize(width: 50, height: 50))
buttonTest.frame = CGRect(x: 0, y: screen.height - 300, width: screen.width * 0.5, height: screen.width * 0.5)
buttonTest.setImage(buttonImg, forState: .Normal)
buttonTest.setTitle("Test", forState: .Normal)
buttonTest.imageView?.contentMode = .ScaleAspectFit
view.addSubview(buttonTest)
The ResizeImage function works, i've used it in other view controllers already. The code for this is quoted below. The buttonTest.frame method doesn't work, the button will always stay in the same place without edits to the size. The image doesn't load either, in the place where the image should be, I can only see a blue square.
Does anyone know how to solve this problem? Thanks in advance!
The ResizeImage func:
func ResizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
let size = image.size
let widthRatio = targetSize.width / image.size.width
let heightRatio = targetSize.height / image.size.height
// Figure out what our orientation is, and use that to form the rectangle
var newSize: CGSize
if(widthRatio > heightRatio) {
newSize = CGSizeMake(size.width * heightRatio, size.height * heightRatio)
} else {
newSize = CGSizeMake(size.width * widthRatio, size.height * widthRatio)
}
// This is the rect that we've calculated out and this is what is actually used below
let rect = CGRectMake(0, 0, newSize.width, newSize.height)
// Actually do the resizing to the rect using the ImageContext stuff
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
image.drawInRect(rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
The first part of your question I already answered in comment
Use imageView.imageRenderingMode = .AlwaysOriginal if you want the image to be the same as the source
and imageView.imageRenderingMode = .AlwaysTemplate if you want the image to be the same color as its container (images with no alpha channel will be a colored square)
For the frame problem, why are you the following line? Remove it.
view.addSubview(buttonTest)
Buttontest already has a superview as it's an outlet from storyboard/xib. Also, do not change frame rect if you're designing the button using storyboard/xib. You should learn how to use constraints for this.
Using FruitAddict's comment:
let buttonImg = ResizeImage(UIImage(named: "Blokker")!, targetSize: CGSize(width: 50, height: 50)).imageWithRenderingMode(.AlwaysOriginal)
solved the image problem, for people who experience the same problem!
The frame problem hasn't changed so far..
according to me please use SDWebImage ThirdParty library please follow below link:-
https://github.com/rs/SDWebImage
or you can also install through pod also and use this library....
i show you below code using swift language:-
let imageurl: NSURL? = NSURL(string: "")
imageview1.sd_setImageWithURL(url, placeholderImage:UIImage(named:"Ahmedabad_BRTS.jpg"))
Related
I have an issue with an imageOutlet on a view controller (First picture), it seems that it's constraints issue. I thought I have not set up properly the constraint on the GoalsVC, but after multiple verifications I noticed I am using the same constraints as the second picture (assistVC) scene.
I even deleted the goalsVC scene and copied the assistVC scene in order to make sure I have the same constraints and just hooked up the Goal swift file and each outlets again. Thought it maybe an issue with the View content Mode, but nope.
However the result is still different between them. Any ideas or suggestions.
I was able to fixed it by resizing the image:
extension UIImage {
func resize(_ width: CGFloat, _ height:CGFloat) -> UIImage? {
let widthRatio = width / size.width
let heightRatio = height / size.height
let ratio = widthRatio > heightRatio ? heightRatio : widthRatio
let newSize = CGSize(width: size.width * ratio, height: size.height * ratio)
let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
self.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
}
I'm developing an app that displays, in the main ViewController, the user's profile image inside a round UIBarButtonItem, so I'm using a custom Button with cornerRadius and clipsToBounds enabled, I am resizing the UIImage's width to 75% of NavigationBar's height to fit well in it, I also used button.imageView?.contentMode = .scaleAspectFill
When I use a squared image(width = height) it works perfect, but if I use a portrait or landscape image it looks like if BarButton was using .scaleAspectFit
I already tried to create first a squared UIImage cropping original profile image without any luck.
This is my Bar button code:
func setProfileButton() {
let width = self.navigationController!.navigationBar.frame.size.height * 0.75
if let image = ResizeImage(CFUser.current!.getProfileImage(), to: width) {
let button = UIButton(type: .custom)
button.setImage(image, for: .normal)
button.imageView?.contentMode = .scaleAspectFill
button.addTarget(self, action: #selector(goProfile), for: .touchUpInside)
button.frame = CGRect(x: 0, y: 0, width: width, height: width)
button.layer.cornerRadius = button.bounds.width / 2
button.clipsToBounds = true
let barButton = UIBarButtonItem(customView: button)
self.navigationItem.rightBarButtonItem = barButton
}
}
This is ResizeImage code:
func ResizeImage(_ image: UIImage, to width: CGFloat) -> UIImage? {
let size = image.size
let ratio = width / image.size.width
let height = image.size.height * ratio
let targetSize = CGSize(width: width, height: height)
let widthRatio = targetSize.width / image.size.width
let heightRatio = targetSize.height / image.size.height
var newSize: CGSize
if(widthRatio > heightRatio) {
newSize = CGSize(width: size.width * heightRatio,height: size.height * heightRatio)
} else {
newSize = CGSize(width: size.width * widthRatio, height: size.height * widthRatio)
}
let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
image.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
Here is the app working with squared image
And this is with a portrait image
Thanks for your help! :)
PD: I'm using Xcode 10 and Swift 4
As the portrait image has different dimensions unlike square image, calculate the minimum dimension and modify the image size accordingly.
Replace method ResizeImage(_ image: UIImage, to width: CGFloat) -> UIImage? with below.
func ResizeImage(_ image: UIImage, to width: CGFloat) -> UIImage? {
let ratio = width / image.size.width
let height = image.size.height * ratio
let dimension = min(width, height)
let targetSize = CGSize(width: dimension, height: dimension)
let rect = CGRect(x: 0, y: 0, width: targetSize.width, height: targetSize.height)
UIGraphicsBeginImageContextWithOptions(targetSize, false, 1.0)
image.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
Square image:
Portrait image:
I had I previuosly question here How to make full screen background image inside ScrollView and keep aspect ratio and get very good aswer from "ekscrypto", thank you again.
I have buttons with text on the image (1, 2, 3, 4, 5 etc.) previously i used hard coded X and Y coordinates to position UI elemnts (buttons) on the background image, this solution worked on all iPhone devices, not on iPads.
I changed my code according to the solution I received from "ekscrypto", and now of course this solution not work on any device.
On the image there is a road, and I need to arrange these buttons on this road. How can I properly position this buttons relative to the image, regardless of the device and image scale?
P.S. Ekscrypto also provided solution for the UI element positioning, but I don't understand how it works.
Here's how I currently attempt to create the buttons:
let imageOne = UIImage(named: "level1") as UIImage?
let levelOne = UIButton(type: UIButtonType.system)
levelOne.frame = CGRect.init(x: 10, y: 10, width: 100, height: 45)
levelOne.setImage(imageOne, for: .normal)
scrollView.addSubview(levelOne)
But the iPhone and iPad button positions and sizes should be different. How can I have them placed properly relative to the image?
Thank you so much ekscrypto, and sorry for delay with answer. Your code is working, and solves my problem, but there is a small problems.
Had to change this line let button = UIButton(type: .system) to .custom, or instead of background image you get button that is filled with blue color.
Button with background image is too big, specially on iPhone 5, changed let backgroundDesignHeight: CGFloat = 330.0 to 730 to make it smaller
All buttons are in same place on iPhone and iPads, except «plus devices» there is a small offset to the bottom(down) button should be slightly higher
On some devices background image on button are little bit blurry, this happened after I changed backgroundDesignHeight to 730
You can solve this a few ways:
Compute the final x/y position manually based on current screen dimension and "design" dimension
Manually create aspect-ratio based constraints and let iOS compute the final position for you
Assuming that your device/app orientation is constant (always landscape or always portrait) and is always fullscreen, it may be easier to compute it by hand.
First, you will need a helper function to resize your image:
private func scaledImage(named imageName: String, scale: CGFloat) -> UIImage? {
guard let image = UIImage(named: imageName) else { return nil }
let targetSize = CGSize(width: image.size.width * scale, height: image.size.height * scale)
return resizeImage(image: image, targetSize: targetSize)
}
// Adapted from https://stackoverflow.com/questions/31314412/how-to-resize-image-in-swift
private func resizeImage(image: UIImage, targetSize: CGSize) -> UIImage? {
let size = image.size
let widthRatio = targetSize.width / size.width
let heightRatio = targetSize.height / size.height
// Figure out what our orientation is, and use that to form the rectangle
var newSize: CGSize
if(widthRatio > heightRatio) {
newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
} else {
newSize = CGSize(width: size.width * widthRatio, height: size.height * widthRatio)
}
// This is the rect that we've calculated out and this is what is actually used below
let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
// Actually do the resizing to the rect using the ImageContext stuff
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
image.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
Next, we will create a function to compute the location of the button, and the size of the button based on the image size:
private func positionScaledButton(x designX: CGFloat, y designY: CGFloat, imageName: String) -> UIButton {
// First, compute our "designScale"
let screenHeight = UIScreen.main.bounds.size.height
let backgroundDesignHeight: CGFloat = 330.0 // ** see below
let designScale = screenHeight / backgroundDesignHeight
// Create button
let button = UIButton(type: .custom)
// Get image to use, and scale it as required
guard let image = scaledImage(named: imageName, scale: designScale) else { return button }
button.frame = CGRect(x: designX * designScale, y: designY * designScale, width: image.size.width, height: image.size.height)
button.setImage(image, for: .normal)
scrollView.addSubview(button)
return button
}
** The value "330.0" in the code above refers to the height of the background image in the scroller, from which the x/y coordinates of the button were measured.
Assuming button's top-left corner should be at x: 10, y: 10, for image "levelOne":
let levelOneButton = positionScaledButton(x: 10, y: 10, imageName: "imageOne")
// To do: addTarget event handler
Use relative, rather than absolute points.
So, rather than saying button 1 is at (30, 150) in points, use the fraction of the screen size instead so it's at (0.0369, 0.4) - then use those fractions to create your auto layout constraints.
For a UIImageView, I am using the aspect fill content mode. It's OK, but for some images, it will cut from the top because I used clipsToBounds = true. So here is what I want: I want to make the two filters active at the same time, for example:
Here is an image view that I set to aspect fill:
...and an image view I set using contentMode = .top:
So I want to merge these two content modes. Is it possible? Thanks in advance.
Update: device scaling is now properly handled, thanks to budidino for that!
You should resize the image, so that it will have the width of your image view, but by keeping its aspect ratio. After that, set the image view's content mode to .top and enable clipping to bounds for it.
The resizeTopAlignedToFill function is a modified version of this answer.
func setImageView() {
imageView.contentMode = .top
imageView.clipsToBounds = true
let image = <custom image>
imageView.image = image.resizeTopAlignedToFill(newWidth: imageView.frame.width)
}
extension UIImage {
func resizeTopAlignedToFill(newWidth: CGFloat) -> UIImage? {
let newHeight = size.height * newWidth / size.width
let newSize = CGSize(width: newWidth, height: newHeight)
UIGraphicsBeginImageContextWithOptions(newSize, false, UIScreen.main.scale)
draw(in: CGRect(origin: .zero, size: newSize))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
}
Try this:
imageView.contentMode = UIViewContentModeTop;
imageView.image = [UIImage imageWithCGImage:image.CGImage scale:image.size.width / imageView.frame.size.width orientation:UIImageOrientationUp];
This is my solution. First, you set comtentMode to top then you resize image
func resize(toWidth scaledToWidth: CGFloat) -> UIImage {
let image = self
let oldWidth = image.size.width
let scaleFactor = scaledToWidth / oldWidth
let newHeight = image.size.height * scaleFactor
let newWidth = oldWidth * scaleFactor
let scaledSize = CGSize(width:newWidth, height:newHeight)
UIGraphicsBeginImageContextWithOptions(scaledSize, false, 0)
image.draw(in: CGRect(x: 0, y: 0, width: scaledSize.width, height: scaledSize.height))
let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return scaledImage!
}
imageView.contentMode = .top
imageView.image = imageView.resize(toWidth:imageView.frame.width)
The accepted answer was scaling down the image and therefore lowering the quality on #2x and #3x devices. This should produce the same result with better image quality:
extension UIImage {
func resizeTopAlignedToFill(containerSize: CGSize) -> UIImage? {
let scaleTarget = containerSize.height / containerSize.width
let scaleOriginal = size.height / size.width
if scaleOriginal <= scaleTarget { return self }
let newHeight = size.width * scaleTarget
let newSize = CGSize(width: size.width, height: newHeight)
UIGraphicsBeginImageContextWithOptions(newSize, false, scale)
self.draw(in: CGRect(origin: .zero, size: newSize))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
}
then to use it just:
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.image = UIImage(named: "portrait").resizeTopAlignedToFill(containerSize: imageView.frame.size)
as a matter of performance I would suggest to put the UIImageView with the full image size / aspect ratio into a ContainerView with clipsToBounds set to true.
I'm Newbie in Swift.
I have a question.
When I add Tabbar Item image from one UIImage, then Nothing show up.
Although, Not in Tabbar Item, Image appear well and image that load from asset to tab bar item works well.
I already resize that thing, and not in tab bar, that resized image load well.
So, I'm so confused how to do that.
Here is my codes
This is load from Facebook profile picture
FBSDKGraphRequest(graphPath: "/me", parameters: ["fields": "email, id, name, picture"]).start { (connection, result, err) in
if err != nil {
print("FBLogin Error: \(err)")
return
}
print(result!)
let dd = result as! [String : AnyObject]
let test = (dd["picture"]!["data"]!! as! [String: AnyObject])["url"]
let url = URL(string: test as! String)
let data_picture = try? Data(contentsOf: url!)
var temp_img = UIImage()
temp_img = UIImage(data: data_picture!)!
temp_tabbar_profile = self.resizeImage(image: temp_img, targetSize: CGSize(width: 30, height: 30))
temp_tabbar_profile is UIImage
And This is resize code.
func resizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
let size = image.size
let widthRatio = targetSize.width / image.size.width
let heightRatio = targetSize.height / image.size.height
// Figure out what our orientation is, and use that to form the rectangle
var newSize: CGSize
if(widthRatio > heightRatio) {
newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
} else {
newSize = CGSize(width: size.width * widthRatio, height: size.height * widthRatio)
}
// This is the rect that we've calculated out and this is what is actually used below
let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
// Actually do the resizing to the rect using the ImageContext stuff
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
image.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
This is set tab bar image code
override func viewDidLoad() {
super.viewDidLoad()
let tabBarItems = tabBar.items! as [UITabBarItem]
tabBarItems[0].selectedImage = temp_tabbar_profile
tabBarItems[0].image = temp_tabbar_profile
tabBarItems[0].title = ""
}
When I run app, then just gray picture appeared.
When I load this temp_tabbar_profile in other view's image view.image,
loaded well!!!
I don't know what is wrong.
Thank you for reading my problem.
You should use tabBarItems[0].image = temp_tabbar_profile.withRenderingMode(.alwaysOriginal). Or the UITabBar will display your image in a abstract way.