【问题标题】:Adding Subviews in a loop displays all the subvies at a time在循环中添加子视图一次显示所有子视图
【发布时间】:2020-06-19 04:40:34
【问题描述】:

我试图在单击按钮时添加 1000 个 UI 标签,但我循环了 1000 次并创建了 1000 个 UI 标签

    @IBAction func display(_ sender: Any) {
      for i in Range(1...1000) {

                      let label =  self.displayLabel(str: "test \(i)",i: i)

                                        )
                        UIView.animate(withDuration: 2.0, delay: 1.0, options: UIView.AnimationOptions.transitionCrossDissolve,animations: {
                            self.view.addSubview(label)
                            label.alpha = 1.0;
                         label.center.y = self.view.center.y/3},
                                       completion: { (value) in label.removeFromSuperview()} )



                      }

}

而displayLabel函数是

    func displayLabel(str:String,i:Int) -> UILabel {

    let label = UILabel.init(frame: CGRect(x: 0, y: 0, width: 200, height: 21))
    label.tag = i

    label.font = UIFont.preferredFont(forTextStyle: .footnote)
    let screenWidth = self.view.frame.size.width
    let screenHeight = self.view.frame.size.height
    label.textColor = .black
    label.center = CGPoint(x: screenWidth * 0.75, y: screenHeight - (screenHeight/3.0))
    label.textAlignment = .center
    label.text = str
    label.backgroundColor = .white
    label.backgroundColor?.withAlphaComponent(0.5)
    return label


}

会发生什么?

屏幕一个接一个地显示标签,然后向上移动并消失。

实际发生的事情

同时添加所有标签,然后它们开始制作动画,使编号为 1000 的标签动画并消失。

你认为为什么会发生这种情况?

这是因为标签的原因还是为什么它等待所有1000个标签并将其添加到子视图中?

我怎样才能达到我想要的?

【问题讨论】:

标签: ios swift addsubview ios-animations


【解决方案1】:

根据您的代码,这是预期的行为,因为您正在删除 completion 处理程序中的标签对象,它是 @escaping 闭包。

这意味着,执行不会等待removeFromSuperview。它将执行addSubview 操作,无需等待completion 处理程序,它将继续前进。

您可以通过在 completion 处理程序之前和之后添加 print 语句来验证此行为。

现在,关于您的要求,可以通过以下方式满足:

声明一个变量来保存标签标签

var tag = 0

避免for循环,在这里使用递归函数,比如

  //function to add and remove label until the defined count reached
  func showLabel(withTag: Int) {
    if self.tag != 1000 {
      let label =  self.displayLabel(str: "test \(withTag)",i: withTag)
      UIView.animate(withDuration: 2.0,
                     delay: 1.0,
                     options: UIView.AnimationOptions.transitionCrossDissolve,
                     animations: {
                      self.view.addSubview(label)
                      label.alpha = 1.0;
                      label.center.y = self.view.center.y/3
      }) { (value) in
        label.removeFromSuperview()
        self.tag = self.tag + 1
        self.showLabel(withTag: self.tag)
      }
    }
  }

  //initial function to start the process for each label
  func display() {
    showLabel(withTag: tag)
  }

  //function to provide new label object
  //no changes here
  func displayLabel(str:String,i:Int) -> UILabel {
    let label = UILabel.init(frame: CGRect(x: 0, y: 0, width: 200, height: 21))
    label.tag = i
    label.font = UIFont.preferredFont(forTextStyle: .footnote)
    let screenWidth = self.view.frame.size.width
    let screenHeight = self.view.frame.size.height
    label.textColor = .black
    label.center = CGPoint(x: screenWidth * 0.75, y: screenHeight - (screenHeight/3.0))
    label.textAlignment = .center
    label.text = str
    label.backgroundColor = .white
    label.backgroundColor?.withAlphaComponent(0.5)
    return label
  }

【讨论】:

  • 嗨,@RJ168 虽然这按预期工作,但它会按顺序显示所有内容我如何使其异步工作,即我不希望第二个标签等待第一个标签执行。有什么帮助吗?
  • @MahiTejGvp 以上代码不会以异步方式执行..您需要更改实现。
【解决方案2】:

您应该在每个 .addSubview 之后布局子视图。所以尝试这样做:

UIView.animate(withDuration: 2.0, delay: 1.0, options: UIView.AnimationOptions.transitionCrossDissolve,animations: {
                        self.view.addSubview(label)
                        label.alpha = 1.0;
                        label.center.y = self.view.center.y/3
                        self.view.layoutSubviews() }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-10
    • 2011-02-05
    • 2020-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-01
    相关资源
    最近更新 更多