iOS动画– UIScrollView内的UIStackView

时间:2020-02-23 14:45:53  来源:igfitidea点击:

之前,我们已经通过示例进行了讨论并实现了UIStackView。
在本教程中,我们将学习如何在UIScrollView内添加UIStackView以及如何以编程方式实现从UIStackView添加和删除视图以及对其进行动画处理。

UIScrollView内的UIStackView

以下是您需要执行的步骤,以便在UIScrollView中添加UIStackView。

  • 将UIScrollView添加到视图控制器视图,并将约束设置到视图的所有侧面。

  • 在UIScrollView内添加一个UIStackView。
    设置约束:ScrollView的前导,尾随,顶部和底部。

  • 如果要垂直滚动StackView,请在UIStackView和UIScrollView之间设置等宽约束。

  • 如果要水平滚动StackView,请在UIStackView和UIScrollView之间设置等高约束。

  • 在UIStackView内添加您的SubView,并享受滚动。

让我们在XCode项目Main.storyboard中进行演示。

现在,我们在StackView中添加一些按钮:

模拟器中的输出如下:

接下来,让我们来看一下以编程方式构建UIStackView的过程。

UIStackView以编程方式

打开您的ViewController.swift文件,并添加以下代码行:

import UIKit

class ViewController: UIViewController {

  
  var stackView = UIStackView()
  var constraintBottom : NSLayoutConstraint?
  
  override func viewDidLoad() {
      super.viewDidLoad()
      //Do any additional setup after loading the view, typically from a nib.
      
      let textField = UITextField()
      textField.placeholder = "Email"
      textField.textColor = UIColor.darkGray
      textField.minimumFontSize = 17.0
      textField.borderStyle = UITextField.BorderStyle.roundedRect
      textField.keyboardType = UIKeyboardType.emailAddress
      textField.returnKeyType = UIReturnKeyType.next
      
      
      let textFieldPassword = UITextField()
      textFieldPassword.placeholder = "Password"
      textFieldPassword.textColor = UIColor.darkGray
      textFieldPassword.minimumFontSize = 17.0
      textFieldPassword.textAlignment = .right
      textFieldPassword.isSecureTextEntry = true
      textFieldPassword.borderStyle = UITextField.BorderStyle.roundedRect
      textFieldPassword.keyboardType = UIKeyboardType.default
      textFieldPassword.returnKeyType = UIReturnKeyType.done
      
      
      let button = UIButton(type: UIButton.ButtonType.system)
      button.setTitle("Login", for: UIControl.State.normal)
      button.setTitleColor(UIColor.white, for: UIControl.State.normal)
      button.backgroundColor = UIColor.black
      button.layer.borderColor = UIColor.white.cgColor
      button.layer.borderWidth = 1.0
      button.layer.cornerRadius = 5.0
      button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
      button.tag = 1
      
      
      stackView = UIStackView(arrangedSubviews: [textField, textFieldPassword, button])
      stackView.axis = .vertical
      stackView.translatesAutoresizingMaskIntoConstraints = false
      stackView.distribution = .fillEqually
      stackView.alignment = .fill
      stackView.spacing = 20.0
      
      view.addSubview(stackView)

      stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true
      stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20).isActive = true
      stackView.topAnchor.constraint(equalTo: view.topAnchor, constant: 40).isActive = true
      constraintBottom = stackView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -40)
      constraintBottom?.isActive = true
      
  }
  
  @objc func buttonAction(sender: UIButton!) {
      
          if(sender.tag == 1){
          constraintBottom?.isActive = false
          stackView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -100).isActive = true
          }
  }

}

在这段代码中,我们在UIStackView中垂直设置了UITextField和Button,它们均等填充。
我们使用NSLayoutConstraint在stackView上设置约束。

子视图在ArrangeSubView数组中传递。
单击"按钮"时,我们设置了一个选择器以禁用StackView的底部约束,并添加一个新的选择器以增加底部边距。

由于UIStackViews使用自动布局,因此必须将" translatesAutoresizingMaskIntoConstraints"设置为false。

isHidden属性用于切换完整StackView(包括其所有元素)的可见性。

使用功能加载子视图

我们可以使用如下所示的函数填充UIStackView,而不是在数组中传递单个subView:

class ViewController: UIViewController {

  
  var stackView = UIStackView()
  var constraintBottom : NSLayoutConstraint?
  
