Facebook Picture zoom animation in swift, picture not showing the initial position - swift

I've been trying to make a zoom animation like Facebook when you click a picture into a cell to move into the middle of the screen. The animation works, but for a reason that I can not figure out, it is not starting from the initial position it is giving me another frame. Please help, I've been struggling with this for a few days now.
I am using a collectionView with CustomCell and everything it's done programmatically:
The function in CenterVC:
//MARK: Function to animate Image View (it will animate to the middle of the View)
func animateImageView(statusImageView : UIImageView) {
//Get access to a starting frame
statusImageView.frame.origin.x = 0
if let startingFrame = statusImageView.superview?.convert(statusImageView.frame, to: nil) {
//Add the view from cell to the main view
let zoomImageView = UIView()
zoomImageView.backgroundColor = .red
zoomImageView.frame = statusImageView.frame
view.addSubview(zoomImageView)
print("Starting frame is: \(startingFrame)")
print("Image view frame is: \(statusImageView.frame)")
UIView.animate(withDuration: 0.75, animations: {
let height = (self.view.frame.width / startingFrame.width) * startingFrame.height
let y = self.view.frame.height / 2 - (height / 2)
zoomImageView.frame = CGRect(x: 0, y: y, width: self.view.frame.width, height: height)
})
}
}
This is the pictureView inside the cell and the constraints (this is where I am setting up the picture for the view, and I am using in cellForRowAtIndexPath cell.centerVC = self):
var centerVC : CenterVC?
func animate() {
centerVC?.animateImageView(statusImageView: pictureView)
}
let pictureView : UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.image = UIImage(named: "cat")
imageView.backgroundColor = UIColor.clear
imageView.layer.masksToBounds = true
imageView.isUserInteractionEnabled = true
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
addConstraintsWithFormat(format: "V:|-5-[v0(40)]-5-[v1]-5-[v2(200)]", views: profileImage, postTextView, pictureView)
addConstraintsWithFormat(format: "H:|[v0]|", views: pictureView)
This is what it prints out in the debugger:
Starting frame is: (5.0, 547.5, 365.0, 200.0)
Image view frame is: (0.0, 195.5, 365.0, 200.0)
As you can see the starting frame it's different from the initial frame and position of the picture. The animation it's not leaving the initial position it just appears somewhere on top and animates to the middle. I don't know what to do, please advice.

For some reason, it was not reading the starting frame rect so I've made a new CGRect that gets the origin and set the size of the picture: (it animates perfectly now)
zoomImageView.frame = CGRect(origin: startingFrame.origin, size: CGSize(width: view.frame.width, height: statusImageView.frame.height))

Related

Buttons on UIScrollView bounces back when centered

