【问题标题】:CAShapeLayer not going awayCAShapeLayer 不会消失
【发布时间】:2021-08-31 15:16:59
【问题描述】:

我有一个向给定 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 是在 storyboard 中实现的 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)
    }

【问题讨论】:

  • 单元格被重复使用,所以每次添加子视图时...所以要么保留一个,要么删除之前添加的...
  • 对,但是删除图层还不够吗?在函数的顶部
  • 问题是你每次都在做view.addSubview(subView)。所以每次,你都在上面添加一个新的TakeProgressView()。另外,所有路径都应该是空的,因为您每次都在创建一个 TakeProgressView 的新实例......脏修复? cell.view.forEach{ ($0 as? TakeProgressView)?.removeFromSuperview() }
  • 该视图还有一个我不想删除的标签
  • 即使那个脏修复也行不通,因为子视图是UIView 而不是TakeProgressView。这很不清楚你为什么使用真正使用TakeProgressView。

标签: ios swift uibezierpath cashapelayer


【解决方案1】:

单元格(在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)
...

因此,让我们返回子视图并给出框架(甚至是尺寸,因为这是您使用的):

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

可能会进行额外的返工,但这应该是一个开始......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多