How to animate UICollectionview cells as i scroll - ios

How can i animate Horizontal Collectionview as it is scrolled i changed alpha to 0 in the cell and in cellForItemAt i animate the alpha back to 1 but that only happens when the Collectionview is scrolled through the first time here is the code i have tried
UIView.animate(withDuration: 0.8) {
cell.imageView.alpha = 1
cell.onboardLabel.alpha = 1
}
I also tried to do this in scrollViewDidEndDecelerating but still not working
let index = Int(scrollView.contentOffset.x) / Int(scrollView.frame.width)
let indexPath = IndexPath(item: index, section: 0)
let cell = collectionView.cellForItem(at: indexPath) as? OnboardingCell
UIView.animate(withDuration: 0.8) {
cell?.imageView.alpha = 1
cell?.onboardLabel.alpha = 1
}

Swift 4:
Use this function from UICollectionViewDelegate:
override func collectionView(_ collectionView: UICollectionView,
willDisplay cell: UICollectionViewCell,
forItemAt indexPath: IndexPath) {
cell.alpha = 0
UIView.animate(withDuration: 0.8) {
cell.alpha = 1
}
}

Firstly you need to know which cells are visible so set this variable at the top of the file.
var visibleIndexPath: IndexPath? = nil
In scrollViewDidEndDecelerating use this code to set the visibleIndexPath:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
var visibleRect = CGRect()
visibleRect.origin = collectionView.contentOffset
visibleRect.size = collectionView.bounds.size
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
if let visibleIndexPath = collectionView.indexPathForItem(at: visiblePoint) {
self.visibleIndexPath = visibleIndexPath
}
}
Now that you have a visibleIndexPath you can animate the cell in the willDisplay cell function.
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if let visibleIndexPath = self.visibleIndexPath {
// This conditional makes sure you only animate cells from the bottom and not the top, your choice to remove.
if indexPath.row > visibleIndexPath.row {
cell.contentView.alpha = 0.3
cell.layer.transform = CATransform3DMakeScale(0.5, 0.5, 0.5)
// Simple Animation
UIView.animate(withDuration: 0.5) {
cell.contentView.alpha = 1
cell.layer.transform = CATransform3DScale(CATransform3DIdentity, 1, 1, 1)
}
}
}
}

Related

Make CollectionView Cell horizontal cell bigger than others

I have a collectionView and want to make the center cell is bigger than other cells and when move to previous or next cell make it bigger in center
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.collectionView {
return slidData.count
} else {
return categoryData.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.collectionView {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imageCell", for: indexPath) as! SliderImgCell
cell.categoryName.text = slidData[indexPath.row].imageTitle
cell.detail.text = slidData[indexPath.row].imageContent
cell.pics = slidData[indexPath.item]
return cell
} else{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "categoryCell", for: indexPath) as! CategoryCell
cell.categoryName.text = categoryData[indexPath.row].depName
cell.pics = categoryData[indexPath.item]
return cell
}
}
You need to save the selected indexPath like this:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedIndexPath = indexPath
}
Your collection view must confirm UICollectionViewDelegateFlowLayout. Then in sizeForItemAt method resize your cell:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if indexPath == selectedIndexPath {
return CGSize(width: 200, height: 90)
} else {
return CGSize(width: 180, height: 80)
}
}
Basically you want a Carousel animation.
Take a look into this library and either use full of it or take help from the code.
You can achieve this by using ScrollViewDidScroll(_:) method and find the center cell and enlarge it.
I wrote clear comments on the code below, if you want to go into details check-out my article about this:
https://medium.com/#sh.soheytizadeh/zoom-uicollectionview-centered-cell-swift-5-e63cad9bcd49
func setFocusedCellStyle(_ scrollView: UIScrollView) {
guard scrollView is UICollectionView else { return }
// get the centerPoint
let centerPoint = CGPoint(x: self.collectionView.frame.size.width / 2 + scrollView.contentOffset.x, y: self.collectionView.frame.size.height / 2 + scrollView.contentOffset.y)
// get the indexPath for the cell at center
if let indexPath = self.collectionView.indexPathForItem(at: centerPoint), self.centerCell == nil {
// centerCell is instance variable of type: YourCell
self.centerCell = (self.colorPickerCollectionView.cellForItem(at: indexPath) as! CustomCollectionViewCell)
UIView.animate(withDuration: 0.2) {
// Choose desired scale value
self.transform = CGAffineTransform(scaleX: 1.58, y: 1.58)
}
}
if let cell = self.centerCell { // center cell is global variable
let offsetX = centerPoint.x - cell.center.x // get to current position of the cell
// when cell is 15 pixels away from the center to the sides
// reset the cell size.
if offsetX < -15 || offsetX > 15 {
UIView.animate(withDuration: 0.2) {
self.transform = CGAffineTransform.identity
}
self.centerCell = nil // set this to nil so next cell in the center will enter the above scope
}
}
}

