I am using the swift extension.
extension UIView {
#IBInspectable var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
layer.masksToBounds = newValue > 0
}
}
}
Which is cookie cutter from several examples regarding #IBInspectable. However, when I use this in my project, the storyboard does not update while viewing in xcode.
When compiling and running however, it does show the rounded corners.
If anyone has any suggestions, it would be very very much appreciated. The project is here. github.com/captainchung/test
You also need to set your view as #IBDesignable. You can try to set it over the extension but not sure it would work, it would work if you subclass UIVIew with your own implementation and then use #IBDesignable and #IBInspectable
Related
I am currently at the start of a project and trying to make some universal inspectable/designable variables for UIViews, UIButtons, and UIImageViews to make designing in InterfaceBuilder easier. For example:
#IBInspectable
var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
}
}
One suggestion I've seen to accomplish this is:
extension UIView {
#IBInspectable
var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
}
}
}
However, the problem with this is that now all subclasses of UIView, show the inspectable properties, which is problematic when I will only be using these properties on maybe three classes, and I add more properties like border width/color, shadow radius, opacity, offset, and color, and these take up a lot of the inspector pane in IB.
I'd like something like this:
#IBDesignable class MyView: UIView, MyDesignable {}
#IBDesignable class MyButton: UIButton, MyDesignable {}
#IBDesignable class MyImageView: UIImageView, MyDesignable {}
protocol MyDesignable {}
extension MyDesignable where Self: UIView {
#IBInspectable
var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
}
}
...
Unfortunately, #IBInspectable springs the error Only instance properties can be declared #IBInspectable.
I also tried:
#IBDesignable class MyView: UIView {}
#IBDesignable class MyButton: UIButton {}
#IBDesignable class MyImageView: UIImageView {}
private extension UIView {
#IBInspectable
var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
}
}
...
}
However, other UIView subclasses still showed the inspectable properties.
Hopefully the question and intent behind it make sense. Please let me know if you have any suggestions. Thank you!
For e.g.
#IBDesignable extension UIView{
#IBInspectable var fillColor:UIColor?{
set{
backgroundColor=newValue
}
get{
return backgroundColor//UIColor(cgColor: backgroundColor!)
}
}
}
I know this is unnecessary but just for checking I have created this and found this is working directly if applied in UIView else its not working.
Can anybody please suggest me am I missing something? I am using swift 3.0.2.
Thanks in advance :)
try this
When you are extending a UIView
class AJView:UIView{
#IBInspectable var fillColor:UIColor? {
didSet {
layer.backgroundColor = fillColor.cgColor
}
}
}
When Using With extension
extension BTextField{
#IBInspectable var fillColor:UIColor? {
get{
return self.fillColor
}
set {
layer.backgroundColor = self.fillColor?.cgColor
}
}
}
Hope it works.
I have edited the answer, you can check now
I've been playing with the IBInspectable/IBDesignable like in this article: http://nshipster.com/ibinspectable-ibdesignable/.
It shows how you can make an extension to add extra editing options in storyboard. The problem however is that you can't see these changes reflected in the preview. For this you need to subclass, use IBDesignable and do the didset{} stuff.
The problem with this is that you need to make a subclass of every stock UIView subclass. So a subclass of UILabel, UITextField and so on. Every time you have to copy/paste the regular UIView stuff like borders and corner radius.
I don't believe Swift supports multiple inheritance, which would have made this much easier.
Let's say your IBDesignable subclass of UIView is called IBView. Is there a way to make e.g. UILabel be a subclass of IBView instead of UIView?
In the end I'm looking if there is a way to make IBDesignable less tedious.
Like you, I'm trying to find a better solution to work with IBDesignable.
What I did to avoid repeat the same code:
I made an extension of UIView to insert all the #IBInspectables I want (like corder radius, border width...).
I created my #IBDesignables that only inherit from UIView, UIButton (or any subclass of UIView I want) in order to render on Interface Builder.
Check this code:
extension UIView {
#IBInspectable var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
layer.masksToBounds = newValue > 0
}
}
#IBInspectable var borderColor: UIColor? {
get {
return UIColor(cgColor: layer.borderColor ?? UIColor.clear.cgColor)
}
set {
layer.borderColor = newValue?.cgColor
}
}
#IBInspectable var borderWidth: Double {
get {
return Double(layer.borderWidth)
}
set {
layer.borderWidth = CGFloat(newValue)
}
}
}
#IBDesignable
class BorderView: UIView { }
#IBDesignable
class BorderButton: UIButton { }
I hope it helps you!
Lots of questions like this explain how to programmatically create a mask and provide rounded corners to a UIView.
Is there a way to do it all within Storyboard? Just asking because it seems like creating rounded corners in Storyboard keeps a clearer demarcation between presentation and logic.
Yes, I use that a lot but question like this was already answered many times.
But anyway in Interface Builder.
You need to add User Defined Runtime Attributes like this:
layer.masksToBounds Boolean YES
layer.cornerRadius Number {View's Width/2}
and enable
Clips subviews
Results:
You can do it in a storyboard by using user-defined properties. Select the view that you want to round and open its Identity Inspector. In the User Defined Runtime Attributes section, add the following two entries:
Key Path: layer.cornerRadius, Type: Number, Value: (whatever radius you want)
Key Path: layer.masksToBounds, Type: Boolean, Value: checked
You may have to import QuartzKit in your view's corresponding class file (if any), but I swear that I've gotten it to work without doing that. Your results may vary.
EDIT: Example of a dynamic radius
extension UIView {
/// The ratio (from 0.0 to 1.0, inclusive) of the view's corner radius
/// to its width. For example, a 50% radius would be specified with
/// `cornerRadiusRatio = 0.5`.
#IBDesignable public var cornerRadiusRatio: CGFloat {
get {
return layer.cornerRadius / frame.width
}
set {
// Make sure that it's between 0.0 and 1.0. If not, restrict it
// to that range.
let normalizedRatio = max(0.0, min(1.0, newValue))
layer.cornerRadius = frame.width * normalizedRatio
}
}
}
I verified that this works in a playground.
Use IBInspectable to add the properties to the Storyboard:
extension UIView {
#IBInspectable var cornerRadiusV: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
layer.masksToBounds = newValue > 0
}
}
#IBInspectable var borderWidthV: CGFloat {
get {
return layer.borderWidth
}
set {
layer.borderWidth = newValue
}
}
#IBInspectable var borderColorV: UIColor? {
get {
return UIColor(cgColor: layer.borderColor!)
}
set {
layer.borderColor = newValue?.cgColor
}
}
}
Even after making all changes in storyboard, Woraphot's answer doesn't work for me.
This worked for me :
layer.cornerRadius = 10
layer.borderWidth = 1
layer.borderColor = UIColor.blue.cgColor
Long answer :
Rounded Corners of UIView/UIButton etc
customUIView.layer.cornerRadius = 10
Border Thickness
pcustomUIView.layer.borderWidth = 1
Border Color
customUIView.layer.borderColor = UIColor.blue.cgColor
You have to connect your view to your code file and then
yourView.layer.cornerRadius = yourView.frame.width / 2
yourView.layer.masksToBounds = true
I am trying to extend the UIButton class by adding a cornerRadius property which can be changed at the design time without having to build the app. I am using the following extension class:
import UIKit
#IBDesignable
extension UIButton {
#IBInspectable var cornerRadius :CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
layer.masksToBounds = newValue > 0
}
}
}
But when I make a change of the property cornerRadius in the Storyboard I do not see the change happening live! Am I missing something!
Extensions don't honor the IBDesignable qualifier. Only actual subclasses do. Annoying but true.
try this code:
#IBDesignable extension UIView {
#IBInspectable var borderColor:UIColor? {
set {
layer.borderColor = newValue!.CGColor
}
get {
if let color = layer.borderColor {
return UIColor(CGColor:color)
}
else {
return nil
}
}
}
}
this will show effect on runtime