Barkley
Barkley

Reputation: 6713

UIView Custom Class not usable by UIView subclasses?

I have the following class that rounds corners and applies a shadow to views.

I have buttons, imageviews, and UILabels that need this styling. Instead of creating a RoundedShadowImageView, RoundedShadowButtonView, etc.. I'd like to have just one class.

When I go to assign RoundedShadowView to anything other than a plain UIView, the class doesn't show up as an option. I should be able to apply this class to anything that is a subclass of UIView such as buttons.

What am I getting wrong here?

class RoundedShadowView : UIView {

    @IBInspectable var cornerRadius: CGFloat = 0
    var shadowLayer: CAShapeLayer!
    private var fillColor: UIColor = .white // the color applied to the shadowLayer, rather than the view's backgroundColor

    override func layoutSubviews() {
        super.layoutSubviews()
        if shadowLayer == nil {
            self.applyShadowLayerWith(cornerRadius: cornerRadius, fillColor: self.backgroundColor ?? .white, toView: self)
        }
        self.backgroundColor = .clear
    }
}

Upvotes: 0

Views: 49

Answers (1)

matt
matt

Reputation: 536027

I should be able to apply this class to anything that is a subclass of UIView such as buttons. What am I getting wrong here?

What you're missing is the entire basic nature of the class/subclass hierarchy. A subclass of UIView is not a subclass of UIButton, nor vice versa; they are independent. Leaving out some intermediate subclasses, what you've created by saying class RoundedShadowView : UIView is this arrangement (with regard to an already existing UIView subclass such as UIButton):

           UIView
           /    \
          /      \
         /        \
        /          \
     UIButton   RoundedShadowView

There is not, and never can be, a hierarchical relationship between UIButton (say) and RoundedShadowView. They are both children of UIView, so in effect they are brothers. My brother cannot magically become my father or my son. A UIButton can never be a RoundedShadowView, and a RoundedShadowView can never be a UIButton.

Now, if you wished to create some functionality that many UIButtons can acquire, you could solve the problem by subclassing UIButton and making your buttons instances of that subclass:

         UIView
            |
         UIButton
            |
       RoundedShadowButton
            |
        (actual buttons)

But you want more than that: you want this functionality to apply to buttons and labels and any other built-in UIView subclass you like. Therefore you just cannot use subclassing plain and simple to solve the problem (as the first chart above demonstrates amply).

Instead, you must find a way to inject the desired functionality into UIView itself or into the particular subclasses that are supposed to acquire it. That would have to be through an extension of some sort:

  • You could extend UIView, so that every UIView is a potential rounded shadow view, and any UIView subclass has the potential to act like a rounded shadow view.

  • Or, if you want to be more selective, you could write a protocol, extend the protocol to have the rounded shadow view functionality, and then make only buttons and labels and image views (or particular button, label, and image view subclasses) adopt that protocol.

However, it's not going to be simple to do that, or at least not as simple as your initial sketch. Your sketch involves overriding layoutSubviews as an opportunity to interfere with the drawing of the view. But you cannot override anything in an extension.

Upvotes: 1

Related Questions