My UIScrollView bounces back from left side, but stays normal from the right side.
Look at the gif please.
Important note: The buttons should be centered when the screen opens.
To center my buttons, I create them like this:
button.frame = CGRect(
x: screenWidth/2 + gap,
y: 0,
width: buttonWidth,
height: buttonHeight)
buttonsScrollView.addSubview(button)
I already set wide content size
buttonsScrollView.contentSize.width = screenWidth
and adding extra space - screenWidth + 100 does not help, it makes wider only from the right side.
You can do this with "calculated" frames or with auto-layout. In either case, the general idea...
Add your buttons to a UIView - we'll call it buttonsView:
Start the first button at gap distance from Zero, and set the frame of buttonsView to the height of the buttons, and add gap distance to the right-end.
Add buttonsView to the scroll view, at x: 0, y: 0.
Set the scroll view's .contentSize = buttonsView.frame.size.
Do all of that in viewDidLoad().
We can't center the buttonsView until we know the scroll view's frame width, which will likely vary depending on device (and if you rotate the device), so...
Add a class property to track the scroll view's width:
// track the scroll view frame width
var scrollViewWidth: CGFloat = 0
then, in viewDidLayoutSubviews() we know the scroll view's frame, so we'll adjust the .contentOffset.x to horizontally center the buttonsView:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// here we know frame size, but
// viewDidLayoutSubviews() can (and usually will) be called multiple times
// so we only want to execute this code when the scroll view width changes
if scrollViewWidth != scrollView.frame.width {
scrollViewWidth = scrollView.frame.width
// calculate content offset x so the row of buttons is centered horizontally
scrollView.contentOffset.x = (buttonsView.frame.width - scrollView.frame.width) * 0.5
}
}
Here's a complete sample implementation. No #IBOutlet connections -- everything is done via code -- so just set a view controller's class to CenterScrollViewController:
class CenterScrollViewController: UIViewController {
// create a scroll view
let scrollView: UIScrollView = {
let v = UIScrollView()
// background color so we can see its frame
v.backgroundColor = .systemYellow
return v
}()
// create a buttons holder view
let buttonsView: UIView = {
let v = UIView()
return v
}()
// gap between buttons and on left/right sides of button row
let gap: CGFloat = 12
// buttons will be (round) at 44 x 44 points
let btnSize: CGFloat = 44
// number of buttons
let numButtons: Int = 9
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(white: 0.9, alpha: 1.0)
title = "Calc"
// add scroll view to view
scrollView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(scrollView)
// add buttons view to scroll view
scrollView.addSubview(buttonsView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// constrain scroll view
// Top + 40
scrollView.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
// Leading and Trailing
scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor),
// Height equal to button height + "padding" on bottom
scrollView.heightAnchor.constraint(equalToConstant: btnSize + gap),
])
// let's add some buttons to the buttons view
var x: CGFloat = gap
for i in 1...numButtons {
let b = UIButton()
b.backgroundColor = .systemBlue
b.setTitle("\(i)", for: [])
b.setTitleColor(.white, for: .normal)
b.setTitleColor(.lightGray, for: .highlighted)
// let's keep the buttons square (1:1 ratio) so we can make them round
b.frame = CGRect(x: x, y: 0, width: btnSize, height: btnSize)
b.layer.cornerRadius = btnSize * 0.5
b.layer.borderColor = UIColor.black.cgColor
b.layer.borderWidth = 1
buttonsView.addSubview(b)
x += btnSize + gap
}
// x now equals the total buttons width plus gap on each side
// so set the frame size of the buttons view to (x, btnSize)
buttonsView.frame = CGRect(x: 0, y: 0, width: x, height: btnSize)
// set scroll view content size to the size of the buttons view
scrollView.contentSize = buttonsView.frame.size
}
// track the scroll view frame width
var scrollViewWidth: CGFloat = 0
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// here we know frame size, but
// viewDidLayoutSubviews() can (and usually will) be called multiple times
// so we only want to execute this code when the scroll view width changes
if scrollViewWidth != scrollView.frame.width {
scrollViewWidth = scrollView.frame.width
// calculate content offset x so the row of buttons is centered horizontally
scrollView.contentOffset.x = (buttonsView.frame.width - scrollView.frame.width) * 0.5
}
}
}

Creating PDF from UIView in Swift

