I am using a tableview where the first cell contains two buttons. When the first button is activated, the second should be disabled (you should not be able to press it). It all works fine until I start scrolling down the tableview. If I scroll down as far as possible while still being able to see the buttons in first cell, and I activate the first button, I am still able to press the other one. Other things also stops working, but I guess that it is cause by the same thing. Do you have any idea on what happens? See the gif below to see what is going on
I have uploaded the source code on this link, if you need it
https://github.com/Rawchris/scroll-down
I hope you can help :)
Table view cells are reused - which means a couple things:
in general (particularly for your case) you should only add UI elements when you initialize the cell. Otherwise, new ones get added over and over and over.
you need to maintain "row" information, usually in your data source. In this example, you want at least an array of Bool values indicating whether the button in the row should be enabled or not when the cell is reused.
Change your View Controller class to this:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
// this would be replaced with your real data
// test with 20 rows
// start with all rows having button enabled
var buttonStatus: [Bool] = Array(repeating: true, count: 20)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//Configure the button
tableView.delegate = self
tableView.dataSource = self
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return CGFloat(200)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return buttonStatus.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell") as! TableViewCell
cell.selectionStyle = UITableViewCell.SelectionStyle.none
cell.setButtonEnabled(buttonStatus[indexPath.row], with: "Row \(indexPath.row)")
cell.callback = { b in
// update data source with enabled state of button
self.buttonStatus[indexPath.row] = b
}
return cell
}
}
and change your cell class to this:
class TableViewCell: UITableViewCell {
var callback: ((Bool) -> ())?
var button = DropDownBtn()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
button = DropDownBtn.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
button.setTitle("Button1", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
//Add Button to the View Controller
self.addSubview(button)
//button Constraints
button.leftAnchor.constraint(equalTo: self.centerXAnchor, constant: 30).isActive = true
button.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
button.widthAnchor.constraint(equalToConstant: 100).isActive = true
button.heightAnchor.constraint(equalToConstant: 40).isActive = true
//Set the drop down menu's options
button.dropView.dropDownOptions = ["Option1", "Option2", "Option3", "Option4"]
self.clipsToBounds = false
self.contentView.clipsToBounds=false
}
func setButtonEnabled(_ b: Bool, with title: String) {
button.isUserInteractionEnabled = b
// update the UI - green enabled, red disabled
button.backgroundColor = b ? UIColor(red: 0.0, green: 0.6, blue: 0.0, alpha: 1.0) : .red
// update the title so we can see what row we're on
button.setTitle(title, for: [])
}
#IBAction func deactivate(_ sender: Any) {
// toggle the enabled property of "button"
button.isUserInteractionEnabled = !button.isUserInteractionEnabled
// tell the controller the status changed
callback?(button.isUserInteractionEnabled)
// update the UI - green enabled, red disabled
button.backgroundColor = button.isUserInteractionEnabled ? UIColor(red: 0.0, green: 0.6, blue: 0.0, alpha: 1.0) : .red
}
}
This will demonstrate using an array to track the Bool enabled state for the dropDown button in each row. It also changes the button's background color to Green when enabled, Red when disabled. And, it sets the Title of the dropDown button to make it easy to see which rows you're looking at when you scroll up and down.
Related
I’m trying to build an app that uses UITableView and UITableView Cell.
I want users to tap an Add button to add an item to the TableView without calling up a new window or an alert pop-up. I also want users to tap a cell to edit its value and then save it.
I’m struggling to find the best way to do this. Based on what Apple documents about UITableViewCell, it doesn’t seem possible.
Is there a better approach?
Here is a very basic example.
In your Storyboard, add a UITableViewController embedded in a UINavigationController. Set the Custom Class of the table view controller to SampleTableViewController. That's all you should need to do to run this.
The table starts out empty. Tap the Add ("+") button on the navigation bar to add a new item to the data array and reload the table.
As you edit a text field, the text will be passed back to the controller via a "callback" closure, where we update the data array with the new string.
There is also a Done button - tapping it will simply print the data array to the debug console so we can see the changes. That is where you'd do something like save the user entered data (or whatever else you're planning to do with it).
SampleTableViewController class
class SampleTableViewController: UITableViewController {
var myData: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
// cells will have text fields, so we want to be able to
// dismiss the keyboard by scrolling the table
tableView.keyboardDismissMode = .onDrag
// register our custom cell
tableView.register(SampleTextFieldCell.self, forCellReuseIdentifier: "cell")
// put system Add "+" button and system "Done" button
// on right side of the navigation bar
let addBtn = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(self.addButtonTapped))
let doneBtn = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.doneButtonTapped))
navigationItem.rightBarButtonItems = [doneBtn, addBtn]
}
#objc func addButtonTapped() -> Void {
// add a new element to data array
myData.append("")
// reload the table
tableView.reloadData()
}
#objc func doneButtonTapped() -> Void {
// do something with the added / edited items
// maybe save then to a database?
// for now, just print the data array to the debug console
print(myData)
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! SampleTextFieldCell
cell.theTextField.text = myData[indexPath.row]
// set the "callback" closure so we can save the text as its being edited
cell.callback = { str in
// update data array when text in cell is edited
self.myData[indexPath.row] = str
}
return cell
}
}
SampleTextFieldCell class
class SampleTextFieldCell: UITableViewCell {
let theTextField = UITextField()
// closure used to tell the controller that the text field has been edited
var callback: ((String) ->())?
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
theTextField.borderStyle = .roundedRect
theTextField.placeholder = "Enter new item..."
theTextField.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(theTextField)
let g = contentView.layoutMarginsGuide
NSLayoutConstraint.activate([
theTextField.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
theTextField.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
theTextField.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
theTextField.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
])
theTextField.addTarget(self, action: #selector(self.textFieldEdited(_:)), for: .editingChanged)
}
#objc func textFieldEdited(_ textField: UITextField) -> Void {
// send newly edited text back to the controller
callback?(textField.text ?? "")
}
}
I’m coding a mock messaging application in Swift Playgrounds for iPad. So far, I have a UITableViewController with a custom cell, whose background color changes every other cell. Now, I’d like to add a sticky footer of some kind to the bottom of the screen that will have a text field and a send button so that the user can send messages. I’m not quite sure how to approach this. Any ideas? Here’s what I have so far:
import UIKit
import PlaygroundSupport
class ViewController: UITableViewController {
let textMessages = [
"Here's my very first message",
"I'm going to message another long message that will word wrap",
"I'm going to message another long message that will word wrap, I'm going to message another long message that will word wrap, I'm going to message another long message that will word wrap",
"Somejfjfidiskkejejsjsjsjdjjdj blah blah blah"
]
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Messages"
navigationController?.navigationBar.prefersLargeTitles = true
tableView.register(ChatMessageCell.self, forCellReuseIdentifier: "cell_1")
tableView.separatorStyle = .none
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return textMessages.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell_1", for: indexPath) as! ChatMessageCell
cell.selectionStyle = .none
if indexPath.row % 2 == 1{
cell.messageLabel.text = textMessages[indexPath.row]
//cell.setupConstraints(side: 1)
cell.bubbleBackgroundView.backgroundColor = UIColor(white: 0.9, alpha: 1)
return cell
}else{
cell.messageLabel.text = textMessages[indexPath.row]
//cell.setupConstraints(side: 0)
cell.bubbleBackgroundView.backgroundColor = .blue
return cell
}
}
//let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! ChatMessageCell
// cell.textLabel?.text = "We want to provide a longer string that is actually going to wrap onto the next line and maybe even a third line."
// cell.textLabel?.numberOfLines = 0
}
class ChatMessageCell: UITableViewCell {
let messageLabel = UILabel()
let bubbleBackgroundView = UIView()
var leadingAnchorConstant = CGFloat()
func setupConstraints(side: Int){
if side == 1{
leadingAnchorConstant = frame.size.width - 176
}else{
leadingAnchorConstant = 32
}
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
bubbleBackgroundView.backgroundColor = .yellow
let gradient = CAGradientLayer()
bubbleBackgroundView.layer.shadowOpacity = 0.35
bubbleBackgroundView.layer.shadowRadius = 6
bubbleBackgroundView.layer.shadowOffset = CGSize(width: 0, height: 0)
bubbleBackgroundView.layer.shadowColor = UIColor.black.cgColor
bubbleBackgroundView.layer.cornerRadius = 25
bubbleBackgroundView.translatesAutoresizingMaskIntoConstraints = false
addSubview(bubbleBackgroundView)
addSubview(messageLabel)
// messageLabel.backgroundColor = .green
messageLabel.text = "We want to provide a longer string that is actually going to wrap onto the next line and maybe even a third line."
messageLabel.numberOfLines = 0
messageLabel.translatesAutoresizingMaskIntoConstraints = false
// lets set up some constraints for our label
let constraints = [messageLabel.topAnchor.constraint(equalTo: topAnchor, constant: 32),
messageLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 32),
messageLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -32),
messageLabel.widthAnchor.constraint(equalToConstant: 250),
bubbleBackgroundView.topAnchor.constraint(equalTo: messageLabel.topAnchor, constant: -16),
bubbleBackgroundView.leadingAnchor.constraint(equalTo: messageLabel.leadingAnchor, constant: -16),
bubbleBackgroundView.bottomAnchor.constraint(equalTo: messageLabel.bottomAnchor, constant: 16),
bubbleBackgroundView.trailingAnchor.constraint(equalTo: messageLabel.trailingAnchor, constant: 16),
]
NSLayoutConstraint.activate(constraints)
// messageLabel.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
PlaygroundPage.current.liveView = ViewController()
I think you are looking for these tableview delegate methods to set up a custom footer:
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
//let cell = tableView.dequeueReusableCell(withIdentifier: "footer_cell") as! FooterCell
// Set up cell
let cell = UITableViewCell()
cell.textLabel?.text = "Footer"
cell.backgroundColor = .white
return cell
}
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 40.0 // Set height of footer
}
You can use custom tableview cells the same way you use them in cellForRow - I just set it up with simple default cells to produce a working sample - you can also create UIView() to return to this method
By default it will stick to bottom of screen above tableview - if this isn't the case or you want it to stick to bottom of table you can change this setting in attributes inspector if using storyboard:
Style - Plain -> Sticks to bottom of view on top of tableview
Style - Grouped -> Sticks to bottom of tableview no matter how tall
Although another option probably even better without the use of a footer is to use a UITableView on UIViewController - this will give you the space to add your TextView, Buttons and whatever else you need directly on the View Controller under the UITableView
Left is UITableViewController - Right is UIViewController with UITableView
Up to you how you want to play it but I'd recommend the second option to provide the most flexibility on a ViewController
Hope this helps!
I'm making an iOS app with swift and Xcode 11. Inside my app, there is a scrollable table view controller, consisting of buttons on the left and right side, like this:
These are 2 of the many UITableViewCells that I've made. When the user presses the red button, the once red button becomes green. But there's a glitch: If I press a red button(button goes green) and then I scroll down inside the UITableView(and scroll back up), the button that was once green(and still should be green) isn't green anymore. I have no idea why this is happening and I've scrounged StackOverflow's other similar questions like this one, but did not manage to find any.
Here's my UITableViewController:
import UIKit
#objcMembers class CustomViewController: UITableViewController {
var tag = 0
override func viewDidLoad() {
super.viewDidLoad()
tag = 0
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
tag = 0
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return SingletonViewController.themes.count
}
// 3
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
tag = tag + 1
let cell = tableView.dequeueReusableCell(withIdentifier: "themeCell", for: indexPath) as! ThemeCell
let cellButton = UIButton(frame: CGRect(x: 0, y: 5, width: 88, height: 119.5))
cellButton.translatesAutoresizingMaskIntoConstraints = false
cell.addSubview(cellButton)
cell.accessoryView = cellButton
cellButton.leadingAnchor.constraint(equalTo: cell.leadingAnchor, constant: 10).isActive = true
cellButton.topAnchor.constraint(equalTo: cell.topAnchor, constant: 10).isActive = true
cellButton.widthAnchor.constraint(equalToConstant: 88).isActive = true
cellButton.heightAnchor.constraint(equalToConstant: 119.5).isActive = true
cellButton.setImage(UIImage(named: SingletonViewController.themes[indexPath.row]), for: UIControl.State.normal)
cellButton.addTarget(self, action: #selector(CustomViewController.backBTN(sender:)), for: .touchUpInside)
cellButton.tag = tag
var cellyi: UIButton!
//red/green button's declaration^
cellyi = UIButton(frame: CGRect(x: 5, y: 5, width: 50, height: 30))
cell.addSubview(cellyi)
cell.accessoryView = cellyi
cellyi.backgroundColor = UIColor.red
cellyi.addTarget(self, action: #selector(CustomViewController.backBTN(sender:)), for: .touchUpInside)
cellyi.tag = tag
print(cellyi.tag)
if UserDefaults.standard.integer(forKey: "like") == 0{
UserDefaults.standard.set(1, forKey: "like")
}
if UserDefaults.standard.integer(forKey: "like") == tag{
cellyi.backgroundColor = UIColor.green
}
tableView.allowsSelection = false
return cell
}
#objc func backBTN(sender: UIButton){
UserDefaults.standard.set(sender.tag, forKey: "like")
tag = 0
tableView.reloadData()
}
}
The cellForRowAt method is not a for loop!
I see that you are using a tag property to control what gets shown in each cell. From the fact that you increment the tag very time cellForRowAt is called, you seem to assume that cellForRowAt will be called once for each row, in order. This is not the case, and you should not implement cellForRowAt like this.
cellForRowAt essentially asks a question: "What should the cell at this index path be?", and you provide the answer. The index path that the table view is asking about is the indexPath parameter. You should make use of this parameter instead of your own tag property, because the table view is not asking about that.
The reason why why your code doesn't work is because table view cells are reused. When cells are scrolled out of view, they are not put aside, so that when new table view cells need to be shown, they can be reconfigured to "appear as if they are new cells". Essentially what this means is that when you scroll up, cellForRowAt is called for the rows that are about to come into view. You didn't expect that, did you?
All that code that sets up each cell should be moved to the initialiser of ThemeCell. Alternatively, design the cell in a storyboard. cellForRowAt should only configure a cell specifically for an index path. ThemeCell should have the properties cellButton and cellyi so that the buttons can be accessed.
Now, cellForRowAt can be written like this:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "themeCell", for: indexPath) as! ThemeCell
cell.cellButton.setImage(UIImage(named: SingletonViewController.themes[indexPath.row]), for: UIControl.State.normal)
cell.cellButton.addTarget(self, action: #selector(CustomViewController.backBTN(sender:)), for: .touchUpInside)
cell.cellyi.addTarget(self, action: #selector(CustomViewController.backBTN(sender:)), for: .touchUpInside)
if UserDefaults.standard.integer(forKey: "like") == indexPath.row {
cell.cellyi.backgroundColor = UIColor.green
} else {
cell.cellyi.backgroundColor = UIColor.red
}
// this line should be moved to viewDidLoad
// tableView.allowsSelection = false
return cell
}
I'm creating a tabbed app with 3 separate view controllers(2 regular views, 1 table view) using Swift 5 and Xcode 11. Inside my 3rd view(which is the one with the table view), and inside of my UITableViewCells, there is 1 button, colored red. I have tested my program on 2 of my testing devices, one with a larger screen, and the other a small, iPhone 5s screen, and here are the results I got:
iPhone with larger screen(iPhone 6 Plus):
All works fine, even if I select the UITableViewCell, the items inside won't disappear
iPhone 5s:
If I don't select the UITableViewCell, all will be fine:
But If I do select the UITableViewCell, the items inside will disappear:
This is my uitableviewcontroller:
import UIKit
#objcMembers class CustomViewController: UITableViewController {
var tag = 0
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
// 3
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
tag = tag + 1
let cell = tableView.dequeueReusableCell(withIdentifier: "themeCell", for: indexPath) as! ThemeCell
/////////
let cellButton = UIButton(frame: CGRect(x: 0, y: 5, width: 50, height: 30))
cellButton.translatesAutoresizingMaskIntoConstraints = false
cell.addSubview(cellButton)
cell.accessoryView = cellButton
cellButton.backgroundColor = UIColor.red
cellButton.leadingAnchor.constraint(equalTo: cell.leadingAnchor, constant: 10).isActive = true
cellButton.topAnchor.constraint(equalTo: cell.topAnchor, constant: 5).isActive = true
cellButton.widthAnchor.constraint(equalToConstant: 50).isActive = true
cellButton.heightAnchor.constraint(equalToConstant: 30).isActive = true
cell.img.image = UIImage(named: SingletonViewController.themes[indexPath.row])
cell.accessoryView = cellButton
cellButton.backgroundColor = UIColor.red
cellButton.addTarget(self, action: #selector(CustomViewController.backBTN(sender:)), for: .touchUpInside)
cellButton.tag = tag
return cell
}
}
Any idea why this is happening?
Remove this code of line
cell.accessoryView = cellButton
Either add button as subview OR set it as accessory view.
You can just disable the table view from being able to be selected, by adding this to your second 'tableView' function:
tableView.allowsSelection = false
I have a UITableView that I'm using to show an array of custom objects. Each object has several properties including a Boolean property that indicates if this item is new or not.
My UITableViewCell content view is defined in the storyboard and has an initial layout similar to this:
In my UITableViewController, when I dequeue my cells, I call a method on my UITableViewCell that configures the data to be displayed in the cell before I return it. One of the properties that I check is the .isNew property that I mentioned previously. If this value is true, then I am creating a UIButton and inserting it as a subview in the cell's content view so I end up with something like this:
Just for context, this button will show a "new" image to indicate that this item is new. I am also hooking up a method that will fire when the button is tapped. That method is also defined in my UITableViewCell and looks like this:
#objc func newIndicatorButtonTapped(sender: UIButton!) {
// call delegate method and pass this cell as the argument
delegate?.newIndicatorButtonTapped(cell: self)
}
I have also created a protocol that defines a delegate method. My UITableViewController conforms to this and I see that code fire when I tap on the button in my cell(s). Here's is the delegate method (defined in an extension on my UITableViewController):
func newIndicatorButtonTapped(cell: UITableViewCell) {
if let indexPath = self.tableView.indexPath(for: cell) {
print(indexPath.row)
}
}
I see the row from the indexPath print out correctly in Xcode when I tap on the cell. When my user taps on this button, I need to remove it (the button) and update the constraint for my UILabel so that is aligned again with the leading edge of the content view as shown in the first mockup above. Unfortunately, I seem to be running into an issue with cell recycling because the UIButton is disappearing and re-appearing in different cells as I scroll through them. Do I need to reset the cell's layout/appearance before it gets recycled or am I misunderstanding something about how cell recycling works? Any tips would be much appreciated!
What you may be thinking is that you get a "fresh" cell, but when a cell gets re-cycled that means it gets re-used.
You can see this very easily by changing the text color of a basic cell.
For example:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyID", for: indexPath) as! MyCustomCell
if indexPath.row == 3 {
cell.theLabel.textColor = .red
}
return cell
}
As you would expect, when the table first loads the text color will change for the 4th row (row indexing is zero-based).
However, suppose you have 100 rows? As you scroll, the cells will be re-used ... and each time that original-4th-cell gets re-used, it will still have red text.
So, as you guessed, yes... you need to "reset" your cell to its original layout / content / colors / etc each time you want to use it:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyID", for: indexPath) as! MyCustomCell
if indexPath.row == 3 {
cell.theLabel.textColor = .red
} else {
cell.theLabel.textColor = .black
}
return cell
}
You may want to consider to have the button hidden and then change the layout when it is clicked.
Firing the action from the cell to the tableView with a protocol and then reseting the layout at cell reuse is a good way to do it
Doing it in a cell fully programatic would be like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! Cell
cell.isNew = indexPath.row == 0 ? true : false
cell.layoutIfNeeded()
return cell
}
And the cell class needs to be similar to: (you can do what you need by changing the Autolayout constraint, manipulating the frame directly or using a UIStackView)
class Cell: UITableViewCell {
var isNew: Bool = false {
didSet {
if isNew {
button.isHidden = true
leftConstraint.constant = 20
} else {
button.isHidden = false
leftConstraint.constant = 100
}
self.setNeedsLayout()
}
}
var button: UIButton!
var label: UILabel!
var leftConstraint: NSLayoutConstraint!
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
button = UIButton(type: .system)
button.setTitle("Click", for: .normal)
self.contentView.addSubview(button)
button.translatesAutoresizingMaskIntoConstraints = false
button.widthAnchor.constraint(equalToConstant: 50).isActive = true
button.heightAnchor.constraint(equalToConstant: 10).isActive = true
button.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 20).isActive = true
button.topAnchor.constraint(equalTo: self.topAnchor, constant: 20).isActive = true
label = UILabel()
label.text = "Label"
self.contentView.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
label.widthAnchor.constraint(equalToConstant: 200).isActive = true
label.heightAnchor.constraint(equalToConstant: 20).isActive = true
label.topAnchor.constraint(equalTo: self.topAnchor, constant: 10).isActive = true
leftConstraint = label.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 100)
leftConstraint.isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}