How can I scroll collectionView when scrollview scrolls in swift?

I have Scrollview and Collectionview, both of them scrolls horizontally
scrollview have pages and I want when scrollview scrolls, also scroll collectionview and select same indexed collectionview cell as scrollview page index
the problem here is that after scrollview scrolls, also scrolls collectionview and it selects cell same indexed as scrollview pages, but after that collectionview doesn't scrolls itself.
Sorry maybe bad format of question, I am new here
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell=collectionView.dequeueReusableCell(withReuseIdentifier: "mycell", for: indexPath) as! MenuListCollectionViewCell
cell.commoninit(name: ListOfMenu[indexPath.row])
let IndexForCol = (scrollview.contentOffset.x / scrollview.frame.size.width).rounded()
if selectedIndex == Int(indexPath.row)
{
cell.backgroundColor = UIColor(hue: 0.6167, saturation: 1, brightness: 0.97, alpha: 1.0)
cell.layer.cornerRadius = 14
}
if indexPath.row == Int(IndexForCol) {
cell.backgroundColor = UIColor(hue: 0.6167, saturation: 1, brightness: 0.97, alpha: 1.0)
}
else
{
cell.backgroundColor = UIColor.clear
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedIndex = indexPath.row
UIView.animate(withDuration: 0.5, animations: {
self.scrollview.contentOffset.x = self.scrollview.frame.width*CGFloat(indexPath.row)
})
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let indexOfPage = round(scrollview.contentOffset.x / scrollview.frame.size.width)
UIView.animate(withDuration: 0.5, animations: {
self.collectionview.scrollToItem(at:IndexPath(item: Int(indexOfPage), section: 0), at: .right, animated: false)
})
collectionview.reloadData()
}
Simulator image:
scrollViewDidScroll is called for both the collectionView and the scrollView so give a tag to the scrollView then
//
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.tag == 2 { // scrollView scrolled
use collectionView's scrollToItem
}
else { // collectionView scrolled
set contentOffset to the scrollView
}
}

How to make the left and right image opacity down?

How to lower the opacity of the the left and right image? I am using a CollectionView to show all the data in the image. I want to lower the opacity of the views to the left and right of the center. I don't know how to do that. I can do all stuff in viewDidLayoutSubviews. Please resolve this issue. This is my code:
var arrHeading = ["Total Visitors in last 30 Days", "Total Departments", "Total Employees"]
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return arrHeading.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "VisitorDashboardCell", for: indexPath) as! VisitorDashboardCell
cell.imgBG.layer.cornerRadius = 10
cell.imgBG.layer.masksToBounds = true
//Set Gradient Color to CollectionViewCell
cell.layer.shadowColor = UIColor.black.cgColor
cell.layer.shadowOffset = CGSize(width: 0, height: 0)
cell.layer.shadowRadius = 2.0;
cell.layer.shadowOpacity = 0.9;
cell.layer.cornerRadius = 10
cell.layer.masksToBounds = false
cell.imgBG.layer.shadowPath = UIBezierPath(rect: CGRect(x: -8, y: -18, width: cell.frame.size.width + 8 , height: cell.frame.size.height + 18)).cgPath
cell.layoutIfNeeded()
cell.imgBG.image = UIImage.init(named: arrImage[indexPath.row])
cell.imgIcon.image = UIImage.init(named: arrIcon[indexPath.row])
cell.lblHeading.text = arrHeading[indexPath.row]
cell.lblNum.text = arrNum[indexPath.row]
return cell
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let middleValue = round(Double(arrHeading.count / 2))
print("Middle Value \(middleValue)")
if arrHeading.count < Int(middleValue)
{
var leftArray = [Int]()
for i in 0..<(Int(middleValue) - 1) {
leftArray.append(i)
}
print("Left Array \(leftArray)")
}
else if arrHeading.count > Int(middleValue)
{
var rightArray = [Int]()
for i in Int(middleValue)..<arrHeading.count
{
rightArray.append(i)
}
print("Right Array \(rightArray)")
}
else
{
//Show middle element of the collection view
let selectedIndex = IndexPath(item: Int(middleValue), section: 0)
self.collectionView.scrollToItem(at: selectedIndex, at: .centeredHorizontally, animated: false)
}
}
Try something like this on your delegate:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
UIView.animate(withDuration: 0.5) {
cell.alpha = cell.isSelected ? 1 : 0.5
}
}

