[英]How to reload custom UICollectionViewCell`s with custom UIViews (and transitions inside)
Hello all good people,大家好,大家好
I am looking for some hint in terms of reloading data in my custom cells based on the indexPath row.我正在根据 indexPath 行在我的自定义单元格中重新加载数据方面寻找一些提示。
The context:上下文:
I have a tutorial slideshow, for which I am using UICollectionView
.我有一个教程幻灯片,我正在使用
UICollectionView
。 Into this view I insert custom UICollectionViewCell
s, for each indexPath.row
different custom one (so I register multiple nibs for UICollectionView
).在这个视图中,我插入自定义
UICollectionViewCell
s,对于每个indexPath.row
不同的自定义一个(所以我为UICollectionView
注册了多个笔尖)。
Within delegate method cellForItemAt indexPath
based on the indexPath.row I dequeue particular custom cell I want在基于
cellForItemAt indexPath
委托方法cellForItemAt indexPath
我出列我想要的特定自定义单元格
The tutorial slideshow has buttons with which you can navigate between specific cells (btw cells take most of the user screen), so you can navigate like Next or Back.教程幻灯片有一些按钮,您可以使用这些按钮在特定单元格之间导航(顺便说一下,单元格占据了用户屏幕的大部分),因此您可以像 Next 或 Back 一样导航。
Each cell within its own custom class is defined with some transitions.自定义类中的每个单元格都定义了一些转换。 So for example cell number 1 starts with some custom elements then after second or so it transits to another sets of elements.
因此,例如,单元格编号 1 以一些自定义元素开头,然后在大约一秒后转换为另一组元素。 So I am creating something like animations.
所以我正在创建类似动画的东西。 These transitions are performed via
DispatchQueue.main.asyncAfter
so I let the user to read the first screen I want, then second.这些转换是通过
DispatchQueue.main.asyncAfter
执行的,所以我让用户阅读我想要的第一个屏幕,然后是第二个。 Then user clicks the button Next and goes for another indexPath.row
with sometimes another transitions within this next "screen"然后用户单击 Next 按钮并转到另一个
indexPath.row
有时在下一个“屏幕”中进行另一个转换
So my intention is to have "clear" default view when the user for example navigates between the cells( indexPath.row
/s) by clicking Next/Back, so when he goes from Screen2 to Screen1, I want him to see the Screen1 from beginning and see the transitions again.所以我的目的是当用户例如通过单击 Next/Back 在单元格 (
indexPath.row
/s) 之间导航时拥有“清晰”的默认视图,所以当他从 Screen2 转到 Screen1 时,我希望他从开始并再次看到过渡。 Now it ends up at the last screen which I transit to.现在它在我过渡到的最后一个屏幕结束。
My actuall Question:我的实际问题:
So is there any way how to refresh the cell with the current design or should I change the way how I structured my collection view?那么有什么方法可以使用当前设计刷新单元格,还是应该更改我构建集合视图的方式?
Please see some example code snippets below.请参阅下面的一些示例代码片段。
1. VC with my UICollectionView 1. VC 与我的 UICollectionView
class IncomingInstructionsVC: UIViewController {
@IBOutlet weak var btnBack: UIButton!
@IBOutlet weak var btnNext: UIButton!
@IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
collectionView.register(Screen1.nib, forCellWithReuseIdentifier: "Screen1ID")
collectionView.register(Screen2.nib, forCellWithReuseIdentifier: "Screen2ID")
collectionView.register(Screen3.nib, forCellWithReuseIdentifier: "Screen3ID")
collectionView.register(Screen4.nib, forCellWithReuseIdentifier: "Screen4ID")
collectionView.register(Screen5.nib, forCellWithReuseIdentifier: "Screen5ID")
collectionView.register(Screen6.nib, forCellWithReuseIdentifier: "Screen6ID")
collectionView.dataSource = self
collectionView.delegate = self
collectionView.isPagingEnabled = false
}
2. IBActions for navigation between UICollectionViewCell/s 2. 用于 UICollectionViewCell/s 之间导航的 IBActions
@IBAction func btnNextTapped(_ sender: UIButton) {
let visibleItems: NSArray = self.collectionView.indexPathsForVisibleItems as NSArray
var minItem: NSIndexPath = visibleItems.object(at: 0) as! NSIndexPath
for itr in visibleItems {
if minItem.row > (itr as AnyObject).row {
minItem = itr as! NSIndexPath
}
}
let nextItem = IndexPath(row: minItem.row + 1, section: 0)
self.collectionView.scrollToItem(at: nextItem as IndexPath, at: .left, animated: false)
}
@IBAction func btnBackTapped(_ sender: UIButton) {
let visibleItems: NSArray = self.collectionView.indexPathsForVisibleItems as NSArray
var minItem: NSIndexPath = visibleItems.object(at: 0) as! NSIndexPath
for itr in visibleItems {
if minItem.row > (itr as AnyObject).row {
minItem = itr as! NSIndexPath
}
}
let nextItem = IndexPath(row: minItem.row - 1, section: 0)
self.collectionView.scrollToItem(at: nextItem as IndexPath, at: .left, animated: false)
}
3. Delegate method cellForItemAt indexPath:
3.委托方法
cellForItemAt indexPath:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
var cell = UICollectionViewCell()
self.pageControl.currentPage = indexPath.row
switch indexPath.row {
case 0:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Screen1ID", for: indexPath) as! Screen1
case 1:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Screen2ID", for: indexPath) as! Screen2
case 2:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Screen3ID", for: indexPath) as! Screen3
.
.
.
continues to the end of my tutorial
.
.
.
}
return cell
}
4. Custom Cell Class definiton with DispatchQueue.main.asyncAfter
logic 4. 自定义 Cell Class 与
DispatchQueue.main.asyncAfter
逻辑
.
.
.
Some IBOutlets here....
.
.
.
override func awakeFromNib() {
super.awakeFromNib()
commonInit()
}
func commonInit() {
greyBackground.layer.cornerRadius = 10
transition1.layer.cornerRadius = 10
transition2.layer.cornerRadius = 10
self.nameIncomingLabel.text = NSLocalizedString("name_inc_head", comment: "")
self.mobileLabel.text = NSLocalizedString("mobile", comment: "")
self.declineImageView.image = UIImage(named: "Reject")
self.declineLabel.text = NSLocalizedString("Decline", comment: "")
self.acceptImageView.image = UIImage(named: "Accept")
self.acceptLabel.text = NSLocalizedString("accept", comment: "")
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [self] in
//transition to "Accept Call" command
UIView.transition(with: transition1, duration: 1, options: .transitionCrossDissolve, animations: {
transition1.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.9)
transition1AcceptImage.image = UIImage(named: "Accept")
transition1Label.font = UIFont.systemFont(ofSize: 21, weight: .semibold)
transition1Label.text = NSLocalizedString("answer_incoming_call", comment: "")
//transition to calling screen with icons
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { [self] in
UIView.transition(with: transition2, duration: 0.5, options: .transitionCrossDissolve, animations: {
transition2.backgroundColor = #colorLiteral(red: 0.3019607843, green: 0.3019607843, blue: 0.3019607843, alpha: 1)
nameIncomingLabelTransition2.text = NSLocalizedString("name_inc_head", comment: "")
....it is continuing with the closing curly braces down below...
The intention of dequeueing reusable cells is to avoid the multiple creation of cells which could faster be reused by the container view (like table view or collection view).出列可重用单元格的目的是避免多次创建可以由容器视图(如表视图或集合视图)更快地重用的单元格。 The container view caches a lot of cells that go off-screen, so you get back that cell once it becomes visible again.
容器视图缓存了许多离开屏幕的单元格,因此一旦它再次可见,您就可以返回该单元格。 Since your animations are implemented in
commonInit
- which is only called by awakeFromNib
- you only see them once, because the view is loaded only once into memory.由于您的动画是在
commonInit
中实现的——它只能由awakeFromNib
调用——你只能看到它们一次,因为视图只加载到内存中一次。
You need call commonInit
manually after a cell has been dequeued, and not call it by awakeFromNib
.您需要在单元格出队后手动调用
commonInit
,而不是通过awakeFromNib
调用它。 Or better: Separate the only once stuff from the animation / content initialization part, and call the first from awakeFromNib
, the latter once the view get's dequeued.或者更好:将唯一一次的东西与动画/内容初始化部分分开,并从
awakeFromNib
调用第一个,一旦视图出列,则调用后者。
This is even better because awakeFromNib
is called even before the view get's visible, hence you don't even know when it is being displayed.这甚至更好,因为甚至在视图可见之前就调用了
awakeFromNib
,因此您甚至不知道它何时显示。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.