I'm creating a settings page for my Swift app and (following examples here on SO) I've subclassed a UITableViewCell and in the init() handlers I've set the accessoryView to be a UISwitch().
I also have a custom #IBInspectable property on the subclass which is also marked #IBDesignable:
#IBDesignable class TableViewSwitchCell: UITableViewCell {
#IBInspectable var settingsKey: String?
func build()
{
accessoryView = UISwitch()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
build()
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
build()
}
// code omitted that uses the settingsKey with NSUserDefaults
}
How can I arrange for the UISwitch to also be visible in InterfaceBuilder so that I can attach additional targets to it whilst still just subclassing from UITableViewCell
Ideally I don't want to create a whole new nib with its own layout, since I still want to retain most of the other features of a standard UITableViewCell.
Drop UISwitch in Interface Builder inside of cell. Then wire it with up accessoryView of your cell. On standard basic cells the control tends to be locked in the middle of cell in IB. However in runtime it will be properly positioned.
Related
I create a UITableViewCell subclass CustomTableViewCell and mark it as #IBDesignable. In CustomTableViewCell.xib file I drag a label to its center, then setup an #IBOutlet and name this label as contentLabel. Next, I drag a TableViewCell and put it on a ViewController's table view in the storyboard file, and change its class to CustomTableViewCell. My question is: how to render this contentLabel in the storyboard?
The following snippet doesn't work and I believe it's because contentLabel is not initialized yet in init(), but I want to give it an initial text and render it in the storyboard. How to achieve this?
#IBDesignable class CustomTableViewCell: UITableViewCell {
#IBOutlet weak var contentLabel: UILabel!
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentLabel.text = "Hello"
}
required init?(coder: NSCoder) {
super.init(coder: coder)
contentLabel.text = "Hello"
}
}
EDIT: This cell needs to reused in several different view controllers.
I've looked around and I can't find any examples of this. I simply want to create a custom initializer on a programmatic UITableViewCell subclass that includes one property.
class CustomCell: UITableViewCell {
var foo: Foo
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// custom init with a foo
}
What I want is:
let cell = CustomCell(foo: myFoo) // other default init params if needed
Not:
let cell = CustomCell()
cell.foo = myFoo
Pointing me to a resource (if I missed one) that shows an implementation like this would be great. I assume this is a common need, but a couple hours being yelled at by init compiler errors and a few Medium articles later and I can't find anything.
Instances of UITableViewCell are created by the system, using the classic init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) initializer.
Don't forget to add this magic line after initializing your UITableView:
myTableView.register(CustomCell.self, forCellReuseIdentifier: Constant.myCellReuseIdentifier)
Let's say you write this:
class CustomCell: UITableViewCell {
convenience init(reuseIdentifier: String, customObject: Any?) {
self.init(style: UITableViewCell.CellStyle.default, reuseIdentifier: reuseIdentifier)
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Then you can create a cell with this line of code:
let cell = CustomCell(reuseIdentifier: Constant.myReuseIdentifier, customObject: nil)
... but what will you do with this cell? How to plug it into your "tableview's cells management" logic.
To inject something to your cell, you may plug in:
tableView(_:cellForRowAt:) for a UITableView (in the object implementing UITableViewDataSource)
collectionView(_:cellForItemAt:) or collectionView:willDisplayCell:forItemAtIndexPath: for a UICollectionView.
Those 3 methods may be call very frequently by the system, avoid memory allocations or any memory / CPU intensive task when possible.
This is a similar question to this but not quite the same.
I have created a subclass of UITableViewCell which references a custom nib and marked it as #IBDesignable. Changes that are made both in code and from the .xib file display correctly in the simulator and on a device but not in the storyboard.
import UIKit
#IBDesignable class TextFieldTableViewCell: UITableViewCell {
var view: UIView!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setup()
}
func setup() {
view = loadViewFromNib()
view.frame = bounds
view.autoresizingMask = [UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleHeight]
contentView.addSubview(view)
}
func loadViewFromNib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "TextFieldTableView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
}
The storyboard displays a permanent "Designables Updating".
Breaking the problem down into a less complex test of only subclassing a UITableViewCell and marking it as #IBDesignable results in the same permanent "Designables Updating".
import UIKit
#IBDesignable class TextFieldTableViewCell: UITableViewCell {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
}
Has anyone had success with creating a #IBDesignable UITableViewCell subclass? This is happening in Xcode 7 beta 6 and beta 5.
This issue has been resolved as of Xcode 9.
I had reported this issue to Apple and at least have the piece of mind knowing that this is a known bug. It is currently an open issue under the problem ID 17973876.
Edit: As of 12/7/2016 this bug is still marked as open.
I was having similar problems. This thread helped me understand the issue: Is there a way for Interface Builder to render IBDesignable views which don't override drawRect:
I got it to work by adding
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
layoutSubviews()
}
as far as i understand after reading the above stack link, IBDesignable loads the nib in storyboard not from nib or from coder but from the init with frame. Not too sure but I think init with style is doing a similar thing.
It seems that the "Updating" bug is happening only when the cell is inside a storyboard. Everything works OK when you create special .xib file just for the cell.
Hopefully, they will fix it soon.
I'm trying to use a custom TableViewCell Class in my programmatically created UITableView and i can't figure out why this don't get to work. I've used custom TableViewCell Classes a few times without any problems (set the Classname in Storyboard) but here i have no Storyboard to set the Class which should be used to generate the Cells.
I'm doing this:
override func viewDidLoad() {
...
self.popupTableView.registerClass(CustomTableViewCellPopup.self, forCellReuseIdentifier: "popupTableViewCell")
...
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("popupTableViewCell") as CustomTableViewCellPopup
...
return cell
}
class CustomTableViewCellPopup: UITableViewCell {
var message: UILabel = UILabel()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required init(coder decoder: NSCoder) {
super.init(coder: decoder)
}
override func awakeFromNib() {
super.awakeFromNib()
println("I'm running!")
self.message.frame = CGRectMake(0, 0, 10, 10);
self.message.backgroundColor = UIColor.brownColor()
self.addSubview(self.message)
}
}
The println() Output never appears. The TableView gets rendered without the additional UILabel (message). Just like an out of the box UITableViewCell.
The same way (without registerClass()) i'm running a TableView with custom Cells from the Storyboard (the Classname directly defined in the Storyboard Inspector) without any problems.
Have you an idea why the custom Class don't get used?
awakeFromNib won't get called unless the cell is loaded from a xib or storyboard. Move your custom code from awakeFromNib into initWithStyle:reuseIdentifier: because that's the initializer used by the tableView when you call its dequeueReusableCellWithIdentifier: method
You're not seeing the println output because that's in awakeFromNib, which is only called if you cell comes from a storyboard or XIB. Here you're just registering the class with the table, so there's no Nib loading going on. Try making a call to configure the cell from tableView:cellForRowAtIndexPath:, rather than configuring in awakeFromNib.
initWithCoder: won't be called for the same reason - try overriding initWithStyle:reuseIdentifier:.
I need to create a custom UITableViewCell,
I have created a class inside of a ViewController class.
I have written the code below;
class FavoritesCell: UITableViewCell
{
var timeLabel:UILabel?
override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
super.init(style: UITableViewCellStyle.Value1, reuseIdentifier: reuseIdentifier)
timeLabel = UILabel(frame: CGRectMake(250, 10, 70, 20))
//how to add this time label as a subview of FavoritesCell
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
As i mentioned in commented line, how to add timeLabel to UITableViewCell?
Thanks
After you've created your timeLabel, this should do it:
self.contentView.addSubview(timeLabel!)
This adds the timeLabel to the cell's contentView rather than the cell itself, but that's generally what you do in table view cells.
Other things to note:
It's fine to use self here - after your super.init call, the object is fully initialised.
You've just created the timeLabel, so it's safe to force-unwrap it in addSubview.
As UITableViewCell class is derived from the UIView, so you can use the same method - self.addSubview(timeLabel!).