I have been stuck/ researching this problem for days, the method below successfully creates the pdf from a regular size UIView. However, I need the contents of my containerView that is located inside a UIScrollview. The height of my containerView is 5000. Can someone help me to render the containerView into multiple PDF pages or direct me to a better way of doing this. `func exportAsPdfFromView() -> String {
func screenShotScrollview() -> String {
let scrollView = waiverViews.scrollView
let pageDimensions = scrollView.bounds
let pageSize = pageDimensions.size
let totalSize = scrollView.contentSize
let numberOfPagesThatFitVertivally = Int(ceil(totalSize.height/pageSize.height))
let outputData = NSMutableData()
UIGraphicsBeginPDFContextToData(outputData, pageDimensions, nil)
let savedContentOffset = scrollView.contentOffset
let savedContentInset = scrollView.contentInset
scrollView.contentInset = UIEdgeInsets.zero
let origin = CGRect(x: 0, y: 0, width: pageSize.width, height: pageSize.height)
if let context = UIGraphicsGetCurrentContext() {
for indexVertical in 0..<numberOfPagesThatFitVertivally {
UIGraphicsBeginPDFPageWithInfo(origin, nil)
let offsetVertical = CGFloat(indexVertical) * pageSize.height
scrollView.contentOffset = CGPoint(x: 0, y: offsetVertical)
context.translateBy(x: 0, y: -offsetVertical)
scrollView.layer.render(in: context)
}
UIGraphicsEndPDFContext()
scrollView.contentInset = savedContentInset
scrollView.contentOffset = savedContentOffset
}
return self.saveViewPdf(data: outputData)
}
Essentially, a scrollView would not want to render all contents to its layer all the time, until it is being viewed.
I am guessing this is returning just the snapshot of the UIScrollView's current window?
To take multiple snapshots of the whole contentBounds of the UIScrollView, you could potentially, setTheContentOffset of the scrollview in its total contentBounds.height/frame.height which would return the pages. And then generate PDFs within the loop?
for instance something like this, and then UX wise, hide the scroll view. While this is being generated, unhide it when it is complete.
for i in 0..<pages {
scrollView.setContentOffset(.init(x: 0, y: i*scrollViewHeight))
//PDF Generation flow
//set the url to something like "pdf_file_\(i).pdf"
}

Swift - TableView background image: how to center the image

I want to add a logo as a background image to my tableView. Image size is 50px, 50px.
I tried the code below, but this puts the image lower right corner.
let imageView = UIImageView(image: UIImage(named: "logo"))
imageView.contentMode = .scaleAspectFit
imageView.layer.frame = CGRect(x: self.view.frame.midX, y: self.view.frame.midY, width: 50, height: 50)
let tableViewBackgroundView = UIView()
tableViewBackgroundView.addSubview(imageView)
self.tableView.backgroundView = tableViewBackgroundView
There are a few points about swift that are pretty key:
1) The x and y parameters in CGRect.init(x:y:width:height:) don't refer to the center of the imageView. Instead, they are points in a coordinate system where (0, 0) is the Upper Left Corner of the view that the CGRect is being presented over, and
2) UIImageView actually inherits from UIView, so because of this you can just say
tableView.backgroundView = imageView
You shouldn't have to fiddle around with any CGRects, I believe this code should work just fine, although you may have to fiddle with different contentMode properties to get it to display how you like.
let imageView = UIImageView(image: UIImage(named: "logo"))
imageView.layer.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
imageView.layer.frame.midX = tableView.layer.frame.midX
imageView.layer.frame.midY = tableView.layer.frame.midY
tableView.backgroundView = imageView

How to change the size of the titleView of Navigation Item? (Swift)

In my app I want to change the titleView of my Navigation Controller to a custom ImageView but I have a very strange problem. I basically just can`t set the frame of my ImageView.
This is my code:
func NavBarEinrichten(){
let logo = UIImage(named: "Notennamen für Griffe 1")!
let imageView = UIImageView(image:logo)
imageView.contentMode = .scaleAspectFit
//To show the problem better
imageView.backgroundColor = UIColor.red
let navController = navigationController!
let bannerWidth:CGFloat = 20
let bannerHeight:CGFloat = navController.navigationBar.frame.size.height
let bannerX = bannerWidth / 2 - logo.size.width / 2
let bannerY = bannerHeight / 2 - logo.size.height / 2
imageView.frame = CGRect(x: bannerX, y: bannerY, width: bannerWidth, height: bannerHeight)
self.navigationItem.titleView?.frame = CGRect(x: bannerX, y: bannerY, width: bannerWidth, height: bannerHeight)
navigationItem.titleView = imageView
print(imageView.frame, "imageView frame")
}
The print statement prints:
(0.0, 0.0, 357.0, 142.0) imageView frame
Which is right, because it looks like this when i run it, but not like it should be. Because I want the width to be 20.
In the simulator it looks like this:
I tried to call this method in viewDidLoad(), viewWillAppear()and viewDidLayoutSubviews()
Every time with the exact same outcome...
Can you help me?

