Ios 如何更改UITableViewCell高度?

Ios 如何更改UITableViewCell高度?,ios,uitableview,Ios,Uitableview,我在单元格内实现了一个带有滚动视图的tableview。单元格由两个视图组成,第二个视图(显示为绿色)在滑动后显示: 我现在要实现的是,当单元格向右滑动时,单元格高度将逐渐扩大。因此,当我开始向右滑动单元格,绿色子视图在主屏幕上变得可见时,我希望单元格的高度增加,直到绿色子视图完全可见。然后我向左滑动,一切都恢复正常 由于UITableViewCell符合scroll view委托,我怀疑我在我的cell子类中编写了一些代码-可能使用scroll视图的contentOffset.y使用scro

我在单元格内实现了一个带有滚动视图的tableview。单元格由两个视图组成,第二个视图(显示为绿色)在滑动后显示:

我现在要实现的是,当单元格向右滑动时,单元格高度将逐渐扩大。因此,当我开始向右滑动单元格,绿色子视图在主屏幕上变得可见时,我希望单元格的高度增加,直到绿色子视图完全可见。然后我向左滑动,一切都恢复正常


由于UITableViewCell符合scroll view委托,我怀疑我在我的cell子类中编写了一些代码-可能使用scroll视图的
contentOffset.y
使用scroll ViewDidScroll

正如DonMag建议的那样,您应该通过调用BeginUpdate和EndUpdate来触发高度更改。虽然不完全相同,但我在这个答案中实现了一些非常相似的东西:


我相信你可以很容易地根据自己的需要调整它。

正如DonMag建议的那样,你应该通过调用BeginUpdate和EndUpdate来触发高度更改。虽然不完全相同,但我在这个答案中实现了一些非常相似的东西:

我相信您可以轻松地根据需要调整它。

下面是一个使用自动布局和自动调整单元格大小的示例(Swift 3)。不确定如何使用绿色视图“开始”,因此本演示将其初始化为40 pts宽(高度包含为宽度的50%)

您只需创建一个新的.swift文件并将其粘贴,然后在情节提要中添加一个UITableViewController,并将其类分配给
StretchCellTableViewController
。其他一切都是用代码创建的。。。不需要IB插座

//
//  StretchCellTableViewController.swift
//  SWTemp2
//
//  Created by Don Mag on 6/22/17.
//  Copyright © 2017 DonMag. All rights reserved.
//

import UIKit

class NonStretchCell: UITableViewCell {

    // pretty standard one-label cell

    var theLabel: UILabel!

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupCell()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupCell()
    }

    func setupCell() {

        theLabel = UILabel()
        theLabel.font = UIFont.systemFont(ofSize: 16.0, weight: UIFontWeightLight)
        theLabel.numberOfLines = 0
        theLabel.translatesAutoresizingMaskIntoConstraints = false

        self.addSubview(theLabel)

        theLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 8.0).isActive = true
        theLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 6.0).isActive = true
        theLabel.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -6.0).isActive = true
        theLabel.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -8.0).isActive = true

    }

}

class StretchCell: UITableViewCell {

    var stretchView: UIView!

    var widthConstraint: NSLayoutConstraint!

    var scaleAction : ((CGFloat)->())?

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupCell()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupCell()
    }

    func setBarWidth(_ w: CGFloat) -> Void {
        widthConstraint.constant = w
    }

    func setupCell() {

        // instantiate the view
        stretchView = UIView()
        stretchView.translatesAutoresizingMaskIntoConstraints = false
        stretchView.backgroundColor = .green

        // add it to self (the cell)
        self.addSubview(stretchView)

        // "pin" it to top, bottom and left
        stretchView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 0.0).isActive = true
        stretchView.topAnchor.constraint(equalTo: self.topAnchor, constant: 0.0).isActive = true
        stretchView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0.0).isActive = true

        // set height constraint to be 50% of the width
        stretchView.heightAnchor.constraint(equalTo: stretchView.widthAnchor, multiplier: 0.5).isActive = true

        // instantiate the width constraint
        widthConstraint = NSLayoutConstraint(item: stretchView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 40)

        // needs priority of 999 so auto-layout doesn't complain
        widthConstraint.priority = 999

        // activate the width constraint
        NSLayoutConstraint.activate([widthConstraint])

        // create a UIPanGestureRecognizer and add it to the stretch view
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(didPan(sender:)))

        stretchView.addGestureRecognizer(panGesture)

    }

    func didPan(sender: UIPanGestureRecognizer) {

        let loc = sender.location(in: self)

        if sender.state == .began {

            // if you want to do something on drag start...
            //print("Gesture began")

        } else if sender.state == .changed {

            //print("Gesture is changing", loc)

            // update the width of the stretch view (but keep it at least 20-pts wide, so it doesn't disappear)
            // height is set to 1:1 so it updates automatically
            widthConstraint.constant = max(loc.x, 20)

            // call back to the view controller
            scaleAction?(widthConstraint.constant)

        } else if sender.state == .ended {

            // if you want to do something on drag end...
            //print("Gesture ended")

        }

    }

}


