In my iOS app, I have a scroll view which has the image view to scroll and zoom images.
What I am unable to do is launch the image view with pre-defined offset and zoom value.
Right now, on launch, the original image is shown which I can zoom-in/out and scroll, but I wanted to zoom-in/out with an offset with default values.
On setting the scrollview.zoomScale, I am not able to scroll the image completely.
Code below:-
let scroller = UIScrollView()
scroller.translatesAutoresizingMaskIntoConstraints = false
scroller.minimumZoomScale = 1
scroller.maximumZoomScale = 5
return scroller
}()
let imageView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFit
iv.translatesAutoresizingMaskIntoConstraints = false
return iv
}()
The first step:
scrollView = UIScrollView(frame: view.bounds)
view.addSubview(scrollView)
imageView.center = view.center
scrollView.addSubview(imageView)
scrollView.minimumZoomScale = 1.0
scrollView.maximumZoomScale = 2.0
scrollView.delegate = self
Step 2: implement the UIScrollViewDelegate method
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
Finally:
private func setImagePosition(_ image: UIImage) {
imageView.image = image
let size = imageSize(WithScreen: image)
imageView.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
scrollView?.contentSize = size
if let scrollView = scrollView, size.height < scrollView.bounds.size.height {
let offsetY = (scrollView.bounds.size.height - size.height) * 0.5
scrollView.contentInset = UIEdgeInsets(top: offsetY, left: 0, bottom: offsetY, right: 0)
}
}
private func imageSize(WithScreen image: UIImage) -> CGSize {
var size = UIScreen.main.bounds.size
size.height = image.size.height * size.width / image.size.width
return size
}
Related
I have a UIImageView inside a scrollView. Its initial width and height are equal to 100. I want this UIImageView to appear in same size even after zooming. For that I modify its size inside scrollViewDidEndZooming method. This is working fine without a problem. However UiImage of the UiImageView looks blurry when zoom scale is increased. I tried to set contentScale property of the UiImageView, but it is not working.
How I can fix this?
import UIKit
class ViewController: UIViewController {
static var zoomScale: CGFloat = 1.0
let scrollView = UIScrollView()
let contentView = UIView()
let imageView: UIImageView = UIImageView()
let imageViewSize: CGFloat = 100
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .yellow
self.setupScrollView()
self.setuContentView()
self.addImageView()
}
func setupScrollView() {
let vWidth = self.view.frame.width
let vHeight = self.view.frame.height
scrollView.delegate = self
scrollView.frame = CGRect(x: 0, y: 0, width: vWidth, height: vHeight)
scrollView.backgroundColor = .lightGray
scrollView.alwaysBounceVertical = false
scrollView.alwaysBounceHorizontal = false
scrollView.showsVerticalScrollIndicator = true
scrollView.flashScrollIndicators()
scrollView.minimumZoomScale = 1.0
scrollView.maximumZoomScale = 10.0
self.view.addSubview(scrollView)
}
func setuContentView() {
contentView.frame = scrollView.frame.insetBy(dx: 20, dy: 20)
contentView.backgroundColor = .white
scrollView.addSubview(contentView)
}
func addImageView(){
let image = UIImage(systemName: "arrow.triangle.2.circlepath")
imageView.frame = CGRect(x: 200, y: 200, width: imageViewSize, height: imageViewSize)
imageView.image = image
imageView.contentMode = .scaleAspectFit
imageView.backgroundColor = .systemBlue
imageView.tintColor = .white
imageView.clipsToBounds = true
imageView.layer.cornerRadius = 0.5 * imageView.bounds.size.width // I want rounded imageView
self.contentView.addSubview(imageView)
}
}
extension ViewController: UIScrollViewDelegate {
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return self.contentView
}
func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {
ViewController.zoomScale = scale
imageView.frame = CGRect(x: imageView.frame.origin.x, y: imageView.frame.origin.y, width: imageViewSize/scale, height: imageViewSize/scale)
imageView.layer.cornerRadius = 0.5 * imageView.bounds.size.width
imageView.layer.contentsScale = scale
}
}
I'm trying to zoom image and crop image along the focusView line.
But image's position isn't center while scrolling.
Also cropImage() doesn't crop properly.
I've already tried below code.
setup() image shows center but after scrolling, image position isn't center.
Also cropImage()
class CropImageView: UIView {
#IBOutlet weak var focusView: UIImage! // crop frame
#IBOutlet weak var scrollView: UIScrollView!
var previewImage: UIImage?
var previewImageView: UIImageView!
var zoomScaleView: UIView!
func setup() {
scrollView.delegate = self
zoomScaleView = UIView(frame: .zero)
scrollView.addSubview(zoomScaleView)
previewImageView = UIImageView(frame: .zero)
previewImageView.image = previewImage
zoomScaleView.addSubview(previewImageView)
scrollView.minimumZoomScale = 1
scrollView.maximumZoomScale = 3
previewImageView.frame = CGRect(x: 0, y: 0,width: focusView.frame.width, height: focusView.frame.width)
scrollView.contentSize = CGSize(width: focusView.frame.width, height: focusView.frame.width)
scrollView.contentOffset = CGPoint(x: 0, y: 0)
previewImageView.contentMode = .scaleAspectFit
previewImageView.backgroundColor = .red
}
func scrollViewDidZoom(_ scrollView: UIScrollView) {
let scrollZoomScale = scrollView.zoomScale
if scrollZoomScale == scrollView.minimumZoomScale {
scrollView.contentInset = UIEdgeInsets.zero
return
}
if previewImageView.contentClippingRect.width <= previewImageView.contentClippingRect.height {
let difference = (previewImageView.frame.width * scrollZoomScale - previewImageView.contentClippingRect.width * scrollZoomScale)
scrollView.contentSize = CGSize(width: previewImageView.frame.width * scrollZoomScale - difference,
height: previewImageView.frame.height * scrollZoomScale)
scrollView.contentInset = UIEdgeInsets.init(
top: 0,
left: -difference/2,
bottom: (self.frame.height - focusView.frame.maxY),
right: difference/2)
} else {
let difference = (previewImageView.frame.height * scrollZoomScale - previewImageView.contentClippingRect.height * scrollZoomScale)
scrollView.contentSize = CGSize(width: previewImageView.frame.width * scrollZoomScale,
height: previewImageView.frame.height * scrollZoomScale - difference)
scrollView.contentInset = UIEdgeInsets.init(
top: -difference/2,
left: 0 ,
bottom: (self.frame.height - focusView.frame.maxY) + difference/2,
right: 0)
}
}
func cropImage() -> UIImage {
return previewImageView.image?.cgImage?.cropping(to: focusView.frame)
}
}
extension UIImageView {
var contentClippingRect: CGRect {
guard let image = image else { return bounds }
guard contentMode == .scaleAspectFit else { return bounds }
guard image.size.width > 0 && image.size.height > 0 else { return bounds }
let scale: CGFloat
if image.size.width > image.size.height {
scale = bounds.width / image.size.width
} else {
scale = bounds.height / image.size.height
}
let size = CGSize(width: image.size.width * scale, height: image.size.height * scale)
let x = (bounds.width - size.width) / 2.0
let y = (bounds.height - size.height) / 2.0
return CGRect(x: x, y: y, width: size.width, height: size.height)
}
}
[Setup]
[After zooming]
I'm struggling with this problem for long time.
Is there any solution?
Thank you.
I am creating a simple app which set image as circle by calculate with frame of image.
Here is I declare image variable:
lazy var imageUserDetailProfileView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.layer.borderWidth = 1
imageView.image = UIImage(named: "profile-icon")
imageView.layer.borderColor = UIColor(red:0.00, green:0.50, blue:0.00, alpha:1.0).cgColor
imageView.clipsToBounds = true
return imageView
}()
Here is i made that frame width and height of image became circle
imageUserDetailProfileView.frame = CGRect(x: view.frame.midX, y: 20,width: 100, height: 100)
imageUserDetailProfileView.layer.cornerRadius = imageUserDetailProfileView.frame.height/2
Now i want image should stay in middle of screen like using NSLayoutConstraint which has method centerXAnchor.
How to solve this problem?
let midX = view.frame.size.width / 2
let midY = view.frame.size.height / 2
Try This Code.
Custom Method For Image Set In Center Of Any View. Just Call Method And Pass Image & View. Customize according to Use. Swift 4
func setImageInCenterOfView(image:UIImage,view:UIView) {
let imageWidth:CGFloat = 100
let myImageView = UIImageView.init(frame: CGRect.init(x: (view.frame.size.width/2)-imageWidth/2, y: (view.frame.size.height/2)-imageWidth/2, width: imageWidth, height: imageWidth))
myImageView.clipsToBounds = true
myImageView.layer.cornerRadius = myImageView.frame.size.height/2
myImageView.image = image
view.addSubview(myImageView)
view.layoutIfNeeded()
}
Let say I have 3 images in the scroll view. Now I am able to scroll it horizontally in either way. However, when reached the image #3, how to allow it to continuous scroll to image #1.
override func viewDidAppear(_ animated: Bool) {
//allow scrolling even outside the scroll view
view.addGestureRecognizer(scrollView.panGestureRecognizer)
var contentWidth : CGFloat = 0.0
let scrollWidth = scrollView.frame.size.width
// append 3 images
for x in 0...2 {
let image = UIImage(named: "icon\(x).png")
let ImageView = (UIImageView(image:image))
images.append(ImageView)
var newX : CGFloat = 0.0
newX = scrollWidth/2 + scrollWidth * CGFloat(x)
scrollView.addSubview(ImageView)
//set the position of the image to center of the screen
ImageView.frame = CGRect(x: newX - 75, y: (scrollView.frame.size.height/2)-75, width: 150, height: 150)
contentWidth += newX
}
scrollView.clipsToBounds = false
scrollView.contentSize = CGSize(width: contentWidth, height: view.frame.size.height)
}
I have a scrollView containing a single image. The image's bounds are greater than the scrollView's frame. I have set the scrollView's contentSize to be equal to the image's bounds.
Yet no scrolling. I have no idea what could be causing this.
override func viewDidLoad() {
super.viewDidLoad()
var matches = SortThread.getSortThread().retrieveMatches()
scrollView.frame = CGRectMake(0, navigationController!.navigationBar.frame.height - 20, UIScreen.mainScreen().bounds.width, view.bounds.height - (navigationController!.navigationBar.frame.height - 20))
var imageName = String()
imageName = matches[0].pictures![0]
var parsedImageName = imageName.componentsSeparatedByString(".") as [String]
var newImageName: String = parsedImageName[0] as String
let path = NSBundle.mainBundle().pathForResource("MVLMP Images (Resized)/" + newImageName, ofType: "jpg")
var image = UIImage()
image = UIImage(contentsOfFile: path!)!
var imageView = UIImageView(image: image)
var ratio: CGFloat = image.size.width/image.size.height
var screenHeight: CGFloat = UIScreen.mainScreen().bounds.height - navigationController!.navigationBar.frame.height - 20
if(ratio > 1){
imageView.frame = CGRectMake(0, 0, ((scrollView.bounds.width)/7) * 6, 0)
imageView.frame = CGRectMake(0, 0, imageView.frame.width, imageView.frame.width * ratio)
} else {
imageView.frame = CGRectMake(0, 0, 0, (screenHeight/9)*8)
imageView.frame = CGRectMake(0, 0, imageView.frame.height * ratio, imageView.frame.height)
}
scrollView.addSubview(imageView)
scrollView.contentSize.width = imageView.frame.width
scrollView.contentSize.height = imageView.frame.height
}
}
I've printed out the scrollView.contentSize.width and the scrollView.bounds.width and the content width is in fact greater than the bounds width by about 40.
As Muc Dong commented, I was adding the width of the images to the scrollView's contentSize.width. This was not necessarily the correct thing to do as in my case there is some margin between the images that I was not accounting for. This margin should of been included in the additions to to scrollView.contentSize.width.