CollectionView animate size cell

collectionview

#1

День добрый
Создаю свой Tabbar
И столкнулся с проблемой в изменение размеров ячеек ( Они дергаются :slightly_frowning_face: )
Как можно сделать это все плавно? ( на se еще заметнее )
И view - которая катается - как можно ей плавно поменять размер?
Видео

Вот код:

class TabBarView: UIView, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource, UICollectionViewDelegate {
private let tabBarImages = ["Images1", "Images4", "Images3", "Images2"]
private let nameCell = ["Home", "Favorite", "History", "Setting"]
var imageCircleView = UIImageView()
let nameCellLabel = UILabel()

lazy var collectionView: UICollectionView = {
    let layout = UICollectionViewFlowLayout.init()
    layout.scrollDirection = .horizontal
    layout.minimumLineSpacing = 0
    layout.minimumInteritemSpacing = 0
    
    let frame = CGRect(x: 0, y: UIScreen.main.bounds.height - 63, width: UIScreen.main.bounds.width, height: 63)
    
    let collectionView = UICollectionView(frame: frame, collectionViewLayout: UICollectionViewFlowLayout.init())
    collectionView.setCollectionViewLayout(layout, animated: true)
    collectionView.delegate = self
    collectionView.dataSource = self
    collectionView.register(TabBarCellCollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
    collectionView.backgroundColor = .clear
    
    return collectionView
}()

lazy var viewSlide: UIView! = {
    let view = UIView()
    
    return view
}()


lazy var circleView: UIView! = {
    let view = UIView()
    
    return view
}()

var selectedIndex = 0
var bigCell: CGFloat! = 0
var smileCell: CGFloat! = 0

//
func setup() {
    backgroundColor = #colorLiteral(red: 0.2588235438, green: 0.7568627596, blue: 0.9686274529, alpha: 1)
    
    let backgroundView = UIView(frame: UIScreen.main.bounds)
    backgroundView.backgroundColor = UIColor(white: 1, alpha: 0.1)
    insertSubview(backgroundView, at: 0)
    
    configureCollectionView()
    configureViewCell()
    configureCircleView()
    configureImageCircleView()
    configureNameCellLabel()
}

func configureCollectionView() {
    addSubview(collectionView)
    collectionView.translatesAutoresizingMaskIntoConstraints = false
    
    collectionView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
    collectionView.heightAnchor.constraint(equalToConstant: 63).isActive = true
    collectionView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
    collectionView.topAnchor.constraint(equalTo: topAnchor).isActive = true
    
}

func configureViewCell() {
    viewSlide.backgroundColor = .clear
    insertSubview(viewSlide, at: 2)
    viewSlide.translatesAutoresizingMaskIntoConstraints = false
    viewSlide.leadingAnchor.constraint(equalTo: collectionView.leadingAnchor).isActive = true
    viewSlide.topAnchor.constraint(equalTo: collectionView.topAnchor).isActive = true
    viewSlide.bottomAnchor.constraint(equalTo: collectionView.bottomAnchor).isActive = true
}

func configureCircleView() {
    circleView.translatesAutoresizingMaskIntoConstraints = false
    viewSlide.addSubview(circleView)
    circleView.leadingAnchor.constraint(equalTo: viewSlide.leadingAnchor, constant: 6).isActive = true
    circleView.topAnchor.constraint(equalTo: viewSlide.topAnchor, constant: 8).isActive = true
    circleView.trailingAnchor.constraint(equalTo: viewSlide.trailingAnchor, constant: -6).isActive = true
    circleView.bottomAnchor.constraint(equalTo: viewSlide.bottomAnchor, constant: -8).isActive = true
    
    circleView.backgroundColor = #colorLiteral(red: 0.3647058904, green: 0.06666667014, blue: 0.9686274529, alpha: 1)
    DispatchQueue.main.async {
        
        self.circleView.layer.cornerRadius = self.circleView.frame.height / 2
        self.circleView.layer.masksToBounds = true
    }
}

func configureNameCellLabel() {
    nameCellLabel.translatesAutoresizingMaskIntoConstraints = false
    circleView.addSubview(nameCellLabel)
    
    nameCellLabel.leadingAnchor.constraint(equalTo: imageCircleView.trailingAnchor, constant: 4).isActive = true
    nameCellLabel.trailingAnchor.constraint(equalTo: circleView.trailingAnchor, constant: -8).isActive = true
    nameCellLabel.centerYAnchor.constraint(equalTo: circleView.centerYAnchor).isActive = true
    
    nameCellLabel.alpha = 0
    nameCellLabel.textColor = .white
    nameCellLabel.font = UIFont.systemFont(ofSize: 14)
    nameCellLabel.sizeToFit()
    nameCellLabel.adjustsFontSizeToFitWidth = false
    
    nameCellLabel.text = self.nameCell[self.selectedIndex]
    nameCellLabel.alpha = 1
}

func configureImageCircleView() {
    
    
    imageCircleView.translatesAutoresizingMaskIntoConstraints = false
    circleView.addSubview(imageCircleView)
    imageCircleView.leadingAnchor.constraint(equalTo: circleView.leadingAnchor, constant: 2).isActive = true
    imageCircleView.topAnchor.constraint(equalTo: viewSlide.topAnchor, constant: 12).isActive = true
    imageCircleView.widthAnchor.constraint(equalToConstant: collectionView.bounds.height - 22).isActive = true
    imageCircleView.bottomAnchor.constraint(equalTo: viewSlide.bottomAnchor, constant: -10).isActive = true
    imageCircleView.contentMode = .scaleAspectFit
    let imageName = tabBarImages[self.selectedIndex]
    imageCircleView.image = UIImage(named: imageName)
    
    DispatchQueue.main.async {
        let frame = UIScreen.main.bounds.width - self.viewSlide.bounds.width
        self.smileCell = frame / 3
        self.collectionView.reloadData()
    }
}


override func layoutSubviews() {
}

//MARK: CollectionView
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return tabBarImages.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! TabBarCellCollectionViewCell
    
    let imageName = self.tabBarImages[indexPath.row]
    cell.imageCell.image = UIImage.init(named: imageName)
    
    return cell
}


func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    
    if selectedIndex != indexPath.row {
        return CGSize(width: smileCell, height: 63)
    } else {
        return CGSize(width: viewSlide.bounds.width, height: 63)
    }
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    if selectedIndex != indexPath.row {
        imageCircleView.image = UIImage(named: tabBarImages[indexPath.row])
        nameCellLabel.text = nameCell[indexPath.row]
        let cell = collectionView.cellForItem(at: indexPath) as? TabBarCellCollectionViewCell
        cell?.animateCell()
        selectedIndex = indexPath.row
        NotificationCenter.default.post(name: Notification.Name.init(rawValue: "didSelectMenu"), object: nil, userInfo: ["index": selectedIndex])
        
        let frame = UIScreen.main.bounds.width - self.viewSlide.bounds.width
        self.smileCell = frame / 3
        self.newFrame(indexPath: indexPath.row)
    }
}

