How to resize image in UIView? - ios

I tried to set image into UIView but I can't resize it in my view I got something like this:
UIview
let imageName = "rectanguloAzul"
let image = UIImage(named: imageName)
let imageView = UIImageView(image: image!)
imageView.contentMode = .scaleAspectFill
self.view.addSubview(imageView)

Welcome.
You need to either give the imageView a frame or use Autolayout to set a layout for the image inside the UIView.
so either add this at the end:
imageView.frame = view.frame
But this will not be dynamic and you should learn how to keep updating the frame whenever the superview's frame changes.
Or you can add this, instead:
imageView.translatesAutoresizingMaskIntoConstraints = false
let constraints = [
imageView.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor),
imageView.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor),
imageView.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor),
imageView.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor)
]
NSLayoutConstraint.activate(constraints)
Anyway, I really recommend you read up about AutoLayout a bit before you continue:
https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/index.html
https://www.raywenderlich.com/811496-auto-layout-tutorial-in-ios-getting-started
If you find programmatic AutoLayout to be too challenging, I would recommend possibly starting with Storyboards first.

Related

Understanding layout anchors in Swift

So, I have this ViewController where I render an image inside a subview.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
let childView = UIView()
childView.backgroundColor = .red
let imageView = UIImageView(image: UIImage(systemName: "tray"))
imageView.contentMode = .scaleAspectFill
childView.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
imageView.heightAnchor.constraint(equalToConstant: 100.0)
])
view.addSubview(childView)
childView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
childView.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor)
])
}
}
As you can see for some reason, the image moves to the left of screen. What is the cause of that?
One more thing I noticed is the subview should have a background color of red as specified, but somehow it's transparent. Why is that?
I expect the result to be something like,
You are adding way too few constraints. The horizontal position and size of the childView are not constrained at all, so the size just defaults to (0, 0), making the view not visible at all, which is why you don't see the red background.
First, let's constrain the horizontal position. This seems to be what you intended:
NSLayoutConstraint.activate([
// wouldn't it be better to use safeAreaLayoutGuide?
childView.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor),
childView.leftAnchor.constraint(equalTo: view.layoutMarginsGuide.leftAnchor)
])
Then, the size of the childView should be the same as the imageView, so you should activate these constraints too:
imageView.leftAnchor.constraint(equalTo: childView.leftAnchor),
imageView.rightAnchor.constraint(equalTo: childView.rightAnchor),
imageView.topAnchor.constraint(equalTo: childView.topAnchor),
imageView.bottomAnchor.constraint(equalTo: childView.bottomAnchor),
There is one more thing though - the size of the image view at this point is not what you expect. The image view has a height of 100, but its width is still 24, which is the intrinsic size of the "tray" image. scaleAspectFill does scale the image to the size you want, but the views' widths stay at 24, and since the scaling is done from the centre of the view, the scaled up image appears to be "off centred".
I think that in general, you'll just have to manually calculate the width you want:
let width = 100 * image.size.width / image.size.height
and constrain both width and height:
imageView.heightAnchor.constraint(equalToConstant: 100.0),
imageView.widthAnchor.constraint(equalToConstant: width),
However, with SF symbols, you can get a bigger image simply by:
let image = UIImage(systemName: "tray", withConfiguration: UIImage.SymbolConfiguration(pointSize: 100))
You don't need any height or width constraints on the image view.

Empty space in UIImageView when using scaleAspectFit

Here is an image of my issue. My problem is that I have an tiny empty space on the right side of my UIImageView that is constrained to the view of my view controller. It's green because of the background I set, and it is more prominent on my device. It's weird because the image should fit the whole screen considering the image was taken on the phone itself and I am using scaleAspectFit.
let imageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.isUserInteractionEnabled = true
imageView.contentMode = .scaleAspectFit
imageView.backgroundColor = .green
imageView.clipsToBounds = true
return imageView
}()
Here is the code for the constraints:
func setupImageView() {
self.view.addSubview(imageView)
let imageViewConstraints = [
imageView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
imageView.topAnchor.constraint(equalTo: self.view.topAnchor),
imageView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
imageView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor)
]
NSLayoutConstraint.activate(imageViewConstraints)
}
I am basically setting the image using self.imageView.image and I end up with a empty space on the right side that is only noticeable when using bright colors as the imageView background. Not sure if this is a bug. The only reason I'm not using fill is because I want to maintain the aspect while showing the whole image.
The contentMode scaleAspectFit will keep the scale of the image, display the whole content of the image. Because your photo scale is same to the screen, if your imageView height is less than screen, the image display width will be less than screen too, which causes the background green color shows.
To ensure the imageView fits the screen, you can add border on it:
imageView.layer.borderColor = UIColor.red.cgColor
imageView.layer.borderWidth = 1.0
Try to use in your imageView{
imageView.contentMode = .scaleAspectFill
}

Centering an UIImage (horizontally or vertically) with programatic constraints UIKit

