I'm currently running into problems with custom UIViews nested in other custom UIViews, with the variables of the nested custom UIView not being able to be changed and hence reflected in the view itself.
Currently, I have 3 custom UIViews:
TokenView, which only has drawRect overridden to make a view with an image in a circle.
@IBDesignable class TokenView: UIView {
@IBInspectable var tokenOutlineColor: UIColor = UIColor.blackColor()
@IBInspectable var tokenBackgroundColor: UIColor = UIColor.lightGrayColor()
@IBInspectable var tokenImage: UIImage!
override init(frame: CGRect){
super.init(frame:frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func drawRect(rect: CGRect) {
var context = UIGraphicsGetCurrentContext()
var thickness: CGFloat = 3
var path = UIBezierPath(ovalInRect: CGRect(origin: CGPointMake(thickness/2, thickness/2), size: CGSize(width: rect.width - thickness, height: rect.height - thickness)))
CGContextSaveGState(context)
path.addClip()
tokenOutlineColor.setStroke()
tokenBackgroundColor.setFill()
path.fill()
if let image = tokenImage {
tokenImage.drawInRect(rect)
}
path.stroke()
}
}
PersonView, which has a TokenView() as a subview, and works as intended as well, when I change my variables of said TokenView.
class PersonView: UIView {
var name: String?
var group: PersonGroup?
required init?(coder aDecoder: NSCoder){
super.init(coder: aDecoder)
makePersonView()
}
override init(frame: CGRect) {
super.init(frame: frame)
makePersonView()
}
func makePersonView(){
if name == nil {
self.name = "Bob"
}
if group == nil {
self.group = PersonGroup.Good
}
let token = TokenView()
token.translatesAutoresizingMaskIntoConstraints = false
switch group! {
case .Good:
token.tokenOutlineColor = UIColor.greenColor()
case .Bad:
token.tokenOutlineColor = UIColor.redColor()
default:
token.tokenOutlineColor = UIColor.blueColor()
}
token.tokenImage = UIImage(named: name!)
token.tokenBackgroundColor = UIColor.clearColor()
token.backgroundColor = UIColor.clearColor()
addSubview(token)
let label = UILabel()
label.text = name
label.translatesAutoresizingMaskIntoConstraints = false
label.textAlignment = NSTextAlignment.Center
addSubview(label)
NSLayoutConstraint.activateConstraints([
token.topAnchor.constraintEqualToAnchor(topAnchor),
token.leadingAnchor.constraintEqualToAnchor(leadingAnchor),
token.trailingAnchor.constraintEqualToAnchor(trailingAnchor),
token.heightAnchor.constraintEqualToConstant(frame.size.height*0.70),
token.bottomAnchor.constraintEqualToAnchor(label.topAnchor),
label.leadingAnchor.constraintEqualToAnchor(leadingAnchor),
label.trailingAnchor.constraintEqualToAnchor(trailingAnchor),
label.bottomAnchor.constraintEqualToAnchor(bottomAnchor)
])
}
and DetailedPersonView class, whereby a PersonView instance is created and its variables being modified from there, and that is where the problem comes about. The other added "details" work fine, just not the ones in the nested PersonView when modified in a function in the class.
class DetailedPersonView: UIView {
var name: String = "Marley"
var group: PersonGroup = PersonGroup.Bad
var quantity: Float = 0.00
var stat: String? = "Strength"
required init?(coder aDecoder: NSCoder){
super.init(coder: aDecoder)
makeDetailedPersonView()
}
override init(frame: CGRect) {
super.init(frame: frame)
makeDetailedPersonView()
}
func makeDetailedPersonView(){
let personView = PersonView()
personView.translatesAutoresizingMaskIntoConstraints = false
personView.name = name
personView.group = group
personView.type = type
addSubview(personView)
let label = UILabel()
let quantityString = String(format: quantity == floor(quantity) ? "%.0f":"%.1f", quantity)
if unit != nil {
label.text = quantityString + " " + stat!
} else {
label.text = quantityString
}
label.translatesAutoresizingMaskIntoConstraints = false
label.textAlignment = NSTextAlignment.Center
addSubview(label)
NSLayoutConstraint.activateConstraints([
personView.topAnchor.constraintEqualToAnchor(topAnchor),
personView.leadingAnchor.constraintEqualToAnchor(leadingAnchor),
personView.trailingAnchor.constraintEqualToAnchor(trailingAnchor),
personView.bottomAnchor.constraintEqualToAnchor(label.topAnchor),
label.leadingAnchor.constraintEqualToAnchor(leadingAnchor),
label.trailingAnchor.constraintEqualToAnchor(trailingAnchor),
label.heightAnchor.constraintEqualToConstant(frame.size.height*0.25),
label.bottomAnchor.constraintEqualToAnchor(bottomAnchor)
])
}
}
So currently my DetailedPersonView has its TokenView (nested within PersonView) showing PersonView's default tokenName and tokenImage, being "Bob", same goes for the circle's outline reflecting PersonGroup.Bad .
I have tried using custom init methods for PersonView, to try to initialize a PersonView in a DetailedPersonView with the variables of DetailedPersonView, but to limited success.
Ideally, this custom subview should work similar to how UILabel does, where UILabel().text changes its text in the view as its variables changes, if that makes sense.
So far haven't found a clear solution to this problem yet :\
Thank you for reading this question! :D
EDIT: One workaround that I thought might work is to implement a class method to the custom UIView to reset each subview's contents and call it every time a variable has been changed. Or is there already a function in a delegate that can achieve the same results, and is called whenever the view is changed?