Achieve exact control of scale and offset of UIImage in UIImageView - ios

I currently have a UIImageView with an image loaded inside with the contentMode being set to scaleAspectFill. Is there a way to specify an exact section of the image to show instead of the default center, or am I approaching this the wrong way?
Swift Code:
basketballImage = UIImageView()
basketballImage.contentMode = .scaleAspectFill
basketballImage.clipsToBounds = true
basketballImage.image = UIImage(named: "Basketball")
Original Image
Desired Result
Failed Example 1: With contentMode = .scaleAspectFill
Failed Example 2: With contentMode = .top

There's no way for iOS to know what you really want since your scaling is arbitrary.
You can effectively crop (zoom-in) by setting the contentScaleFactor property. Aspect-fit is unrelated to your goal.
Now, the arbitrary vertical offset requires an affine transform, but only works with a container UIView to maintain the layout. You have to transform the entire UIImageView frame within its parent (unless you want to get very fancy and override the draw method or re-implement UIImageView with an affine-transform hook).
I achieved roughly what you want by installing that image at 2x resolution and using:
override func viewDidLoad() {
super.viewDidLoad()
let offset: CGFloat = 120.0
let scale: CGFloat = 3.0
/* imageView is a *child* of imageContainer and constrained to be exactly the same size and position */
imageContainer.clipsToBounds = true
imageView.image = UIImage(named: "basketball")
imageView.contentMode = .center
imageView.contentScaleFactor = scale
imageView.transform = CGAffineTransform(translationX: 0, y: offset)
}
It's harder than I'd like, what with another layer of nesting, but UIImageView is just not that sophisticated.

Related

How to make a UIImage Scrollable inside a UIScrollView?

I currently have a ScrollView and inside the ScrollView i have a UIImageView.
I get different image sizes from my server and most images are larger than the bounds of my screen.
I would like to scroll through the image if it is bigger than my screen.
Something like this....
This is what i have tried so far.
let image = UIImage(named: "myImg")
let heightInPoints = image?.size.height
let heightInPixels = heightInPoints ?? 0 * image!.scale
let widthInPoints = image?.size.width
let widthInPixels = widthInPoints ?? 0 * image!.scale
self.imageView.frame = CGRect(x: 0, y: 0, width: widthInPixels, height: heightInPixels) //= image
self.imageView.image = image
scrollView.contentSize = CGSize(width: imageView.frame.width, height: imageView.frame.height)
But it doesn't seem to work. Either it only scrolls vertically or horizontally or it never scrolls.
What am I doing wrong. Or is there a better approach to get this effect ?
Solution 1. Updating Frames
Firstly, make sure the views hierarchy is correctly setup (the imageView is added to the scrollView):
scrollView.addSubview(imageView)
Then I'd suggest rewriting this code as something like:
let image = UIImage(named: "myImg")
imageView.image = image // setup image to imageView
imageView.frame.size = image?.size ?? .zero // setup image size or zero to imageView
scrollView.contentSize = image.size ?? .zero // setup image size or zero as a content size
Solution 2. Using constraints
There is also another solution using constraints instead of manually setting up the sizes. This takes a bit more code but doesn't require sizes recomputing when you change the image.
scrollView.addSubview(imageView) // Setup the views hierarchy
imageView.translatesAutoresizingMaskIntoConstraints = false // Make sure constraints won't interfere with autoresizing mask
NSLayoutConstraint.activate(
[
imageView.leftAnchor.constraint(equalTo: scrollView.leftAnchor), // attaching to the left
imageView.topAnchor.constraint(equalTo: scrollView.topAnchor), // attaching to the top
imageView.rightAnchor.constraint(equalTo: scrollView.rightAnchor), // attaching to the right
imageView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor) // attaching to the bottom
]
)
Then we replace existing image with a new one like this:
imageView.image = UIImage(named: "myImg")
Both approaches work for me in Playground. So, if these still won't work for you, please share more information about how you set up the hierarchy and additional parameters of the scroll view.

ios swift create rounded profile image like twitter, instagram,

I would like to create a very simple image editor, same as twitter (for the profile image)
I know how to pinch or move an image.
But i don’t know how to create the "circle layer" and just keep this part of the image, like this :
Make sure to import QuarzCore.
func maskRoundedImage(image: UIImage, radius: CGFloat) -> UIImage {
let imgView: UIImageView = UIImageView(image: image)
let layer = imgView.layer
layer.masksToBounds = true
layer.cornerRadius = radius
UIGraphicsBeginImageContext(imgView.bounds.size)
layer.render(in: UIGraphicsGetCurrentContext()!)
let roundedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return roundedImage!
}
https://github.com/andreaantonioni/AAPhotoCircleCrop
Each view has an underlying layer onto which you apply a corner radius. Then you must apply clipToBounds on that layer in order to apply that mask to the overlying UIView. The corner radius must be half the width of the view in order to get a circle effect. Otherwise the corners of the view will be rounded.
For example:
let square = UIView()
square.center = view.center
square.bounds.size = CGSize(width: 100, height: 100)
square.backgroundColor = .red
view.addSubview(square)
square.layer.cornerRadius = 50
square.clipsToBounds = true
Above mentioned ways are good, But you can not achieved exact output as in above image E.g You can not get alpha effect.
I suggest simple way to do it.
1) Add new image to project with transparent background with Opocity and circle.
2) Add new imageView above to mainview as below.
let image = UIImageView(frame: view.bounds)
mage.image = UIImage.init(named:"imageName")
view.addSubview(image)
Then output should be as per your requirement.

How to set half-round UIImage in Swift like this screenshot

