UIScrollView scrolls out of image after image is zoomed in? - ios

I'm trying to implement a image zooming functionality using UIScrollview. where as I kept image as aspect fit.
Image is inside a UIScrollView, and image frame has been given similar to UIScrollView.
Here is my code.
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view.
scroller.minimumZoomScale = 1.0
scroller.maximumZoomScale = 7.0
}
// MARK: - User Defined Methods
#IBAction func doubleTapGestureAction(_ sender: UITapGestureRecognizer)
{
if scroller.zoomScale == 1
{
scroller.zoom(to: zoomForScale(scale: scroller.maximumZoomScale, center: sender.location(in: sender.view)), animated: true)
}
else
{
scroller.setZoomScale(1, animated: true)
}
print(isZoomedIn)
}
func zoomForScale(scale: CGFloat, center: CGPoint) -> CGRect
{
var zoomRect = CGRect.zero
zoomRect.size.height = image.frame.size.height / scale
zoomRect.size.width = image.frame.size.width / scale
let newCenter = image.convert(center, from: scroller)
zoomRect.origin.x = newCenter.x - (zoomRect.size.width / 2.0)
zoomRect.origin.y = newCenter.y - (zoomRect.size.height / 2.0)
return zoomRect
}
func viewForZooming(in scrollView: UIScrollView) -> UIView?
{
return image
}

Here is sample code:
import UIKit
class ViewController: UIViewController,UIScrollViewDelegate {
var imgDemo: UIImageView = {
let img = UIImageView()
img.contentMode = .scaleAspectFill
img.isUserInteractionEnabled = true
return img
}()
var scrollView:UIScrollView = {
let scroll = UIScrollView()
scroll.maximumZoomScale = 4.0
scroll.minimumZoomScale = 0.25
scroll.clipsToBounds = true
return scroll
}()
override func viewDidLoad() {
super.viewDidLoad()
imgDemo.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height)
imgDemo.image = UIImage(named: "5.jpg")
scrollView.delegate = self
scrollView.frame = imgDemo.frame
scrollView.addSubview(imgDemo)
view.addSubview(scrollView)
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imgDemo
}
}

Take a look at these methods. May be it will help. I have scroll view stretched to controller's view size. customizeScrollView() will calculate min and max scale options. centerImageView() will put UIImageView in the center of your UIScrollView
Call the customizeScrollView function in viewDidload.
fileprivate func customizeScrollView() {
guard let image = imageView?.image else { return }
var minZoom = fmin(self.view.frame.width / image.size.width, self.view.frame.height / image.size.height)
minZoom = fmin(1.0, minZoom)
scrollView?.contentSize = image.size
scrollView?.minimumZoomScale = minZoom
scrollView?.addSubview(self.imageView!)
scrollView?.setZoomScale(minZoom, animated: false)
centerImageView()
}
fileprivate func centerImageView() {
guard let imageView = imageView else { return }
guard let scrollView = scrollView else { return }
let boundsSize = scrollView.bounds.size
var frameToCenter = imageView.frame
// Center horizontally
if frameToCenter.size.width < boundsSize.width {
frameToCenter.origin.x = (boundsSize.width - frameToCenter.size.width) / 2
} else {
frameToCenter.origin.x = 0
}
// Center vertically
if frameToCenter.size.height < boundsSize.height {
frameToCenter.origin.y = (boundsSize.height - frameToCenter.size.height) / 2
} else {
frameToCenter.origin.y = 0
}
imageView.frame = frameToCenter
}
public func scrollViewDidZoom(scrollView: UIScrollView) {
print(imageView.frame)
centerImageView()
}

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.
}
}

Image inside Scrollview with gestures