I am trying to simply center a 5x5 image in a horizontal row in UIKit.
On the left of the view I have a UIView that has its left and top margins attached to the parent view and has intrinsic width and height. It might not exactly fill half of the containing view (so assume its width is arbitrary).
To the right of it (but on the same row) I am trying to put a UIImage that is centered in the blank space to the right of the left object. Meaning it is both centered horizontally and vertically but to the right of the other object.
I really have no clue how to accomplish this although I figure there are both more and less elegant ways to achieve this.
After you set a proper width and height for it set these constraints
smallView.centerYAnchor.constraint(equalTo: greenView.centerYAnchor).isActive = true
smallView.centerXAnchor.constraint(equalTo: parentView.centerXAnchor, multiplier:1.5).isActive = true
It's pretty simple. You'll use a layout guide to define the beginning and end of the horizontal space. Then you'll center your view in the layout guides center. I have included layoutMarginsGuide which can be adjusted by setting container.layoutMargins.
let containerView = UIView()
containerView.backgroundColor = .gray
// Add view to parent ...
let greenView = UIView()
greenView.translatesAutoresizingMaskIntoConstraints = false
greenView.backgroundColor = .green
containerView.addSubview(greenView)
greenView.topAnchor.constraint(equalTo: containerView.layoutMarginsGuide.topAnchor).isActive = true
greenView.leadingAnchor.constraint(equalTo: containerView.layoutMarginsGuide.leadingAnchor).isActive = true
let horizontalGuide = UILayoutGuide()
containerView.addLayoutGuide(horizontalGuide)
horizontalGuide.leadingAnchor.constraint(equalTo: greenView.trailingAnchor, constant: containerView.layoutMargins.left).isActive = true
horizontalGuide.trailingAnchor.constraint(equalTo: containerView.layoutMarginsGuide.trailingAnchor).isActive = true
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.backgroundColor = .red
containerView.addSubview(imageView)
imageView.centerXAnchor.constraint(equalTo: horizontalGuide.centerXAnchor).isActive = true
imageView.centerYAnchor.constraint(equalTo: greenView.centerYAnchor).isActive = true

UICollectionView.backgroundView broken

I have a problem with backgroundView property. I tried to add an imageView to background like this
let backgroundImage = UIImage(named: "Fridge_background")!
let backgroundView = UIImageView(image: backgroundImage)
collectionView?.backgroundView = backgroundView
but the problem is that it did not even add this view to view hierarchy. I have already read this article, but this solution did not help me either. What it can be and how did I can fix it? Funny think is that in tableView similar property work just fine as it must.
Broken it is indeed.
I was researching improper positioning of uicollectionview background view
and run into this:
https://blog.spacemanlabs.com/2013/11/uicollectionviews-backgroundview-property-is-horribly-broken/
describes your issue as well.
This seemed to work well in the UIColllectionViewController's viewDidAppear method. All behaviors matched expectations.
let myView = UIView(frame: self.view.frame)
let image = UIImage(named: "image name")
let imageView = UIImageView(frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: image!.size))
imageView.image = image
myView.addSubview(imageView)
self.collectionView.backgroundView = myView

(Swift) programmatically constrain UIButton to corner

I have the following code for an image that is a round button:
let settingsButton = UIButton(type: .Custom)
settingsButton.frame = CGRectMake(160, 100, 50, 50)
settingsButton.layer.cornerRadius = 0.5 * settingsButton.bounds.size.width
settingsButton.setImage(UIImage(named:"settingsButton.png"), forState: .Normal)
settingsButton.clipsToBounds = true
view.addSubview(settingsButton)
I want to constrain it to the top left corner of my view controller, but since I made this button programmatically, I can't see it in my storyboard and therefore cannot move and constrain it manually. Is there a way to be able to see this programmatically created button in my storyboard's view controller? If not, how can I programmatically constrain this button I created to the top left corner of my view controller?
Any help is greatly appreciated!
The easiest way to do this, since you're creating the button in code, is to use the button's autoresizing mask. First, set the button's frame so it's in the top right corner of the superview. Then set the button's autoresizingMask to allow only the distances to the left and bottom edges of the superview to vary:
settingsButton.frame = CGRect(x: view.bounds.maxX - 50, y: 0, width: 50, height: 50)
settingsButton.autoresizingMask = [.flexibleLeftMargin, .flexibleBottomMargin]
view.addSubview(settingsButton)
My code is in Swift 3 syntax but it should be trivial to convert it so Swift 2.
Keep in mind that autoresizing masks work fine under auto layout. Many of Apple's standard classes still use autoresizing masks internally. Xcode 8 added the ability to mix constraints and autoresizing masks in a storyboard or xib, so clearly Apple thinks you should use autoresizing when it's a good fit.
If I interpret constrain as-in using constraints, you can use layout anchors. The gotchas here are:
Always set translatesAutoresizingMaskIntoConstraints = false on your view.
Set .active = true on your layout anchors.
Only available in iOS >= 9.0 (use normal NSlayoutConstraints if you need to support earlier versions of iOS).
Example code:
let settingsButton = UIButton(type: .Custom)
view.addSubview(settingsButton)
settingsButton.backgroundColor = UIColor.redColor()
settingsButton.translatesAutoresizingMaskIntoConstraints = false
settingsButton.widthAnchor.constraintEqualToConstant(50).active = true
settingsButton.heightAnchor.constraintEqualToConstant(50).active = true
settingsButton.topAnchor.constraintEqualToAnchor(view.topAnchor, constant: 10).active = true
settingsButton.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor, constant: -10).active = true
settingsButton.setNeedsLayout()
settingsButton.layoutIfNeeded()
settingsButton.layer.cornerRadius = 0.5 * settingsButton.bounds.size.width
settingsButton.setImage(UIImage(named:"settingsButton.png"), forState: .Normal)
settingsButton.clipsToBounds = true
Note that using constraints is superior to setting frames because constraints adapt to changes in the parent view sizeĀ (e.g device rotation to landscape mode).
You can use this :
let settingsButton = UIButton()
settingsButton.translatesAutoresizingMaskIntoConstraints = false
settingsButton.trailingAnchor.constraint(equalTo: view.leadingAnchor,constant: 160).isActive = true
settingsButton.bottomAnchor.constraint(equalTo: view.topAnchor,constant: 100).isActive = true
settingsButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
settingsButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
settingsButton.widthAnchor.constraint(equalToConstant: 50).isActive = true
settingsButton.layer.cornerRadius = 0.5 * settingsButton.bounds.size.width
settingsButton.clipsToBounds = true
view.addSubview(settingsButton)

Resources