I have created nested tableView approach, In a view controller I set tableView and then nested tableView for the Cell.
So its like Parent tableView and Child tableView.
For adjusting content height tableView row height autoDimension I have created custom class for it and override intrinsicContentSize but I am still getting scrollbar in nested tableview. ContentSize updating but row height not adjusting. I have already set automatic row height for both the parent and child table view.
How can I avoid this scrollbar when my content expand it should auto set tableView row height?.
Attaching GitHub code reference and images as well.
https://github.com/MasamMahmood/autoHeightTableView
Custom Class Code:
class MyOwnTableView: UITableView {
override var intrinsicContentSize: CGSize {
self.layoutIfNeeded()
print("ContentSizee \(contentSize)")
return self.contentSize
}
override var contentSize: CGSize {
didSet{
self.invalidateIntrinsicContentSize()
}
}
override func reloadData() {
super.reloadData()
self.invalidateIntrinsicContentSize()
}
}
Images:
Related
I have a custom uitableviewcell that has an embeded child view controller. This child view controller uses autolayout and contains another uitableview. I'm trying to render the cell so that the child view controller's tableview is exactly the height of the contents.
I know that you can do that by setting tableview height constraint equal to the contentsize.height
but since it's in a tableviewcell, there is already an encapsulated height calculated. How do I force the cell to resize with the new child view controller's uitableview updated height constraint?
Try to Use AutoHeight TableView inside your custom cell instead of child View Controller.
Set scrolling and jumping property to false of AutoHeight Table.
final class AutoHeightTableView: UITableView {
override var intrinsicContentSize: CGSize {
self.layoutIfNeeded()
return self.contentSize
}
override var contentSize: CGSize {
didSet{
UIView.performWithoutAnimation {
self.invalidateIntrinsicContentSize()
}
}
}
}
Insted of scroll view i used Tableview controller, inside Tableview controller i desined by adding collection view, textfield also i want to add table view inside it.
I implemeted but it crashes the app beacuse of parent table view. Any solution?
Create a custom cell with tableView(Autoheight TableView) inside it. Add cell to your TableViewController.
Custom Cell with AutoHeightTableView
Set isScrolling, bounces of AutoHeightTable to false
Register custom cell to TableViewController
Load custom cell table data
final class AutoHeightTableView: UITableView {
override var intrinsicContentSize: CGSize {
self.layoutIfNeeded()
return self.contentSize
}
override var contentSize: CGSize {
didSet{
UIView.performWithoutAnimation {
self.invalidateIntrinsicContentSize()
}
}
}
}
I have create a custom view MyIntrincView which calculates its height automatically when setting its content. This works fine both in simulator and InterfaceBuilder.
However, when placing MyIntrinsicView inside a UITableViewCell, the cell height is not calculated correctly. Instead of automatically adopting the cell height to the intrinsic height of the view, all cell keep the same, initial height.
// A simple, custom view with intrinsic height. The height depends on
// the value of someProperty. When the property is changed setNeedsLayout
// is set and the height changes automatically.
#IBDesignable class MyIntrinsicView: UIView {
#IBInspectable public var someProperty: Int = 5 {
didSet { setNeedsLayout() }
}
override func layoutSubviews() {
super.layoutSubviews()
calcContent()
}
func calcContent() {
height = CGFloat(20 * someProperty)
invalidateIntrinsicContentSize()
}
#IBInspectable var height: CGFloat = 50
override var intrinsicContentSize: CGSize {
return CGSize(width: super.intrinsicContentSize.width, height: height)
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
invalidateIntrinsicContentSize()
}
}
// A simple cell which only contains a MyIntrinsicView subview. The view
// is attached to trailing, leading, top and bottom anchors of the cell.
// Thus the cell height should automatically match the height of the
// MyIntrinsicView
class MyIntrinsicCell: UITableViewCell {
#IBOutlet private var myIntrinsicView: MyIntrinsicView!
var someProperty: Int {
get { return myIntrinsicView.someProperty }
set {
myIntrinsicView.someProperty = newValue
// Cell DOES NOT rezise without manualle calling layoutSubviews()
myIntrinsicView.layoutSubviews()
}
}
}
...
// Simple tableView delegate which should create cells of different heights
// by giving each cell a different someProperty
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "IntrinsicCell", for: indexPath) as? MyIntrinsicCell ?? MyIntrinsicCell()
// Give all cell a different intrinsic height by setting someProperty to rowIndex
cell.someProperty = indexPath.row
return cell
}
I would expect, that each cell has a different height (20 * someProperty = 20 * indexPath.row). However, instead all cell have the same, initial height.
Only when explicitly calling myIntrinsicView.layoutSubviews() the cells are created with the correct height.
It seems that the tableView does not call myIntrinsicView.layoutSubviews(). Why is this?
When using a UILabel instad of MyIntrinsicView as cell content with different text lengths, everything works as expected. Thus the overall tableView setup is correct (= cell sizes are calculated automatically) and there has to be way to use intrinsic sizes correctly in UITableView as well. So, what exactly is the correct way to do this?
As with your previous question here I think you're not really understanding what intrinsicContentSize does and does not do.
When setting the text of a UILabel, yes, its intrinsicContentSize changes, but that's not all that happens.
You also don't want to do what you're trying inside layoutSubviews() ... if your code does trigger a change, you'll get into an infinite recursion loop (again, as with your previous question).
Take a look at modifications to your code:
// A simple, custom view with intrinsic height. The height depends on
// the value of someProperty. When the property is changed setNeedsLayout
// is set and the height changes automatically.
#IBDesignable class MyIntrinsicView: UIView {
#IBInspectable public var someProperty: Int = 5 {
didSet {
calcContent()
setNeedsLayout()
}
}
func calcContent() {
height = CGFloat(20 * someProperty)
invalidateIntrinsicContentSize()
}
#IBInspectable var height: CGFloat = 50
override var intrinsicContentSize: CGSize {
return CGSize(width: super.intrinsicContentSize.width, height: height)
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
invalidateIntrinsicContentSize()
}
}
// A simple cell which only contains a MyIntrinsicView subview. The view
// is attached to trailing, leading, top and bottom anchors of the cell.
// Thus the cell height should automatically match the height of the
// MyIntrinsicView
class MyIntrinsicCell: UITableViewCell {
#IBOutlet private var myIntrinsicView: MyIntrinsicView!
var someProperty: Int {
get { return myIntrinsicView.someProperty }
set {
myIntrinsicView.someProperty = newValue
}
}
}
Two side notes...
1 - Your posted code shows you calling myIntrinsicView.layoutSubviews()... from Apple's docs:
You should not call this method directly. If you want to force a layout update, call the setNeedsLayout method instead to do so prior to the next drawing update. If you want to update the layout of your views immediately, call the layoutIfNeeded method.
2 - For the direction it looks like you're headed, you would probably be better off manipulating constraint constants, rather than intrinsic content size.
I am working with nested tableViews having a parentTableView and childTableView .
parentTableView has the cards and childTableView will have the data which will be available at runtime so I have used resizable cells
Now my problem is when I initially load the tableviews, the childTableView data is getting clipped
But when i reload the parentTableView (I have managed a logic for that) using reloadData(), the data is displaying correctly
I have subclassed my childTableView like --
class SectionsTableView: UITableView {
override var intrinsicContentSize: CGSize {
self.layoutIfNeeded()
return self.contentSize
}
override var contentSize: CGSize {
didSet{
self.invalidateIntrinsicContentSize()
}
}
override func reloadData() {
super.reloadData()
self.invalidateIntrinsicContentSize()
}
}
This reloadData() is a workaround but it creates issues in other part of my code which I have to explicitly deal with. Has anyone experienced the same ?
I'm working on a project in Swift 3.0 and it has a UITableView inside a UIScrollView that has already been set its constraints.
The requirement is to display a list of songs that would return from an array in this UITableView, but the size of this UITableView should dynamically arrange according to the size of the array, so I do not need to scroll the UITableView since I can see all the songs in the UITableView (this UITableView is inside my scrollView, so instead I can use my scrollView do move up or down the list).
How would I achieve this?
You can change height of the tableview based on the content.
var frame = tableView.frame
frame.size.height = tableView.contentSize.height
tableView.frame = frame
If you are using autolayout create outlet for tableview height and assign tableview content size to its constant.
tableviewHeightConstraint.constant = tableview.contentSize.height
1.Create a subclass for tableView and override intrinsicContentSize.
class MyOwnTableView: UITableView {
override var intrinsicContentSize: CGSize {
self.layoutIfNeeded()
return self.contentSize
}
override var contentSize: CGSize {
didSet{
self.invalidateIntrinsicContentSize()
}
}
override func reloadData() {
super.reloadData()
self.invalidateIntrinsicContentSize()
}
}
2. In Interface builder change the class of your tableView to MyOwnTableView (subclass of UITableView).
Set automatic row height for the table view.
tableView.estimatedRowHeight = 60.0
tableView.rowHeight = UITableViewAutomaticDimension