UIImageView in ScrollView programmatically - ios

I'm trying add UIImageViews to the ScrollView to get horizontaly pagging effect.
let pagesScrollViewSize = scrollView.frame.size
scrollView.contentSize = CGSizeMake(pagesScrollViewSize.width * CGFloat(pageImages.count), pagesScrollViewSize.height)
for var index = 0; index < 3; ++index {
var frame = containerView.bounds
frame.origin.x = frame.size.width * CGFloat(index)
frame.origin.y = 0.0
let newPageView = UIImageView(image: pageImages[index])
newPageView.frame = frame
newPageView.contentMode = .ScaleAspectFit
scrollView.addSubview(newPageView)
}
Here is my layout:
But on phone/emulator image is scaled to ScrollView height. I want scale image to scrollview width, so on one page will be one image.

To scale image to scrollview width you need to resize (scale image to width) + crop image first. Setting content mode to ScaleAspectFit will only "...scale the content to fit the size of the view by maintaining the aspect ratio. Any remaining area of the view’s bounds is transparent".

The problem was that I was using autolayout in my Storyboard but I was adding new view's without adding constrains. So I've added this photos manualy in storyboard like was shown here: UIScrollView Paging Autolayout & Storyboard

Related

Reposition view which is going out of screen frame

I have a imageView inside a UIView which displays on top of button when that button is tapped. The position of the button is dynamic.
If the button is on the extreme right of the screen, on tap of that button, half of the view which displays is going out of screen (i.e., only half is displayed)
In the code below, I'm setting my view's frame equal to image width and its height, imageView's position is (center of image is on top center of button )
Pls advice how i can reposition the such that the view will always inside the bounds. Below is the code Im using to display my custom view on top of button
//calculate frame for view
let imageHeight = myImage.size.height
let imageWidth = myImage.size.width
let imageX = myButton.minX -
((myView.myImageView.bounds.width)/2) + 15
let imageY = currentCellRect.minY -
(myView.myImageView.bounds.height) + 15
let imageFrame = CGRect(x: imageX, y: imageY, width:
imageWidth, height: imageHeight)
//Assign calculated from to the tool tip view
toolTipView.frame = imageFrame
After calculating imageWidth and imageX you could make a check like this:
[...]
var imageX = myButton.minX -
((myView.myImageView.bounds.width)/2) + 15
imageX = min(imageX, view.frame.width - imageWidth)
[...]
Notice that i changed imageX from let to var.

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.

UIScrollView Content Size with Autolayout

I am using UIScrollView with Auto-layout to change contentSenter code hereize value as following :
UIView
ScrollView
UIView (contentView)
In run time I am adding UITextView & UIImageView to conentView with constraint(Top,Bottom,Left,Right)
but the contentView size is not changing and UIScrollView contentSize also.
So what could be the problem ?
In run time I am adding UITextView & UIImageView to conentView with constraint(Top,Bottom,Left,Right)
Maybe you should add constraint (Top, Left, Height, Width),or (Top, Left, Right, Height)
If you persist in (Top,Bottom,Left,Right), ScrollView will keep the old content size, and make your UITextView & UIImageView (Height = 0, Width = 0).
Here's a neat way of updating scroll view's content size. It's Swift so you'll need a bridging header if you're working in Objective C.
extension UIScrollView {
func updateContentViewSize() {
var newHeight: CGFloat = 0
for view in subviews {
let ref = view.frame.origin.y + view.frame.height
if ref > newHeight {
newHeight = ref
}
}
let oldSize = contentSize
let newSize = CGSize(width: oldSize.width, height: newHeight + 20)
contentSize = newSize
}
}
Just call it on your scroll view's object whenever you add a child view to your scroll view.

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