当前位置:网站首页>Create cool collectionviewcell conversion animation
Create cool collectionviewcell conversion animation
2022-06-11 05:26:00 【the Summer Palace】
newly build iOS App project , open Main.storyboad, Drag into one CollectionView, Create layout constraints for it as follows :

by CollectionView Create a IBOutlet Connect :
@IBOutlet weak var collectionView: UICollectionView!
newly build swift file , Act as our model , This is what we're going to render in cell The data on the :
public struct SalonEntity {
// MARK: - Variables
/// Name
public internal(set) var name: String?
/// Address
public internal(set) var address: String?
// MARK: - Init
/// Convenience init
public init(name: String, address: String) {
self.name = name
self.address = address
}
}
newly build UICollectionViewCell Subclass SalonSelectorCollectionViewCell. open SalonSelectorCollectionViewCell.xib, Create as follows UI :

SalonSelectorCollectionViewCell It is still very simple :
class SalonSelectorCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var containerView: UIView!
@IBOutlet weak var salonNameLabel: UILabel!
@IBOutlet weak var salonAddressLabel: UILabel!
@IBOutlet weak var separatorLine: UIView!
func configure(with salon: SalonEntity) {
salonNameLabel.text = salon.name
salonAddressLabel.text = salon.address
}
override func prepareForReuse() {
super.prepareForReuse()
salonNameLabel.text = nil
salonAddressLabel.text = nil
}
}
extension UICollectionViewCell {
class var reuseIdentifier: String {
return NSStringFromClass(self).components(separatedBy: ".").last! }
}
open ViewController.swift, stay viewDidLoad in :
collectionView.register(UINib(nibName: "SalonSelectorCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: SalonSelectorCollectionViewCell.reuseIdentifier)
collectionView.dataSource = self
collectionView.delegate = self
Then implement UICollectionViewDataSource:
extension ViewController: UICollectionViewDataSource {
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
salons.count
}
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let selectorCell = collectionView.dequeueReusableCell(withReuseIdentifier: SalonSelectorCollectionViewCell.reuseIdentifier, for: indexPath) as? SalonSelectorCollectionViewCell else {
return UICollectionViewCell() }
let salon = salons[indexPath.item]
selectorCell.configure(with: salon)
return selectorCell
}
}
extension ViewController: UICollectionViewDelegate {
public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
}
}
function App,collect view It is shown in 5 individual cell:

