UIScroll View set initial image size less than full size - ios

This view loads just one image and allows the user to zoom in and out to view parts of the image up close. However, it loads at a gigantic size, and I want it to load at screen size. Or if screen size is hard to get, then just loading at 50% size would work.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.scrollView.minimumZoomScale = 0
self.scrollView.maximumZoomScale = 1
self.scrollView.delegate = self
self.imageView.image = self.image!
}
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return self.imageView
}
}
How do I set the initial image size to a reasonable size, but allow for zooming to the full size image?
Thanks!

You just have to calculate the zoom dividing your view width by your image size width as follow:
scrollView.zoomScale = view.frame.width / imageView.image.size.width

Get the screen size: (objective-C)
let screenSize: CGRect = UIScreen.mainScreen().bounds
let screenWidth = screenSize.width
let screenHeight = screenSize.height
Set the UIImageView frame to the screen size, and then set the aspect to fit:
imageView.contentMode = .ScaleAspectFit (UIViewContentModeScaleAspectFit in Obj-C)
Then, just set the zoomScale:
self.scrollView.zoomScale = .5;

Related

Swift - Mapping invisible button on UIImage which zoom In/Out

Can some one suggest the best way to do this..
In the Below Image
Add invisible buttons over the image for each section of the map.
The image should be in a scrollview to zoom in and out the image.
Zooming in/out should not change the button mapping area
Should support for all iPhone models.
What I did..
Added a UIImageView inside a UIScrollView(for zoom in/out) and on viewDidAppear() manually added invisible button for the UIImage like this.
self.image.frame = CGRect(x: xValue , y:yValue, width: 60, height: 60)
Is there any better solution for finding the UIImage coordinates?
Very late to the party, but this should work:
in ViewDidLoad add this:
scrollView.minimumZoomScale = 0.5
scrollView.maximumZoomScale = 6.0
scrollView.contentSize = self.imageView.frame.size
scrollView.delegate = self
After ViewDidLoad add this:
// MARK: - Update the minimum zoom scale each time the controller updates its subviews
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
updateMinZoomScaleForSize(view.bounds.size)
}
Then create a file private function to calculate the zoom scale for scrollView
fileprivate func updateMinZoomScaleForSize(_ size: CGSize) {
let widthScale = size.width / imageView.bounds.width
let heightScale = size.height / imageView.bounds.height
let minScale = min(widthScale, heightScale)
imageScrollView.minimumZoomScale = minScale
imageScrollView.zoomScale = minScale
}
Are you using nine imageViews? No. it's not correct it seems.
Try like this :
Take a collection view and give necessary constraints like top, bottom, left and right.
Add image view to collection view cell. Add corner radius properties(it seems ur image views need this).
For zoom in and zoom out actions, add pinch gesture to collection view.
Add tap gesture for image view, instead of buttons.

Limit image size to ScrollView, Swift

