UIscrollView Paging and Zooming images in swift - ios

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.

Related

Zoom on UIView contained in UIScrollView

I have some trouble handling zoom on UIScrollView that contains many subviews. I already saw many answers on SO, but none of them helped me.
So, basically what I'm doing is simple : I have a class called UIFreeView :
import UIKit
class UIFreeView: UIView, UIScrollViewDelegate {
var mainUIView: UIView!
var scrollView: UIScrollView!
var arrayOfView: [UIView]?
override init(frame: CGRect) {
super.init(frame: frame)
self.setupView()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
fileprivate func setupView() {
// MainUiView
self.mainUIView = UIView(frame: self.frame)
self.addSubview(mainUIView)
// ScrollView
self.scrollView = UIScrollView(frame: self.frame)
self.scrollView.delegate = self
self.addSubview(self.scrollView)
}
func reloadViews(postArray:[Post]?) {
if let postArray = postArray {
print("UIFreeView::reloadVIew.postArraySize = \(postArray.count)")
let size: CGFloat = 80.0
let margin: CGFloat = 20.0
scrollView.contentSize.width = (size * CGFloat(postArray.count))+(margin*CGFloat(postArray.count))
scrollView.contentSize.height = (size * CGFloat(postArray.count))+(margin*CGFloat(postArray.count))
for item in postArray {
let view = buildPostView(item)
self.scrollView.addSubview(view)
}
}
}
fileprivate func buildPostView(_ item:Post) -> UIView {
// Const
let size: CGFloat = 80.0
let margin: CGFloat = 5.0
// Var
let view = UIView()
let textView = UITextView()
let backgroundImageView = UIImageView()
// Setup view
let x = CGFloat(UInt64.random(lower: UInt64(0), upper: UInt64(self.scrollView.contentSize.width)))
let y = CGFloat(UInt64.random(lower: UInt64(0), upper: UInt64(self.scrollView.contentSize.height)))
view.frame = CGRect(x: x,
y: y,
width: size,
height: size)
// Setup background view
backgroundImageView.frame = CGRect(x: 0,
y: 0,
width: view.frame.size.width,
height: view.frame.size.height)
var bgName = ""
if (item.isFromCurrentUser) {
bgName = "post-it-orange"
} else {
bgName = "post-it-white"
}
backgroundImageView.contentMode = .scaleAspectFit
backgroundImageView.image = UIImage(named: bgName)
view.addSubview(backgroundImageView)
// Setup text view
textView.frame = CGRect(x: margin,
y: margin,
width: view.frame.size.width - margin*2,
height: view.frame.size.height - margin*2)
textView.backgroundColor = UIColor.clear
textView.text = item.content
textView.isEditable = false
textView.isSelectable = false
textView.isUserInteractionEnabled = false
view.addSubview(textView)
let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
view.addGestureRecognizer(gestureRecognizer)
return view
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return self.scrollView
}
func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
if gestureRecognizer.state == .began || gestureRecognizer.state == .changed {
let translation = gestureRecognizer.translation(in: self.scrollView)
// note: 'view' is optional and need to be unwrapped
gestureRecognizer.view!.center = CGPoint(x: gestureRecognizer.view!.center.x + translation.x, y: gestureRecognizer.view!.center.y + translation.y)
gestureRecognizer.setTranslation(CGPoint.zero, in: self.scrollView)
}
}
/*
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
// Drawing code
}
*/
}
This class is working perfectly, I can scroll through all my views, but I can't zoom-in and zoom-out in order to see less/more views on my screen.
I think the solution is simple, but I can't seem to find a real solution for my problem ..
Thanks !

UIScrollView scrolls out of image after image is zoomed in?

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()
}

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)

scrollViewDidEndZooming not called while zooming in a UIScrollView

This could possibly be an Xcode bug? I have an UIImage inside a UIScrollView done programatically in code. The user can zoom into the image using the zoom gesture or double tapping the image. This part all works fine.
Next, I am trying to detect when the scroll view has finished zooming after a zoom gesture or double tap using the below function scrollViewDidEndZooming. However, scrollViewDidEndZooming never gets called, and doesn't print the line I just finished zooming!
Code not working:
func scrollViewDidEndZooming(scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {
print("I just finished zooming!")
}
Question:
What might be going on here, why isn't scrollViewDidEndZooming(...)
getting called?
Note: I've referred to the below document with no luck.
https://developer.apple.com/reference/uikit/uiscrollviewdelegate/1619407-scrollviewdidendzooming
Complete code:
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 scrollViewDidEndZooming(scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {
print("I just finished zooming!")
}
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)
}
}
}
You make a small mistake. Try this code:
func scrollViewDidEndZooming(scrollView: UIScrollView, withView view: UIView?, atScale scale: CGFloat) {
print("I just finished zooming!")
}

Resources