Width of UITableView content view does not match Container - swift

I have a TableVC embedded in a Container. The width of the Container running on an iPhone5 is 320. However the width of the ContentView in the TableView cell is 600. How can I make them match? (+/- padding). Am I missing a constraint? I have also tried setNeedsLayout() and layoutSubViews() in cellForRowAtIndexPath and in the custom cells subclass, but this doesn't seem to work either.
In the picture below, I want the width of the darkgrey to match the light grey (+- padding)
Any help much appreciated.....
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("EventCell") as! CustomResultsTVCell
// cell.setNeedsLayout()
// cell.layoutSubviews()
// cell.layoutIfNeeded()
let barViewWidth = Float(cell.barView.frame.width)
print("barview width is \(barViewWidth)")
// prints 584
let contentViewWidth = cell.myContentView.frame.width
print("contentView width is \(contentViewWidth)")
// prints 600
The CustomCell class is
import Foundation
import UIKit
class CustomResultsTVCell: UITableViewCell {
#IBOutlet weak var myContentView: UIView!
#IBOutlet weak var barView: UIView!
override func awakeFromNib() {
super.awakeFromNib()
// super.layoutSubviews()
// setNeedsLayout()
// layoutSubviews()
layoutIfNeeded()
}

Can you check property of your leading and trailing constraints. Make sure it unchecked relative to margin for both first item and second item.
see attached screenshots if it helps you.
Hope this will help you to fix your issue.

Related

How to give dynamic width for childStackview in parentStack in Swift

I using stackview in tableview cell
I have one parentStackview with two childStackviews
for parentStackview i have given constraints like below
leading = 10, trailing = 10, top = 10, height = 50
for two childStackviews in parentStackview i have given like this in storyboard
now if i hide childOneStack then childTwoStack showing in full width in parentStackview.. but i dont want like that i need childTwoStack should half of the parentStackview when i hide childOneStack
code to hide childOneStack in tableview cell:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ViewTableVIewCell", for: indexPath) as! ViewTableVIewCell
let bidData = viewData?.result?.bids?[indexPath.row]
if awardData?.status == "A"{
cell.childOneStack.isHidden = true
cell.childTwoStack.frame = CGRect(x: 0, y: 0, width: 200, height: 40)
}
}
class ViewTableVIewCell: UITableViewCell {
#IBOutlet weak var parentStackview: UIStackView!
#IBOutlet weak var childOneStack: UIStackView!
#IBOutlet weak var childTwoStack: UIStackView!
}
error O/p: this is childTwoStack showing full width in parentStackview, please guide me to solve this
You could embed a stack view, which you plan to hide/unhide, in a UIView - this container view will take half of the parent stack even when child stack is hidden.
You could not hide you views, but change its alpha to 0 - in this case you need to disable user interaction, since the views will be transparent, but still interactable.

iOS13 UICollectionViewFlowLayout subclass not receiving collectionView frame changes

