Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 如何显示tableview之外的可滚动父视图?_Ios_Swift_Uitableview_Tableview - Fatal编程技术网

Ios 如何显示tableview之外的可滚动父视图?

Ios 如何显示tableview之外的可滚动父视图?,ios,swift,uitableview,tableview,Ios,Swift,Uitableview,Tableview,我有一个场景,需要显示一个具有阴影和圆角半径的父视图,其中包含一长串可重用项。我使用tableView来显示项目。但我坚持让我的tableview像它的contentSize一样扩展。它有效,但不准确。有什么解决办法吗 编辑: 预期结果: 我使用了下面的参考来自调整tableview的大小。 我做了一些修改如下: final class SelfSizedTableView: UITableView { var maxHeight = CGFloat.greatestFiniteM

我有一个场景,需要显示一个具有阴影和圆角半径的父视图,其中包含一长串可重用项。我使用tableView来显示项目。但我坚持让我的tableview像它的contentSize一样扩展。它有效,但不准确。有什么解决办法吗

编辑:

预期结果:

我使用了下面的参考来自调整tableview的大小。

我做了一些修改如下:

final class SelfSizedTableView: UITableView {

    var maxHeight = CGFloat.greatestFiniteMagnitude

    override func reloadData() {
        super.reloadData()
        self.invalidateIntrinsicContentSize()
        self.layoutIfNeeded()
    }

    override var intrinsicContentSize: CGSize {
        let height = min(contentSize.height, maxHeight)
        let size = CGSize(width: contentSize.width, height: height)
        return size
    }

}
我使用了一个父表视图,其中一个单元格有我的containerView并嵌入了这个自大小的表视图

class MyContainerViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    // MARK: - IBOutlets
    @IBOutlet weak var parentTableView: UITableView!

    // MARK: - Life Cycle
    override func viewDidLoad() {
        super.viewDidLoad()
        setupViews()
    }

    private func estimateDataHeight() -> CGFloat {
        let detailCellHeight: CGFloat = 32
        let headingCellHeight: CGFloat = 43
        let headings: CGFloat = headingCellHeight*2
        let detailsHeight: CGFloat = detailCellHeight*4
        let baseHeight = headings + detailsHeight
        let membersHeight =
            CGFloat(sectionsArray.count) * detailCellHeight
        return baseHeight + membersHeight
    }
}

// MARK: - UITableViewDataSource
extension MyContainerViewController {

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

    func tableView(_ tableView: UITableView,
                   cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let id = String(describing: MyContainerTVCell.self)
        guard let cell = tableView
            .dequeueReusableCell(withIdentifier: id, for: indexPath)
            as? MyContainerTVCell else {
                return UITableViewCell()
        }

        cell.policyDetails = dataSource
        // my cheat/trick doesn't work on large data.
        DispatchQueue.main.asyncAfter(deadline: .now()+0.4) {
            tableView.beginUpdates()
            cell.tableView.layoutIfNeeded()
            cell.tableView.reloadData() // the overridden one
            tableView.endUpdates()
        }
        return cell
    }
}

extension MyContainerViewController {

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableViewAutomaticDimension
    }

    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        return estimateDataHeight()
    }
}
My cell类,具有自身大小的tableView和containerView:

class MyContainerTVCell: UITableViewCell, UITableViewDataSource, UITableViewDelegate {

    // MARK: - IBOutlets
    @IBOutlet weak var containerView: UIView!
    @IBOutlet weak var shadowView: UIView!
    @IBOutlet weak var tableView: SelfSizedTableView!

    // MARK: - Properties
    let titles = ["Email ID:", "Mobile Number:", "Address:", "ID: "] // first section data array
    let moreData: [String] = [] // remaining reusable sections array

    // no of subsequent sections for moreData array type
    var numberOfSections: Int {
        return 4
    }

    // MARK: -
    var dataSource: MyDataSource!

    // MARK: - Life Cycle
    override func awakeFromNib() {
        super.awakeFromNib()
        setupView()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
    }

    // MARK: - Setup
    func setupView() {
        containerView.rounded(with: 10)
        shadowView.layer.applyShadow()

        tableView.dataSource = self
        tableView.delegate = self
    }
}

// MARK: - UITableViewDataSource
extension MyContainerTVCell {
    func numberOfSections(in tableView: UITableView) -> Int {
        return numberOfSections + 1
    }

