CAShapeLayer 不会消失
CAShapeLayer not going away
我有一个 class 可以将进度视图添加到给定的 UIView。我在其单元格的集合视图中使用它。它在前几个单元格上看起来不错,但在滑动几次后,您可以看到应该在那里的微弱标记。我将附上我的意思的截图。不确定为什么会这样?
这里是cellForItemAt
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: self.cellId, for: indexPath) as? TakeCollectionViewCell else {return UICollectionViewCell()}
let service = TakeProgressView()
let random = Double(indexPath.row) / 10
service.progress = random
service.addView(view: cell.takeProgressView, withParticipants: false)
return cell
其中 takeProgressView
是在情节提要中实现的 UIView
添加视图的函数如下:
func addView(view: UIView, withParticipants: Bool){
disagreePath.removeAllPoints()
agreePath.removeAllPoints()
path.removeAllPoints()
circlePath.removeAllPoints()
agreeLayer.removeFromSuperlayer()
disagreeLayer.removeFromSuperlayer()
backgroundFill.removeFromSuperlayer()
let width:CGFloat = 270
let height:CGFloat = 360
let viewX = (view.frame.size.width - width) / 2
let viewY = (view.frame.size.height - height) / 2
subView = UIView(frame: CGRect(x: viewX - 20, y: viewY, width: width + 40, height: height))
path = UIBezierPath(ovalIn: CGRect(x: 20, y: 0, width: width, height: height))
let rect = CGRect(x: 60, y: 40, width: width - 80, height: height - 80)
circlePath = UIBezierPath(ovalIn: rect)
path.append(circlePath)
path.usesEvenOddFillRule = true
backgroundFill = CAShapeLayer()
backgroundFill.path = path.cgPath
backgroundFill.lineWidth = 40.0
backgroundFill.fillRule = .evenOdd
backgroundFill.fillColor = #colorLiteral(red: 0.9371728301, green: 0.9373074174, blue: 0.9371433854, alpha: 1)
backgroundFill.opacity = 0.9
disagreePath = UIBezierPath(ovalIn: CGRect(x: 30, y: 10, width: width - 20, height: height - 20))
disagreeLayer = CAShapeLayer()
disagreeLayer.path = disagreePath.cgPath
disagreeLayer.fillColor = UIColor.clear.cgColor
disagreeLayer.strokeColor = #colorLiteral(red: 1, green: 0.4117892087, blue: 0.4117360711, alpha: 1)
disagreeLayer.strokeStart = 0.0
disagreeLayer.strokeEnd = CGFloat(1 - progress)
disagreeLayer.lineWidth = 20.0
disagreeLayer.lineCap = .round
backgroundFill.addSublayer(disagreeLayer)
agreePath = UIBezierPath(ovalIn: CGRect(x: 50, y: 30, width: width - 60, height: height - 60))
agreeLayer = CAShapeLayer()
agreeLayer.path = agreePath.cgPath
agreeLayer.fillColor = UIColor.clear.cgColor
agreeLayer.strokeColor = UIColor.uStadium.primary.cgColor
agreeLayer.strokeStart = CGFloat(1 - progress) + 0.02
agreeLayer.strokeEnd = 0.98
agreeLayer.lineWidth = 20.0
agreeLayer.lineCap = .round
backgroundFill.addSublayer(agreeLayer)
subView.layer.addSublayer(backgroundFill)
view.addSubview(subView)
}
单元格(在 UITableView
或 UICollectionView
中)被重复使用。
你的代码太耦合了,你应该改变它的架构。
如果我理解这个逻辑:
TakeCollectionViewCell
应该有一个 属性 TakeProgressView
:
class TakeCollectionViewCell: UICollectionViewCell {
var takeProgress = TakeProgressView()
...
}
所以你的代码应该是:
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: self.cellId, for: indexPath) as? TakeCollectionViewCell else {return UICollectionViewCell()}
let service = TakeProgressView()
let random = Double(indexPath.row) / 10
cell.takeProgress.progress = random
cell.takeProgress.addView(view: cell.takeProgressView, withParticipants: false)
return cell
在func addView(view: UIView, withParticipants: Bool)
中,你只用view
用于:帧计算+addSuview:
...
let viewX = (view.frame.size.width - width) / 2
let viewY = (view.frame.size.height - height) / 2
...
view.addSubview(subView)
...
因此,让我们 return 子视图并给出框架(甚至尺寸,因为这就是您使用的):
func progressSubview(with size: CGSize, withParticipants: Bool) -> UIView {
...
// let viewX = (view.frame.size.width - width) / 2
let viewX = (size.width - width) / 2
// let viewY = (view.frame.size.height - height) / 2
let viewY = (size.height - height) / 2
...
// view.addSubview(subView)
return subview
...
}
让我们将该子视图保留为 TakeCollectionViewCell
的 属性,然后使用新方法。
class TakeCollectionViewCell: UICollectionViewCell {
var subProgressView: UIView?
...
func updateProgressView(with progress: Double, withParticipants: Bool) {
takeProgress.progress = progress
subProgressView = takeProgress.progressSubview(with: self.takeProgressView.size, withParticipants: withParticipants)
}
}
现在让我们覆盖重用:
class TakeCollectionViewCell: UICollectionViewCell {
override func prepareForReuse() {
super.prepareForReuse()
subProgressView?.removeFromSuperview()
}
}
在 cellForRow 中现在应该是:
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: self.cellId, for: indexPath) as? TakeCollectionViewCell else {return UICollectionViewCell()}
let random = Double(indexPath.row) / 10
cell.updateProgressView(with: random, withParticipants: false)
return cell
可能会进行额外的返工,但这应该是一个开始...
我有一个 class 可以将进度视图添加到给定的 UIView。我在其单元格的集合视图中使用它。它在前几个单元格上看起来不错,但在滑动几次后,您可以看到应该在那里的微弱标记。我将附上我的意思的截图。不确定为什么会这样?
这里是cellForItemAt
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: self.cellId, for: indexPath) as? TakeCollectionViewCell else {return UICollectionViewCell()}
let service = TakeProgressView()
let random = Double(indexPath.row) / 10
service.progress = random
service.addView(view: cell.takeProgressView, withParticipants: false)
return cell
其中 takeProgressView
是在情节提要中实现的 UIView
添加视图的函数如下:
func addView(view: UIView, withParticipants: Bool){
disagreePath.removeAllPoints()
agreePath.removeAllPoints()
path.removeAllPoints()
circlePath.removeAllPoints()
agreeLayer.removeFromSuperlayer()
disagreeLayer.removeFromSuperlayer()
backgroundFill.removeFromSuperlayer()
let width:CGFloat = 270
let height:CGFloat = 360
let viewX = (view.frame.size.width - width) / 2
let viewY = (view.frame.size.height - height) / 2
subView = UIView(frame: CGRect(x: viewX - 20, y: viewY, width: width + 40, height: height))
path = UIBezierPath(ovalIn: CGRect(x: 20, y: 0, width: width, height: height))
let rect = CGRect(x: 60, y: 40, width: width - 80, height: height - 80)
circlePath = UIBezierPath(ovalIn: rect)
path.append(circlePath)
path.usesEvenOddFillRule = true
backgroundFill = CAShapeLayer()
backgroundFill.path = path.cgPath
backgroundFill.lineWidth = 40.0
backgroundFill.fillRule = .evenOdd
backgroundFill.fillColor = #colorLiteral(red: 0.9371728301, green: 0.9373074174, blue: 0.9371433854, alpha: 1)
backgroundFill.opacity = 0.9
disagreePath = UIBezierPath(ovalIn: CGRect(x: 30, y: 10, width: width - 20, height: height - 20))
disagreeLayer = CAShapeLayer()
disagreeLayer.path = disagreePath.cgPath
disagreeLayer.fillColor = UIColor.clear.cgColor
disagreeLayer.strokeColor = #colorLiteral(red: 1, green: 0.4117892087, blue: 0.4117360711, alpha: 1)
disagreeLayer.strokeStart = 0.0
disagreeLayer.strokeEnd = CGFloat(1 - progress)
disagreeLayer.lineWidth = 20.0
disagreeLayer.lineCap = .round
backgroundFill.addSublayer(disagreeLayer)
agreePath = UIBezierPath(ovalIn: CGRect(x: 50, y: 30, width: width - 60, height: height - 60))
agreeLayer = CAShapeLayer()
agreeLayer.path = agreePath.cgPath
agreeLayer.fillColor = UIColor.clear.cgColor
agreeLayer.strokeColor = UIColor.uStadium.primary.cgColor
agreeLayer.strokeStart = CGFloat(1 - progress) + 0.02
agreeLayer.strokeEnd = 0.98
agreeLayer.lineWidth = 20.0
agreeLayer.lineCap = .round
backgroundFill.addSublayer(agreeLayer)
subView.layer.addSublayer(backgroundFill)
view.addSubview(subView)
}
单元格(在 UITableView
或 UICollectionView
中)被重复使用。
你的代码太耦合了,你应该改变它的架构。
如果我理解这个逻辑:
TakeCollectionViewCell
应该有一个 属性 TakeProgressView
:
class TakeCollectionViewCell: UICollectionViewCell {
var takeProgress = TakeProgressView()
...
}
所以你的代码应该是:
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: self.cellId, for: indexPath) as? TakeCollectionViewCell else {return UICollectionViewCell()}
let service = TakeProgressView()
let random = Double(indexPath.row) / 10
cell.takeProgress.progress = random
cell.takeProgress.addView(view: cell.takeProgressView, withParticipants: false)
return cell
在func addView(view: UIView, withParticipants: Bool)
中,你只用view
用于:帧计算+addSuview:
...
let viewX = (view.frame.size.width - width) / 2
let viewY = (view.frame.size.height - height) / 2
...
view.addSubview(subView)
...
因此,让我们 return 子视图并给出框架(甚至尺寸,因为这就是您使用的):
func progressSubview(with size: CGSize, withParticipants: Bool) -> UIView {
...
// let viewX = (view.frame.size.width - width) / 2
let viewX = (size.width - width) / 2
// let viewY = (view.frame.size.height - height) / 2
let viewY = (size.height - height) / 2
...
// view.addSubview(subView)
return subview
...
}
让我们将该子视图保留为 TakeCollectionViewCell
的 属性,然后使用新方法。
class TakeCollectionViewCell: UICollectionViewCell {
var subProgressView: UIView?
...
func updateProgressView(with progress: Double, withParticipants: Bool) {
takeProgress.progress = progress
subProgressView = takeProgress.progressSubview(with: self.takeProgressView.size, withParticipants: withParticipants)
}
}
现在让我们覆盖重用:
class TakeCollectionViewCell: UICollectionViewCell {
override func prepareForReuse() {
super.prepareForReuse()
subProgressView?.removeFromSuperview()
}
}
在 cellForRow 中现在应该是:
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: self.cellId, for: indexPath) as? TakeCollectionViewCell else {return UICollectionViewCell()}
let random = Double(indexPath.row) / 10
cell.updateProgressView(with: random, withParticipants: false)
return cell
可能会进行额外的返工,但这应该是一个开始...