Next , We're going to use UICollectionViewDelegate Agreement let collection view Display a little different style when it is selected :
public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
guard let cell = collectionView.cellForItem(at: indexPath) as? SalonSelectorCollectionViewCell else {
return }
cell.containerView.backgroundColor = .lightGray
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
guard let cell = collectionView.cellForItem(at: indexPath) as? SalonSelectorCollectionViewCell else {
return }
cell.containerView.backgroundColor = .white
}
In this way, one of the cell when ,cell The background color turns grey . But this is obviously not cool enough . We need to add a little animation to it .
First , We are SalonSelectorCollectionViewCell Add a state :
enum State {
case collapsed
case expanded
var backgroundColor: UIColor {
switch self {
case .collapsed:
return UIColor.lightGray
case .expanded:
return .white
}
}
}
State There are two states :collapsed and expanded, The difference between the two is backgroundColor - collapse This value is gray in the state , and expanded It is white in the state , It is similar to what we have just done , When cell When selected, it is a color , The reverse selection is another color .
Except for the background color, of course , We also need to let cell Do something in two different states UI Change on , For example expanded Let... In a state cell Get a little bigger . This requires us to create some for some layout constraints IBOutlet:
@IBOutlet weak var interLabelsPaddingConstraint: NSLayoutConstraint! // Two label Between the padding
@IBOutlet weak var separatorLineWidthConstraint: NSLayoutConstraint! // The width of the middle thin line
@IBOutlet weak var separatorLineHeightConstraint: NSLayoutConstraint! // The height of the middle thin line
@IBOutlet weak var containerViewHeightConstraint: NSLayoutConstraint! // Whole cell The height of
@IBOutlet weak var containerViewWidthConstraint: NSLayoutConstraint! // Whole cell The width of
@IBOutlet weak var salonNameLeadingConstraint: NSLayoutConstraint! // Salon name ( above label) Of leading
@IBOutlet weak var salonAddressLeadingConstraint: NSLayoutConstraint! // Salon address ( Below label) Of leading
At the same time enm State The definition of , Specified in different states ( collapase State and expanded state ) Under the corresponding constraint constant value , In general, except for the different background colors , Will make cell stay expanded It is slightly larger in the state , meanwhile collapsed In this state, the split line in the middle is invisible :
enum State {
...
var interLabelPadding: CGFloat {
switch self {
case .collapsed:
return 6
case .expanded:
return 56
}
}
var separatorWidth: CGFloat {
switch self {
case .collapsed:
return 0
case .expanded:
return 240
}
}
var separatorHeight: CGFloat {
switch self {
case .collapsed:
return 0
case .expanded:
return 2
}
}
var salonNameLeadingConstant: CGFloat {
switch self {
case .collapsed:
return 20
case .expanded:
return 40
}
}
var salonAddressLeadingConstant: CGFloat {
switch self {
case .collapsed:
return 60
case .expanded:
return 80
}
}
var containerWidth: CGFloat {
switch self {
case .collapsed:
return 250
case .expanded:
return 320
}
}
var containerHeight: CGFloat {
switch self {
case .collapsed:
return 150
case .expanded:
return 200
}
}
}
And then to SalonSelecotrCollectionViewCell Add a property :
var state: State = .collapsed {
didSet {
guard oldValue != state else {
return }
updateViewConstraints()
}
}
And then in updateViewConstraints In the method , Modify constraint constants according to different states :
private func updateViewConstraints() {
containerView.backgroundColor = state.backgroundColor
containerViewWidthConstraint.constant = state.containerWidth
containerViewHeightConstraint.constant = state.containerHeight
salonNameLeadingConstraint.constant = state.salonNameLeadingConstant
salonAddressLeadingConstraint.constant = state.salonAddressLeadingConstant
interLabelsPaddingConstraint.constant = state.interLabelPadding
separatorLineWidthConstraint.constant = state.separatorWidth
separatorLineHeightConstraint.constant = state.separatorHeight
layoutIfNeeded()
}
Of course , By default cell yes collapsed state ( Reverse election ):
override func prepareForReuse() {
...
state = .collapsed
}
go back to view controller modify didSelectItemAt Method :
public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
guard let cell = collectionView.cellForItem(at: indexPath) as? SalonSelectorCollectionViewCell else {
return }
cell.containerView.backgroundColor = .lightGray
UIView.animate(withDuration: 0.3) {
cell.state = .expanded
}
}
actually ,didDeselectItemAt Methods are unnecessary , We can delete it .
function App, Now we choose cell when ,cell The background color changes from light grey to white , meanwhile cell Zoom in :