    func tableView(_ tableView: UITableView,
                   numberOfRowsInSection section: Int) -> Int {
        if section == 0 { return titles.count + 1 }
        else if section == 1 { return moreData.count + 1 }
        else { return moreData.count }
    }

    func tableView(_ tableView: UITableView,
                   cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let headerID = String(describing: MyHeaderTVCell.self)
        let itemID = String(describing: MyItemTVCell.self)

        switch indexPath.section {
        case 0:
            if indexPath.row == 0 {
                guard let cell = tableView
                    .dequeueReusableCell(withIdentifier: headerID, for: indexPath)
                    as? MyHeaderTVCell else {
                        return UITableViewCell()
                }
                cell.titleLabel.text = dataSource.title
                return cell
            } else {
                guard let cell = tableView
                    .dequeueReusableCell(withIdentifier: itemID, for: indexPath)
                    as? MyItemTVCell else {
                        return UITableViewCell()
                }
                let item = titles[indexPath.row-1]
                cell.titleLabel.text = item
                cell.separatorView.isHidden = true
                let data: String
                switch indexPath.row {
                case 1:
                    data = dataSource.emailID
                case 2:
                    data = dataSource.mobileNo
                case 3:
                    data = dataSource.address
                case 4:
                    data = dataSource.name
                case 5:
                    data = dataSource.age
                case 6:
                    data = dataSource.id
                case 7:
                    data = dataSource.office
                case 8:
                    data = dataSource.academic
                default: data = String()
                }
                cell.detailLabel.text = data
                return cell
            }

        case 1:
            if indexPath.row == 0 {
                guard let cell = tableView
                    .dequeueReusableCell(withIdentifier: headerID, for: indexPath)
                    as? MyHeaderTVCell else {
                        return UITableViewCell()
                }
                cell.titleLabel.text = "More Data"
                return cell
            } else {
                guard let cell = tableView
                    .dequeueReusableCell(withIdentifier: itemID, for: indexPath)
                    as? MyItemTVCell else {
                        return UITableViewCell()
                }
                let sectionIndex = indexPath.section-1
                guard sectionIndex <= numberOfSections-1,
                    let section = sectionsArray?[indexPath.section-1] else {
                        return UITableViewCell()
                }
                cell.titleLabel.text = moreData[indexPath.row-1]
                cell.separatorView.isHidden = true
                switch indexPath.row {
                case 1:
                    cell.detailLabel.text = section.a
                case 2:
                    cell.detailLabel.text = section.b
                case 3:
                    cell.detailLabel.text = "\(section.c ?? 0)"
                case 4:
                    cell.detailLabel.text = section.d
                case 5:
                    cell.detailLabel.text = section.e
                case 6:
                    cell.detailLabel.text = section.f
                    if indexPath.section < numberOfSections {
                        cell.separatorView.isHidden = false
                    }
                default: break
                }
                return cell
            }
        default:
            guard let cell = tableView
                .dequeueReusableCell(withIdentifier: itemID, for: indexPath)
                as? MyItemTVCell else {
                    return UITableViewCell()
            }
            let sectionIndex = indexPath.section-1
            guard sectionIndex <= numberOfSections-1,
                let section = sectionsArray?[indexPath.section-1] else {
                    return UITableViewCell()
            }
            cell.titleLabel.text = moreData[indexPath.row]
            cell.separatorView.isHidden = true
            switch indexPath.row {
            case 0:
                cell.detailLabel.text = section.a
            case 1:
                cell.detailLabel.text = section.b
            case 2:
                cell.detailLabel.text = "\(section.c ?? 0)"
            case 3:
                cell.detailLabel.text = section.d
            case 4:
                cell.detailLabel.text = section.e
            case 5:
                cell.detailLabel.text = section.f
                if indexPath.section < numberOfSections {
                    cell.separatorView.isHidden = false
                }
            default: break
            }
            return cell
        }
    }
}