  override func viewDidLoad() {
      super.viewDidLoad()
      //Do any additional setup after loading the view, typically from a nib.
      
      
      stackView = UIStackView(arrangedSubviews: createButtonArray(named: "1","2","3","4"))
      

      stackView.axis = .vertical
      stackView.translatesAutoresizingMaskIntoConstraints = false
      stackView.distribution = .fillEqually
      stackView.alignment = .fill
      stackView.spacing = 20.0

      view.addSubview(stackView)

      stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true
      stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20).isActive = true
      stackView.topAnchor.constraint(equalTo: view.topAnchor, constant: 40).isActive = true
      constraintBottom = stackView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -40)
      constraintBottom?.isActive = true
      
  }

  
  func createButtonArray(named: String...) -> [UIButton]
  {
      return named.map{name in
          let button  = UIButton()
          button.translatesAutoresizingMaskIntoConstraints = false
          button.setTitle("Button \(name)", for: .normal)
          button.backgroundColor = UIColor.red
          button.setTitleColor(UIColor.white, for: .normal)
          return button
      }
  }
}

createButtonArray通过将字符串转换为相应的Button实例来组成数组,从而创建一个数组。

单击添加子视图

我们将上述每个按钮配置为在单击按钮时添加另一个subView。
我们将添加一个嵌套的子视图。

viewDidLoad方法与以前相同。
ViewController.swift中的其他方法是:

func createButtonArray(named: String...) -> [UIButton]
  {
      return named.map{name in
          let button  = UIButton()
          button.translatesAutoresizingMaskIntoConstraints = false
          button.setTitle("Button \(name)", for: .normal)
          button.backgroundColor = UIColor.red
          button.setTitleColor(UIColor.white, for: .normal)
          button.tag = named.firstIndex(of: name)!
          button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
          return button
      }
  }
  
  @objc func buttonAction(sender: UIButton!) {
          print("Button tag is")
          print(sender.tag)
          createNestedSubView(sender.tag)
  }
  
  func createNestedSubView(_ tag: Int)
  {
      let ss = UIStackView(arrangedSubviews: createButtonArray(named: "\(tag+1).1","\(tag+1).2","\(tag+1).3","\(tag+1).4"))
      
      
      ss.axis = .horizontal
      ss.translatesAutoresizingMaskIntoConstraints = false
      ss.distribution = .fillEqually
      ss.alignment = .fill
      ss.spacing = 5.0
      
      stackView.insertArrangedSubview(ss, at: tag)
      
      ss.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true
      ss.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20).isActive = true
      ss.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
  }

因此,在单击按钮时,我们传递按钮的索引。
创建一个嵌套的水平StackView。
新的堆栈视图将插入标签编号索引处。

insertArrangedSubview用于将SubView插入到UIStackView中的某个索引处。

ArrangeSubView用于在UIStackView的末尾插入新的SubView。

以编程方式删除SubView

我们可以使用UIStackView实例上的removeArrangedSubview函数删除SubView。
另外,我们也需要从SuperView中删除该视图。

在ViewController.swift createButtonArray函数中,我们为嵌套的StackView按钮添加了另一个按钮单击动作。
单击它们中的任何一个时,它们将被删除:

func createButtonArray(named: String...) -> [UIButton]
  {
      return named.map{name in
          let button  = UIButton()
          button.translatesAutoresizingMaskIntoConstraints = false
          button.setTitle("Button \(name)", for: .normal)
          button.backgroundColor = UIColor.red
          button.setTitleColor(UIColor.white, for: .normal)
          button.tag = named.firstIndex(of: name)!
          if(name.contains("."))
          {
          button.addTarget(self, action: #selector(deleteAction), for: .touchUpInside)
          }
          else{
          button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
          }
          return button
      }
  }

 @objc func deleteAction(sender: UIButton!) {
      print("Delete tag is")
      print(sender.titleLabel?.text! ?? "NA")
      stackView.removeArrangedSubview(sender)
      sender.removeFromSuperview()
      
  }

动画子视图

当使用以下方法切换isHidden属性时,我们可以为subViews设置动画:

UIView.animate(withDuration: 0.5){
                  button.isHidden = true //or false
              }

在上面的应用程序中,当单击按钮4时,我们将其隐藏并设置动画:

@objc func buttonAction(sender: UIButton!) {
          print("Button tag is")
          print(sender.tag)
      
          if(sender.titleLabel?.text?.contains("4"))!
          {
              UIView.animate(withDuration: 0.5){
                  sender.isHidden = true //or false
              }
          }
      
          createNestedSubView(sender.tag)
  }