Usually select one cell You need to click on it , But we often have some app see , occasionally cell You don't need to click , Just scroll it to the center of the view and it will be automatically selected , How does this work ?
This actually takes advantage of UIScrollView The relevant agent of the company and not UICollectionView. go back to ViewController.swift, Implement the following method :
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
var offsetAdjustment = CGFloat.greatestFiniteMagnitude
let horizontalCenter = targetContentOffset.pointee.x + collectionView.bounds.width / 2
let targetRect = CGRect(origin: targetContentOffset.pointee, size: collectionView.bounds.size)
guard let layoutAttributes = collectionView.collectionViewLayout.layoutAttributesForElements(in: targetRect) else {
return }
for layoutAttribute in layoutAttributes {
let itemHorizontalCenter = layoutAttribute.center.x
if abs(itemHorizontalCenter - horizontalCenter) < abs(offsetAdjustment) {
offsetAdjustment = itemHorizontalCenter - horizontalCenter
}
}
targetContentOffset.pointee.x += offsetAdjustment
}
such , Rolling scroll view when , When you release your finger , This method automatically returns scroll view The scrolling position is adjusted to cell Center alignment , Of course , Premise is contentView There is enough space ( Exceptions : first cell And the last cell). You can run App Look at the effect .
Then define a new enumeration , Used to record ScrollView The scrolling state of :
enum SelectionCollectionViewScrollingState {
case idle
case scrolling(animateSelectionFrame: Bool)
}
idle Express scroll view Scrolling has stopped ,scrolling It means you are still scrolling . stay ViewController Define a SelectorCollectionViewScrollingState attribute :
private var scrollingState: SelectionCollectionViewScrollingState = .idle {
didSet {
if scrollingState != oldValue {
updateSelection()
}
}
}
Here to SelectionCollectionViewScrollingState the != Compare , Need make SelectionCollectionViewScrollingState Realization Equatable agreement :
extension SelectionCollectionViewScrollingState: Equatable {
public static func ==(lhs: SelectionCollectionViewScrollingState, rhs: SelectionCollectionViewScrollingState) -> Bool {
switch (lhs, rhs) {
case (.idle, .idle):
return true
case (.scrolling(_), .scrolling(_)):
return true
default:
return false
}
}
}
When scrollingState When there is a change , call updateSelection To modify cell The state of :
func updateSelection() {
func updateSelection() {
UIView.animate(withDuration: 0.15) {
() -> Void in
guard let indexPath = self.getSelectedIndexPath(),
let cell = self.collectionView.cellForItem(at: indexPath) as? SalonSelectorCollectionViewCell else {
return
}
switch self.scrollingState {
case .idle:
cell.state = .expanded
case .scrolling(_):
cell.state = .collapsed
}
}
}
}
func getSelectedIndexPath() -> IndexPath? {
let visibleRect = CGRect(origin: collectionView.contentOffset, size: collectionView.bounds.size)
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
if let visibleIndexPath = collectionView.indexPathForItem(at: visiblePoint) {
return visibleIndexPath
}
return nil
}
getSelectedIndex() First of all get collection view Of the current viewable area frame, And then get its center point , call collectionView.indexPathForItem() Method and pass in this central point , You can know the cell Of indexPath.
Then implement scrollView Two methods of agency :
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
scrollingState = .scrolling(animateSelectionFrame: true)
}
public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
scrollingState = .idle
}
such , When you scroll collection view when , Scroll to the center of the screen cell Will automatically select and render expanded state :
video link: https://gitee.com/kmyhy/CollectionViewCoolAnimation/raw/master/5.movIf the video doesn't play , Download here :https://gitee.com/kmyhy/CollectionViewCoolAnimation/raw/master/5.mov
It's not cool enough , We are going to select the cell Add another type of viewfinder outside :
First , stay Main.storyboard, Drag into one view, And create a IBOutlet:
@IBOutlet weak var selectionFrameView: UIView!
stay selectionFrameView Put two on top image view, Add corresponding constraints , Wide and high 340*220 And let it and collection view Center alignment , Like this :

