【问题标题】:Swift 3: Stretchy UITableView footerSwift 3:有弹性的 UITableView 页脚
【发布时间】:2017-04-03 17:19:46
【问题描述】:

谁能告诉我如何实现一个有弹性的 UITableView 页脚。

我希望我的页脚中的图像在用户“过度滚动”时拉伸/增加大小。 (如果用户在 UITableView 已经在底部时向下滚动)

当前代码:

private let tableFooterHeight: CGFloat = 300
private var footerCustomView = UIImageView()

    func setupFooterView(){
         // Footer view
         self.footerCustomView = UIImageView(frame: CGRect.zero)
         self.footerCustomView.backgroundColor = UIColor.brown
         self.footerCustomView.image = UIImage(named: "image")

         self.view.addSubview(self.footerCustomView)
//        self.view.bringSubview(toFront: self.tableView)

         self.tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: self.tableFooterHeight, right: 0)

         self.footerCustomView.translatesAutoresizingMaskIntoConstraints = false

         let leadingConstraint = NSLayoutConstraint(item: self.footerCustomView,
                                               attribute: .leading,
                                               relatedBy: .equal,
                                               toItem: self.tableView,
                                               attribute: .leading,
                                               multiplier: 1,
                                               constant: 0)

         let trailingConstraint = NSLayoutConstraint(item: self.footerCustomView,
                                           attribute: .trailing,
                                           relatedBy: .equal,
                                           toItem: self.tableView,
                                           attribute: .trailing,
                                           multiplier: 1,
                                           constant: 0)

        let bottomConstraint = NSLayoutConstraint(item: self.footerCustomView,
                                           attribute: .bottom,
                                           relatedBy: .equal,
                                           toItem: self.tableView,
                                           attribute: .bottom,
                                           multiplier: 1,
                                           constant: 0)

        let heightConstraint = NSLayoutConstraint(item: self.footerCustomView,
                                              attribute: .height,
                                              relatedBy: .equal,
                                              toItem: nil,
                                              attribute: .height,
                                              multiplier: 1,
                                              constant: self.tableFooterHeight)

        self.view.addConstraints([bottomConstraint, trailingConstraint, heightConstraint, leadingConstraint])
}

func scrollViewDidScroll(_ scrollView: UIScrollView) {

    self.updateFooterView()
}

func updateFooterView() {        
    if self.tableView.bounds.origin.y > 1559 { // 1559 is end of tableView
        let diff = self.tableView.contentOffset.y - 1559
        self.footerCustomView.frame.size.height = self.tableFooterHeight + diff
    }
}

谢谢!

正常:


拉伸模式:

【问题讨论】:

  • 您应该将底部的 contentInset 添加到表格视图中,并在表格视图的超级视图底部添加一个图像视图。确保它被添加到表格视图的后面。并在滚动视图委托中,scrollViewDidScroll,调整图像视图框架的过度滚动量。
  • 感谢您的意见!我在上面的问题中更新了我的代码。 tableFooterView 正在向下增长。我试图在 tableviews 底部和 footerCustomView 之间添加底部约束,但没有运气。此外,当我调用 self.view.bringSubview(toFront: self.tableView) 时,我的 customView 不可见,并且被我最后一个单元格背景颜色覆盖。您有什么想法吗?我是否按照您的描述实现了代码?

标签: ios swift uitableview swift3 ios-animations


【解决方案1】:

一个 UITableView 已经有一个属性 tableFooterView

我们可以用一个 UIImageView、一个 UIScrollView 和另一个 UIView 子类化 UIView 来作为 UIImageView 的容器。我们称之为 StretchyFooterView。

我喜欢使用名为 PureLayout 的库来添加约束。

class YourView: UIView, UITableViewDelegate {

fileprivate let tableView = UITableView(frame: .zero, style: .plain)

fileprivate let image = UIImage(named: "yourImage")!

// ----------------------------------------------------------------------------
// MARK: Init
// ----------------------------------------------------------------------------

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