https://www.dropbox.com/s/wlizis5zybsvnfz/File%202017-04-04%2C%201%2052%2024%20PM.jpeg?dl=0
Hello all Swifters,
Could anyone tell me how to set this kind of UI? Is there any half rounded image that they have set?
Or there are two images. One with the mountains in the background and anohter image made half rounded in white background and placed in on top?
Please advise
Draw an ellipse shape using UIBezier path.
Draw a rectangle path exactly similar to imageView which holds your image.
Transform the ellipse path with CGAffineTransform so that it will be in the center of the rect path.
Translate rect path with CGAffineTransform by 0.5 to create intersection between ellipse and the rect.
Mask the image using CAShapeLayer.
Additional: As Rob Mayoff stated in comments you'll probably need to calculate the mask size in viewDidLayoutSubviews. Don't forget to play with it, test different cases (different screen sizes, orientations) and adjust the implementation based on your needs.
Try the following code:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
guard let image = imageView.image else {
return
}
let size = image.size
imageView.clipsToBounds = true
imageView.image = image
let curveRadius = size.width * 0.010 // Adjust curve of the image view here
let invertedRadius = 1.0 / curveRadius
let rect = CGRect(x: 0,
y: -40,
width: imageView.bounds.width + size.width * 2 * invertedRadius,
height: imageView.bounds.height)
let ellipsePath = UIBezierPath(ovalIn: rect)
let transform = CGAffineTransform(translationX: -size.width * invertedRadius, y: 0)
ellipsePath.apply(transform)
let rectanglePath = UIBezierPath(rect: imageView.bounds)
rectanglePath.apply(CGAffineTransform(translationX: 0, y: -size.height * 0.5))
ellipsePath.append(rectanglePath)
let maskShapeLayer = CAShapeLayer()
maskShapeLayer.frame = imageView.bounds
maskShapeLayer.path = ellipsePath.cgPath
imageView.layer.mask = maskShapeLayer
}
}
Result:
You can find an answer here:
https://stackoverflow.com/a/34983655/5479510
But generally, I wouldn't recommend using a white image overlay as it may appear distorted or pixelated on different devices. Using a masking UIView would do just great.
Why you could not just create (draw) rounded transparent image and add UIImageView() with UIImage() at the top of the view with required height and below this view add other views. I this this is the easiest way. I would write comment but I cant.

Drawing multiple UIImageViews with the same UIImage

I am trying to draw a line using multiple UIImageView of the same circle image.
I have tried the following:
let imageName = "circle.jpg"
let image = UIImage(named: imageName)
for var i in 0..<100 {
i += 1
let imageView = UIImageView(image: image!)
imageView.frame = CGRect(x: i, y: 200, width: 25, height: 25)
view.addSubview(imageView)
}
This produces one circle at the position (100, 200). This happens because the same UIImageView is being added to the subview so it is only updating the position rather than adding a new UIImageView. If I create a new UIImageView named "imageView1" and add it to the subview, it will create a new circle.
For the purpose of forming a line by overlapping the UIImageViews of these circles, manually creating a UIImageView for each circle is obviously inefficient.
So, how can I use the same UIImage to draw multiple UIImageViews?
Any other suggestions on how I can get around accomplishing this?
You need a circle to form a line like this
Well here the code I used for this using While loop
let imageName = "synergy-many-people-turning-in-gears_gg55375354.jpg"
let image = UIImage(named: imageName)
var i = 0
while(i<100)
{
let imageView = UIImageView(image: image!)
imageView.frame = CGRect(x: i, y: 200, width: 25, height: 25)
view.addSubview(imageView)
i = i + 25//Here I set it to the width so that the images don't overlap
//you can use any value for the desired effect it just sets the location
//of X-Co-ordinate where the next image would be added
}
I would quickly try out something like this (didn't test it though):
var imageView = UIImageView(image: image!)
Creating multiple UIImageViews is the thing you need to do. If this will be to slow (btw you should place your image inside assets catalogue to allow caching and improve performance), you should switch to lower level api. Check iOS - An easy way to draw a circle using CAShapeLayer
And, btw, why do you change i variable inside loop, this is very bad practice

UIImageView AspectFill failing

I'm rendering a 16:9 pixel image programatically and then use UIImageView with kCAFilterNearest filter and .ScaleAspectFill content mode to display it as a background image. The result I get is this:
On the picture you can see that, for whatever reason, it scales the picture exactly right but slightly moves it up (like, half a scaled pixel) and leaves a line at the bottom, which belongs to the UIImageView that the image is displayed on (it's the only view on this UIViewController and its background color is "navy").
What might be the reason behind this, considering that I use UIScreen.mainScreen().bounds rectangle for the UIImageView?
P.S. ScaleToFill content mode gives kind of the same result (the line at the bottom remains)
I use a function to resize the image to fit on the screen
fnc imageResize (imageObj:UIImage, sizeChange:CGSize)-> UIImage{
let hasAlpha = false
let scale: CGFloat = 0.0 // Automatically use scale factor of main screen
UIGraphicsBeginImageCOntextWithOptions(sizeChange, !hasAlpha, scale)
imageObj.drawInRect(CGRect(origin: CGPointZero, size : sizeChange))
let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
retunr scaledImage
}
and to call
let mainScreenSize: CGRect = UIScreen.mainScreen().bounds
let image: UIImage! = self.imageResize(UIImage(named: "IMAGE_NAME")!, sizeChange: CGSizeMake(mainScreenSize.width, mainScreenSize.height))
the initial image that I used was 16:9 ratio as well

Resources