UIView Frame View and CGRect Not Working on First Call - ios

So I am trying to slide a tableview in over top of a lower view, which happens to also to be a uitableview. I have a sandwich icon to slide it in and a close icon to slide it out.
The button switching works great. However, when clicking the close button, the first time, the tableview will not slide out, it will basically slid out and right back to where it is.
However subsequent times, after the close icon switches back to sandwich, and then I click again to bring back close, it will slide it out just fine. Why it not work on the first try.
Below is my code. As you can see my CGRect is supposed to animate and slide the view to the displaywidth X.
#objc func showNewsList(_ sender: UIButton) -> Void {
let displayWidth: CGFloat = self.view.frame.width
let displayHeight: CGFloat = self.view.frame.height
newsIconClose.isHidden = true
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
newsSourceTable.frame = CGRect(x: displayWidth, y: 0, width:
displayWidth, height: displayHeight + 100)
self.addNewsIcon()
})
}

Bingo, figured it out. For whatever reason, CGRect wasn't liked, but this is.
self.newsSourceTable?.frame.origin.x = 0

Related

Moving or snapping a UIView to other side of screen with animation

I'm using the Floaty Cocoapod to make a floating action button for my iOS app. I'd like to be able to drag this button around and have it snap to the other side of the screen if the user would like to move it out of the way. The Floaty cocoapod already comes with a way to drag it, and I'm trying to modify this method so that the button will snap with animation to the opposite corner of the screen (lower left). Here is where I've got so far:
extension UIView {
func addDragging(){
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(draggedAction(_ :)))
self.addGestureRecognizer(panGesture)
}
#objc private func draggedAction(_ pan:UIPanGestureRecognizer){
let translation = pan.translation(in: self.superview)
self.center = CGPoint(x: self.center.x + translation.x, y: self.center.y + translation.y)
pan.setTranslation(CGPoint.zero, in: self.superview)
// Added the following lines myself - not working
if let superview = self.superview {
if self.center.x < superview.frame.size.width / 2 {
//self.transform = CGAffineTransform( translationX: 50, y: 0.0 )
}
}
}
}
The code I have added myself recognises the button has been moved over to the left side of the screen, but that's as far as I've got. I just need to get it to animate itself into the lower left corner when the user stops dragging the button, and then to the other side if they move it to the right again. I'm not sure if I can do this with constraints, as I'm not using storyboards and have no idea how this cocoapod constrains itself. Very grateful for any help!
You can accomplish this by replacing your added code with something like:
if let superview = self.superview {
// Case to move to the left
if self.center.x < superview.frame.size.width / 2 {
UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut) {
self.frame = // Whatever your left frame is
} completion: { (blockCalledAfterAnimationBool) in
// A completion handler if you want it
}
} else { // Move to the right
UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut) {
self.frame = // Whatever your right frame is
} completion: { (blockCalledAfterAnimationBool) in
// A completion handler if you want it
}
}
}
Main point is recommended use of the UIView.animate() function. Adjust the parameters as necessary to get the animation you desire.

UICollectionView zoom entire grid

I am using a UICollectionView to display a grid of cells with 3 columns. When a cell is selected, I'd like to zoom into the entire collection with the selected cell in the centre. I'd also like to fade out the surrounding cells and keep the selected on at full opacity.
The following code scales the grid but doesn't scroll to the selected cell:
UIView.animate(withDuration: 0.35, animations: {
self.collectionView.transform = CGAffineTransform(scaleX: 3, y: 3)
})
I was hoping I could do it by changing the UICollectionViewFlowLayout and the UICollectionView frame but I'm not sure whether I'm going down the wrong path with this (the following code just moves all the cells over to the left):
UIView.animate(withDuration: 0.35, animations: {() -> Void in
self.collectionView.setCollectionViewLayout(self.zoomedGridLayout, animated: true)
let zoomedRect = CGRect(x: -rect.width, y: 0, width: rect.width*3, height: rect.height)
self.collectionView.frame = zoomedRect
self.collectionView.collectionViewLayout.invalidateLayout()
})
The collection view doesn't need to be scrollable after the animation (I intend to use it only as a transition to another view).

How to implement such pop over view animation?

I was using this ride-sharing ios app and found this pop over animation of options view. I wanted to implement similar pop over but could figure out if it is a custom transition or animation? Here is a link to the GIF of popover in application.
It will be helpful to link me to examples/tutorial/code with similar animation so that I can begin implementing on my ios app.
This is pretty simple. Just position your options view on the screen where you want it to appear and set the alpha to 0 so it is hidden. Then, prior to animation, make the view wider using scaleX, and translate it down using translationY. Then simply animate it back to .identity and animate the alpha back to 1.0 so it fades in. A basic example is below. When you dismiss the view you just do the opposite. Let me know if you need help with that.
yourView.transform = CGAffineTransform(scaleX: 1.3, y: 0)
yourView.transform = CGAffineTransform(translationX: 0.0, y: 200.0)
yourView.alpha = 0
UIView.animate(withDuration: 0.3, animations: {
yourView.transform = .identity
yourView.alpha = 1.0
})
I achieved the following animation using leading, trailing and button constraints. Please let me know if such animation can be done in other ways.
yourview.alpha = 0
UIView.animate(withDuration: 0.6, animations: {
self.leadingConstraints.constant = 20
self.trailConstraints.constant = -20
self.buttonConstraints.constant = 20
self.yourview.alpha = 1
self.yourview.layoutIfNeeded()
})