var xPosition: CGFloat = 0
func position(indexPath: Int) {
    
    let step = smileCell
    switch indexPath {
    case 0:
        xPosition = 0
    case 1:
        xPosition = step!
    case 2:
        xPosition = step! + step!
    case 3:
        xPosition = step! + step! + step!
    default:
        break
    }
    
    
    UIView.animate(withDuration: 0.5, animations: {
        self.viewSlide.transform = CGAffineTransform(translationX: self.xPosition, y: 0)
        self.collectionView.performBatchUpdates({
            self.collectionView.reloadData()
            
        }, completion: nil)
        
    }) { (_) in
        let cell = self.collectionView.cellForItem(at: IndexPath(row: self.selectedIndex, section: 0)) as? TabBarCellCollectionViewCell
        cell?.showCell()
    }
}

func newFrame(indexPath: Int) {
    UIView.animate(withDuration: 0.001, animations: {
        
    }) { (_) in
        let frame = UIScreen.main.bounds.width - self.viewSlide.bounds.width
        self.smileCell = frame / 3
        self.position(indexPath: indexPath)
    }
}

override func awakeFromNib() {
    super.awakeFromNib()
    setup()
}

deinit {
    NotificationCenter.default.removeObserver(self)
     }
 }

class TabBarCellCollectionViewCell: UICollectionViewCell {

var imageCell = UIImageView()

override func draw(_ rect: CGRect) {
}

override init(frame: CGRect) {
    super.init(frame: frame)
    configureImageCell()
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

override func awakeFromNib() {
    super.awakeFromNib()
    contentView.frame.size = CGSize(width: UIScreen.main.bounds.width, height: 63)
    configureImageCell()
    backgroundColor = .clear
    contentView.backgroundColor = .clear
}

func animateCell() {
    UIView.animate(withDuration: 0.002, animations: {
        self.imageCell.alpha = 0
    }) { (_) in
        
    }
}

func showCell() {
    UIView.animate(withDuration: 0.3, animations: {
        self.imageCell.alpha = 1
    }) { (_) in
        
    }
}

func configureImageCell() {
    imageCell.translatesAutoresizingMaskIntoConstraints = false
    contentView.addSubview(imageCell)
    //    icon.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 7).isActive = true
    //    icon.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8).isActive = true
    imageCell.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
    imageCell.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
    imageCell.widthAnchor.constraint(equalToConstant: contentView.bounds.height - 16).isActive = true
    imageCell.heightAnchor.constraint(equalToConstant: contentView.bounds.height - 16).isActive = true
    
    imageCell.contentMode = .scaleAspectFit
   }
}

#2

Не знаю пока ответа на основной вопрос, но на глаза попался код:

let step = smileCell
switch indexPath {
case 0:
    xPosition = 0
case 1:
    xPosition = step!
case 2:
    xPosition = step! + step!
case 3:
    xPosition = step! + step! + step!
default:
    break
}

Это же: xPosition = smileCell! * CGFloat(indexPath)


#3

Там вообще больше кода - это только малая часть