I am working on chat application. I am using UIcollectionview for display message. I am trying to create animation on the send button. When the user taps on send UIButton at that I need animation like iMessage.
For creating such animation I use two different ways but not get proper animation.
I created one demo. In that demo, I implemented different approaches.
Demo link:
https://www.dropbox.com/s/z8rxjkpuxzs95kp/AdvanceCollection.zip?dl=0
Below is animation that actually I need:
https://www.dropbox.com/s/yo35lsm7yrc2oqu/Screen%20Recording.mov?dl=0
I apply 2 approaches. Below is approach description.
First approach:
In the first approach, I customized FlowLayout. I know this is proper way but not getting proper curve animation.
override func initialLayoutAttributesForAppearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
guard let attributes = super.initialLayoutAttributesForAppearingItem(at: itemIndexPath),
let added = addedItem,
added == itemIndexPath else {
return nil
}
// set new attributes
attributes.frame = CGRect(x: 0, y: 0, width: 500, height: 500)
//attributes.center = CGPoint(x: self.collectionView!.frame.width - 23.5, y: -24.5)
attributes.center = CGPoint(x: 0.0, y: 100.0)
attributes.alpha = 1.0
attributes.transform = CGAffineTransform(scaleX: 0.15, y: 0.15)
attributes.zIndex = 20
return attributes
}
Second approach: In the second approach, I am implementing animation in willdisplaycell method. According to my point of view, I know this is not the proper approach to customize layout but I tried. In second approach I am getting animation from bottom but x, y, width and height. Also whatever animation is visible is also not same as iMessage send message animation
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if !self.collectionData[indexPath.row].isAnimated
{
cell.frame = CGRect(x: 0, y: chatView.frame.origin.y, width: 1000.0, height: chatView.frame.size.height)
UIView.animate(withDuration: 10.0, delay: 0, usingSpringWithDamping: 0.4, initialSpringVelocity: 0.6, options: UIViewAnimationOptions.curveEaseIn, animations: {
cell.frame = CGRect(x:0, y: cell.frame.origin.y, width: cell.frame.size.width, height: cell.frame.size.height)
}, completion: { finished in
self.collectionData[indexPath.row].isAnimated = true
})
}
}
Edit: see tableView demo here animateCell
I think you may try using tableView instead of the collectionView to accomplish that as collectionView layout is awfully silly
I assume you have created a custom xib cell for your collectionView then do this
1- set the top , bottom , leading , trailing constraints properly to the superview of your message label
2- change the top constraint of the message label to be say 400
3- set hook that top constraint as IBOutlet
4- in cellForRowAt set that constraint to say 20
5- then do animation like that
UIView.animateWithDuration(1.0,
{
cell.layoutSubview()
cell.layoutIfNeeded()
}
note: the problem with collectionView is chagning size for item so animation can happen , above solution works perfectly with tableView
Related
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).
I'm trying to make this animation
so i want that when the user picks up with his finger the cell get smaller and then when it stops pressing come back on the original size, important is that i'm not using a custom cell but the default UITableViewCell, here is my code with whom i tried to do the animation (after watching old question and tutorial)
var originalCellSize: CGRect!
func tableView(_ tableView: UITableView, didHighlightRowAt indexPath: IndexPath) {
print("I'm Highlighted at \(indexPath.section)")
guard let cell = tableView.cellForRow(at: indexPath) else {
return
}
originalCellSize = cell.frame
UIView.animate(withDuration: 0.1, animations: {
cell.frame = CGRect(x: cell.frame.origin.x + 20, y: cell.frame.origin.y, width: cell.frame.width - 40, height: cell.frame.height)
})
}
func tableView(_ tableView: UITableView, didUnhighlightRowAt indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) else {
return
}
UIView.animate(withDuration: 0.1, animations: {
cell.frame = CGRect(x: 0, y: self.originalCellSize.origin.y, width: self.view.bounds.width, height: 180)
})
originalCellSize = .zero
}
i don't know why but something is wrong and the animation do not work, can someone help me (it also happens that after pushing on the cell this changes position in a definitive way)
Don't manipulate UITableViewCell's frame directly.
Use it's transform property.
Likewise:
Scale down the cell upon highlight / selection.
UIView.animate(withDuration: 0.3) {
cell.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
cell.layoutIfNeeded()
}
Scale back to normal:
UIView.animate(withDuration: 0.3) {
cell.transform = CGAffineTransform.identity
cell.layoutIfNeeded()
}
Don't forget to call cell.layoutIfNeeded() before the animation block and inside (right after assigning the CGAffineTransform).
You can approach the problem in a different way. You can resize a view inside the Table view cell.
Like you can keep a view with white color and cell background as grey color. In highlight delegate method, you can change the frame of UIView inside the cell and on unhighlight method, you can resize to back to cell size.
WhenEver You want to change layout of cell you must need to call cell.layoutIfNeeded().
Set flag that cell should change size.
Add flag check for heightForRowAtIndexPath
On highlighting use:
table.beginUpdates()
table.reloadRowsAt(...)
table.endUpdates()
Should work just fine.
I'm not sure you can just change frame of the cell. So you can also try try to change cell's content view size. Or your custom view frame itself.
Vis of problem: http://i.imgur.com/TastPR9.gifv
func animateHeaderResize(height: CGFloat) {
let layout = self.collectionView?.collectionViewLayout as! UICollectionViewFlowLayout;
layout.headerReferenceSize = CGSize(width: UIScreen.main.bounds.width, height: height);
UIView.animate(withDuration: 1, delay: 0, options: .curveEaseOut, animations: {
self.collectionView?.layoutIfNeeded();
}) { (finished) in
//self.loadPosts();
}
}
I am attempting to animate a change in the header size of a UICollectionView through it's UICollectionViewLayout. The resulting animation has a weird flash and stretch that might be a cross dissolve transition being triggered somewhere. I have tried many variations of setting the layout of the collection view including setCollectionViewLayout(layout:animated:) and implementing collectionView(_ collectionView: layout: referenceSizeForHeaderInSection section:) but all result in the same animation.
I have noticed that the same flash occurs when changing the item size of the collection view. Maybe this is some default behavior I can modify? Do I have to subclass UICollectionViewFlowLayout? I have tried searching and can't find a solution, would appreciate just a step in the right direction.
This ended up working for me:
func animateHeaderResize(height: CGFloat) {
self.collectionView?.performBatchUpdates({
let layout = self.collectionView?.collectionViewLayout as! UICollectionViewFlowLayout;
layout.headerReferenceSize = CGSize(width: UIScreen.main.bounds.width, height: height);
}, completion: { (fin) in
self.loadPosts();
});
}
Saw the same issue and I could see that animation looks better if i set:
layout.sectionHeadersPinToVisibleBounds = false
How can i animate the loading of cells into a collectionview.
Ive been playing with the following code but it only animates cells that are off screen when i scroll.
How to animate the all the cells not the screen to start?
let finalFrame: CGRect = cell.frame
cell.frame = CGRect(x: finalFrame.origin.x - 1000, y: -500, width: 0, height: 0)
UIView.animate(withDuration: 0.5, animations: {
cell.frame = finalFrame
})
Use performBatchUpdates(_:completion:)
And inside the performBatchUpdates block:
For items:
Insert: insertItems(at:)
Delete: deleteItems(at:)
Move/Reorder: moveItem(at:to:)
For sections:
Insert: insertSections(_:)
Delete: deleteSections(_:)
Move/Reorder: moveItem(at:to:)
If you want to further customize your animations:
1: Check this thread
2: YouTube tutorial
3: Github Project
4: Alternative UIStackView for Swift 3 Youtube Tutorial
What I already have: a horizontally scrolled UICollectionView, and its cells (just a single line of cells).
What I want to do: animate the cells when they are about to appear -- cells slide in from right (outside the screen) to left, eventually stop at the left border of the UICollectionView.
How could I achieve this? Any help is greatly appreciated!
You have to move the collectionView cell from their position to previous cell position by using following method
[collectionView moveItemAtIndexPath:fromIndexPath toIndexPath:toIndexPath];
I have implement same animation in collection view as given bellow :
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
let myreact = cell.frame
cell.frame = CGRect(x: cell.frame.origin.x+320, y: cell.frame.origin.y, width: cell.frame.size.width, height: cell.frame.size.height)
let value = Double(indexPath.row)*0.1
UIView.animate(withDuration: 0.8, delay:value, options: .curveEaseInOut, animations: {
cell.frame = CGRect(x: myreact.origin.x+100, y: myreact.origin.y, width: myreact.size.width, height: myreact.size.height)
}) { (finish) in
UIView.animate(withDuration: 0.8, animations: {
cell.frame = myreact
})
}
}
}
Try with it in Swift 3.0
Instead of animating the cells/the layout, I animate the UICollectionView, whose background color is [UIColor clearColor]...