    setupViews()
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

// ----------------------------------------------------------------------------
// MARK: UIView
// ----------------------------------------------------------------------------

override func updateConstraints() {
    tableView.autoPinEdgesToSuperviewEdges()

    super.updateConstraints()
}

override func layoutSubviews() {
    super.layoutSubviews()

    // do this after the view lays out so we know the frame width and height
    let imageAspect = image.size.width / image.size.height
    let footerWidth = frame.size.width
    let footerHeight = footerWidth / imageAspect
    let footerSize = CGSize(width: footerWidth, height: footerHeight)
    let footerFrame = CGRect(origin: .zero, size: footerSize)

    tableView.tableFooterView = StretchyFooterView(frame: footerFrame, image: image)
}

// ----------------------------------------------------------------------------
// MARK: Internal
// ----------------------------------------------------------------------------

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let verticalScrollDistance = scrollView.contentOffset.y
    let bottomOfView = frame.height

    if let stretchyFooterView = tableView.tableFooterView as? StretchyFooterView {
        stretchyFooterView.stretchBy(verticalScrollDistance, bottomBound: bottomOfView)
    }
}

// ----------------------------------------------------------------------------
// MARK: Private
// ----------------------------------------------------------------------------

fileprivate func setupViews() {
    tableView.delegate = self

    addSubview(tableView)
}
}

class StretchyFooterView: UIView {

fileprivate let containerView = UIView()
fileprivate let scrollView = UIScrollView()
fileprivate let imageView = UIImageView()

fileprivate let image: UIImage

// ----------------------------------------------------------------------------
// MARK: Init
// ----------------------------------------------------------------------------

init(frame: CGRect, image: UIImage) {
    self.image = image

    super.init(frame: frame)

    setupViews()
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

// ----------------------------------------------------------------------------
// MARK: UIView
// ----------------------------------------------------------------------------

override func updateConstraints() {
    containerView.autoCenterInSuperview()
    containerView.autoMatch(.height, to: .height, of: scrollView)

    imageView.autoPinEdgesToSuperviewEdges()
    imageView.autoMatch(.width, to: .height, of: scrollView, withMultiplier: image.aspect)

    super.updateConstraints()
}

// ----------------------------------------------------------------------------
// MARK: Internal
// ----------------------------------------------------------------------------

func stretchBy(_ distanceScrolled: CGFloat, bottomBound: CGFloat) {
    let distanceFromTop = bottomBound + distanceScrolled // the footer could be offscreen, so we need to add the distance scrolled to the bottom of the view
    let distanceFromBottom = frame.maxY - distanceFromTop // this is how much we need to scroll

    if distanceFromBottom < 0 { // once we hit zero and below, we need to stretch the height
        let origin = CGPoint.zero // since we are scrolling, the origin needs to stay at zero
        let newSize = CGSize(width: frame.width, height: frame.height - distanceFromBottom) // subtract distanceFromBottom because it's negative

        scrollView.frame = CGRect(origin: origin, size: newSize)
    }
}

// ----------------------------------------------------------------------------
// MARK: Private
// ----------------------------------------------------------------------------

fileprivate func setupViews() {
    imageView.image = image

    containerView.addSubview(imageView)

    scrollView.frame = bounds
    scrollView.addSubview(containerView)

    addSubview(scrollView)
}
}

【讨论】:

    【解决方案2】:

    如果您使用 Storyboard,则为简单变体:

    1. Add empty view as tableView footer
    2. Connect an outlet to tableView delegate
    3. 实施 scrollViewDidScroll(_ scrollView: UIScrollView):

      func scrollViewDidScroll(_ scrollView: UIScrollView) { guard scrollView == mainTableView else { return } updateTableFooterFrame() }

      func updateTableFooterFrame() { let distanceFromTop = mainTableView.frame.height + mainTableView.contentOffset.y var distanceScrolled = distanceFromTop - mainTableView.contentSize.height distanceScrolled = distanceScrolled > 0 ? distanceScrolled : 0 let newFooterFrame = CGRect( x: 0, y: mainTableView.contentSize.height, width: mainTableView.frame.width, height: distanceScrolled ) tableFooterView.frame = newFooterFrame }

    【讨论】:

    • 如果可能,请努力提供额外的解释,而不仅仅是代码。此类答案往往更有用,因为它们可以帮助社区成员,尤其是新开发人员更好地理解解决方案的推理,并有助于避免需要解决后续问题。
    猜你喜欢
    • 1970-01-01
    • 2016-11-23
    • 2016-03-08
    • 1970-01-01
    • 2016-11-05
    • 1970-01-01
    • 2011-04-02
    • 1970-01-01
    • 2017-07-26
    相关资源
    最近更新 更多