zoom image with scrollview swift ios - ios

I have a problem with zooming an image with scroll view.
If I put the scroll view on the left with width 125 and height 375, it does not zoom the image.
It only works if I put the scroll view on the center of the view.
Screenshot:
Why is the scroll view not zooming when it's on the left side?
Here is my code
var imgview:UIImageView!
var imagepicked:UIImage!
var minZoomScale:CGFloat!
let picker = UIImagePickerController()
#IBOutlet weak var scrollViewSquare: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
picker.delegate = self
scrollViewSquare.delegate = self
picker.allowsEditing = false
picker.sourceType = .PhotoLibrary
}
func imagePickerController(
picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [String : AnyObject])
{
imagepicked = (info[UIImagePickerControllerOriginalImage] as? UIImage)!
ImageViewInit()
dismissViewControllerAnimated(false, completion: nil)
}
#IBAction func Pick(sender: AnyObject) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.SavedPhotosAlbum){
self.presentViewController(picker, animated: true, completion: nil)
}
}
func ImageViewInit(){
imgview = UIImageView()
imgview.frame = CGRectMake(0, 0, imagepicked.size.width, imagepicked.size.height)
imgview.image = imagepicked
imgview.contentMode = .ScaleAspectFit
imgview.backgroundColor = UIColor.greenColor()
scrollViewSquare.maximumZoomScale = 4;
scrollViewSquare.minimumZoomScale = 0.02;
scrollViewSquare.bounces = true;
scrollViewSquare.bouncesZoom = true;
scrollViewSquare.contentMode = .ScaleAspectFit
scrollViewSquare.contentSize = imagepicked.size
scrollViewSquare.autoresizingMask = UIViewAutoresizing.FlexibleWidth
scrollViewSquare.addSubview(imgview)
setZoomScale()
}
func setZoomScale(){
let imageViewSize = imgview.bounds.size
let scrollViewSize = scrollViewSquare.bounds.size
let widthScale = scrollViewSize.width / imageViewSize.width
let heightScale = scrollViewSize.height / imageViewSize.height
minZoomScale = max(widthScale, heightScale)
scrollViewSquare.minimumZoomScale = minZoomScale
scrollViewSquare.zoomScale = minZoomScale
}
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return imgview
}

Hello #Bensalem Ilyes,
I've tried your code and zooming does not work on simulator because the centre of pinch gesture is in the midle so pinch on scrollview is translated as simple pan gesture. I tried your code on real device and zooming works fine.
For repositioning pinch gesture on simulator:
alt+shift key

Related

Image Zoom using uiscrollview working unexpectedly. swift