Note that the picture in the lower left corner can be rotated 180 degree :layer.transform.rotation.z = 3.14
Similar to State Enumerate what has been done , We will SelectionCollectionViewScrollingState The two states of are bound to the other two properties :
enum SelectionCollectionViewScrollingState {
...
var alpha: CGFloat {
switch self {
case .idle:
return 1
case .scrolling(let animateSelectionFrame):
return animateSelectionFrame ? 0 : 1
}
}
var transform: CGAffineTransform {
switch self {
case .idle:
return .identity
case .scrolling(let animateSelectionFrame):
return animateSelectionFrame ? CGAffineTransform(scaleX: 1.5, y: 1.5) : CGAffineTransform(scaleX: 1.15, y: 1.15)
}
}
}
When idle In the state of ,selectionFrameView Of alpha Will be set to 1, Switch to .scrolling Post state ,alpha according to animatedSelectionFrame And decide , by true when = 0, by false when = 1, meanwhile transform Will also make corresponding changes . such , Just switch idle/scrolling state , Can change “ finder frame ” Show / Hidden state and frame size .
Whenever... Is selected cell Will be called updateSelection Method , We just need to updateSelection Method to add this 2 sentence :
UIView.animate(withDuration: 0.15) {
() -> Void in
self.selectionFrameView.transform = self.scrollingState.transform
self.selectionFrameView.alpha = self.scrollingState.alpha
...
}
You can make the viewfinder display automatically , And execute a slightly enlarged animation .
And then in UICollectionViewDelegate Agreed didSelectItem In the method , increase
scrollingState = .scrolling(animateSelectionFrame: false)
In this way, when the user selects a by clicking rather than dragging cell when ,“ Viewfinder animation ” Still play .
Then, when we load view 1, the first one is selected by default cell. stay viewDidLoad() in :
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
[weak self] in
self?.updateSelection()
}
because collection view stay viewDidLoad It is very likely that there is no rendering , here collection view There may be no time to instantiate any cell , Lead to update cell Status failed , So we delay 0.5 Seconds before calling updateSelection Method , To solve this problem . This is an imperfect solution .
video link: 7.movIf the video doesn't play , Please download here :https://gitee.com/kmyhy/CollectionViewCoolAnimation/raw/master/7.mov
You can find , As mentioned earlier , first cell And the last cell Not scrolling to the center of the screen . This can be done by making ViewController Realization UICollectionViewDelegateFlowLayout Agreement to solve :
extension ViewController: UICollectionViewDelegateFlowLayout {
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
let padding = (collectionView.bounds.width - SalonSelectorCollectionViewCell.State.expanded.containerWidth) / 2
return UIEdgeInsets(top: 10, left: padding, bottom: 10, right: padding)
}
}
Through adjustment cell About padding , Give Way cell Auto Center . The end result is as follows :
video link: 8.movIf the video doesn't play , Please download here :https://gitee.com/kmyhy/CollectionViewCoolAnimation/raw/master/8.mov
边栏推荐
- Tianchi - student test score forecast
- Section II: structural composition characteristics of asphalt pavement (1) structural composition
- 1. use alicloud object OSS (basic)
- Get the third-party interface
- 1.使用阿里云对象OSS(初级)
- (十五)红外通信
- Section V: Recycling Application of asphalt pavement materials
- Conversion relationship between coordinate systems (ECEF, LLA, ENU)
- 在未来,机器人或 AI 还有多久才能具备人类的创造力?
- Technology | image motion drive interpretation of first order motion model
猜你喜欢

Huawei equipment configuration MCE

Linked list de duplication

The solution "no hardware is configured for this address and cannot be modified" appears during botu simulation

Number of atoms (easy to understand)

jvm调优六:GC日志分析和常量池详解

WinForm (I) introduction to WinForm and use of basic controls

在未来,机器人或 AI 还有多久才能具备人类的创造力?

Overview of self attention acceleration methods: Issa, CCNET, cgnl, linformer

Stone game -- leetcode practice

22、生成括号
随机推荐
Why is the smart door lock so popular? What about the smart door locks of MI family and zhiting?
Paper recommendation: relicv2, can the new self supervised learning surpass supervised learning on RESNET?
Huawei device configuration bgp/mpls IP virtual private network command
智能门锁为什么会这么火,米家和智汀的智能门锁怎么样呢?
jvm调优五:jvm调优工具和调优实战
Cross modal retrieval | visual representation learning
mysql字符串转数组,合并结果集,转成数组
PCB走線到底能承載多大電流
SQLite installation and configuration tutorial +navicat operation
Deep search + backtracking
Huawei equipment is configured with bgp/mpls IP virtual private network
Overview of self attention acceleration methods: Issa, CCNET, cgnl, linformer
Games101 job 7-path tracing implementation process & detailed interpretation of code
Retinanet+keras train their own data set to tread on the pit
Share 𞓜 jointly pre training transformers on unpaired images and text
Huawei equipment configures local virtual private network mutual access
Recommend a free intranet penetration open source software that can be used in the local wechat official account under test
Apply the intelligent OCR identification technology of Shenzhen Yanchang technology to break through the bottleneck of medical bill identification at one stroke. Efficient claim settlement is not a dr
Restoration of binary tree -- number restoration
Top 100 video information of station B