class StretchCellTableViewController: UITableViewController {

    // array to track the bar widths, assuming we have more than one row with a bar
    // only a few rows will have the "stretch bar" - but for this example we'll just track a barWidth for *every* row
    var barWidths = [CGFloat]()

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.rowHeight = UITableViewAutomaticDimension
        tableView.estimatedRowHeight = 80

        tableView.register(StretchCell.self, forCellReuseIdentifier: "StretchCell")
        tableView.register(NonStretchCell.self, forCellReuseIdentifier: "NonStretchCell")

        // init array for barWidths... initial value: 40, 30 slots
        barWidths = Array(repeating: 40, count: 30)
    }

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

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return barWidths.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        // just make every 5th row a "Stretch" cell (starting at #3)
        if indexPath.row % 5 == 3 {
            let cell = tableView.dequeueReusableCell(withIdentifier: "StretchCell", for: indexPath) as! StretchCell
            cell.selectionStyle = .none

            // cells are reused, so set the bar width to our saved value
            cell.setBarWidth(barWidths[indexPath.row])

            // "call-back" function
            cell.scaleAction = {
                (newWidth) in
                // update the bar width in our tracking array
                self.barWidths[indexPath.row] = newWidth

                // disable Animations, because we're changing the size repeatedly
                UIView.setAnimationsEnabled(false)

                // wrap begin/end updates() to force row-height re-calc
                self.tableView.beginUpdates()
                self.tableView.endUpdates()

                // re-enable Animations
                UIView.setAnimationsEnabled(true)
            }

            cell.preservesSuperviewLayoutMargins = false
            cell.separatorInset = UIEdgeInsets.zero
            cell.layoutMargins = UIEdgeInsets.zero

            return cell
        }

        let cell = tableView.dequeueReusableCell(withIdentifier: "NonStretchCell", for: indexPath) as! NonStretchCell

        // just for demonstration's sake

        if indexPath.row % 7 == 5 {
            cell.theLabel.text = "Row: \(indexPath.row) - This is just to show the text wrapping onto multiple lines. Pretty standard for auto-sizing UITableView cells."
        } else {
            cell.theLabel.text = "Row: \(indexPath.row)"
        }

        cell.preservesSuperviewLayoutMargins = false
        cell.separatorInset = UIEdgeInsets.zero
        cell.layoutMargins = UIEdgeInsets.zero

        return cell
    }

}
结果是:

以下是使用自动布局和自动调整单元格大小的示例(Swift 3)。不确定如何使用绿色视图“开始”,因此本演示将其初始化为40 pts宽(高度包含为宽度的50%)

您只需创建一个新的.swift文件并将其粘贴,然后在情节提要中添加一个UITableViewController,并将其类分配给
StretchCellTableViewController
。其他一切都是用代码创建的。。。不需要IB插座

//
//  StretchCellTableViewController.swift
//  SWTemp2
//
//  Created by Don Mag on 6/22/17.
//  Copyright © 2017 DonMag. All rights reserved.
//

import UIKit

class NonStretchCell: UITableViewCell {

    // pretty standard one-label cell

    var theLabel: UILabel!

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupCell()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupCell()
    }

    func setupCell() {

        theLabel = UILabel()
        theLabel.font = UIFont.systemFont(ofSize: 16.0, weight: UIFontWeightLight)
        theLabel.numberOfLines = 0
        theLabel.translatesAutoresizingMaskIntoConstraints = false

        self.addSubview(theLabel)

        theLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 8.0).isActive = true
        theLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 6.0).isActive = true
        theLabel.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -6.0).isActive = true
        theLabel.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -8.0).isActive = true

    }

}

class StretchCell: UITableViewCell {

    var stretchView: UIView!

    var widthConstraint: NSLayoutConstraint!

