I'm a newbie to swift development and I was looking for help for this use case of panning, zooming image and gestures.
On android this library provides all the functionalities
https://github.com/davemorrissey/subsampling-scale-image-view
Any help from people who have solved this on the iOS ?
If you're allowed/able to use UIKit, this works very well for me:
import UIKit
class PanZoomImageViewController : UIViewController, UIScrollViewDelegate
{
#IBOutlet private weak var imageView: UIImageView!
#IBOutlet private weak var scrollView: UIScrollView!
var image: UIImage?
override func viewDidLoad()
{
super.viewDidLoad()
scrollView.contentSize = CGSize(width: image?.size.width ?? 0, height: image?.size.height ?? 0)
scrollView.minimumZoomScale = 1.0
scrollView.maximumZoomScale = 4.0
imageView.image = image
}
#IBAction private func dismiss()
{
dismiss(animated: true)
}
func viewForZooming(in scrollView: UIScrollView) -> UIView?
{
return imageView
}
}
Related
I am new to iOS and swift, I was trying to override scrollViewDidScroll() from UIScrollViewDelegate but it was showing me "Method does not override any method from its superclass" , I was following this tutorial https://www.youtube.com/watch?v=XQ3CVd8-zNE
This is the code I did.
class ViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var scrolliew: UIScrollView!
#IBOutlet weak var pageControl: UIPageControl!
var contentWidth:CGFloat=0.0
override func viewDidLoad() {
super.viewDidLoad()
scrolliew.delegate=self
for image in 0...3 {
let imageToDisplay = UIImage(named:"\(image).png")
let imageView = UIImageView(image:imageToDisplay)
scrolliew.addSubview(imageView)
let xCordinates = view.frame.minX + view.frame.width * CGFloat(image)
contentWidth += view.frame.width
imageView.frame=CGRect(x:xCordinates,y:view.frame.height/2,width:100,height:100)
}
scrolliew.contentSize=CGSize(width: contentWidth, height: view.frame.height)
}
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
//my code here
}
}
You don't actually have to override the method. scrollViewDidScroll(...) is part of the UIScrollViewDelegate protocol whose implementation is optional.
Just remove the override keyword in order to fix the error.
I have an image view as a subview of a UIScrollView in order to enable zooming the image. It somewhat works but not well.
class LargeImageViewController: UIViewController {
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var imageViewBottomConstraint: NSLayoutConstraint!
#IBOutlet weak var imageViewLeadingConstraint: NSLayoutConstraint!
#IBOutlet weak var imageViewTopConstraint: NSLayoutConstraint!
#IBOutlet weak var imageViewTrailingConstraint: NSLayoutConstraint!
var selectedImage: UIImage?
override func viewDidLoad() {
super.viewDidLoad()
if let image = selectedImage {
imageView.image = image
}
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
updateMinZoomScaleForSize(view.bounds.size)
}
func updateMinZoomScaleForSize(_ size: CGSize) {
let widthScale = size.width / imageView.bounds.width
let heightScale = size.height / imageView.bounds.height
let minScale = min(widthScale, heightScale)
scrollView.minimumZoomScale = minScale
scrollView.zoomScale = minScale
}
#IBAction func doneTapped(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
}
extension LargeImageViewController: UIScrollViewDelegate {
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
func scrollViewDidZoom(_ scrollView: UIScrollView) {
updateConstraintsForSize(view.bounds.size)
}
func updateConstraintsForSize(_ size: CGSize) {
let yOffset = max(0, (size.height - imageView.frame.height) / 2)
imageViewTopConstraint.constant = yOffset
imageViewBottomConstraint.constant = yOffset
let xOffset = max(0, (size.width - imageView.frame.width) / 2)
imageViewLeadingConstraint.constant = xOffset
imageViewTrailingConstraint.constant = xOffset
view.layoutIfNeeded()
}
}
Any ideas?
I have now tried following the tutorial suggested and it behaves a little better, but the image is zoomed in and huge.
My constraints are still giving me issues even though I followed the tutorial.
Couple reasons your code is not working like the tutorial.
1 - You missed setting the scroll view delegate (unless you set it in Storyboard). If you did not set it in Storyboard:
override func viewDidLoad() {
super.viewDidLoad()
if let image = selectedImage {
imageView.image = image
}
// add this
scrollView.delegate = self
}
2 - It will still not be quite correct, because the tutorial sets the image in Storyboard, but you're setting it in viewDidLoad(). To fix that:
// remove this
//override func viewWillLayoutSubviews() {
// super.viewWillLayoutSubviews()
// updateMinZoomScaleForSize(view.bounds.size)
//}
// add this
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
updateMinZoomScaleForSize(scrollView.bounds.size)
updateConstraintsForSize(scrollView.bounds.size)
}
3 - To get rid of the constraint errors in your Storyboard, give the image view Width and Height constraints (such as 100 each), and set them as Placeholders so they will not be used at run-time:
Can't say for sure where the problem is since you've probably configured the storyboard/xib file as well.
However, I recommend you to go through the guide: https://www.raywenderlich.com/5758454-uiscrollview-tutorial-getting-started.
I'm doing official iOS development tutorial from Apple. There is a task to make a zoomable image in a scrollView.
I believe that did it right. There is mistake, since I cant zoom image in.
The task is below in screenshots.
Task part 1
Task part 2
Here is my code:
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//set the scroll view's deligate to be the viewcontroller instance
self.scrollView.delegate = self
viewForZooming(in: scrollView)
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
override func viewDidAppear(_ animated: Bool) {
updateZoomFor(size: view.bounds.size)
}
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.zoomScale = scale
}
}
Mainscroll is scrollview which was added into another internal UIView and i have UISlider to change internal view scale.
But, MainScroll.setZoomScale(CGFloat(sender.value), animated: true) this line is not work.
==> Here is my code.
override func viewDidLoad() {
super.viewDidLoad()
MainScroll.maximumZoomScale = 1
MainScroll.minimumZoomScale = 10
MainScroll.delegate = self
MainScroll.zoomScale = 5
}
#IBAction func Scrolling(_ sender: UISlider) {
MainScroll.setZoomScale(CGFloat(sender.value), animated: true)
}
Here is a minimal example for getting a UIScrollView to zoom.
The key is that you have to implement func viewForZooming(in scrollView: UIScrollView) -> UIView? and return a view (that is inside your scrollView) that is to be scaled (think of it like your 'document' or 'canvas' view).
Also, notice that zoom is working for the default pinch gestures on the scrollView as well.
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
// Assume that outlets exist on a storyboard
#IBOutlet var scrollView: UIScrollView!
#IBOutlet var canvas: UIView! // A view that is added in the scrollView
#IBOutlet var slider: UISlider!
let minScale: CGFloat = 1
let maxScale: CGFloat = 10
let initialScale: CGFloat = 1
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
scrollView.minimumZoomScale = minScale
scrollView.maximumZoomScale = maxScale
scrollView.zoomScale = initialScale
slider.minimumValue = Float(minScale)
slider.maximumValue = Float(maxScale)
slider.value = Float(initialScale)
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return canvas
}
#IBAction func sliderValueChanged(_ sender: UISlider) {
scrollView.zoomScale = CGFloat(sender.value)
}
}
My problem is pretty simple really...
Imagine a background image that represents the streets and buildings around your house, note that this is a purpose built image. This image (a view) is zoomable and so far so good. Similar to map, but with an image instead.
Now image that on top of the streets drawn on the image there are markers representing cars. These will move over time and therefore will be moving dynamically. I have successfully placed the cars in the right place on the image, but when I zoom in/out the cars move out of place. Note that I don't want the cars to change in size, they will always remain the same.
Essentially, very similar to a map marker on top of google maps, but instead of the map I have a background picture and instead of the markers I have other images (the cars).
Now for the implementation...
I have a simple ScrollableView which contains an image view. I am trying to overlay other multiple pictures that I want to keep placement but not zoom in or out (or at least not as much as the main picture). I would say that it is similar to a map which has location pins on it, but it is just using pictures.
I am doing this in Swift and the latest iOS version (9x)
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate
{
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var pin1View: UIImageView!
#IBOutlet weak var pin2View: UIImageView!
override func viewDidLoad()
{
super.viewDidLoad()
self.scrollView.minimumZoomScale = 1.0;
self.scrollView.maximumZoomScale = 10.0;
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView?
{
let pin1_X = self.pin1View.frame.origin.x
let pin2_Y = self.pin2View.frame.origin.y
//I guess I need to do something here but not sure
return self.imageView
}
}
Any tips much appreciated. I googled it but couldn't find examples and still learning views and swift as well as general mobile dev.
Thanks for your help.
You have the change centre of the pin accordingly. Use this updated code:
class ViewController: UIViewController, UIScrollViewDelegate
{
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var pin1View: UIImageView!
#IBOutlet weak var pin2View: UIImageView!
var pin1ViewCenter : CGPoint = CGPointZero
var pin2ViewCenter : CGPoint = CGPointZero
override func viewDidLoad()
{
super.viewDidLoad()
self.scrollView.scrollEnabled = true
self.scrollView.minimumZoomScale = 1.0
self.scrollView.maximumZoomScale = 10.0
pin1ViewCenter = pin1View.center
pin2ViewCenter = pin2View.center
self.scrollView.contentSize = self.imageView.frame.size
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView?
{
return self.imageView
}
func scrollViewDidZoom(scrollView: UIScrollView) {
let scaleAffineTransform = CGAffineTransformScale(CGAffineTransformIdentity, scrollView.zoomScale, scrollView.zoomScale)
var translatedPoint = CGPointApplyAffineTransform(pin1ViewCenter, scaleAffineTransform)
pin1View.transform = CGAffineTransformTranslate(CGAffineTransformIdentity, translatedPoint.x - pin1ViewCenter.x , translatedPoint.y - pin1ViewCenter.y)
translatedPoint = CGPointApplyAffineTransform(pin2ViewCenter, scaleAffineTransform)
pin2View.transform = CGAffineTransformTranslate(CGAffineTransformIdentity, translatedPoint.x - pin2ViewCenter.x, translatedPoint.y - pin2ViewCenter.y)
}
func scrollViewDidEndZooming(scrollView: UIScrollView, withView view: UIView?, atScale scale: CGFloat) {
let scaleAffineTransform = CGAffineTransformScale(CGAffineTransformIdentity, scale, scale)
scrollView.contentSize = CGSizeApplyAffineTransform(self.imageView.bounds.size, scaleAffineTransform)
}
}