Ios 如何显示tableview之外的可滚动父视图?
我有一个场景,需要显示一个具有阴影和圆角半径的父视图,其中包含一长串可重用项。我使用tableView来显示项目。但我坚持让我的tableview像它的contentSize一样扩展。它有效,但不准确。有什么解决办法吗 编辑: 预期结果: 我使用了下面的参考来自调整tableview的大小。 我做了一些修改如下:Ios 如何显示tableview之外的可滚动父视图?,ios,swift,uitableview,tableview,Ios,Swift,Uitableview,Tableview,我有一个场景,需要显示一个具有阴影和圆角半径的父视图,其中包含一长串可重用项。我使用tableView来显示项目。但我坚持让我的tableview像它的contentSize一样扩展。它有效,但不准确。有什么解决办法吗 编辑: 预期结果: 我使用了下面的参考来自调整tableview的大小。 我做了一些修改如下: final class SelfSizedTableView: UITableView { var maxHeight = CGFloat.greatestFiniteM
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我已添加了代码和编辑标签。请检查并询问是否有任何疑问。这是正确的方法还是其他解决方案?