【问题标题】:UIScrollView animate offset change when removing nested view删除嵌套视图时 UIScrollView 动画偏移更改
【发布时间】:2020-08-21 14:14:51
【问题描述】:

我有一个包含堆栈视图的UIScrollView - 我基本上是在复制标签功能。

一个标签的视图比另一个高,所以当我在堆栈视图中隐藏视图时,它会调整大小。

这会导致滚动视图跳转到适合较短视图的偏移量,以防用户滚动到顶部。

是否可以改为动画此更改?视图滚动到正确的偏移量而不是跳转?我不确定如何实现这一点。


final class ScrollViewController: UIViewController {

  private var visibleTab: TabState = .overview {
    didSet {
      guard oldValue != visibleTab else { return }
      switch visibleTab {
        case .overview:
          self.spacesTab.isHidden = true
          self.overviewTab.isHidden = false
        case .spaces:
          self.spacesTab.isHidden = false
          self.overviewTab.isHidden = true
      }
    }
  }

  enum TabState {
    case overview
    case spaces
  }

  private lazy var scrollView: UIScrollView = {
    let view = UIScrollView(frame: .zero)
    view.translatesAutoresizingMaskIntoConstraints = false
    view.backgroundColor = .white
    view.delegate = self
    view.alwaysBounceVertical = true
    return view
  }()

  private let contentStackView: UIStackView = {
    let view = UIStackView(frame: .zero)
    view.translatesAutoresizingMaskIntoConstraints = false
    view.axis = .vertical
    view.alignment = .fill
    view.spacing = 8
    view.distribution = .fill
    return view
  }()

  private let tabSelectorView: UIStackView = {
    let view = UIStackView(frame: .zero)
    view.axis = .horizontal
    view.distribution = .fillEqually
    return view
  }()

  private let overviewTab: UIView = {
    let view = UIView(frame: .zero)
    view.backgroundColor = .darkGray
    view.heightAnchor.constraint(equalToConstant: 100).isActive = true
    view.isHidden = false
    return view
  }()

  private let spacesTab: UIView = {
    let view = UIView(frame: .zero)
    view.backgroundColor = .lightGray
    view.heightAnchor.constraint(equalToConstant: 780).isActive = true
    view.isHidden = true
    return view
  }()

  private let profileHeader = ScrollViewProfileHeaderView(frame: .zero)

  private lazy var overviewTabButton = makeButton(title: "Overview")
  private lazy var spacesTabButton = makeButton(title: "Spaces")

  override func viewDidLoad() {
    super.viewDidLoad()
    configureUI()
  }

}

extension ScrollViewController: UIScrollViewDelegate { }

private extension ScrollViewController {
  func configureUI() {
    overviewTabButton.addTarget(self, action: #selector(showOverviewTab), for: .touchUpInside)
    spacesTabButton.addTarget(self, action: #selector(showSpacesTab), for: .touchUpInside)

    [overviewTabButton, spacesTabButton].forEach(tabSelectorView.addArrangedSubview)

    profileHeader.translatesAutoresizingMaskIntoConstraints = false
    tabSelectorView.translatesAutoresizingMaskIntoConstraints = false

    [overviewTab, spacesTab].forEach(contentStackView.addArrangedSubview)

    [profileHeader, tabSelectorView, contentStackView].forEach(scrollView.addSubview(_:))
    view.addSubview(scrollView)
    NSLayoutConstraint.activate([
      scrollView.topAnchor.constraint(equalTo: view.topAnchor),
      scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
      scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
      scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),

      profileHeader.topAnchor.constraint(equalTo: scrollView.topAnchor),
      profileHeader.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
      profileHeader.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),

      tabSelectorView.topAnchor.constraint(equalTo: profileHeader.bottomAnchor),
      tabSelectorView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
      tabSelectorView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),

      contentStackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
      contentStackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
      contentStackView.topAnchor.constraint(equalTo: tabSelectorView.bottomAnchor, constant: 8),
      contentStackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
      contentStackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor)
    ])
  }

  func makeButton(title: String) -> UIButton {
    let button = UIButton(type: .system)
    button.setTitle(title, for: .normal)
    button.backgroundColor = .lightGray
    return button
  }

  @objc func showOverviewTab() {
    visibleTab = .overview
  }

  @objc func showSpacesTab() {
    visibleTab = .spaces
  }
}

final class ScrollViewProfileHeaderView: UIView {

  private let headerImage: UIImageView = {
    let view = UIImageView(frame: .zero)
    view.translatesAutoresizingMaskIntoConstraints = false
    view.contentMode = .scaleAspectFill
    view.clipsToBounds = true
    view.backgroundColor = .systemTeal
    return view
  }()

  private let profileCard: ProfileCardView = {
    let view = ProfileCardView(frame: .zero)
    view.translatesAutoresizingMaskIntoConstraints = false
    view.backgroundColor = .purple
    return view
  }()

  override init(frame: CGRect) {
    super.init(frame: frame)

    backgroundColor = .white

    [headerImage, profileCard].forEach(addSubview(_:))

    NSLayoutConstraint.activate([
      headerImage.topAnchor.constraint(equalTo: topAnchor),
      headerImage.leadingAnchor.constraint(equalTo: leadingAnchor),
      headerImage.trailingAnchor.constraint(equalTo: trailingAnchor),
      headerImage.heightAnchor.constraint(equalToConstant: 180),

      profileCard.topAnchor.constraint(equalTo: headerImage.centerYAnchor),
      profileCard.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor, constant: 48),
      profileCard.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor, constant: -32),
      profileCard.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor, constant: -48),
      profileCard.heightAnchor.constraint(equalToConstant: 270),
    ])
  }

  required init?(coder: NSCoder) {
    return nil
  }
}

【问题讨论】:

    标签: swift uiscrollview uistackview


    【解决方案1】:

    您可能想要进行一些额外的更改,但这可能会让您顺利上路。

    在您的 visibleTab / didSet 块中,当您隐藏 spacesTab 时使用 UIView.animate()

    private var visibleTab: TabState = .overview {
        didSet {
            guard oldValue != visibleTab else { return }
            switch self.visibleTab {
            case .overview:
                // set duration longer, such as 1.0, to clearly see the animation...
                UIView.animate(withDuration: 0.3) {
                    self.spacesTab.isHidden = true
                    self.overviewTab.isHidden = false
                }
            case .spaces:
                self.spacesTab.isHidden = false
                self.overviewTab.isHidden = true
            }
        }
    }
    

    【讨论】:

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