I was developing an app in which a user adds a photo and edits it. When the image is added to imageView and zoomed it works fine but when I add a new image, unexpectedly the scrollView increases in length and the image is viewed in the middle of the scrollView has coded, but the scrollView increases in size. I have to scroll to the middle to view the image. Below is the code I am using.
#IBAction func addPhotoTrigered(_ sender: Any) {
addPhotoCall()
}
func addPhotoCall() {
print("dsds")
let image = UIImagePickerController()
image.delegate = self
image.sourceType = UIImagePickerControllerSourceType.photoLibrary
image.allowsEditing = false
self.present(image, animated: true) {
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
imagePic = info[UIImagePickerControllerOriginalImage] as? UIImage
addImageView.isHidden = true
imageView.image = imagePic
newImageButton.isHidden = false
photoStatus = true
imageView.contentMode = UIViewContentMode.center
imageView.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: imagePic!.size.width, height: imagePic!.size.height))
print(imageView.frame)
scrollView.contentSize = imagePic!.size
let scrollViewFrame = scrollView.frame
let scrollWidth = scrollViewFrame.size.width / scrollView.contentSize.width
let scrollHeight = scrollViewFrame.size.height / scrollView.contentSize.height
let minScale = min(scrollHeight, scrollWidth)
scrollView.minimumZoomScale = minScale
scrollView.maximumZoomScale = 1.0
scrollView.zoomScale = minScale
centreScrollViewContent()
self.dismiss(animated: true, completion: nil)
}
func centreScrollViewContent() {
let boundSize = scrollView.bounds.size
var contentFrame = imageView.frame
if contentFrame.size.width < boundSize.width {
contentFrame.origin.x = (boundSize.width - contentFrame.size.width) / 2
} else {
contentFrame.origin.x = 0
}
if contentFrame.size.height < boundSize.height {
contentFrame.origin.y = (boundSize.height - contentFrame.size.height) / 2
} else {
contentFrame.origin.y = 0
}
imageView.frame = contentFrame
}
func scrollViewDidZoom(_ scrollView: UIScrollView) {
centreScrollViewContent()
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
#IBAction func newImageTrigered(_ sender: Any) {
imageView.image = nil
addImageView.isHidden = false
newImageButton.isHidden = true
}
please fix the code. I have tried many ways but was not able to understand why its happening.
make an outlet from your scroll view and put delegate self and add uiscrollViewDelegate to viewcontroller and then it should work
i have a sample code to
class ViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
updateZoomFor(size: scrollView.bounds.size)
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
func updateZoomFor(size: CGSize) {
let widthScale = size.width / imageView.bounds.width
let heightScale = size.height / imageView.bounds.height
let scale = min(widthScale, heightScale)
scrollView.minimumZoomScale = scale
scrollView.maximumZoomScale = 5
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

Scrollview only zooms to upper left corner

I've created a scrollview programmatically and added an image as it's subview but when I try to zoom into the image it only zooms into the upper corner and it doesn't let me scroll around to see different parts of the image.
Here's the code I used to create the scrollview:
let scrollView = UIScrollView()
var image: NSData!
override func viewDidLoad() {
super.viewDidLoad()
scrollView.minimumZoomScale = 1.0
scrollView.maximumZoomScale = 3.0
scrollView.zoomScale = 1.0
scrollView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height)
scrollView.delegate = self
scrollView.isPagingEnabled = false
scrollView.contentSize = CGSize(width: self.view.frame.width, height: self.view.frame.height)
view.addSubview(scrollView)
scrollView.addSubview(imageView)
imageView.image = UIImage(data: image as Data)
imageView.contentMode = .scaleAspectFit
imageView.isUserInteractionEnabled = true
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(share))
longPress.minimumPressDuration = 0.5
longPress.numberOfTapsRequired = 0
imageView.addGestureRecognizer(longPress)
let doubleTap = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap(recognizer:)))
doubleTap.numberOfTapsRequired = 2
scrollView.addGestureRecognizer(doubleTap)
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
func share(sender: UILongPressGestureRecognizer) {
if sender.state == .ended {
if UIImage(data: image as Data) != nil {
let Item = UIImage(data: self.image! as Data)
let activity = UIActivityViewController(activityItems: [Item!], applicationActivities: nil)
activity.excludedActivityTypes = [UIActivityType.print, UIActivityType.addToReadingList, UIActivityType.openInIBooks]
self.present(activity, animated: true, completion: nil)
}
}
}
func handleDoubleTap(recognizer: UITapGestureRecognizer) {
if scrollView.zoomScale > scrollView.minimumZoomScale {
scrollView.setZoomScale(scrollView.minimumZoomScale, animated: true)
} else {
scrollView.setZoomScale(scrollView.maximumZoomScale, animated: true)
}
}
Thank you very much for any kind of help
The issue is in your code when you set the zoomscale of your scrollView. You don't specify where it should zoom to. So naturally, it zooms and stays in the top left corner.
You need to get the location of the touch in your handleDoubleTap(recognizer: UITapGestureRecognizer), calculate the rect for zoom, and call scrollRectToVisible on your scrollview.

Zooming into an image from user's touch point with UIScrollView in Swift

