iOS button design - ios

What is the best way to design custom buttons and using them within Xcode. I want them not to look like random buttons. They should look like button as the were from Apple themselves.

You can use just the UIButton, you can set easily:
background color, background image
font type, font color
round corner
dimensions even dynamics with the right constraints
What kind of button do you want to make? See this link for a basic tutorial meantime.

Create a new file called design.swift then add these:
import Foundation
import UIKit
#IBDesignable class CustomTextView : UITextView
{
#IBInspectable var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
layer.masksToBounds = newValue > 0
}
}
#IBInspectable var borderWidth: CGFloat{
set {
layer.borderWidth = newValue
}
get{
return self.layer.borderWidth
}
}
#IBInspectable var borderColor: UIColor? {
set {
layer.borderColor = newValue?.CGColor
}
get{
let c = UIColor(CGColor: layer.borderColor!)
return c
}
}
}
#IBDesignable class CustomView : UIView{
#IBInspectable var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
layer.masksToBounds = newValue > 0
}
}
#IBInspectable var borderWidth: CGFloat{
set {
layer.borderWidth = newValue
}
get{
return self.layer.borderWidth
}
}
#IBInspectable var borderColor: UIColor? {
set {
layer.borderColor = newValue?.CGColor
}
get{
let c = UIColor(CGColor: layer.borderColor!)
return c
}
}
}
#IBDesignable class CustomButton : UIButton{
#IBInspectable var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
layer.masksToBounds = newValue > 0
}
}
#IBInspectable var borderWidth: CGFloat{
set {
layer.borderWidth = newValue
}
get{
return self.layer.borderWidth
}
}
#IBInspectable var borderColor: UIColor? {
set {
layer.borderColor = newValue?.CGColor
}
get{
let c = UIColor(CGColor: layer.borderColor!)
return c
}
}
}
then click at your button go to class right Custom

Related

How setting up shadow of the CALayer breaks AutoLayout constraints?

I have cell's imageView shadow customization:
override func layoutSubviews() {
moviePosterImageView.layer.shadowOffset = .zero
moviePosterImageView.layer.shadowColor = UIColor.black.cgColor
moviePosterImageView.layer.shadowRadius = 5
moviePosterImageView.layer.shadowOpacity = 1
moviePosterImageView.layer.masksToBounds = false
moviePosterImageView.layer.shadowPath = UIBezierPath(rect: moviePosterImageView.bounds).cgPath
}
But it breaks imageView sizes and constraints. Without shadow it works pretty good.
But it breaks imageView sizes and constraints.
Yes, because you forgot to start by saying
override func layoutSubviews() {
super.layoutSubviews() // important
Since autolayout happens in layoutSubviews, if you don’t call super you prevent it from operating.
Use This Code in another swift File and set shadow in story board or xib easily
extension UIView {
#IBInspectable
var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
}
}
#IBInspectable
var borderWidth: CGFloat {
get {
return layer.borderWidth
}
set {
layer.borderWidth = newValue
}
}
#IBInspectable
var borderColor: UIColor? {
get {
if let color = layer.borderColor {
return UIColor(cgColor: color)
}
return nil
}
set {
if let color = newValue {
layer.borderColor = color.cgColor
} else {
layer.borderColor = nil
}
}
}
#IBInspectable
var shadowRadius: CGFloat {
get {
return layer.shadowRadius
}
set {
layer.shadowRadius = newValue
}
}
#IBInspectable
var shadowOpacity: Float {
get {
return layer.shadowOpacity
}
set {
layer.shadowOpacity = newValue
}
}
#IBInspectable
var shadowOffset: CGSize {
get {
return layer.shadowOffset
}
set {
layer.shadowOffset = newValue
}
}
#IBInspectable
var shadowColor: UIColor? {
get {
if let color = layer.shadowColor {
return UIColor(cgColor: color)
}
return nil
}
set {
if let color = newValue {
layer.shadowColor = color.cgColor
} else {
layer.shadowColor = nil
}
}
}
}

How can I fix this warning msg. Warning: Ignoring user defined runtime attribute for key path "radius" on instance of "UIButton"

