如何使用自定义 UIView(和内部转换)重新加载自定义 UICollectionViewCell
How to reload custom UICollectionViewCell`s with custom UIViews (and transitions inside)
大家好,
我正在寻找一些关于根据 indexPath 行在我的自定义单元格中重新加载数据的提示。
上下文:
我有一个教程幻灯片,我正在使用 UICollectionView
。在此视图中,我为每个 indexPath.row
不同的自定义插入自定义 UICollectionViewCell
s(因此我为 UICollectionView
注册了多个笔尖)。
在基于 indexPath.row 的委托方法 cellForItemAt indexPath
中,我将我想要的特定自定义单元格出队
教程幻灯片包含可在特定单元格之间导航的按钮(顺便说一句,单元格占据了大部分用户屏幕),因此您可以像“下一步”或“返回”一样导航。
其自定义 class 中的每个单元格都定义了一些转换。因此,例如,单元格编号 1 以一些自定义元素开始,然后在第二个左右之后过渡到另一组元素。所以我正在创建类似动画的东西。这些转换是通过 DispatchQueue.main.asyncAfter
执行的,所以我让用户阅读我想要的第一个屏幕,然后是第二个。然后用户单击下一步按钮并转到另一个 indexPath.row
,有时会在下一个“屏幕”中进行另一个转换
所以我的意图是当用户例如通过单击 Next/Back 在单元格之间导航(indexPath.row
/s)时拥有“清晰”的默认视图,所以当他从 Screen2 转到 Screen1,我希望他从头看到 Screen1 并再次看到转换。现在它结束在我过渡到的最后一个屏幕。
我的实际问题:
那么有没有什么方法可以用当前设计刷新单元格,或者我应该改变我构建集合视图的方式吗?
请查看下面的一些示例代码片段。
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。在 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。委托方法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。自定义单元格 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...
出队可重用单元格的目的是避免多次创建单元格,容器视图(如table视图或集合视图)可以更快地重用这些单元格.容器视图缓存了很多 off-screen 的单元格,因此一旦该单元格再次可见,您就可以取回该单元格。
由于您的动画是在 commonInit
中实现的 - 仅由 awakeFromNib
调用 - 您只看到它们一次,因为视图仅一次加载到内存中。
您需要在信元出队后手动调用 commonInit
,而不是 awakeFromNib
调用它。
或者更好:将 only once 与动画/内容初始化部分分开,然后从 awakeFromNib
调用第一个,后者在视图出队后调用。
这更好,因为 awakeFromNib
甚至在视图可见之前就被调用了,因此您甚至不知道它何时显示。
大家好,
我正在寻找一些关于根据 indexPath 行在我的自定义单元格中重新加载数据的提示。
上下文:
我有一个教程幻灯片,我正在使用
UICollectionView
。在此视图中,我为每个indexPath.row
不同的自定义插入自定义UICollectionViewCell
s(因此我为UICollectionView
注册了多个笔尖)。在基于 indexPath.row 的委托方法
cellForItemAt indexPath
中,我将我想要的特定自定义单元格出队教程幻灯片包含可在特定单元格之间导航的按钮(顺便说一句,单元格占据了大部分用户屏幕),因此您可以像“下一步”或“返回”一样导航。
其自定义 class 中的每个单元格都定义了一些转换。因此,例如,单元格编号 1 以一些自定义元素开始,然后在第二个左右之后过渡到另一组元素。所以我正在创建类似动画的东西。这些转换是通过
DispatchQueue.main.asyncAfter
执行的,所以我让用户阅读我想要的第一个屏幕,然后是第二个。然后用户单击下一步按钮并转到另一个indexPath.row
,有时会在下一个“屏幕”中进行另一个转换所以我的意图是当用户例如通过单击 Next/Back 在单元格之间导航(
indexPath.row
/s)时拥有“清晰”的默认视图,所以当他从 Screen2 转到 Screen1,我希望他从头看到 Screen1 并再次看到转换。现在它结束在我过渡到的最后一个屏幕。
我的实际问题:
那么有没有什么方法可以用当前设计刷新单元格,或者我应该改变我构建集合视图的方式吗?
请查看下面的一些示例代码片段。
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。在 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。委托方法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。自定义单元格 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...
出队可重用单元格的目的是避免多次创建单元格,容器视图(如table视图或集合视图)可以更快地重用这些单元格.容器视图缓存了很多 off-screen 的单元格,因此一旦该单元格再次可见,您就可以取回该单元格。
由于您的动画是在 commonInit
中实现的 - 仅由 awakeFromNib
调用 - 您只看到它们一次,因为视图仅一次加载到内存中。
您需要在信元出队后手动调用 commonInit
,而不是 awakeFromNib
调用它。
或者更好:将 only once 与动画/内容初始化部分分开,然后从 awakeFromNib
调用第一个,后者在视图出队后调用。
这更好,因为 awakeFromNib
甚至在视图可见之前就被调用了,因此您甚至不知道它何时显示。