UIView.animate problems with view frame

I'm struggling trying to make an animation. This is what's happening: video
The back card was supposed to do the same animation as in the beginning of the video, but it's doing a completely different thing. I'm checking the UIView.frame at the beginning of the animation and it's the same as the first time the card enters, but obviously something is wrong... Here is the code:
func cardIn() {
let xPosition = (self.darkCardView?.frame.origin.x)! - 300
let yPosition = (self.darkCardView?.frame.origin.y)!
self.initialPos = self.darkCardView.frame
let height = self.darkCardView?.frame.size.height
let width = self.darkCardView?.frame.size.width
self.darkCardView?.transform = (self.darkCardImageView?.transform.rotated(by: CGFloat(Double.pi/4)))!
UIView.animate(withDuration: 1.1, animations: {
self.darkCardView?.frame = CGRect(x: xPosition, y: yPosition, width: width!, height: height!)
self.darkCardView?.transform = (self.darkCardImageView?.transform.rotated(by: CGFloat(0)))!
})
}
func cardOut() {
let xPosition = (self.darkCardView?.frame.origin.x)! - 600
let yPosition = (self.darkCardView?.frame.origin.y)!
let height = self.darkCardView?.frame.size.height
let width = self.darkCardView?.frame.size.width
self.darkCardView?.transform = (self.darkCardImageView?.transform.rotated(by: CGFloat(0)))!
UIView.animate(withDuration: 1.0, delay: 0, options: .allowAnimatedContent, animations: {
self.darkCardView?.frame = CGRect(x: xPosition, y: yPosition, width: width!, height: height!)
self.darkCardView?.transform = (self.darkCardImageView?.transform.rotated(by: CGFloat(-Double.pi/4)))!
}) { (true) in
self.darkCardView?.transform = (self.darkCardImageView?.transform.rotated(by: CGFloat(0)))!
self.darkCardView?.frame = self.initialPos
self.cardIn()
}
}
Does somebody know how can I repeat the same animation that's in the beginning of the video after cardOut function is called?
Given that we do not know where/when you are calling the above two functions I can only take a guess at what is happening.
So you have an animate in and an animate out, but what about a reset function?
Timeline:
Animate the card in.
...
Eventually animate the card out
...
Reset the cards location to off screen to the right (location before animating in for the first time)
...
animate the card in
...
Repeat, ect....
I managed to solve the animation problem by calling viewDidLoad() instead of calling self.cardIn() in the end o cardOut completion block. But I don't want to depend on calling viewDidLoad every time a new card has to enter the screen...
Also, I didn't set any properties of the back card in viewDidLoad. I only have it in the .xib file. Any ideas?
Note that if you set a view's transform to anything other than the identity transform then the view's frame rect becomes "undefined". You can neither set it to a new value nor read it's value reliably.
You should change your code to use the view's center property if you're changing the transform.
As Jerland points out in their post, you also probably need to reset your back card to it's starting position before beginning the next animation cycle. (Set it to hidden, put it's center back to the starting position and set it's transform back to the identity transform.
EDIT:
This code:
UIView.animate(withDuration: 1.0, delay: 0, options: .allowAnimatedContent, animations: {
self.darkCardView?.frame = CGRect(x: xPosition, y: yPosition, width: width!, height: height!)
self.darkCardView?.transform = (self.darkCardImageView?.transform.rotated(by: CGFloat(-Double.pi/4)))!
}) { (true) in
self.darkCardView?.transform = (self.darkCardImageView?.transform.rotated(by: CGFloat(0)))!
self.darkCardView?.frame = self.initialPos
self.cardIn()
}
Does not set the transform to identity. Try changing that line to
self.darkCardView?.transform = .identity

How to show a growing sub view over a parent view

I have a view as follows
The colored tiles are basically views. When i long press on the tiled views i am creating a copy of the tile in which it was long pressed. Also when it is long pressed there should be a view as per the following image.
The drop area should come up from bottom part or it should grow from bottom insect of the screen.
When long pressing on the tiled view i am creating a copy of the view and i am able to make the copy successfully and drag on the screen, but i am stuck at creation of this drop area and its animation.
Can someone guide me how to implement this....
Thanks in advance...
let dropView = UIView(frame: CGRect(x:0, y:0, width:300, height:100))
dropView.frame.origin = CGPoint(x: 0, y: self.view.frame.size.height)
dropView.center = CGPoint(x:self.view.frame.size.width/2, y:dropView.center.y)
dropView.backgroundColor = UIColor.blue
self.view.addSubview(dropView)
When you want to animate it to show up use this:
UIView.animate(withDuration: 0.5, delay: 0.0, options: [.repeat, .curveEaseOut, .autoreverse], animations: {
dropView.frame.origin = CGPoint(x:dropView.frame.origin.x, y:dropView.frame.origin.y - dropView.frame.size.width - 10)
}, completion: nil)

Resources