The below Swift code manages zooming in and out of an UIImage inside a UIScrollView.
When double tapping, the image zooms into the centre and zooms out to the centre.
Question:
What code changes need to be made to set the zoom in point to be the centre of the image area the user touches on screen?
(For example, if the user double taps the top left of the image, the image would correspondingly zoom into the top left of the image.)
class ScrollViewController: UIViewController, UIScrollViewDelegate {
var scrollView: UIScrollView!
var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
imageView = UIImageView(image: UIImage(named: "image.png"))
scrollView = UIScrollView(frame: view.bounds)
scrollView.backgroundColor = UIColor.blackColor()
scrollView.contentSize = imageView.bounds.size
scrollView.autoresizingMask = [UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleHeight]
scrollView.contentOffset = CGPoint(x: 1000, y: 450)
scrollView.addSubview(imageView)
view.addSubview(scrollView)
scrollView.delegate = self
setZoomScale()
setupGestureRecognizer()
}
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return imageView
}
override func viewWillLayoutSubviews() {
setZoomScale()
}
func setZoomScale() {
let imageViewSize = imageView.bounds.size
let scrollViewSize = scrollView.bounds.size
let widthScale = scrollViewSize.width / imageViewSize.width
let heightScale = scrollViewSize.height / imageViewSize.height
scrollView.minimumZoomScale = min(widthScale, heightScale)
scrollView.zoomScale = 1.0
}
func scrollViewDidZoom(scrollView: UIScrollView) {
let imageViewSize = imageView.frame.size
let scrollViewSize = scrollView.bounds.size
let verticalPadding = imageViewSize.height < scrollViewSize.height ? (scrollViewSize.height - imageViewSize.height) / 2 : 0
let horizontalPadding = imageViewSize.width < scrollViewSize.width ? (scrollViewSize.width - imageViewSize.width) / 2 : 0
scrollView.contentInset = UIEdgeInsets(top: verticalPadding, left: horizontalPadding, bottom: verticalPadding, right: horizontalPadding)
}
func setupGestureRecognizer() {
let doubleTap = UITapGestureRecognizer(target: self, action: "handleDoubleTap:")
doubleTap.numberOfTapsRequired = 2
scrollView.addGestureRecognizer(doubleTap)
}
func handleDoubleTap(recognizer: UITapGestureRecognizer) {
if (scrollView.zoomScale > scrollView.minimumZoomScale) {
scrollView.setZoomScale(scrollView.minimumZoomScale, animated: true)
} else {
scrollView.setZoomScale(scrollView.maximumZoomScale, animated: true)
}
}
}
According to this post. It works fine with me.
func handleDoubleTap(recognizer: UITapGestureRecognizer) {
if (scrollView.zoomScale > scrollView.minimumZoomScale) {
scrollView.setZoomScale(scrollView.minimumZoomScale, animated: true)
} else {
let touchPoint = recognizer.locationInView(view)
let scrollViewSize = scrollView.bounds.size
let width = scrollViewSize.width / scrollView.maximumZoomScale
let height = scrollViewSize.height / scrollView.maximumZoomScale
let x = touchPoint.x - (width/2.0)
let y = touchPoint.y - (height/2.0)
let rect = CGRectMake(x, y, width, height)
scrollView.zoomToRect(rect, animated: true)
}
}
Here's a Swift 2.3 function for returning the location of a touch inside a zoomable UIScrollView:
UIScrollView with UIImageView inside
Zoomed or not - scrollView.zoomScale
imageView.contentMode = .ScaleAspectFit
The image can be bigger, high res than imageView and scrollView
Any shape of the image, portrait, landscape or square
imageView.contentMode = .ScaleAspectFit
//import AVFoundation // needed for AVMakeRectWithAspectRatioInsideRect()
func getLocationOfTouchInImageInScrollView(paintLocation:CGPoint)->CGPoint {
let imageSize = imageViewInScrollView.image!.size
let imageFrame = scrollView.frame
let imageRect = AVMakeRectWithAspectRatioInsideRect(imageSize, imageFrame)
let imageHeightToViewHeight = max(imageSize.height, imageSize.width) / imageFrame.size.height
let px = (max(0, min(imageSize.width, ((paintLocation.x - imageRect.origin.x) * imageHeightToViewHeight))))
let py = (max(0, min(imageSize.height, ((paintLocation.y - imageRect.origin.y ) * imageHeightToViewHeight))))
var imageTouchPoint = CGPointMake(CGFloat(px), CGFloat(py))
return imageTouchPoint
}
Took me DAYS to write this one since I couldn't figure out the imageHeightToViewHeight variable, thought there was something else funny going on.

Paging UIScrollView seems to place content off centre