I am testing out some code and it looks like in iOS13 the UICollectionViewFlowLayout is not receiving the changes in the collectionView frame.
Below is a sample code, in which I simply change the height of the collectionView based on the amount I scroll inthe tableview below the collectionView:
ViewController
func scrollViewDidScroll(_ scrollView: UIScrollView) {
collectionView.collectionViewLayout.invalidateLayout()
let totalScroll = scrollView.contentSize.height - scrollView.bounds.size.height
let offset = (scrollView.contentOffset.y)
let percentage = offset / totalScroll
var frame = collectionView.frame
frame.size.height = 40 - (40 * percentage)
collectionView.frame = frame
}
CustomCollectionViewFlowLayout: UICollectionViewFlowLayout
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let attributes = super.layoutAttributesForElements(in: rect)
print(collectionView?.frame)
return attributes
}
The print statement inside the CustomCollectionViewFlowLayout in iOS 12 and below prints out the changes in collectionView.frame correctly i.e. the height actually changes. But in iOS 13, it isn't being reflected at all.
Help anybody?
First of all,
func scrollViewDidScroll(_ scrollView: UIScrollView) {
collectionView.collectionViewLayout.invalidateLayout()
...
}
looks suspicious. Are you sure that your layout should be invalidated inside the scrollViewDidScroll function?
There is a proper place where a layout should be invalidated while scrolling:
final class CustomCollectionViewFlowLayout: UICollectionViewFlowLayout {
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
// proper place to invalidate layout while scrolling
}
}
If you invalidate your layout inside the layout class you will be able to calculate the desired layout container height properly. And then you can inform your collection view that its height should be changed. For example, with the help of some delegate:
protocol CustomCollectionViewFlowLayoutSizeDelegate: class {
func newSizeAvailableFor(layout: CustomCollectionViewFlowLayout, progress: CGFloat)
}
final class CustomCollectionViewFlowLayout: UICollectionViewFlowLayout {
weak var sizeDelegate: CustomCollectionViewFlowLayoutSizeDelegate?
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
// proper place to invalidate layout while scrolling
}
}
final class CustomViewController: CustomCollectionViewFlowLayoutSizeDelegate {
func newSizeAvailableFor(layout: CustomCollectionViewFlowLayout, progress: CGFloat) {
// change collectionView frame
}
}
Conclusion:
Your layout is trying to listen to its container height, but its container height is calculated based on your layout. You can easily drop the container dependency for height calculation or just provide the layout with initial container height. In the end the layout will be responsible for all the calculations.

Dynamic UICollectionView inside dynamic UITableViewCell