    var scaleAction : ((CGFloat)->())?

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupCell()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupCell()
    }

    func setBarWidth(_ w: CGFloat) -> Void {
        widthConstraint.constant = w
    }

    func setupCell() {

        // instantiate the view
        stretchView = UIView()
        stretchView.translatesAutoresizingMaskIntoConstraints = false
        stretchView.backgroundColor = .green

        // add it to self (the cell)
        self.addSubview(stretchView)

        // "pin" it to top, bottom and left
        stretchView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 0.0).isActive = true
        stretchView.topAnchor.constraint(equalTo: self.topAnchor, constant: 0.0).isActive = true
        stretchView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0.0).isActive = true

        // set height constraint to be 50% of the width
        stretchView.heightAnchor.constraint(equalTo: stretchView.widthAnchor, multiplier: 0.5).isActive = true

        // instantiate the width constraint
        widthConstraint = NSLayoutConstraint(item: stretchView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 40)

        // needs priority of 999 so auto-layout doesn't complain
        widthConstraint.priority = 999

        // activate the width constraint
        NSLayoutConstraint.activate([widthConstraint])

        // create a UIPanGestureRecognizer and add it to the stretch view
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(didPan(sender:)))

        stretchView.addGestureRecognizer(panGesture)

    }

    func didPan(sender: UIPanGestureRecognizer) {

        let loc = sender.location(in: self)

        if sender.state == .began {

            // if you want to do something on drag start...
            //print("Gesture began")

        } else if sender.state == .changed {

            //print("Gesture is changing", loc)

            // update the width of the stretch view (but keep it at least 20-pts wide, so it doesn't disappear)
            // height is set to 1:1 so it updates automatically
            widthConstraint.constant = max(loc.x, 20)

            // call back to the view controller
            scaleAction?(widthConstraint.constant)

        } else if sender.state == .ended {

            // if you want to do something on drag end...
            //print("Gesture ended")

        }

    }

}


class StretchCellTableViewController: UITableViewController {

    // array to track the bar widths, assuming we have more than one row with a bar
    // only a few rows will have the "stretch bar" - but for this example we'll just track a barWidth for *every* row
    var barWidths = [CGFloat]()

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.rowHeight = UITableViewAutomaticDimension
        tableView.estimatedRowHeight = 80

        tableView.register(StretchCell.self, forCellReuseIdentifier: "StretchCell")
        tableView.register(NonStretchCell.self, forCellReuseIdentifier: "NonStretchCell")

        // init array for barWidths... initial value: 40, 30 slots
        barWidths = Array(repeating: 40, count: 30)
    }

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

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return barWidths.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        // just make every 5th row a "Stretch" cell (starting at #3)
        if indexPath.row % 5 == 3 {
            let cell = tableView.dequeueReusableCell(withIdentifier: "StretchCell", for: indexPath) as! StretchCell
            cell.selectionStyle = .none

            // cells are reused, so set the bar width to our saved value
            cell.setBarWidth(barWidths[indexPath.row])

            // "call-back" function
            cell.scaleAction = {
                (newWidth) in
                // update the bar width in our tracking array
                self.barWidths[indexPath.row] = newWidth

                // disable Animations, because we're changing the size repeatedly
                UIView.setAnimationsEnabled(false)

                // wrap begin/end updates() to force row-height re-calc
                self.tableView.beginUpdates()
                self.tableView.endUpdates()

                // re-enable Animations
                UIView.setAnimationsEnabled(true)
            }

            cell.preservesSuperviewLayoutMargins = false
            cell.separatorInset = UIEdgeInsets.zero
            cell.layoutMargins = UIEdgeInsets.zero

            return cell
        }

        let cell = tableView.dequeueReusableCell(withIdentifier: "NonStretchCell", for: indexPath) as! NonStretchCell

        // just for demonstration's sake

        if indexPath.row % 7 == 5 {
            cell.theLabel.text = "Row: \(indexPath.row) - This is just to show the text wrapping onto multiple lines. Pretty standard for auto-sizing UITableView cells."
        } else {
            cell.theLabel.text = "Row: \(indexPath.row)"
        }

        cell.preservesSuperviewLayoutMargins = false
        cell.separatorInset = UIEdgeInsets.zero
        cell.layoutMargins = UIEdgeInsets.zero

        return cell
    }

}
结果是:


一种方法。。。设置自动调整单元格大小,使用绿色子视图的框架强制调整高度。向右滑动(更可能是平移)时,缩放
绿色
宽度和高度,并使用
.beginUpdate()
.endUpdates()
触发表格重画。一种方法。。。设置自动调整单元格大小,使用绿色子视图的框架强制调整高度。向右滑动(更可能是平移)时,缩放
绿色
宽度和高度,并使用
.beginUpdate()
.endUpdates()
触发表格重画。链接到的方法将很难实现问题的提问方式。您使用的是两个固定高度值,需要调用
heightforrowatinexpath
。使用自动布局和约束自动调整单元格内容的大小要好得多。OP主要询问如何更改单元格高度。他从来没有说过他没有固定的高度或使用自动布局。“我现在想实现的是,当单元格向右滑动时,单元格高度逐渐扩大。”---我不是想和你争论,只是想把OP指向正确的方向。“…逐步扩展…”是OP描述他/她想要实现的目标的关键部分。您链接到的方法将很难实现问题提出的方式。您使用的是两个固定高度值,需要调用
heightforrowatinexpath
。使用自动布局和约束自动调整单元格内容的大小要好得多。OP主要询问如何更改单元格高度。他从来没有说过他没有固定的高度或使用自动布局。“我现在想实现的是,当单元格向右滑动时,单元格高度逐渐扩大。”---我不是想和你争论,只是想把OP指向正确的方向。“…逐步扩展…”是OP描述他/她想要实现的目标的关键部分。