I am getting this warning message. How can I fix this.
Warning: IB Designables: Ignoring user defined runtime attribute for key path radius on instance of UIButton. Hit an exception when attempting to set its value: [ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key radius.
Here is custom UIButtonRounded class
#IBDesignable class UIButtonRounded: UIButton
{
override func layoutSubviews() {
super.layoutSubviews()
updateCornerRadius()
}
#IBInspectable var rounded: Bool = false {
didSet {
updateCornerRadius()
}
}
#IBInspectable var border: Bool = false {
didSet {
updateCornerRadius()
}
}
#IBInspectable var radious: CGFloat = 0 {
didSet {
updateCornerRadius()
}
}
func updateCornerRadius() {
layer.cornerRadius = rounded ? radious : 0
layer.masksToBounds = true
if(border){
layer.borderWidth = 1.3
layer.borderColor = UIColor(named:"color_bg_white")?.cgColor
}
}
}
Thanks In advance.
If you make a value and change it later it will still exists in the user defined runtime attributes in the Identity Inspector. Go there and delete the old value.
It's working for me:
import UIKit
#IBDesignable
class DesignableView: UIView {
}
#IBDesignable
class DesignableButton: UIButton {
}
#IBDesignable
class DesignableLabel: UILabel {
}
extension UIView {
#IBInspectable
var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
}
}
#IBInspectable
var borderWidth: CGFloat {
get {
return layer.borderWidth
}
set {
layer.borderWidth = newValue
}
}
#IBInspectable
var borderColor: UIColor? {
get {
if let color = layer.borderColor {
return UIColor(cgColor: color)
}
return nil
}
set {
if let color = newValue {
layer.borderColor = color.cgColor
} else {
layer.borderColor = nil
}
}
}
#IBInspectable
var shadowRadius: CGFloat {
get {
return layer.shadowRadius
}
set {
layer.shadowRadius = newValue
}
}
#IBInspectable
var shadowOpacity: Float {
get {
return layer.shadowOpacity
}
set {
layer.shadowOpacity = newValue
}
}
#IBInspectable
var shadowOffset: CGSize {
get {
return layer.shadowOffset
}
set {
layer.shadowOffset = newValue
}
}
#IBInspectable
var shadowColor: UIColor? {
get {
if let color = layer.shadowColor {
return UIColor(cgColor: color)
}
return nil
}
set {
if let color = newValue {
layer.shadowColor = color.cgColor
} else {
layer.shadowColor = nil
}
}
}
}

IBInspectable not updating in storyboard but works on simulator

I can view the changes made using IBInspectable on my simulator but not in my storyboard
I tried reinstalling my Xcode but it didn't fix this issue. Here are some screenshots :
So i know my code works fine because it runs in the simulator and this is a new project altogether so I do not have any of the "Storyboard might still be loading the changes" problems.
import UIKit
extension UIView {
#IBInspectable
var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
layer.masksToBounds = newValue > 0
}
}
#IBInspectable
var borderWidth: CGFloat {
get {
return layer.borderWidth
}
set {
layer.borderWidth = newValue
}
}
#IBInspectable
var borderColor: UIColor? {
get {
let color = UIColor(cgColor: layer.borderColor!)
return color
}
set {
layer.borderColor = newValue?.cgColor
}
}
#IBInspectable
var shadowRadius: CGFloat {
get {
return layer.shadowRadius
}
set {
layer.shadowColor = UIColor.black.cgColor
layer.shadowOffset = CGSize(width: 0, height: 2)
layer.shadowOpacity = 0.4
layer.shadowRadius = shadowRadius
}
}
}
Firstly, you need #IBDesignable directive to render the updates in Storyboard whereas #IBInspectable is only to access the property directly in the Storyboard.
Secondly, you have extended the UIView class to show the inspectable properties in the Storyboard but without #IBDesignable.
Now you would think adding #IBDesignable would solve your problem but sadly you can't apply #IBDesignable on an extension like so:
#IBDesignable //won't work on an extension
extension UIView {
//...
}
You can only apply the #IBDesignable directive on a class you have access to, like so:
#IBDesignable
class MyPrettyDesignableView: UIView {
//...
}
Solution:
Bottomline is that you should subclass UIView and apply the #IBDesignable directive on this class.
Basically, your only option is:
#IBDesignable
class MyPrettyDesignableView: UIView {
#IBInspectable var cornerRadius: CGFloat = 0 {
didSet {
self.layer.cornerRadius = cornerRadius
self.layer.masksToBounds = true
}
}
#IBInspectable var borderWidth: CGFloat = 0 {
didSet {
self.layer.borderWidth = borderWidth
}
}
#IBInspectable var borderColor: UIColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1) {
didSet {
self.layer.borderColor = borderColor.cgColor
}
}
}
Then in the storyboard, go to the view that you want designable in storyboard and change it's custom class to MyPrettyDesignableView.
Change it's custom class to your IBDesignable subclass:
Set the IBInspectable properties:
Have you checked that in Interface Builder (Editor Menu) that you have set Automatically Refresh Views and Refresh All Views?
Update: Try this:
#IBDesignable public class CustomView: UIView {
#IBInspectable var borderColor: UIColor = .white{
didSet {
layer.borderColor = borderColor.cgColor
}
}
#IBInspectable var borderWidth: CGFloat = 2.0 {
didSet {
layer.borderWidth = borderWidth
}
}
#IBInspectable var cornerRadius: CGFloat = 10.0 {
didSet {
layer.cornerRadius = cornerRadius
}
}
#IBInspectable var shadowRadius: CGFloat {
get {
return layer.shadowRadius
}
set {
layer.shadowColor = UIColor.black.cgColor
layer.shadowOffset = CGSize(width: 0, height: 2)
layer.shadowOpacity = 0.4
layer.shadowRadius = shadowRadius
}
}
override public func layoutSubviews() {
super.layoutSubviews()
clipsToBounds = true
}
}
Please update your code as below. You must have to set layer.maskToBound = false and view.clipToBounds = false
import UIKit
extension UIView {
#IBInspectable
var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
layer.masksToBounds = newValue > 0
}
}
#IBInspectable
var borderWidth: CGFloat {
get {
return layer.borderWidth
}
set {
layer.borderWidth = newValue
}
}
#IBInspectable
var borderColor: UIColor? {
get {
let color = UIColor(cgColor: layer.borderColor!)
return color
}
set {
layer.borderColor = newValue?.cgColor
}
}
#IBInspectable
var shadowRadius: CGFloat {
get {
return layer.shadowRadius
}
set {
layer.shadowColor = UIColor.black.cgColor
layer.shadowOffset = CGSize(width: 0, height: 2)
layer.shadowOpacity = 0.4
layer.shadowRadius = shadowRadius
layer.maskToBounds = false
}
}
}
Have you tried to check Automatically Refresh Views or Refresh All Views? It works in my Xcode 9.4.1.
Editor -> Automatically Refresh Views
Assuming you have already applied #IBDesignable correctly at the declaration of a class. And assuming you have already applied #IBInspectable at the properties of the classes, then here is the trick that worked for me.
I delete and retype #IBDesignable.
sometimes even after adding #IBDesignable on the class and #IBInspectable on property definition, your Xcode might not show and refresh, so first
make sure you are using them correctly. if it is not refreshing in my case i had to close all instance of Xcode and restart the Xcode, then it will load the new fresh Interface builder files.