I have a UIScrollView that I want to have paging functionality (think an initial splash screen). I want that content (a UILabel and a UIImageView) to be placed centrally in each paging view on the scrollView. My problem is is that it is always slightly off centre ().
Here is the complete code:
var splashScreenObjects = [SplashScreenObject]()
var imageViewArray = [UIImageView]()
var subtitleViewArray = [UILabel]()
#IBOutlet var scrollView: UIScrollView!
#IBOutlet var pageControl: UIPageControl!
override func viewDidLoad() {
super.viewDidLoad()
createSplashScreenObjects()
configurePageControl()
configureScrollView()
}
func createSplashScreenObjects() {
let firstScreen: SplashScreenObject = SplashScreenObject(subtitle: "Medication reminders on your phone. Never miss your next dose", image: UIImage(named: "splashScreen1")!)
let secondScreen: SplashScreenObject = SplashScreenObject(subtitle: "Track how good you have been with your medication", image: UIImage(named: "splashScreen2")!)
let thirdScreen: SplashScreenObject = SplashScreenObject(subtitle: "The better you are with your medication, the more points you'll earn!", image: UIImage(named: "splashScreen3")!)
splashScreenObjects.append(firstScreen)
splashScreenObjects.append(secondScreen)
splashScreenObjects.append(thirdScreen)
}
func configureScrollView() {
self.scrollView.layoutIfNeeded()
self.scrollView.showsHorizontalScrollIndicator = false
self.scrollView.showsVerticalScrollIndicator = false
self.scrollView.pagingEnabled = true
self.scrollView.delegate = self
let width = view.frame.size.width
for index in 0..<splashScreenObjects.count {
let subtitle = UILabel(frame: CGRectMake((width * CGFloat(index)) + 25, self.scrollView.frame.size.height-75, width-50, 75))
subtitle.text = splashScreenObjects[index].subtitle
subtitle.textAlignment = NSTextAlignment.Center
subtitle.textColor = UIColor.whiteColor()
subtitle.font = UIFont(name:"Ubuntu", size: 16)
subtitle.numberOfLines = 2
subtitle.backgroundColor = UIColor.clearColor()
self.scrollView.addSubview(subtitle)
self.subtitleViewArray.append(subtitle)
subtitle.alpha = 0
let mainImage = UIImageView(frame: CGRectMake((width * CGFloat(index)), 50, width, self.scrollView.frame.size.height-150))
mainImage.image = splashScreenObjects[index].image
mainImage.contentMode = UIViewContentMode.ScaleAspectFit
self.scrollView.addSubview(mainImage)
self.imageViewArray.append(mainImage)
mainImage.alpha = 0
}
self.scrollView.contentSize = CGSizeMake(width * CGFloat(splashScreenObjects.count), self.scrollView.frame.size.height-50)
animateViews(Int(0))
}
func configurePageControl() {
self.pageControl.numberOfPages = splashScreenObjects.count
self.pageControl.currentPage = 0
self.view.addSubview(pageControl)
pageControl.addTarget(self, action: #selector(SplashViewController.changePage(_:)), forControlEvents: UIControlEvents.ValueChanged)
}
func changePage(sender: AnyObject) -> () {
let x = CGFloat(pageControl.currentPage) * self.view.frame.size.width
scrollView.setContentOffset(CGPointMake(x, 0), animated: true)
}
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
let pageNumber = round(scrollView.contentOffset.x / self.view.frame.size.width)
pageControl.currentPage = Int(pageNumber)
animateViews(Int(pageNumber))
}
func animateViews(pageNumber: Int) {
UIView.animateWithDuration(0.5, animations: {
self.imageViewArray[pageNumber].alpha = 1.0
self.subtitleViewArray[pageNumber].alpha = 1.0
})
}
Here are my auto layout constraints for the UIScrollView:
Your leading and trailing spaces are both -20, which means that the scroll view is 40 points wider than its superview. Change these to 0.
You should replace
self.scrollView.layoutIfNeeded()
to
self.view.layoutIfNeeded()
because layoutIfNeeded layout caller subviews, not itself. So, scrollView, when you add subtitle and mainImage on it, has wrong frame.

ImageView in a ScrollView to zoom, crop and save swift