I have an image which is set inside a scroll view, though I have set the frame of the scrollView to fixed height and width as shown below, the image goes beyond the bounds (see below picture).
How can I limit the picture to fit inside the scrollView.
imageScrollView.frame = CGRect(x: 0, y: 0, width: viewWidth, height: viewHeight-50)
imageScrollView.clipsToBounds = true // Has no affect on the image
Do you have a reference to the UIImageView? If so, then set its content mode to aspect fit. Like this:
theImageView.contentMode = .scaleAspectFit
The clipsToBounds you set only covers up any parts of child views that are sticking out of the bounds of the parent view, so that's why it doesn't do anything for you.
OR if you're using Interface Builder, set this option:
So, what if you don't have the reference to the UIImageView?...
You could iterate through the subviews of your scroll view, and whenever it finds a UIImageView, you can set the content mode like that. Something like:
//This is off the top of my head, so my filtering may not be right...
//This is also a one and done solution if you've got a lot of images in your scroll view
for anImgVw in imageScrollView.subviews.filter({$0.isKind(of: UIImageView.self)})
{
anImgVw.contentMode = .scaleAspectFit
}
Otherwise, I'm not sure if it's possible without a reference to the UIImageView.
The library you are using is coded to match the scaling to the device orientation. So, if the image orientation doesn't match the view orientation, you end up with the image not quite fitting in your scroll view.
You'll need to edit the ImageScrollView.swift source file. Assuming you're using the same version that is currently at the link you provided ( https://github.com/huynguyencong/ImageScrollView ), change the setMaxMinZoomScalesForCurrentBounds() function as follows:
fileprivate func setMaxMinZoomScalesForCurrentBounds() {
// calculate min/max zoomscale
let xScale = bounds.width / imageSize.width // the scale needed to perfectly fit the image width-wise
let yScale = bounds.height / imageSize.height // the scale needed to perfectly fit the image height-wise
// fill width if the image and phone are both portrait or both landscape; otherwise take smaller scale
//let imagePortrait = imageSize.height > imageSize.width
//let phonePortrait = bounds.height >= bounds.width
//var minScale = (imagePortrait == phonePortrait) ? xScale : min(xScale, yScale)
//
// just take the min scale, so the image will completely fit regardless of orientation
var minScale = min(xScale, yScale)
let maxScale = maxScaleFromMinScale*minScale
// don't let minScale exceed maxScale. (If the image is smaller than the screen, we don't want to force it to be zoomed.)
if minScale > maxScale {
minScale = maxScale
}
maximumZoomScale = maxScale
minimumZoomScale = minScale * 0.999 // the multiply factor to prevent user cannot scroll page while they use this control in UIPageViewController
}
you can use the screenHeight rather than the viewHeight
let screenSize: CGRect = UIScreen.mainScreen().bounds
let screenWidth = screenSize.width
let screenHeight = screenSize.height
imageScrollView.frame = CGRect(x: 0, y: 0, width: viewWidth, height: screenHeight-50)

UIImageView keep aspect ratio, but fit to width

I have a UIImageView with a fixed width and height. I don't want to change the frame of the UIImageView. I want to have it hold an image where I keep the aspect ratio and I fit the width and let the image be either too tall, or too short for the UIImageView's frame. Like this:
The red is the UIImageView's frame. The gray is the actual image as it's displayed.
I think the best way to do it is to play with the mode of your imageView (Aspect Fill, Aspect Width, etc) and this is based on the ratio between the width and height of the image
if image.width > image.height {
imageView.contentMode = UIViewContentModeScaleAspectFit
//since the width > height we may fit it and we'll have bands on top/bottom
} else {
imageView.contentMode = UIViewContentModeScaleAspectFill
//width < height we fill it until width is taken up and clipped on top/bottom
}
UIViewContentModeScaleAspectFit
Scales the content to fit the size of the view by maintaining the
aspect ratio. Any remaining area of the view’s bounds is transparent.
UIViewContentModeScaleAspectFill
Scales the content to fill the size of the view. Some portion of the
content may be clipped to fill the view’s bounds.
I haven't tested it but off the top of my head this seems right
I think you need to compare the image aspect ratio to the aspect ratio of the UIImageView itself:
private func updateUI() {
guard let image = image else { return }
let viewAspectRatio = self.bounds.width / self.bounds.height
let imageAspectRatio = image.size.width / image.size.height
if viewAspectRatio > imageAspectRatio {
self.contentMode = .scaleAspectFill
} else {
self.contentMode = .scaleAspectFit
}
}
override var image: UIImage? { didSet { updateUI() }}
override func layoutSubviews() {
super.layoutSubviews()
updateUI()
}
Note: this is aspect fit width
Swift 5.1 iOS 13
Because mine was on the header cell on a collection view this is what worked for me:
if headerCell!.imageView.frame.width > headerCell!.imageView.frame.height {
headerCell!.imageView.contentMode = .scaleAspectFit
//since the width > height we may fit it and we'll have bands on top/bottom
} else {
headerCell!.imageView.contentMode = .scaleAspectFill
//width < height we fill it until width is taken up and clipped on top/bottom
}
For my case solution was to set UIImageView's contentMode based on if ratio of image's height and width is bigger than of imageView's.
func setupImageViewContentMode() {
if let image = imageView.image, image.size.height / image.size.width > imageView.frame.height / imageView.frame.width {
imageView.contentMode = .scaleAspectFit
} else {
imageView.contentMode = .scaleAspectFill
}
}
Also, note that you have to setup this according to current layout, so calling this method e.g. in layoutSubviews(), in viewDidLayoutSubviews(), after image is loaded from backend or wherever you need it does the job.

Image overlaps previous view when tapping/swiping back

I have a UIScrollView which covers one of my views entirely. I have added a background image to this same view which scrolls at a slightly different rate to the actual UIScrollView. This works absolutely fine unless I use the back swipe gesture or tap the 'Back' button. What happens is the image covers the view for about 0.5 seconds before disappearing, and it looks pretty bad.
This is what I mean:
As you can see, that is mid way through the gesture, and rather than being able to see the previous view, you just see the part of the image that is off to the left. It doesn't happen on the first page of the UIScrollView so I guess it's because the image is overlapping the previous view.
Here is my code:
override func viewDidLoad() {
let pagesScrollViewSize = scrollView.frame.size
scrollView.contentSize = CGSize(width: pagesScrollViewSize.width * CGFloat(images.count), height: pagesScrollViewSize.height)
backgroundImageView.frame = CGRect(x: 0, y: 0, width: 2484, height: 736)
backgroundImageView.image = UIImage(named: "SF.png")
var visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .Light)) as UIVisualEffectView
visualEffectView.frame = backgroundImageView.bounds
backgroundImageView.addSubview(visualEffectView)
view.addSubview(backgroundImageView)
view.sendSubviewToBack(backgroundImageView)
scrollView.backgroundColor = UIColor.clearColor()
}
func scrollViewDidScroll(scrollView: UIScrollView) {
loadVisiblePages()
var factor = scrollView.contentOffset.x / (scrollView.contentSize.width - 414);
if factor < 0 {
factor = 0
}
if factor > 1 {
factor = 1
}
var frame: CGRect = backgroundImageView.frame
frame.origin.x = factor * (414 - backgroundImageView.frame.size.width)
backgroundImageView.frame = frame
}
Anyone have any suggestions?
You have to add the following in your viewDidLoad function:
self.view.clipsToBounds = true or scrollView.clipsToBounds = true if you just want to clip the subviews in your UIScrollView.
Setting this value to true causes subviews to be clipped to the bounds of the receiver. If set to false, subviews whose frames extend beyond the visible bounds of the receiver are not clipped. The default value is false.
From Apple' doc : https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/index.html#//apple_ref/occ/instp/UIView/clipsToBounds

