ios - UITableView - 让图像跨越多个 UITableViewCells 并滚动

标签 ios swift uitableview

我有一个相当标准的 ipad tableview,我通过向 UITableViewCell.contentView 添加 subview 来放置两行数据。

我想在这个表格的右侧添加一个图像,并让它跨越多行,就像这样(见右图):

Screenshot

现在的问题是,当我滚动表格时,一旦该单元格不再完全显示在 View 中,图像就会被截断,如下所示:

Screenshot2

我添加这张图片的方式是

// priority 999 helps save a lot of headache on troubleshooting auto layout warnings for code created views
extension NSLayoutConstraint {
    func activateWithPriority(_ val: Float) {
        self.priority = UILayoutPriority(val)
        self.isActive = true
    }

    func activateWithBasicPriority() {
        self.priority = UILayoutPriority(999)
        self.isActive = true
    }
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) ?? UITableViewCell()

        if !cell.contentView.subviews.isEmpty {
            for sv in cell.contentView.subviews {
                sv.removeFromSuperview()
            }
        }

        if indexPath.row == 1 {
            let image = UIImageView(image: UIImage(named: "product_placeholder"))
            image.translatesAutoresizingMaskIntoConstraints = false
            cell.contentView.addSubview(image)

            image.widthAnchor.constraint(equalToConstant: 200).activateWithBasicPriority()
            image.heightAnchor.constraint(equalToConstant: 200).activateWithBasicPriority()
            image.rightAnchor.constraint(equalTo: cell.contentView.rightAnchor, constant: -10).activateWithBasicPriority()
            image.topAnchor.constraint(equalTo: cell.contentView.topAnchor, constant: 10).activateWithBasicPriority()
        }

// other stuff here

return cell

}

我可以将该图像粘贴在我的 tableview 之外,以覆盖它,但问题是这会使它不可滚动,而我希望它与我的表格一起滚动。

此外,我知道我可能可以将图像左侧的所有其他行放到一行中,就像一个巨大的单元格,但我想尽可能避免这种情况。

最佳答案

您可以通过将 imageView 添加为 tableView 的 subview 来实现。然后它将与单元格一起滚动。

设置它的约束有点棘手,因为你需要让它水平相对于 tableView 的后缘,垂直相对于所需的单元格。

但是,tableView 的尾部约束对其 subview 不起作用,并且在呈现单元格之前您不知道单元格的位置。

所以,一些事情:

  1. 我们会将 tableView 嵌入“容器”UIView,并将该 View 的尾部约束用于 ImageView 的尾部边缘。

  2. 我们将创建一个 Top Constraint 变量并在 viewDidAppear() 中设置它的 .constant

这是一个例子。这都是代码(没有@IBOutlets)所以只需添加一个新的空 View Controller 并将其类分配给TableWithSubViewViewController:

//  TableWithSubViewViewController.swift
//  Created by Don Mag on 5/10/19

class SimpleOneLabelCell: UITableViewCell {

    // very simple one-label tableView cell

    let theLabel: UILabel = {
        let v = UILabel()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.numberOfLines = 0
        return v
    }()

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        contentView.addSubview(theLabel)

        NSLayoutConstraint.activate([
            theLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8.0),
            theLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8.0),
            theLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8.0),

            // trailing constraint set to -150, to allow room for our 120x120 imageview (with padding)
            theLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -150.0),
            ])

    }

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

}

class TableWithSubViewViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    let theContainerView: UIView = {
        let v = UIView()
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()

    let theTableView: UITableView = {
        let v = UITableView()
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()

    let overlayImageView: UIImageView = {
        let v = UIImageView()
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()

    // top constraint for the image view
    var overlayViewTopConstraint: NSLayoutConstraint = NSLayoutConstraint()

    let reuseID = "SimpleOneLabelCell"

    override func viewDidLoad() {
        super.viewDidLoad()

        theTableView.dataSource = self
        theTableView.delegate = self

        theTableView.register(SimpleOneLabelCell.self, forCellReuseIdentifier: reuseID)

        // set the imageView's image
        if let img = UIImage(named: "overlay") {
            overlayImageView.image = img
        }

        // add the views
        view.addSubview(theContainerView)
        theContainerView.addSubview(theTableView)
        theTableView.addSubview(overlayImageView)

        // constrain the top of the imageView above the top of the tableView
        //   we'll change the constant in viewDidAppear()
        overlayViewTopConstraint = overlayImageView.topAnchor.constraint(equalTo: theTableView.topAnchor, constant: -120.0)

        NSLayoutConstraint.activate([

            // constrain containerView to all 4 sides (safe-area)
            theContainerView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            theContainerView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
            theContainerView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
            theContainerView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),

            // constrain tableView to all 4 sides of constainerView
            theTableView.topAnchor.constraint(equalTo: theContainerView.topAnchor),
            theTableView.bottomAnchor.constraint(equalTo: theContainerView.bottomAnchor),
            theTableView.leadingAnchor.constraint(equalTo: theContainerView.leadingAnchor),
            theTableView.trailingAnchor.constraint(equalTo: theContainerView.trailingAnchor),

            // constrain the imageView using the Top Constraint we already created, plus
            overlayViewTopConstraint,

            // 20-pts from the right (trailing) edge of the Container View, plus
            overlayImageView.trailingAnchor.constraint(equalTo: theContainerView.trailingAnchor, constant: -20.0),

            // width and height at 120-pt constants
            overlayImageView.widthAnchor.constraint(equalToConstant: 120.0),
            overlayImageView.heightAnchor.constraint(equalToConstant: 120.0),
            ])

    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        // at this point we have the table and its initial cells laid out, so we can use it for
        //  vertical positioning of the image view
        if let c = theTableView.cellForRow(at: IndexPath(row: 1, section: 0)) as? SimpleOneLabelCell {

            // get the frame of the cell on row 1
            let f = c.frame

            // add half-cell-height to the origin.y
            var y = f.origin.y + (f.size.height * 0.5)

            // get the frame of the image view
            let r = overlayImageView.frame

            // subtract half-imageView-height
            y -= (r.height * 0.5)

            // update imageView's top constraint
            overlayViewTopConstraint.constant = y

        }

    }

    // MARK: - Table view data source

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 20
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: reuseID, for: indexPath) as! SimpleOneLabelCell

        cell.theLabel.text = "\(indexPath)\nLine 2\nLine 3"

        return cell
    }

}

结果:

enter image description here

enter image description here

(使用这张我从你的图片中剪下的图片):

enter image description here

关于ios - UITableView - 让图像跨越多个 UITableViewCells 并滚动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56073115/

相关文章:

iphone - 将实用程序应用程序(2 个 View Controller )转换为选项卡栏应用程序

ios - PreferredStatusBarStyle 和presentModalView Controller

ios - 根据按钮选择状态将无法识别的选择器发送到实例

swift - 旋转 UICollectionView 会导致错误

swift - 当滚动甚至存储在 NSCache 中时,UIImage 一直保持加载 - swift

iOS UITableView headerView 没有隐藏

ios - 何时使用 sceneDidLoad v didMove(查看 :)

ios - NSFetchedResultsController 正在删除行而不是在更新核心数据后更新它们

ios - UITableView 滚动时重置 ContentOffset

ios - 如何在 iOS CollectionView 的 Footer 中添加 loading Indicator