I am new to swift.
I am doing an exercise from an app development book. I am trying to create an UIImageView and put a image in it, but I can not zoom the image in. There is something wrong in my code, but I don't know what is going on.
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var image: UIImageView!
#IBOutlet weak var scroll: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
scroll.delegate = ViewController()
updateZoomFor(size:view.bounds.size)
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
private func viewForZooming(in scrollView: UIScrollView) -> UIImageView{
return image
}
func updateZoomFor(size:CGSize){
let widthScale = size.width / image.bounds.width
let heightScale = size.height / image.bounds.height
let scale = min(widthScale, heightScale)
scroll.minimumZoomScale = scale
}
}
First, set scroll.delegate = self as suggested by 3stud1ant3.
Second, you need to match the definition of theUIScrollViewDelegate method:
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return image
}
Make sure you set the zoom scale in updateZoomFor as well: scroll.zoomScale = scale.
Also you need to implement this:
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
updateZoomFor(size: view.bounds.size)
}
func scrollViewDidZoom(_ scrollView: UIScrollView) {
updateConstraintsForSize(view.bounds.size)
}
fileprivate 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()
}
Related
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.
}
}
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()
}
}
How should I use UIpageControl from UIScrollView? I am stuck, help me out.
Here is my code please help;
class home: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var mainScrollView: UIScrollView!
#IBOutlet weak var pagecontrol: UIPageControl!
var imageArray = [UIImage]()
var pageControl : UIPageControl!
override func viewDidLoad() {
super.viewDidLoad()
mainScrollView.delegate = self
imageArray = [#imageLiteral(resourceName: "sliderImage"), #imageLiteral(resourceName: "clothing"), #imageLiteral(resourceName: "sports")]
for i in 0..<imageArray.count{
let imageView = UIImageView()
imageView.image = imageArray[i]
imageView .contentMode = .scaleToFill
let xPosition = self.view.frame.width * CGFloat(i)
imageView.frame = CGRect(x: xPosition, y: 0, width: self.mainScrollView.frame.width, height: self.mainScrollView.frame.height)
mainScrollView.contentSize.width = mainScrollView.frame.width * CGFloat(i + 1)
mainScrollView.addSubview(imageView)
}
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
Check out this answer
Things have been pretty much the same over these years:
Set your UIScrollView delegate to your view controller (which you did);
Add code for scrollViewDidScroll delegate method:
func scrollViewDidScroll(_ scrollView: UIScrollView)
{
self.pageControl.currentPage = Int(floorf(Float(scrollView.contentOffset.x / scrollView.width)))
}
Add the same in scrollViewDidEndDecelerating method:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView)
{
self.pageControl.currentPage = Int(floorf(Float(scrollView.contentOffset.x / scrollView.width)))
}
Although, it depends on your needs - try how it works with and without each of them.
I'm having trouble getting my UIScrollView to zoom. My code is below:
class ViewController: UIViewController, UIScrollViewDelegate {
let imageView = UIImageView()
#IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
let image = UIImage(named: "cats.jpg")
imageView.image = image
imageView.frame = CGRect(origin: CGPointZero, size: image!.size)
scrollView.addSubview(imageView)
scrollView.contentSize = image!.size
scrollView.clipsToBounds = false
scrollView.layer.borderColor = UIColor.yellowColor().CGColor
scrollView.layer.borderWidth = 4.0
let scrollViewFrame = scrollView.frame
let scaleWidth = scrollViewFrame.size.width / scrollView.contentSize.width
let scaleHeight = scrollViewFrame.size.height / scrollView.contentSize.height
let minScale = min(scaleWidth, scaleHeight);
scrollView.minimumZoomScale = minScale;
scrollView.maximumZoomScale = 1.0
scrollView.zoomScale = minScale;
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return imageView
}
}
What am I doing wrong here? I have tried adjusting the min and max scale but doesn't make any difference. Any pointers on this would be really appreciated. Thanks!
Add this to viewDidLoad:
scrollView.delegate = self
The scroll view needs a delegate (your view controller) to get the view for zooming (the delegate method you implemented).
I have searched many articles about UIScrollView with an UIImageView in, but all without AutoLayout info. What I have done is: place a UIScrollView in UIViewController with constraints top 10, leading 10, bottom 50, trailing 10; place a UIImageView inside of the UIScrollView with constraints top 0, leading 0, bottom 0, trailing 0. What I want is simple: let my UIImageView fit my UIScrollView when app first loaded, and let my UIImageView centered horizontally and vertically. Now I can see the image and just fit the screen nicely but the image is just at the top of UIScrollView.(notes: in this circumstance, the width of my image after being zoomed to minimum zoomScale equals to the width of UIScrollView, the height of my image after being zoom to minimum zoomScale less than the width of UIScrollView. )
I really can't move my UIImageView to center of UIScrollView vertically and can not find where I made an error. Thanks a lot.
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.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func centerScrollViewContents() {
let boundsSize = scrollView.bounds.size
var contentsFrame = imageView.frame
if contentsFrame.size.width < boundsSize.width {
contentsFrame.origin.x = (boundsSize.width - contentsFrame.size.width) / 2.0
} else {
contentsFrame.origin.x = 0.0
}
if contentsFrame.size.height < boundsSize.height {
contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2.0
} else {
contentsFrame.origin.y = 0.0
}
}
override func viewDidLayoutSubviews() {
let myImage = UIImage(named: "7.jpg")
imageView.image = myImage
let weightScale = scrollView.bounds.size.width / myImage!.size.width
let heightScale = scrollView.bounds.size.height / myImage!.size.height
let minScale = min(weightScale, heightScale)
let imagew = myImage!.size.width * minScale
let imageH = myImage!.size.height * minScale
let imageRect = CGRectMake(0, 0, imagew, imageH)
imageView.frame = imageRect
scrollView.contentSize = myImage!.size
scrollView.maximumZoomScale = 1.0
scrollView.minimumZoomScale = minScale
scrollView.zoomScale = minScale
imageView.frame = imageRect
centerScrollViewContents()
}
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return imageView
}
}
Piggy backing on pic-o-matic's answer. I had a case where I needed to center the image only if it was smaller than the scrollview frame. Using insets made for a straightforward solution.
if imageView.frame.height <= scrollView.frame.height {
let shiftHeight = scrollView.frame.height/2.0 - scrollView.contentSize.height/2.0
scrollView.contentInset.top = shiftHeight
}
if imageView.frame.width <= scrollView.frame.width {
let shiftWidth = scrollView.frame.width/2.0 - scrollView.contentSize.width/2.0
scrollView.contentInset.left = shiftWidth
}
I experienced the same problem. I found a perfect solution for me, check out this github project: https://github.com/evgenyneu/ios-imagescroll-swift
How it essentially works is as follows: it adjusts your constraints as to center the image if it is zoomed out far enough and to enable it to zoom and scroll after the width or height exceeds the respective width or height of your container.
Found it thanks to this thread: Zooming UIImageView inside UIScrollView with autolayout (obj-c and swift solution available)!
// ViewController.swift
// image-scroll-swift
//
// Created by Evgenii Neumerzhitckii on 4/10/2014.
// Copyright (c) 2014 Evgenii Neumerzhitckii. All rights reserved.
//
import UIKit
let imageScrollLargeImageName = "wallabi.jpg"
class ViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var imageConstraintTop: NSLayoutConstraint!
#IBOutlet weak var imageConstraintRight: NSLayoutConstraint!
#IBOutlet weak var imageConstraintLeft: NSLayoutConstraint!
#IBOutlet weak var imageConstraintBottom: NSLayoutConstraint!
var lastZoomScale: CGFloat = -1
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
imageView.image = UIImage(named: imageScrollLargeImageName)
scrollView.delegate = self
updateZoom()
}
// Update zoom scale and constraints
// It will also animate because willAnimateRotationToInterfaceOrientation
// is called from within an animation block
//
// DEPRECATION NOTICE: This method is said to be deprecated in iOS 8.0. But it still works.
override func willAnimateRotationToInterfaceOrientation(
toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
super.willAnimateRotationToInterfaceOrientation(toInterfaceOrientation, duration: duration)
updateZoom()
}
func updateConstraints() {
if let image = imageView.image {
let imageWidth = image.size.width
let imageHeight = image.size.height
let viewWidth = view.bounds.size.width
let viewHeight = view.bounds.size.height
// center image if it is smaller than screen
var hPadding = (viewWidth - scrollView.zoomScale * imageWidth) / 2
if hPadding < 0 { hPadding = 0 }
var vPadding = (viewHeight - scrollView.zoomScale * imageHeight) / 2
if vPadding < 0 { vPadding = 0 }
imageConstraintLeft.constant = hPadding
imageConstraintRight.constant = hPadding
imageConstraintTop.constant = vPadding
imageConstraintBottom.constant = vPadding
// Makes zoom out animation smooth and starting from the right point not from (0, 0)
view.layoutIfNeeded()
}
}
// Zoom to show as much image as possible unless image is smaller than screen
private func updateZoom() {
if let image = imageView.image {
var minZoom = min(view.bounds.size.width / image.size.width,
view.bounds.size.height / image.size.height)
if minZoom > 1 { minZoom = 1 }
scrollView.minimumZoomScale = minZoom
// Force scrollViewDidZoom fire if zoom did not change
if minZoom == lastZoomScale { minZoom += 0.000001 }
scrollView.zoomScale = minZoom
lastZoomScale = minZoom
}
}
// UIScrollViewDelegate
// -----------------------
func scrollViewDidZoom(scrollView: UIScrollView) {
updateConstraints()
}
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return imageView
}
}
Make sure your storyboard contains a viewcontroller. In the 'View' place a 'Scroll View' and in that 'Scroll View' place an 'Image View'.
Establish top/bottom/leading/trailing constraints of 0 (or whatever value you prefer) between the 'Scroll View' and the 'View'. Then establish the same constraints between the image and the scroll view and connect them to the #IBOutlets.
This should work fine as the code changes the constraints as you zoom.
I had the same "issue".. without auto layout though. I came up with this solution(using insets to center the image).
The automaticallyAdjustsScrollViewInsets property must be set to false.
override func viewDidLoad() {
super.viewDidLoad()
//create scrollview
self.automaticallyAdjustsScrollViewInsets = false
myScrollview = MyScrollview(frame: self.view.frame)
myScrollview.alwaysBounceHorizontal = true
myScrollview.alwaysBounceVertical = true
myScrollview.delegate = self
//....
}
override func viewWillLayoutSubviews() {
//setup frame portrait and landscape
myScrollview.frame = self.view.frame
myScrollview.zoomScale = self.view.frame.width / photo.size.width
myScrollview.minimumZoomScale = self.view.bounds.width / photo.size.width
// calculate inset to center vertically
let shift = myScrollview.frame.height/2.0 - myScrollview.contentSize.height/2.0
myScrollview.contentInset.top = shift
}
override func viewDidLayoutSubviews() {
}
func scrollViewDidZoom(scrollView: UIScrollView) {
let shift = myScrollview.frame.height/2.0 - myScrollview.contentSize.height/2.0
myScrollview.contentInset.top = shift
}
I used a subclass of UIScrollView, "MyScrollview" to "see" whats going on, i think this is useful to learn about scrollview, bounds frames and content size:
//
// MyScrollview.swift
// CampingDeHooiberg
//
// Created by Andre Lam on 09-03-15.
// Copyright (c) 2015 Andre Lam. All rights reserved.
//
import UIKit
class MyScrollview: UIScrollView {
override var bounds: CGRect { willSet { println("bounds set: \(newValue) contentSize:\(self.contentSize) frame:\(self.frame)")}}
override var contentSize: CGSize { willSet { println("bounds:\(self.bounds) set contentsize:\(newValue) frame: \(self.frame)")}}
override var frame: CGRect { willSet { println("bounds: \(self.bounds) contentSize:\(self.contentSize) frame set:\(newValue)")}}
override init(frame: CGRect) {
super.init(frame: frame)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}