// MARK: - UITableViewDelegate
extension MyContainerTVCell {
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableViewAutomaticDimension
    }

    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        if indexPath.section == 0 && indexPath.row == 0 { return 43 }
        if indexPath.section == 1 && indexPath.row == 0 { return 43 }
        return 32
    }
}
MyContainerTVCell类:UITableViewCell、UITableViewDataSource、UITableViewDelegate{ //标记:-IB出口 @IBOutlet弱var containerView:UIView! @ibvar shadowView:UIView! @IBVAR表格视图:SelfSizedTableView! //标记:-属性 让titles=[“电子邮件ID:”,“手机号码:”,“地址:”,“ID:”]//第一节数据数组 let moreData:[String]=[]//剩余可重用节数组 //moreData数组类型的后续节数 变量numberOfSections:Int{ 返回4 } //标记:- var数据源:MyDataSource! //马克:生命周期 重写func awakeFromNib(){ super.awakeFromNib() setupView() } 覆盖func布局子视图(){ super.layoutSubviews() } //标记:-设置 func setupView(){ 容器视图四舍五入(带:10) shadowView.layer.applyShadow() tableView.dataSource=self tableView.delegate=self } } //标记:-UITableViewDataSource 延伸支原体细胞{ func numberOfSections(在tableView:UITableView中)->Int{ 返回节数+1 } func tableView(tableView:UITableView, numberOfRowsInSection部分:Int)->Int{ 如果节==0{返回titles.count+1} 如果节==1{return moreData.count+1},则为else else{return moreData.count} } func tableView(tableView:UITableView, cellForRowAt indexPath:indexPath)->UITableViewCell{ 让headerID=String(描述:MyHeaderTVCell.self) 让itemID=String(描述:MyItemTVCell.self) 开关indexPath.section{ 案例0: 如果indexath.row==0{ guard let单元格=表视图 .dequeueReusableCell(标识符为headerID,for:indexath) 作为?我的头还是其他{ 返回UITableViewCell() } cell.titleLabel.text=dataSource.title 返回单元 }否则{ guard let单元格=表视图 .dequeueReusableCell(标识符为:itemID,for:indexPath) 作为?MyItemTVCell,还有别的吗{ 返回UITableViewCell() } let item=标题[indexPath.row-1] cell.titleLabel.text=项 cell.separatorView.ishiden=true 让数据:字符串 切换到xpath.row{ 案例1: data=dataSource.emailID 案例2: data=dataSource.mobileNo 案例3: data=dataSource.address 案例4: data=dataSource.name 案例5: data=dataSource.age 案例6: data=dataSource.id 案例7: data=dataSource.office 案例8: data=dataSource.academic 默认值:data=String() } cell.detailLabel.text=数据 返回单元 } 案例1: 如果indexath.row==0{ guard let单元格=表视图 .dequeueReusableCell(标识符为headerID,for:indexath) 作为?我的头还是其他{ 返回UITableViewCell() } cell.titleLabel.text=“更多数据” 返回单元 }否则{ guard let单元格=表视图 .dequeueReusableCell(标识符为:itemID,for:indexPath) 作为?MyItemTVCell,还有别的吗{ 返回UITableViewCell() } 设sectionIndex=indexPath.section-1 保护区索引CGFloat{ 如果indexPath.section==0&&indexPath.row==0{return 43} 如果indexPath.section==1&&indexPath.row==0{return 43} 返回32 } }
既然
tableView
已经可以滚动,为什么要将
tableView
扩展到其内容大小以使其可滚动

但是,如果屏幕上除了表格之外还有其他内容,并且希望它们一起滚动,则需要将所有内容嵌入到
UIScrollView

然后,在xib/情节提要中使用任意值为您的
tableView
创建高度约束。 然后你可以这样做:

// in your view controller
private var heightObservation: NSKeyValueObservation?

// called once, for example, in viewDidLoad()
private func setupTableView() {
    ...

    observation = tableView.constraintFrameHeightToContentSizeHeight()
}

extension UITableView {

    func constraintFrameHeightToContentSizeHeight() -> NSKeyValueObservation {
        return observe(\.contentSize, changeHandler: { (tableView, _) in
            tableView.heightConstraint?.constant = tableView.contentSize.height
        })
    }
}

// find height constraint
extension UIView {

    var heightConstraint: NSLayoutConstraint? {
        return constraints.first(where: { $0.firstAttribute == .height })
    }
}

不要忘记取消选中“已启用滚动”在xib/storyboard中显示该表视图。

您有任何屏幕截图要共享吗?请显示代码。您尝试了什么?我不明白为什么objective-c和swift是标记,因为您的问题中没有代码。@Glenn我已在编辑中添加了详细信息。如果对理解代码或预期结果有任何疑问,请询问。@MikeTaverne我已添加了代码和编辑标签。请检查并询问是否有任何疑问。这是正确的方法还是其他解决方案?