Why properties tagged #IBInspectable is not working?

I followed the tutorial here to create an inspectable and designable view. I just want to add border color, border width, and rounded border capability into the UIView.
I have been successful to show the properties. But doesn't matter what I set on the storyboard, the result is still like if they aren't there. There's no border, even though I've set the border to be 2 in width and black in color. It's not showing both on the storyboard and at the run time. I have set the border to be 2 width, but at run time, I print the border width value at didViewLoad, and the result is 0. What could be possibly wrong?
#IBDesignable extension view: UIView {
#IBInspectable var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
layer.masksToBounds = newValue > 0
}
}
#IBInspectable var borderWidth: CGFloat {
get {
return layer.borderWidth;
}
set {
layer.borderWidth = borderWidth;
}
}
#IBInspectable var borderColor: UIColor? {
get {
return UIColor(CGColor: layer.borderColor!);
}
set {
layer.borderColor = borderColor?.CGColor
}
}
}
And this doesn't work either:
#IBDesignable class BOView: UIView {
#IBInspectable var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
layer.masksToBounds = newValue > 0
}
}
#IBInspectable var borderWidth: CGFloat {
get {
return layer.borderWidth;
}
set {
layer.borderWidth = borderWidth;
}
}
#IBInspectable var borderColor: UIColor? {
get {
return UIColor(CGColor: layer.borderColor!);
}
set {
layer.borderColor = borderColor?.CGColor
}
}
}
Try using newValue instead of the real value.
For instance,
#IBInspectable var borderWidth: CGFloat {
get {
return layer.borderWidth
}
set {
layer.borderWidth = newValue
}
}
Chen, I do prefer the way you are doing it, but also note that what you are trying to do is possible from Storyboard directly without using IBDesignable. You can set the layer properties in User Defined Runtime Attributes.

UIButton Border Color on Selected State using IBInspectable

I am using #IBInspectable to set a border color on a UIButton using a Swift extension like this:
extension UIButton {
#IBInspectable var borderWidth: CGFloat {
get {
return layer.borderWidth
}
set {
layer.borderWidth = newValue
layer.masksToBounds = newValue > 0
}
}
}
...but I also want to have a selectedBorderColor property for the .Selected state of the button. Is this possible with an extension like this? Do I have to subclass UIButton and check the button state somehow instead?
extension UIButton {
#IBInspectable var borderWidth: CGFloat {
get {
return layer.borderWidth
}
set {
layer.borderWidth = newValue
layer.masksToBounds = newValue > 0
}
}
//This is what I want to do...
#IBInspectable var selectedBorderWidth: CGFloat {
get {
return layer.borderWidth
}
set {
layer.borderWidth = newValue
layer.masksToBounds = newValue > 0
}
}
}
Thanks in advance.
You can subclass UIButton like this:
class SBButton: UIButton {
#IBInspectable var borderColor : UIColor = UIColor.whiteColor() {
didSet {
self.setNeedsDisplay()
}
}
#IBInspectable var selectedBorderColor : UIColor = UIColor.blackColor() {
didSet {
self.setNeedsDisplay()
}
}
override var selected: Bool {
didSet {
if selected {
layer.borderColor = selectedBorderColor.CGColor
} else {
layer.borderColor = borderColor.CGColor
}
}
}
}
and use button.selected = true

Resources