I have a control I'm making that includes having an image inside a scrollview, and I applied many gestures to it especially for zooming (pinch). Problem is, I want the scrollView's content size to match image new size without affecting:
Image center current location
Size
I can scroll to see all of image boundaries, with no extra space.
If there was anything not clear, please let me know.
You should do like this:
Swift3:
import UIKit
class ViewController: UIViewController,UIScrollViewDelegate
{
#IBOutlet weak var ScrollView: UIScrollView!
#IBOutlet weak var ScrollImgView: UIImageView!
override func viewDidLoad()
{
super.viewDidLoad()
self.ScrollView.minimumZoomScale = 0.1
self.ScrollView.maximumZoomScale = 5.0
ScrollView.isUserInteractionEnabled = true
}
func viewForZooming(in scrollView: UIScrollView) -> UIView?
{
return self.ScrollImgView
}
func scrollViewDidZoom(_ scrollView: UIScrollView)
{
let imgViewSize:CGSize! = self.ScrollImgView.frame.size;
let imageSize:CGSize! = self.ScrollImgView.image?.size;
var realImgSize : CGSize;
if(imageSize.width / imageSize.height > imgViewSize.width / imgViewSize.height)
{
realImgSize = CGSize(width: imgViewSize.width,height: imgViewSize.width / imageSize.width * imageSize.height);
}
else
{
realImgSize = CGSize(width: imgViewSize.height / imageSize.height * imageSize.width, height: imgViewSize.height);
}
var fr:CGRect = CGRect.zero
fr.size = realImgSize;
self.ScrollImgView.frame = fr;
let scrSize:CGSize = scrollView.frame.size;
let offx:CGFloat = (scrSize.width > realImgSize.width ? (scrSize.width - realImgSize.width) / 2 : 0);
let offy:CGFloat = (scrSize.height > realImgSize.height ? (scrSize.height - realImgSize.height) / 2 : 0);
scrollView.contentInset = UIEdgeInsetsMake(offy, offx, offy, offx);
let scrollViewSize:CGSize = self.scrollViewVisibleSize();
var imageCenter:CGPoint = CGPoint(x: self.ScrollView.contentSize.width/2.0, y:
self.ScrollView.contentSize.height/2.0);
let scrollViewCenter:CGPoint = self.scrollViewCenter()
if (self.ScrollView.contentSize.width < scrollViewSize.width)
{
imageCenter.x = scrollViewCenter.x;
}
if (self.ScrollView.contentSize.height < scrollViewSize.height)
{
imageCenter.y = scrollViewCenter.y;
}
self.ScrollImgView.center = imageCenter;
}
func scrollViewCenter() -> CGPoint
{
let scrollViewSize:CGSize = self.scrollViewVisibleSize()
return CGPoint(x: scrollViewSize.width/2.0, y: scrollViewSize.height/2.0);
}
func scrollViewVisibleSize() -> CGSize
{
let contentInset:UIEdgeInsets = self.ScrollView.contentInset;
let scrollViewSize:CGSize = self.ScrollView.bounds.standardized.size;
let width:CGFloat = scrollViewSize.width - contentInset.left - contentInset.right;
let height:CGFloat = scrollViewSize.height - contentInset.top - contentInset.bottom;
return CGSize(width:width, height:height);
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
}

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.

UIButton not showing when UIScrollView showing on ViewController

I have a UIViewController that is attached to a class, Swift code below. The code basically adds to the View Controller a UIScrollView with an image.
I am wanting to add a UIButton to the ViewController which I could do through code, however in this case, I want to add the UIButton to the ViewController using the Storyboard.
When I add a UIButton and then run my project, the UIButton is not visible, only the UIScrollView is visible.
Question:
What is going on, why is the UIButton not visible? How can I add a UIButton (to the Storyboard) and ensure that it is visible and in front of the UIScrollView (that is created programatically) when I run the project?
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)
}
}
}
Your scrollview is blocking the UIButton on z axis, please use
- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index;
to insert scrollview below UIButton
Swift:
func insertSubview(view: UIView, atIndex index: Int) {
}
Answer:
Instead of this line view.addSubview(scrollView), you need to do self.view.insertSubview(scrollView, atIndex: 0) and make sure UIButton is above the scrollView.
You have to write:
self.view.insertSubview(scrollview, belowSubview: button)

UIscrollView Paging and Zooming images in swift

Having a image array(Download from server) which i want to show in scrollview with paging and zooming enable but i didn't find any solution. I am searching a lot but i didn't get any solution.
Any help is really appreciating.
Thanks!
In MainController
var mainScrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
var x:CGFloat = 0
mainScrollView = UIScrollView(frame: view.bounds)
mainScrollView.pagingEnabled = true
let images=["image.png","photo.jpg","3.png"]
for var i = 0; i < images.count; i++
{
let imageView = UIImageView(image: UIImage(named: images[i]))
let scrollView = SlideShow(image: imageView, scrollFrame: CGRectMake(x, view.bounds.origin.y, view.bounds.width, view.bounds.height))
x = x + UIScreen.mainScreen().bounds.size.width
mainScrollView.addSubview(scrollView)
}
mainScrollView.contentSize=CGSizeMake(x, self.mainScrollView.frame.size.height);
mainScrollView.contentOffset=CGPointMake(0, 0);
view.addSubview(mainScrollView)
// Do any additional setup after loading the view.
}
In SubClass
public class SlideShow: UIScrollView, UIScrollViewDelegate {
public var imageView = UIImageView()
// MARK: - Life cycle
init(image: UIImageView, scrollFrame: CGRect) {
super.init(frame: scrollFrame)
//image.setToImageView(imageView)
imageView = image
imageView.clipsToBounds = true
imageView.userInteractionEnabled = true
// UIScrollView(frame: bounds)
delegate = self
showsVerticalScrollIndicator = false
showsHorizontalScrollIndicator = false
backgroundColor = UIColor.blackColor()
// contentSize = imageView.bounds.size
// autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
contentOffset = CGPoint(x: 1000, y: 450)
addSubview(imageView)
// setZoomScale()
setupGestureRecognizer()
}
func setupGestureRecognizer() {
let doubleTap = UITapGestureRecognizer(target: self, action: "handleDoubleTap:")
doubleTap.numberOfTapsRequired = 2
addGestureRecognizer(doubleTap)
}
func handleDoubleTap(recognizer: UITapGestureRecognizer) {
if (zoomScale > minimumZoomScale) {
setZoomScale(minimumZoomScale, animated: true)
} else {
setZoomScale(maximumZoomScale, animated: true)
}
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override public func layoutSubviews() {
setZoomScale()
//setZoomScale(minimumZoomScale, animated: false)
}
public func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return imageView
}
func setZoomScale() {
let imageViewSize = imageView.bounds.size
let scrollViewSize = bounds.size
let widthScale = scrollViewSize.width / imageViewSize.width
let heightScale = scrollViewSize.height / imageViewSize.height
minimumZoomScale = min(widthScale, heightScale)
zoomScale = 1.0
}
public func scrollViewDidZoom(scrollView: UIScrollView) {
let imageViewSize = imageView.frame.size
let scrollViewSize = 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)
}
}
Solution 1 :- Agrume Library with load photo url.
There are multiple ways you can use the image viewer (and the included Example project shows them all).
This one is best library for that.
Solution 2 :-
This library provide multiple images and zoom also.

Resources