I have a collection view that is dynamic and can have any number of cells in it. It is positioned inside a table view cell.
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
My table view is correctly configured to be dynamic because the other cells work fine so the issue is not there.
Here is what I currently have... As you can see there is no collection view below
This is what my desired out come is... (Forcing a height constraint on the collection view)
I have configured constraints on all sides of the collection view correctly, as it works when I give a fix height constraint. But this defeats the object of a dynamic collection view...
I have linked an outlet to the UICollectionViewFlowLayout and set an estimated cell size and given the cell the correct constraints on the label inside as you can see in the image where I forced the height constraint.
Create a subclass for collectionView and override intrinsicContentSize.
class DynamicCollectionView: UICollectionView {
override func layoutSubviews() {
super.layoutSubviews()
if !__CGSizeEqualToSize(bounds.size, self.intrinsicContentSize) {
self.invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
return collectionViewLayout.collectionViewContentSize
}
}
In Interface builder change the class of your collectionView to DynamicCollectionView (subclass UICollectionView).
Set estimated cell size of UICollectionViewFlowLayout.
flowLayout.estimatedItemSize = CGSize(width: 1,height: 1)

Swift: Dynamic Cell in table view

I'm trying to make the height of table view cell = the content of the cell.
I implemented these 2 lines in the viewDidLoad():
tableView.estimatedRowHeight = 200.0
tableView.rowHeight = UITableViewAutomaticDimension
Still, the cell is changing its height!
TextView will not expand to fit the entire text by default because it has scrolling capabilities, for what you want you should disable scrolling in the textView.
Select the textView and in the Attributes Inspector tab scroll down and uncheck the "Scrolling Enabled"
It appears to me that your issue may be that the height of the UITextView is not explicitly stated. The natural behaviour of the text view is not to be a tall as it's content.
I would suggest adding a height constraint within interface builder, hooking it up to an outlet, and then within the cell layoutSubviews function calculating the height like so:
#IBOutlet var textViewHeightConstraint: NSLayoutConstraint!
func layoutSubviews() {
super.layoutSubviews()
let fixedWidth = textView.frame.size.width
textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
textViewHeightConstraint.constant = newSize.height
}
try to use heightForRowAt indexpath
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {return UITableViewAutomaticDimension}
+
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
In ViewDidLoad
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 200
And put your both Title Label and Text Label (replace Text View) in a UIView. and give constraints to UIView
1. trailing, leading, bottom and top space as ZERO
2. give fixed hight as 200 and change relation as Greater than or equal (>=)
Then give constrains to Title label
1. trailing, leading and top space as ZERO
2. give fixed hight as 20 (your choice)
Give constrains to Text Label
1. trailing, leading, bottom and top space as ZERO
2. give fixed hight as 180 and change relation as Greater than or equal (>=)

Custom UITableViewCell programmatically with SWIFT

Attached you may find a picture of (left) my attempt to create a similar (right) UITableView. they look like buttons but they're only cells that can be clicked on as a tableview cell.
I have tried many different things including adding a container window inside a custom cell, adding a UIImage inside the custom cell but I just can't replicate these cells!
I have tried using a custom cell class, I have tried doing it through IB and I for the crazyiness of me, cannot recreate it.
Would anyone be able to give me a hint on how to create the (inside cell) text-bounding box/square? with the different background colour lighting?
If this can easily be done with IB I'd rather do it this way, but if you have a sample customcell class that I can take a look at that'd be greatly appreciated too!
Thank you for taking the time to look at my question.
I have made a sample for you close to your requirement. Have a look
https://github.com/RajanMaheshwari/CustomTableCell
I would like to do this using a UITableView.
My approach will be taking a custom cell and add a UIView with some constraints from left, right, up and down.
Also I will provide the same background color to UITableView, UIView which is the superview and the cell content view and also make the separator of UITableView as None and Selection of TableCell as None so that the UI looks like
Next after applying every constraint and making a CustomCell and making IBOutlets we will jump to code.
I will do all the shadow and outlining in Custom Cell's awakeFromNib method
This will be my CustomTableViewCell class
class CustomTableViewCell: UITableViewCell {
#IBOutlet weak var labelBackgroundView: UIView!
#IBOutlet weak var cellLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
labelBackgroundView.layer.borderWidth = 0.5
labelBackgroundView.layer.borderColor = UIColor.lightGrayColor().CGColor
labelBackgroundView.layer.shadowColor = UIColor.lightGrayColor().CGColor
labelBackgroundView.layer.shadowOpacity = 0.8
labelBackgroundView.layer.shadowRadius = 5.0
labelBackgroundView.layer.shadowOffset = CGSizeMake(0.0, 2.0)
labelBackgroundView.layer.masksToBounds = false;
}
I have two outlets.
One is the label in which you will be displaying the name.
Other is the outer view which you want to display with some outlining and shadow.
The ViewController code will be:
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
var array = [String]()
#IBOutlet weak var myTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
array = ["Wealth","Health","Esteem","Relationship"]
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CustomTableViewCell") as! CustomTableViewCell
cell.cellLabel.text = array[indexPath.row]
cell.labelBackgroundView.tag = indexPath.row
cell.labelBackgroundView.userInteractionEnabled = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(cellViewTapped))
cell.labelBackgroundView.addGestureRecognizer(tapGesture)
return cell
}
func cellViewTapped(sender:UITapGestureRecognizer) {
let view = sender.view
let index = view?.tag
print(index!)
}
}
Here I have not used didSelectIndex of UITableViewDelegate as I only want the tap on the Outlining LabelBackgroundView and not on complete cell.
So the final outcome is like this
I think you are on the right path. I did something similar in a project. I created a subclass of UIView (too add a shadow to the view) and added a view with this type inside the cell.
class ShadowedView: UIView {
override func awakeFromNib() {
layer.shadowColor = UIColor(red: 157.0/255.0, green: 157.0/255.0, blue: 157.0/255.0, alpha: 0.5).CGColor
layer.shadowOpacity = 0.8
layer.shadowRadius = 5.0
layer.shadowOffset = CGSizeMake(0.0, 2.0)
}
}
Don't forget to add some constraints to the view inside the cell.
You can arrange your collection view layout in "Size insepector"
And customise your image in the cell.