I am trying to let the user make a profile picture on my app, but I have been running into problems I can seem to solve.
I have added a uiscrollview on my viewcontroller. Next I added a UIimageview into the uiscrollview, both are the same width and height.
The first thing I was trying to solve is I wanted the picture the user inputs to fill the uiimageview by the shortest side. So if the image had a width of 500 and height of 1000, I want the width to fill the image view with the extra height off the top and bottom waiting for the user to scroll.
I am also having trouble panning images. It seems like I can't pan an image until I pinch zoom on the image. Saying this I also think my full image is not being displayed which may be causing some problems, I'm not sure why.
class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate, UIScrollViewDelegate {
#IBOutlet var scrollView: UIScrollView!
#IBOutlet var imageViewPicture: UIImageView!
#IBOutlet var addPicture: UIButton!
let image = UIImagePickerController()
#IBAction func addPicture(sender: AnyObject) {
self.presentViewController(image, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
self.dismissViewControllerAnimated(true, completion: nil)
imageViewPicture.image = image
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.orangeColor()
self.scrollView.backgroundColor = UIColor.blueColor()
self.scrollView.delegate = self
//setting the min and max amount of zoom on the picture
self.scrollView.minimumZoomScale = 1.0
self.scrollView.maximumZoomScale = 4.0
self.scrollView.bouncesZoom = false
self.scrollView.bounces = false
self.scrollView.alwaysBounceVertical = false
self.scrollView.alwaysBounceHorizontal = false
self.scrollView.scrollEnabled = true
image.delegate = self
image.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
image.allowsEditing = false
scrollView.layer.cornerRadius = (imageViewPicture.frame.size.width) / 2
scrollView.layer.masksToBounds = true
//gets rid of the indicator that shows where you are when scrolling
scrollView.showsHorizontalScrollIndicator = false
scrollView.showsVerticalScrollIndicator = false
imageViewPicture.userInteractionEnabled = true
let doubleTap = UITapGestureRecognizer(target: self, action: "doubleTapped")
doubleTap.numberOfTapsRequired = 2
imageViewPicture.addGestureRecognizer(doubleTap)
}
func doubleTapped() {
if scrollView.zoomScale > 1.0 {
scrollView.zoomScale = 1.0
} else {
scrollView.zoomScale = 2.0
}
}
func cropAndSave() {
UIGraphicsBeginImageContextWithOptions(scrollView.bounds.size, true, UIScreen.mainScreen().scale)
let offset = scrollView.contentOffset
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), -offset.x, -offset.y)
scrollView.layer.renderInContext(UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return self.imageViewPicture
}
Background:
UIScrollview (with user interaction enabled and multiple touch enabled)added in the storyboard and set the height width ration 1 - just to make it a square. Panning and zooming is possible with this. I did not do additional set up like corner radius etc. I did this recently - thought it may help you.
class ViewController: UIViewController, UIImagePickerControllerDelegate,UINavigationControllerDelegate ,UIScrollViewDelegate{
var imgview: UIImageView!
var imagepicked:UIImage!
#IBOutlet weak var scrollViewSquare: UIScrollView!
let picker = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
picker.delegate = self
scrollViewSquare.delegate = self
//ImageViewInit()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func ImageViewInit(){
imgview = UIImageView()
imgview.frame = CGRectMake(0, 0, imagepicked.size.width, imagepicked.size.height)
imgview.image = imagepicked
imgview.contentMode = .ScaleAspectFit
imgview.backgroundColor = UIColor.lightGrayColor()
scrollViewSquare.maximumZoomScale=4;
scrollViewSquare.minimumZoomScale=0.02;
scrollViewSquare.bounces=true;
scrollViewSquare.bouncesZoom=true;
scrollViewSquare.contentMode = .ScaleAspectFit
scrollViewSquare.contentSize = imagepicked.size
scrollViewSquare.autoresizingMask = UIViewAutoresizing.FlexibleWidth
scrollViewSquare.addSubview(imgview)
setZoomScale()
}
var minZoomScale:CGFloat!
func setZoomScale(){
let imageViewSize = imgview.bounds.size
let scrollViewSize = scrollViewSquare.bounds.size
let widthScale = scrollViewSize.width / imageViewSize.width
let heightScale = scrollViewSize.height / imageViewSize.height
minZoomScale = max(widthScale, heightScale)
scrollViewSquare.minimumZoomScale = minZoomScale
scrollViewSquare.zoomScale = minZoomScale
print("height nd width scale \(widthScale) & \(heightScale) Min zoom scale \(minZoomScale)")
}
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return imgview
}
func imagePickerController(
picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [String : AnyObject])
{
imagepicked = (info[UIImagePickerControllerOriginalImage] as? UIImage)!
print("Image (h,w) = (\(imagepicked.size.height) , \(imagepicked.size.width))")
ImageViewInit()
dismissViewControllerAnimated(false, completion: nil)
}
#IBAction func Pick(sender: AnyObject) {
picker.allowsEditing = false
picker.sourceType = .PhotoLibrary
presentViewController(picker, animated: true, completion: nil)
}
}

Resources