Swift ImageCropper returns an image outside of the specified "window"

I am making an app that has a UIWebView along with a button on a single view controller. When the button is clicked, an image (of the UIWebView) is captured using UIGraphicsContext.
This part works great! But when the button is clicked, after capturing the image, it displays the image as a subview on the same view, and I have been trying to use an ImageCropper Library that draws a CGRect in another subview over the UIImageView on the screen with a submit button. The rectangle itself can be resized (dragging the corners/edges) and moved around the view.
When the submit button is clicked, another subview is displayed in the top left hand portion of screen and display the image that was cropped (after clicking submit button) The idea is to only capture what is inside the rectangle. I am able to get the code working but the image captured is of the same image but not a section that is inside the CGRect.
I have 3 images that show how it works and shows the image that is cropped incorrectly.enter image description here . Shot 1 . Shot 2
Shot 3. I believe my problems lies within the size of image captured and the size of the image with the crop rect are not equal and that is why it is distorting it.
Does anyone know what might be the cause? Sorry for the long winded question but any help would be greatly appreciated!
Here is my code below:
ViewController.swift:
class ViewController: UIViewController {
#IBOutlet var webView: UIWebView!
#IBOutlet var imageView: UIImageView!
override func viewDidLoad() {
imageView.isHidden = true
let aString = URL(string: "https://www.kshuntfishcamp.com/home.page")
webView.loadRequest(URLRequest(url: aString!))
super.viewDidLoad()
}
#IBAction func takePhotoPressed(_ sender: UIButton) {
UIGraphicsBeginImageContextWithOptions(webView.bounds.size, false, 0.0)
if let aContext = UIGraphicsGetCurrentContext(){
webView.layer.render(in: aContext)
}
let capturedImage:UIImage? = UIGraphicsGetImageFromCurrentImageContext()
imageView = UIImageView(frame: CGRect(x: 22, y: 123, width: 330, height: 330))
let image = capturedImage
imageView.image = image
imageView.contentMode = UIViewContentMode.scaleAspectFill
imageView.clipsToBounds = true
imageView.isHidden = true
webView.isHidden = true
let editView = EditImageView(frame: self.view.frame)
let image2 = capturedImage!
editView.initWithImage(image: image2)
let croppedImage = editView.getCroppedImage()
self.view.addSubview(editView)
self.view.backgroundColor = UIColor.clear
UIImageWriteToSavedPhotosAlbum(croppedImage, nil, nil, nil)
}
EditImageView.swift - source (https://github.com/Thanatos-L/LyEditImageView)-only including parts that seem relevant to solving the problem
func initWithImage(image:UIImage){
imageView = UIImageView(frame: CGRect(x: 22, y: 123, width: 330, height: 330))
imageView.tag = IMAGE_VIEW_TAG;
self.addSubview(self.imageView)
imageView.isUserInteractionEnabled = true;
imageView.image = image
imageView.frame = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)
let frame = AVMakeRect(aspectRatio: imageView.frame.size, insideRect: self.frame);
imageView.frame = frame
originImageViewFrame = frame
NSLog("initWithImage %#", NSStringFromCGRect(originImageViewFrame))
imageZoomScale = 1.0
commitInit()
}
private func cropImage() {
let rect = self.convert(cropView.frame, to: imageView)
let imageSize = imageView.image?.size
let ratio = originImageViewFrame.size.width / (imageSize?.width)!
let zoomedRect = CGRect(x: rect.origin.x / ratio, y: rect.origin.y / ratio, width: rect.size.width / ratio, height: rect.size.height / ratio)
let croppedImage = cropImage(image: imageView.image!, toRect: zoomedRect)
var view: UIImageView? = self.viewWithTag(1301) as? UIImageView
if view == nil {
view = UIImageView()
}
view?.frame = CGRect(x: 0, y: 0, width: croppedImage.size.width , height: croppedImage.size.height)
view?.image = croppedImage
view?.tag = 1301
self.addSubview(view!)
}