ImageView in a ScrollView to zoom, crop and save swift - ios

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

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 Selected From Image Picker Not Displaying

I'm kind of lost. My Image Picker is working but the image is not displaying in my Image View. I have looked over my code and various solutions and it still is not working. I have set the delegate to self and double checked my methods and it is still not showing the image where it is supposed to.
import UIKit
class AlterProfileViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
view?.backgroundColor = UIColor.white
navigationItem.title = "Profile Settings"
view.addSubview(selectProfileImage)
///Constraints for all views will go here
_ = selectProfileImage.anchor(view.centerYAnchor, left: view.leftAnchor, bottom: nil, right: nil, topConstant: -275, leftConstant: 135, bottomConstant: 0, rightConstant: 0, widthConstant: 100, heightConstant: 100)
// selectProfileImage.layer.cornerRadius = selectProfileImage.frame.size.width/2
///////////////////////////////////////////////
// Do any additional setup after loading the view.
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
selectProfileImage.layer.cornerRadius = selectProfileImage.frame.size.width / 2;
selectProfileImage.layer.masksToBounds = true
}
//Where all buttons and labels will be added
//will just be a nice looking image view to be next to the profile settings button
lazy var selectProfileImage: UIImageView = {
let selectPicture = UIImageView()
// self.selectProfileImage.layer.cornerRadius = self.selectProfileImage.frame.size.width / 2;
selectPicture.image = UIImage(named: "Paris")
// selectPicture.layer.cornerRadius = selectPicture.frame.size.width / 2;
selectPicture.clipsToBounds = true
selectPicture.translatesAutoresizingMaskIntoConstraints = false
selectPicture.layer.cornerRadius = selectPicture.frame.size.width/2
selectPicture.contentMode = .scaleAspectFill
selectPicture.isUserInteractionEnabled = true
selectPicture.layer.shouldRasterize = true
// will allow you to add a target to an image click
selectPicture.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleSelectProfileImageView)))
selectPicture.layer.masksToBounds = true
return selectPicture
}()
func handleSelectProfileImageView() {
print("123")
let picker = UIImagePickerController()
picker.delegate = self
picker.allowsEditing = true
present(picker, animated: true, completion: nil)
}
// will dispaly info of image selected
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
print("info")
var selectedImageFromPicker: UIImage?
if let editedImage = info["UIImagePickerControllerEditedImage"] as? UIImage{
print((editedImage as AnyObject).size)
selectedImageFromPicker = editedImage
}else if let originalImage = info["UIImagePickerControllerOriginalImage"] as? UIImage{
print((originalImage as AnyObject).size)
selectedImageFromPicker = originalImage
}
if let selectedImage = selectedImageFromPicker {
selectProfileImage.image = selectedImage
}
dismiss(animated: true, completion: nil)
}
// will handle the picker being closed/canceled
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
print("picker canceled")
dismiss(animated: true, completion: nil)
}
///////////////////////////////////////////////////////////////////////////////////
}

How to apply an animation effect to UIImageView slideshow

On Swift 3.0 how can I apply some animation effect to this slideshow? Cannot find animation effects related to animationWithDuration method.
let image1 = UIImage(named: "image1")!
let image2 = UIImage(named: "image2")!
let image3 = UIImage(named: "image3")!
var imagesArray : [UIImage] = []
override func viewDidLoad() {
super.viewDidLoad()
imagesArray = [image1, image2, image3]
myView.clipsToBounds = true
myView.animationImages = imagesArray
myView.animationDuration = 10.0
myView.animationRepeatCount = 0
myView.startAnimating()
}
It looks like you are using the build in frame animation for UIImageView. This is designed to just cycle through the images, like an animated gif. It doesn't really have more sophisticated animation than that. What you can do if you want transition effects is alternate between two image views and use the UIView Animation methods to switch between them. This just does a crossfade by manipulating alpha:
var images = [UIImage]()
var currentImageindex = 0
func animateImageViews() {
swap(&firstImageView, &secondImageView)
secondImageView.image = images[currentImageindex]
currentImageindex = (currentImageindex + 1) % images.count
UIView.animate(withDuration: 1, animations: {
self.firstImageView.alpha = 0
self.secondImageView.alpha = 1
}, completion: { _ in
self.animateImageViews()
})
}
Here is playground that shows how it works. You need to drop 2 images into the resources folder named 1.png and 2.png for it to work. Note that setting the view frames like this is horrible programming practice i just did it here for brevity. use interface builder and autolayout in your actual code.
import PlaygroundSupport
import UIKit
class Demo: UIViewController {
let button = UIButton()
var firstImageView = UIImageView()
var secondImageView = UIImageView()
var images = [UIImage]()
var currentImageindex = 0
override func viewDidLoad() {
view.addSubview(firstImageView)
view.addSubview(secondImageView)
images.append(UIImage(named: "1.png")!)
images.append(UIImage(named: "2.png")!)
firstImageView.image = images[0]
secondImageView.image = images[1]
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
firstImageView.frame = view.frame
secondImageView.frame = view.frame
}
override func viewDidAppear(_ animated: Bool) {
animateImageViews()
}
func animateImageViews() {
swap(&firstImageView, &secondImageView)
secondImageView.image = images[currentImageindex]
currentImageindex = (currentImageindex + 1) % images.count
UIView.animate(withDuration: 1, animations: {
self.firstImageView.alpha = 0
self.secondImageView.alpha = 1
}, completion: { _ in
self.animateImageViews()
})
}
}
let viewcontroller = Demo()
viewcontroller.view.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
PlaygroundPage.current.liveView = viewcontroller.view

zoom image with scrollview swift 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

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.

Resources