I am reloading from a UIButton with observers an UITableView on my Swift App.
I'm using this code:
self.myTableView.beginUpdates()
self.myTableView.reloadSections(NSIndexSet(index: 1), withRowAnimation: UITableViewRowAnimation.None)
self.myTableView.endUpdates()
self.myTableView.layoutIfNeeded()
It's working perfectly on iOS 13, but on iOS 12 I need push the UIButton two times to reload correctly an UITableViewCell that contains a multiline UILabel and the headerView.
How can I do or what need I change on my code?
My content of Cell is:
let sectionView: UIView = SectionView.fromNib()//Nib haven't nothing added. All from this code
var constraints = [NSLayoutConstraint]()
let titleLabel = UILabel()
titleLabel.text = "Hello World"
titleLabel.sizeToFit()
titleLabel.translatesAutoresizingMaskIntoConstraints = false
sectionView.addSubview(titleLabel)
constraints.append(NSLayoutConstraint(item: titleLabel, attribute: NSLayoutConstraint.Attribute.leading, relatedBy: NSLayoutConstraint.Relation.equal, toItem: sectionView, attribute: NSLayoutConstraint.Attribute.leading, multiplier: 1.0, constant: 10.0))
constraints.append(NSLayoutConstraint(item: titleLabel, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.equal, toItem: sectionView, attribute: NSLayoutConstraint.Attribute.trailing, multiplier: 1.0, constant: -10.0))
constraints.append(NSLayoutConstraint(item: titleLabel, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: sectionView, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1.0, constant: 10.0))
constraints.append(NSLayoutConstraint(item: titleLabel, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: sectionView, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1.0, constant: -10.0))
sectionView.addConstraints(constraints)
EDIT: I have also tried performBatchUpdates then rs7 comment but I'm getting the same problem, the row with an UILabel not reload without scroll on iOS 12...
self.myTableView.performBatchUpdates ({
self.myTableView.reloadSections(NSIndexSet(index: 1), withRowAnimation: UITableViewRowAnimation.None)
},
completion: { (success) in
self.myTableView.layoutIfNeeded()
}
)
Thanks!
Related
I've an UITableView with some cells, in the first cell I would like to add multiple UILabel. That's the code I am using inside a function in UITableViewCell sub class (called in cellForRowAt):
...
let constantTop = 16
for (index,optional) in optionals.enumerated(){
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "\(optional.name)"
label.tag = 10010132
label.font = CocoFonts.semibold(size: 15)
label.textColor = CocoColors.FedericoMalagoni.textVeryDarkBlue
self.contentView.addSubview(label)
let constant:CGFloat = CGFloat(constantTop * (index + 1))
print(constant)
let horizontalConstraint = NSLayoutConstraint(item: label, attribute: NSLayoutAttribute.leading, relatedBy: NSLayoutRelation.equal, toItem: self.contentView, attribute: NSLayoutAttribute.leading, multiplier: 1, constant: 16)
let verticalConstraint = NSLayoutConstraint(item: label, attribute: NSLayoutAttribute.trailing, relatedBy: NSLayoutRelation.equal, toItem: self.contentView, attribute: NSLayoutAttribute.trailing, multiplier: 1, constant: 16)
let height = NSLayoutConstraint(item: label, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 20)
let top = NSLayoutConstraint(item: label, attribute: NSLayoutAttribute.top, relatedBy: NSLayoutRelation.equal, toItem: self.lblInfo, attribute: NSLayoutAttribute.bottomMargin, multiplier: 1, constant: constant)
let bottom = NSLayoutConstraint(item: label, attribute: NSLayoutAttribute.bottom, relatedBy: NSLayoutRelation.equal, toItem: self.contentView, attribute: NSLayoutAttribute.bottom, multiplier: 1, constant: constant)
NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint, top, bottom, height])
}
self.contentView.setNeedsUpdateConstraints()
self.contentView.setNeedsLayout()
self.contentView.layoutIfNeeded()
...
Now,
The labels are over the edge of the cell like this:
The gray separator divide the cell.
Essentially the height of the cell is not updated.
It would be more clear if you could share full implementation of cellForRowAt.
I faced similar issue where cell contents were overlapping. I was adding custom view to the cell as subview.
This happens because Table view re uses its cells. So one solution is to remove old label from the cell before you add new.
for content in cell.contentView.subviews {
content.removeFromSuperview()
}
I'm building a UICollectionViewCell interface by code. Everything works fine, except the right constraint. When I run the app the title label has a zero margin from the right. Here is my code
let titleLabel: UILabel = {
let label = UILabel()
label.backgroundColor = UIColor.purple
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
func setupViews() {
addSubview(titleLabel)
// titleLabel
// top constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1, constant: 16))
// left constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1, constant: 8))
// right constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1, constant: 16))
// height constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 0, constant: 20))
}
I'm thinking it has something to do with toItem: self, because self is the uilabel and I want to related it the UICollectionViewCell
The problem is the order of your items in your constraint. You are currently saying the label is 16 past the right edge of its superview. You can either switch the item and toItem in your right constraint, or use -16 as your constant.
So either this:
addConstraint(NSLayoutConstraint(item: self, attribute: .right, relatedBy: .equal, toItem: titleLabel, attribute: .right, multiplier: 1, constant: 16))
or this:
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1, constant: -16))
will work.
I have a segmented control which switches between two UIViewControllers. A info view, and a list view (TableView).
I want to use the first UIViewController as the first cell of my TableView (that is on the other segment).
Is there a way to convert a UIViewController to a cell or someway to use it as a cell for a TableView?
Use this code with your own way. Here we are adding the controllers view as subview of cell and using auto layout to manage properly. You just need to use the code by understanding.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath:indexPath)
cell.layoutIfNeeded()
let infoVC = self.storyboard.instantiateViewControllerWithIdentifier("InfoVC")
self.addChildViewController(infoVC)
cell.contentView.addSubview(infoVC.view)
infoVC.view.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addConstraint(NSLayoutConstraint(item: infoVC.view, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: cell.contentView, attribute: NSLayoutAttribute.Leading, multiplier: 1.0, constant: 0.0))
cell.contentView.addConstraint(NSLayoutConstraint(item: infoVC.view, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: cell.contentView, attribute: NSLayoutAttribute.Trailing, multiplier: 1.0, constant: 0.0))
cell.contentView.addConstraint(NSLayoutConstraint(item: infoVC.view, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: cell.contentView, attribute: NSLayoutAttribute.Top, multiplier: 1.0, constant: 0.0))
cell.contentView.addConstraint(NSLayoutConstraint(item: infoVC.view, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: cell.contentView, attribute: NSLayoutAttribute.Bottom, multiplier: 1.0, constant: 0.0))
infoVC.didMoveToParentViewController(self)
infoVC.view.layoutIfNeeded()
}
Swift 5.0 Syntax
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for:indexPath)
cell.layoutIfNeeded()
let storyboard = UIStoryboard(name: "StoryboardName", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "ViewControllerNameHere")
self.addChild(vc)
cell.contentView.addSubview(vc.view)
vc.view.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addConstraint(NSLayoutConstraint(item: vc.view, attribute: NSLayoutConstraint.Attribute.leading, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cell.contentView, attribute: NSLayoutConstraint.Attribute.leading, multiplier: 1.0, constant: 0.0))
cell.contentView.addConstraint(NSLayoutConstraint(item: vc.view, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cell.contentView, attribute: NSLayoutConstraint.Attribute.trailing, multiplier: 1.0, constant: 0.0))
cell.contentView.addConstraint(NSLayoutConstraint(item: vc.view, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cell.contentView, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1.0, constant: 0.0))
cell.contentView.addConstraint(NSLayoutConstraint(item: vc.view, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: cell.contentView, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1.0, constant: 0.0))
vc.didMove(toParent: self)
vc.view.layoutIfNeeded()
return cell
Well, i'd recomend to create a custom UITableViewCell with its own nib file and load it from nib.
This can than added/dequeud to a UITableViewSection.
The Cell itself can then be design inside of the UI Builder in any way you want it to look like. You can put literaly everything into the cell you like.
Here is a short tutorial how todo so:
using-nib-xib-files
A question to that topic can be find here:
Custom UITableViewCell from nib in Swift
I am trying to add a overlay over for all my viewcontrollers by adding this code to my "BaseViewController". However it result in all ViewControllers turning black and behaving oddly.
override public func viewDidLoad()
{
super.viewDidLoad()
overlayView = UIView()
overlayView.backgroundColor = UIColor.redColor() //For testing
view.addSubviewWithMatchingConstraints(overlayView)
...
}
And in UIView extension:
func addSubviewWithMatchingConstraints(subView: UIView)
{
translatesAutoresizingMaskIntoConstraints = false
addSubview(subView)
addConstraint(NSLayoutConstraint(item: subView, attribute: .Width, relatedBy: .Equal, toItem: self, attribute: .Width, multiplier: 1, constant: 0))
addConstraint(NSLayoutConstraint(item: subView, attribute: .Height, relatedBy: .Equal, toItem: self, attribute: .Height, multiplier: 1, constant: 0))
addConstraint(NSLayoutConstraint(item: subView, attribute: .CenterX, relatedBy: .Equal, toItem: self, attribute: .CenterX, multiplier: 1.0, constant: 0))
addConstraint(NSLayoutConstraint(item: subView, attribute: .CenterY, relatedBy: .Equal, toItem: self, attribute: .CenterY, multiplier: 1.0, constant: 0))
}
The issue was that I set translatesAutoresizingMaskIntoConstraints on the parent rather than the child.
childView.translatesAutoresizingMaskIntoConstraints = false
fixed it
I've got a situation where I would like a view to be centered in its superview, remain square, but fill as much height as possible without going off the edge, i.e., it should look at the available vertical and horizontal space, choosing the smallest between the 2.
There are 2 other views, one below and one above, that will both be either a button or label. The bottom/top of these views should be attached to the top/bottom of the central view. I can get this to work, to an extent, but I'll explain my issue below, and what I've got so far:
Top label has:
.Top >= TopLayoutGuide.Bottom
.Top = TopLayoutGuide.Bottom (priority 250)
.Right = CentralView.Right
Central view has:
Center X and Y = Superview Center X and Y
.Height <= Superview.Width * 0.9
.Width = self.Height
.Top = TopLabel.Bottom
Bottom button has:
.Right = CentralView.Right
.Top = CentralView.Bottom
.Bottom <= (BottomLayoutGuide.Top - 16)
Running this seems fine, and produces the desired results:
However, if I make the view an instance of my custom class and add a UIButton subview, it all goes wrong. In this class I perform:
self.topLeftButton = CustomButtonClass()
self.topLeftButton.setTranslatesAutoresizingMaskIntoConstraints(false)
self.addSubview(self.topLeftButton)
self.addConstraints([
NSLayoutConstraint(item: self.topLeftButton, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: 0),
NSLayoutConstraint(item: self.topLeftButton, attribute: .Left, relatedBy: .Equal, toItem: self, attribute: .Left, multiplier: 1, constant: 0),
NSLayoutConstraint(item: self.topLeftButton, attribute: .Height, relatedBy: .Equal, toItem: self, attribute: .Height, multiplier: 0.5, constant: 0),
NSLayoutConstraint(item: self.topLeftButton, attribute: .Width, relatedBy: .Equal, toItem: self.topLeftButton, attribute: .Width, multiplier: 1, constant: 0)
])
Using this code the view collapses down to the following:
I can't figure out why this is. I've made a few small tweaks here and there, but not managed to get it to work as desired. If I add the same button in IB the view wants to collapse again, and it's as if the button will not grow in height.
In real life I wouldn't subclass UIButton, but have done in my answer, as that is what the question indicated. UIButton works best through composition. So maybe better to create a UIButton, then modify its properties.
class FooViewController: UIViewController {
override func viewDidLoad() {
var view = CustomView()
view.backgroundColor = UIColor.darkGrayColor()
var label = UILabel()
label.text = "Label"
var button = UIButton.buttonWithType(.System) as UIButton
button.setTitle("Button", forState: .Normal)
view.setTranslatesAutoresizingMaskIntoConstraints(false)
label.setTranslatesAutoresizingMaskIntoConstraints(false)
button.setTranslatesAutoresizingMaskIntoConstraints(false)
self.view.addSubview(view)
self.view.addSubview(label)
self.view.addSubview(button)
// The width should be as big as possible...
var maxWidthConstraint = NSLayoutConstraint(item: view, attribute: .Width, relatedBy: .Equal, toItem: view.superview, attribute: .Width, multiplier: 1, constant: 0);
// ... but not at the expense of other constraints
maxWidthConstraint.priority = 1
self.view.addConstraints([
// Max width, if possible
maxWidthConstraint,
// Width and height can't be bigger than the container
NSLayoutConstraint(item: view, attribute: .Width, relatedBy: .LessThanOrEqual, toItem: view.superview, attribute: .Width, multiplier: 1, constant: 0),
NSLayoutConstraint(item: view, attribute: .Width, relatedBy: .LessThanOrEqual, toItem: view.superview, attribute: .Height, multiplier: 1, constant: 0),
// Width and height are equal
NSLayoutConstraint(item: view, attribute: .Height, relatedBy: .Equal, toItem: view, attribute: .Width, multiplier: 1, constant: 0),
// View is centered
NSLayoutConstraint(item: view, attribute: .CenterX, relatedBy: .Equal, toItem: view.superview, attribute: .CenterX, multiplier: 1, constant: 0),
NSLayoutConstraint(item: view, attribute: .CenterY, relatedBy: .Equal, toItem: view.superview, attribute: .CenterY, multiplier: 1, constant: 0),
])
// Label above view
self.view.addConstraints([
NSLayoutConstraint(item: label, attribute: .Top, relatedBy: .GreaterThanOrEqual, toItem: label.superview, attribute: .Top, multiplier: 1, constant: 0),
NSLayoutConstraint(item: label, attribute: .Bottom, relatedBy: .Equal, toItem: view, attribute: .Top, multiplier: 1, constant: 0),
NSLayoutConstraint(item: label, attribute: .Right, relatedBy: .LessThanOrEqual, toItem: view, attribute: .Right, multiplier: 1, constant: 0),
])
// Button below view
self.view.addConstraints([
NSLayoutConstraint(item: button, attribute: .Bottom, relatedBy: .LessThanOrEqual, toItem: button.superview, attribute: .Bottom, multiplier: 1, constant: 0),
NSLayoutConstraint(item: button, attribute: .Top, relatedBy: .Equal, toItem: view, attribute: .Bottom, multiplier: 1, constant: 0),
NSLayoutConstraint(item: button, attribute: .Right, relatedBy: .LessThanOrEqual, toItem: view, attribute: .Right, multiplier: 1, constant: 0),
])
}
}
class CustomView: UIView {
required init(coder: NSCoder) {
super.init(coder: coder)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
override init() {
super.init()
var button = CustomButton()
button.setTitle("Custom Button", forState: UIControlState.Normal)
button.setTranslatesAutoresizingMaskIntoConstraints(false)
self.addSubview(button)
// Custom button in the top left
self.addConstraints([
NSLayoutConstraint(item: button, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: 0),
NSLayoutConstraint(item: button, attribute: .Left, relatedBy: .Equal, toItem: self, attribute: .Left, multiplier: 1, constant: 0),
])
}
}
class CustomButton: UIButton {
required init(coder: NSCoder) {
super.init(coder: coder)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
override init() {
super.init()
self.backgroundColor = UIColor.greenColor()
}
}