Scrollview doesn't cover all width

I have a ScrollView combined with a PageControll and it contains 5 images which I want them to scroll. My problem is that the ScrollView width even if it is 320 in simulator it doesn't show covering the all width.
This is my code:
override func viewDidLoad() {
super.viewDidLoad()
images.append(UIImage(named: "one.jpg")!)
images.append(UIImage(named: "two.jpg")!)
images.append(UIImage(named: "three.jpg")!)
images.append(UIImage(named: "four.jpg")!)
images.append(UIImage(named: "five.jpg")!)
for var i = 0; i < images.count; i++ {
var frame: CGRect = CGRectMake(0, 0, 0, 0)
frame.origin.x = self.scrollView.frame.size.width * CGFloat(i)
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
var imageView: UIImageView = UIImageView(frame: frame)
imageView.image = images[i]
self.scrollView.addSubview(imageView)
}
self.scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * CGFloat(images.count), scrollView.frame.size.height)
}
Most likely, the scroll view's width is the correct size, but the content-mode of the UIImageView is set incorrectly such that as a result of the image being displayed having a smaller size than the scroll view, it will not fill the whole of the image view as you wanted.
imageView.contentMode = UIViewContentModeScaleAspectFill;
// Swift
imageView.contentMode = .ScaleAspectFit
Try adding constraints to your image in your interface builder.
Put Constraints:
Main.storyboard -> UIImageView (for each UIImageView) -> Editor -> Pin -> Select leading,top space, bottom and trailing space to superview.
Your scrollView doesn't have constraints

Resources