How to animate UIView inside UICollectionViewCell?

I have created a custom UICollectionViewCell and it contains a subView named animView which I intend to animate. The shape of animView is a regular vertical rectangle.
In the configureCell() method, I use the code below to configure the cells and create an animation, but I do not see the animation.
animView.transform = CGAffineTransform(scaleX: 1.0, y: 0.5)
self.layoutIfNeeded()
UIView.animate(withDuration: 0.7, delay: 0, options: [.curveEaseOut], animations: {
self.animView.transform = CGAffineTransform.identity
self.layoutIfNeeded()
}, completion: nil)
However, when I try to animate whole cell, I see the cell animate successfully.
self.transform = CGAffineTransform(scaleX: 1.0, y: 0.5)
self.layoutIfNeeded()
UIView.animate(withDuration: 0.7, delay: 0, options: [.curveEaseOut], animations: {
self.transform = CGAffineTransform.identity
self.layoutIfNeeded()
}, completion: nil)
I appreciate your time and answer.
EDIT:
As per the suggestions, I changed where I call the animation as shows below. Now, when I try to animate whole cell it is working. However, I want to animate the animView which is a subview of the custom UICollectionViewCell (BarCell). But it is not animating. Any ideas?
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
let cells = collectionView.visibleCells
for cell in cells {
let current = cell as! BarCell
let curAnimView = current.animView
curAnimView?.transform = CGAffineTransform(translationX: 0, y: current.animFillHeightCons.constant)
UIView.animate(withDuration: 0.7) {
curAnimView?.transform = CGAffineTransform.identity
}
}
}
You need to start animation for only visible cells.
Here is how you can do that.
add this
UIScrollViewDelegate
It will provide the method
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let cells = colAnim.visibleCells
for cell in cells
{
let current = cell as! testCollectionViewCell
UIView.animate(withDuration: 2.0, animations: {
current.animView.transform = CGAffineTransform(translationX: -400, y: 0)
//Change this animation
})
}
}
Also make sure do this also.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "testCollectionViewCell", for: indexPath) as! testCollectionViewCell
cell.animView.transform = CGAffineTransform(translationX: 0, y: 0)// This one
return cell
}
By doing this you can achieve animation only when cell is visible.
Thanks.
There are 2 conditions to make it happen:
You will need to reset the properties you are animating every cell binding
You will have to start the animation only when the cell is about to be visible
Also, there are exceptions (like what I had), sometimes the cell binding or the layout of your collection is complex or custom thus, in these cases we will have to delay the animation so it will actually work.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// your dequeue code...
// ...
// Reseting your properties as described in 1
cell.myImageView.alpha = 1
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
let myCell = cell as! MyCell
// As described in 2
myCell.animate()
}
class MyCell: UICollectionViewCell {
func animate() {
// Optional: As described above, if your scene is custom/complex delaying the animation solves it though it depends on your code
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
// Animation code
UIView.animate(withDuration: 1,
delay: 0,
options: [.autoreverse, .repeat]) {
self.seenNotSeenImageView.alpha = 0.5
}
}
}
}
There's also a third condition:
If your cell will be covered by another VC, you will want to initiate the same animated() method as follow, in your viewWillAppear of the VC that holds the collectionView:
collectionView.visibleCells.forEach{($0 as? MyCell)?.animate()}

Collectionview animated

I have collection view with items, each item has dimension (65 * 65) with horizontal flow, and I have button.
So when I click on the button all items must stack over first item, then I need to make collection layout vertically (like table view).
How to make it (with animation)?
func collectionView(collectionView: UICollectionView,layout collectionViewLayout: UICollectionViewLayout,sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
if self.isClose {
return CGSizeMake(50, 50)
}else{
if self.isOpen {
return CGSizeMake(320, 50)
}else {
return CGSizeMake(50, 50)
}
}
}
Screenshot
In Swift 3 and 4
func collectionView(_ collectionView: UICollectionView, didHighlightItemAt indexPath: IndexPath) {
UIView.animate(withDuration: 0.5) {
if let cell = collectionView.cellForItem(at: indexPath) as? SSProductCell {
cell.imageView.transform = .init(scaleX: 0.95, y: 0.95)
cell.contentView.backgroundColor = UIColor(red: 0.95, green: 0.95, blue: 0.95, alpha: 1)
}
}
}
func collectionView(_ collectionView: UICollectionView, didUnhighlightItemAt indexPath: IndexPath) {
UIView.animate(withDuration: 0.5) {
if let cell = collectionView.cellForItem(at: indexPath) as? SSProductCell {
cell.imageView.transform = .identity
cell.contentView.backgroundColor = .clear
}
}
}

Resources