How can I mask an UIView or UIImageView so that a text is cutout from it?
I googled a lot and it seems that many people struggled the same. Most irritating I always tried to invert the alpha of a snapshotted view to get the result.
What I want looks like this:
This is the custom mask label.
import UIKit
final class MaskLabel: UILabel {
// MARK: - IBInspectoable
#IBInspectable var cornerRadius: CGFloat {
get { return self.layer.cornerRadius }
set { self.layer.cornerRadius = newValue }
}
#IBInspectable var borderWidth: CGFloat {
get { return self.layer.cornerRadius }
set { self.layer.borderWidth = newValue }
}
#IBInspectable var borderColor: UIColor {
get { return UIColor(cgColor: self.layer.borderColor ?? UIColor.clear.cgColor) }
set { self.layer.borderColor = newValue.cgColor }
}
#IBInspectable var insetTop: CGFloat {
get { return self.textInsets.top }
set { self.textInsets.top = newValue }
}
#IBInspectable var insetLeft: CGFloat {
get { return self.textInsets.left }
set { self.textInsets.left = newValue }
}
#IBInspectable var insetBottom: CGFloat {
get { return self.textInsets.bottom }
set { self.textInsets.bottom = newValue }
}
#IBInspectable var insetRight: CGFloat {
get { return self.textInsets.right }
set { self.textInsets.right = newValue }
}
// MARK: - Value
// MARK: Public
private var textInsets = UIEdgeInsets.zero
private var originalBackgroundColor: UIColor? = nil
// MARK: - Initializer
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setLabelUI()
}
override init(frame: CGRect) {
super.init(frame: frame)
setLabelUI()
}
override func prepareForInterfaceBuilder() {
setLabelUI()
}
// MARK: - Draw
override func drawText(in rect: CGRect) {
super.drawText(in: UIEdgeInsetsInsetRect(rect, textInsets))
guard let context = UIGraphicsGetCurrentContext() else { return }
context.saveGState()
context.setBlendMode(.clear)
originalBackgroundColor?.setFill()
UIRectFill(rect)
super.drawText(in: rect)
context.restoreGState()
}
// MARK: - Function
// MARK: Private
private func setLabelUI() {
// cache (Before masking the label, the background color must be clear. So we have to cache it)
originalBackgroundColor = backgroundColor
backgroundColor = .clear
layer.cornerRadius = cornerRadius
layer.borderWidth = borderWidth
layer.borderColor = borderColor.cgColor
}
}
This is the result.
The main problem I had was my understanding. Instead of taking a colored view and trying to make a transparent hole in it, we can just layer it the other way around.
So we have the colored background in the back, followed by the image in front that has the mask on it to only show the text part. And actually, that's pretty simple if you're using iOS 8+ by using the maskView property of UIView.
So it could look something like this in swift:
let coloredBackground = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 100))
coloredBackground.backgroundColor = UIColor.greenColor()
let imageView = UIImageView(frame: coloredBackground.bounds)
imageView.image = UIImage(named: "myImage")
coloredBackground.addSubview(imageView)
let label = UILabel(frame: coloredBackground.bounds)
label.text = "stackoverflow"
coloredBackground.addSubview(label)
imageView.maskView = label
Related
I am trying to create an overlay view, that has a "cutout" part that comes from a frame that is passed to the view, that size and position of that passed frame will change upon creation of the view. And in that "cutout" part I am expecting to see the content that is under that overlay view. Tried to set border to a rounded rectangle that is added to a CGMutablePath, but no luck.
The expected result is something like this:
The code I currently have in my UIView class, without tried solutions as I can't seem to get them to work properly. This current code displays the expected result, but without the red border:
override func draw(_ rect: CGRect) {
super.draw(rect)
UIColor.blue.setFill()
UIRectFill(rect)
let shapeLayer = CAShapeLayer()
let path = CGMutablePath()
// frame that will change position on the screen
if let frame = changingFrame {
path.addRoundedRect(in: frame, cornerWidth: 16, cornerHeight: 16)
}
path.addRect(bounds)
shapeLayer.path = path
shapeLayer.fillRule = CAShapeLayerFillRule.evenOdd
self.layer.mask = shapeLayer
}
I have tried solutions from here, here, but no luck as CAShapeLayer for border just overlays existing one.
What can I do differently to achieve the expected result? Thanks!
try this ⭐️
If all you want to do is create a rounded rectangle, then you can simply use.
let rectangle = CGRect(x: 0, y: 0, width: 100, height: 100)
let path = UIBezierPath(roundedRect: rectangle, cornerRadius: 20)
view.clipsToBounds = true
view.layer.cornerRadius = 10.0
let border = CAShapeLayer()
border.path = UIBezierPath(roundedRect:view.bounds, cornerRadius:10.0).cgPath
border.frame = view.bounds
border.fillColor = nil
border.strokeColor = UIColor.purple.cgColor
border.lineWidth = borderWidth * 2.0 // doubled since half will be clipped
border.lineDashPattern = [1.0]
view.layer.addSublayer(border)
One approach is to use two sublayers... a "cutout" layer and a "border" layer.
Use the same path for the cutout and the border shape, setting the line width and stroke color for the "outline".
Here's an example -- including making it #IBDesignable with a few #IBInspectable properties:
#IBDesignable
class BorderedCutoutView: UIView {
#IBInspectable
var bkgColor: UIColor = .systemBlue {
didSet {
setNeedsLayout()
}
}
#IBInspectable
var brdColor: UIColor = .white {
didSet {
setNeedsLayout()
}
}
#IBInspectable
var brdWidth: CGFloat = 1 {
didSet {
setNeedsLayout()
}
}
#IBInspectable
var radius: CGFloat = 20 {
didSet {
setNeedsLayout()
}
}
#IBInspectable
var horizInset: CGFloat = 40.0 {
didSet {
setNeedsLayout()
}
}
#IBInspectable
var vertInset: CGFloat = 60.0 {
didSet {
setNeedsLayout()
}
}
private let cutoutLayer = CAShapeLayer()
private let borderLayer = CAShapeLayer()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
backgroundColor = .clear
}
private func commonInit() -> Void {
backgroundColor = .clear
layer.addSublayer(cutoutLayer)
layer.addSublayer(borderLayer)
}
override func layoutSubviews() {
super.layoutSubviews()
let path = UIBezierPath(rect: bounds)
let cp = UIBezierPath(roundedRect: bounds.insetBy(dx: horizInset, dy: vertInset), cornerRadius: radius)
path.append(cp)
path.usesEvenOddFillRule = true
cutoutLayer.path = path.cgPath
cutoutLayer.fillRule = .evenOdd
cutoutLayer.fillColor = bkgColor.cgColor
borderLayer.path = cp.cgPath
borderLayer.fillColor = UIColor.clear.cgColor
borderLayer.lineWidth = brdWidth
borderLayer.strokeColor = brdColor.cgColor
}
}
This example uses horizontal and vertical "inset" values to center the cutout in the view.
Result:
Hy,
I'm trying to customize a slider by changing the thumb image and add a label over the picture.
For this, in my view in I set the image for slider thumb:
class SliderView: NibLoadingView {
#IBOutlet weak var slider: ThumbTextSlider!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
contentView = legacyLoadXib()
setup()
}
override func setup() {
super.setup()
self.slider.setThumbImage(UIImage(named: "onb_cc_slider_thumb")!, for: .normal)
self.slider.thumbTextLabel.font = UIFont(name: Fonts.SanFranciscoDisplayRegular, size: 14)
}
}
In ThumbTextSlider class I set the text label as below:
class ThumbTextSlider: UISlider {
var thumbTextLabel: UILabel = UILabel()
private var thumbFrame: CGRect {
return thumbRect(forBounds: bounds, trackRect: trackRect(forBounds: bounds), value: value)
}
override func layoutSubviews() {
super.layoutSubviews()
thumbTextLabel.frame = thumbFrame
}
override func awakeFromNib() {
super.awakeFromNib()
addSubview(thumbTextLabel)
thumbTextLabel.layer.zPosition = layer.zPosition + 1
}
}
When I made test the result was a little different.
How, can I fix the issue ?
The expected result:
Kind regards
This class may help you. In class instead of image I created image you can replace with you thumb image.
class ThumbTextSlider: UISlider {
private var thumbTextLabel: UILabel = UILabel()
private var thumbFrame: CGRect {
return thumbRect(forBounds: bounds, trackRect: trackRect(forBounds: bounds), value: value)
}
private lazy var thumbView: UIView = {
let thumb = UIView()
return thumb
}()
override func layoutSubviews() {
super.layoutSubviews()
thumbTextLabel.frame = CGRect(x: thumbFrame.origin.x, y: thumbFrame.origin.y, width: thumbFrame.size.width, height: thumbFrame.size.height)
self.setValue()
}
private func setValue() {
thumbTextLabel.text = self.value.description
}
override func awakeFromNib() {
super.awakeFromNib()
addSubview(thumbTextLabel)
thumbTextLabel.textAlignment = .center
thumbTextLabel.textColor = .blue
thumbTextLabel.adjustsFontSizeToFitWidth = true
thumbTextLabel.layer.zPosition = layer.zPosition + 1
let thumb = thumbImage()
setThumbImage(thumb, for: .normal)
}
private func thumbImage() -> UIImage {
let width = 100
thumbView.frame = CGRect(x: 0, y: 15, width: width, height: 30)
thumbView.layer.cornerRadius = 15
let renderer = UIGraphicsImageRenderer(bounds: thumbView.bounds)
return renderer.image { rendererContext in
rendererContext.cgContext.setShadow(offset: .zero, blur: 5, color: UIColor.black.cgColor)
thumbView.backgroundColor = .red
thumbView.layer.render(in: rendererContext.cgContext)
}
}
override func trackRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(origin: bounds.origin, size: CGSize(width: bounds.width, height: 5))
}
}
So I am trying to create the following effect using xcode swift.
I am trying to re-create the form bubble which contains the text fields and the text fields themselves, in the following style.
What I have tried so far:
Creating a UI View with curved borders, then using a transparent textfield and UILabels to indicate the field content.
I assume that the that must be a UItableview given the indent line but I am not sure how to style the tableview the same way. I assumed I can use the layer.cornerRadius as I did for the UIView but this doesn't seem to work.
Also is the entire view controller a UItableview controller or UICollectionView?
Any help on how to create the form as below would be appreciated.
In iOS 13 you can simply set the Style to Inset Grouped and the UITableView looks exactly like that - no additional changes necessary.
Using layer.cornerRadius for the whole tableview will not work. You should use a UITableviewController or a normal UIViewController which contains a tableView then divide your tableview into 3 sections
First section should be profile: no doubt about this section, border your cell the be the same as design
Second section should be personal information. 3 cells, each cell contain the text field. You can calculate and create border for the cell by corresponding position (top cell will be bordered top left & right, bottom cell will be bordered bottom left & right, otherwise no bordered)
Third section: no doubt about this, just one cell (switch account)
SWIFT Solution
Thanks to Paulo Silva
Step 1:
You can simply create a swift file named it as 'CUIView' (or your own wish) and use following IBDesignable code inside it and save .
//
// CUIView.swift
// CustomUIView
//
// Created by Paulo Silva on 23/08/2019.
// Copyright © 2019 example. All rights reserved.
//
import UIKit
import UIKit
import CoreGraphics
#IBDesignable class CUIView: UIView {
// MARK: - Private Variables -
private let containerView = UIView()
private var containerImageView = UIImageView()
// MARK: - Public Attributes -
#IBInspectable public var backgroundImage: UIImage? {
get {
return self.containerImageView.image
}
set {
// addShadowColorFromBackgroundImage()
self.containerImageView.image = newValue
}
}
override open var backgroundColor: UIColor? {
didSet(new) {
if let color = new {
containerView.backgroundColor = color
}
if backgroundColor != UIColor.clear { backgroundColor = UIColor.clear }
}
}
#IBInspectable var borderColor: UIColor {
get {
return UIColor(cgColor: self.containerView.layer.borderColor!)
}
set {
self.layer.borderColor = newValue.cgColor
self.containerView.layer.borderColor = newValue.cgColor
}
}
#IBInspectable var borderWidth: CGFloat {
get {
return self.containerView.layer.borderWidth
}
set {
self.layer.borderWidth = newValue
self.containerView.layer.borderWidth = newValue
}
}
#IBInspectable var cornerRadius: CGFloat {
get {
return self.containerView.layer.cornerRadius
}
set {
self.layer.cornerRadius = newValue
self.containerView.layer.cornerRadius = newValue
}
}
#IBInspectable var shadowOpacity: Float {
get {
return self.layer.shadowOpacity
}
set {
self.layer.shadowOpacity = newValue
}
}
#IBInspectable var shadowRadius: CGFloat {
get {
return self.layer.shadowRadius
}
set {
self.layer.shadowRadius = newValue
}
}
#IBInspectable var shadowOffset: CGSize {
get {
return self.layer.shadowOffset
}
set {
self.layer.shadowOffset = newValue
}
}
#IBInspectable var shadowColor: UIColor {
get {
return UIColor(cgColor: self.layer.shadowColor!)
}
set {
self.layer.shadowColor = newValue.cgColor
}
}
// #IBInspectable var shadowColorFormImage: Bool = false {
// didSet {
// addShadowColorFromBackgroundImage()
// }
// }
// MARK: - Life Cycle -
override init(frame: CGRect) {
super.init(frame: frame)
addViewLayoutSubViews()
refreshViewLayout()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
addViewLayoutSubViews()
refreshViewLayout()
}
override open func draw(_ rect: CGRect) {
super.draw(rect)
refreshViewLayout()
// addShadowColorFromBackgroundImage()
}
override func layoutSubviews() {
super.layoutSubviews()
refreshViewLayout()
// addShadowColorFromBackgroundImage()
}
// MARK: - Private Methods -
private func refreshViewLayout() {
// View
self.clipsToBounds = true
self.layer.masksToBounds = false
self.layer.cornerRadius = cornerRadius
// Shadow
self.layer.shadowOpacity = shadowOpacity
self.layer.shadowColor = shadowColor.cgColor
self.layer.shadowOffset = shadowOffset
self.layer.shadowRadius = shadowRadius
// Container View
self.containerView.layer.masksToBounds = true
self.containerView.layer.cornerRadius = cornerRadius
// Image View
self.containerImageView.backgroundColor = UIColor.clear
self.containerImageView.image = backgroundImage
self.containerImageView.layer.cornerRadius = cornerRadius
self.containerImageView.layer.masksToBounds = true
self.containerImageView.clipsToBounds = true
self.containerImageView.contentMode = .redraw
}
private func addViewLayoutSubViews() {
// add subViews
self.addSubview(self.containerView)
self.containerView.addSubview(self.containerImageView)
// add image constraints
self.containerImageView.translatesAutoresizingMaskIntoConstraints = false
self.containerImageView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
self.containerImageView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
self.containerImageView.topAnchor.constraint(equalTo: topAnchor).isActive = true
self.containerImageView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
// add view constraints
self.containerView.translatesAutoresizingMaskIntoConstraints = false
self.containerView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
self.containerView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
self.containerView.topAnchor.constraint(equalTo: topAnchor).isActive = true
self.containerView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
// private func addShadowColorFromBackgroundImage() {
// // Get the averageColor from the image for set the Shadow Color
// if shadowColorFormImage {
// let week = self
// DispatchQueue.main.async {
// week.shadowColor = (week.containerImageView.image?.averageColor)!
// }
// }
// }
}
extension UIImage {
static func imageWithColor(tintColor: UIColor) -> UIImage {
let rect = CGRect(x: 0, y: 0, width: 1, height: 1)
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0)
tintColor.setFill()
UIRectFill(rect)
let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}
func withBackground(color: UIColor, opaque: Bool = true) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, opaque, scale)
guard let ctx = UIGraphicsGetCurrentContext() else { return self }
defer { UIGraphicsEndImageContext() }
let rect = CGRect(origin: .zero, size: size)
ctx.setFillColor(color.cgColor)
ctx.fill(rect)
ctx.concatenate(CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: size.height))
ctx.draw(cgImage!, in: rect)
return UIGraphicsGetImageFromCurrentImageContext() ?? self
}
var averageColor: UIColor? {
guard let inputImage = CIImage(image: self) else { return nil }
let extentVector = CIVector(x: inputImage.extent.origin.x, y: inputImage.extent.origin.y, z: inputImage.extent.size.width, w: inputImage.extent.size.height)
guard let filter = CIFilter(name: "CIAreaAverage", parameters: [kCIInputImageKey: inputImage, kCIInputExtentKey: extentVector]) else { return nil }
guard let outputImage = filter.outputImage else { return nil }
var bitmap = [UInt8](repeating: 0, count: 4)
let context = CIContext(options: [.workingColorSpace: kCFNull as Any])
context.render(outputImage, toBitmap: &bitmap, rowBytes: 4, bounds: CGRect(x: 0, y: 0, width: 1, height: 1), format: .RGBA8, colorSpace: nil)
return UIColor(red: CGFloat(bitmap[0]) / 255, green: CGFloat(bitmap[1]) / 255, blue: CGFloat(bitmap[2]) / 255, alpha: CGFloat(bitmap[3]) / 255)
}
}
extension NSLayoutConstraint {
func constraintWithMultiplier(_ multiplier: CGFloat) -> NSLayoutConstraint {
return NSLayoutConstraint(item: self.firstItem!, attribute: self.firstAttribute, relatedBy: self.relation, toItem: self.secondItem, attribute: self.secondAttribute, multiplier: multiplier, constant: self.constant)
}
}
extension UIScreen {
enum SizeType: CGFloat {
case unknown = 0.0
case iPhone4 = 960.0
case iPhone5 = 1136.0
case iPhone6 = 1334.0
case iPhone6Plus = 1920.0
}
var sizeType: SizeType {
let height = nativeBounds.height
guard let sizeType = SizeType(rawValue: height) else { return .unknown }
return sizeType
}
}
Step 2 : Connect your view associated class as 'CUIView' as following image
Step 3: Give corner radius and set background as like as following image .
For all the group textField and textfield you can use a view as parents view and associated class to get this outcome . For underline you can use simple view with minimum height to get desired design .
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I tried the bellow code then I got the result like above image
Expected result for Image view is shown bellow
I have posted the image of expectated result.
I have dragged the UIImage view and I want to make the image view that display in round format.
So please guide me out.
#IBOutlet weak var imgView : UIImageView!
imgView.layer.borderWidth = 1
imgView.layer.masksToBounds = true
imgView.layer.borderColor = UIColor.black.cgColor
imgView.layer.cornerRadius = imgView.frame.width/2
imgView.clipsToBounds = true
//I tried this still not getting the answer
UIImageView is subclass of UIView. Each UIView has its own CALayer. You can set the border color, border width and corner radius of the view by using its layer. To show the UIImageView in circular shape, first height and weight of the view should be equal and then set corner radius as height/2 or width/2.
If myImage is UIImageView for which height and weight are equal, then:
myImage.layer.cornerRadius = myImage.frame.size.height / 2
Simply you can do that like following
override func viewDidLoad() {
super.viewDidLoad()
profilePhoto.layer.borderWidth = 1
profilePhoto.layer.borderColor = UIColor.black.cgColor
profilePhoto.layer.masksToBounds = false
profilePhoto.layer.cornerRadius = profilePhoto.frame.width/2
profilePhoto.clipsToBounds = true
}
Step1: You can do this by using custom view class. Create a new swift file and set name to UIImageViewX then paste the below code.
import UIKit
#IBDesignable
class UIImageViewX: UIImageView {
// MARK: - Properties
#IBInspectable public var borderColor: UIColor = UIColor.clear {
didSet {
layer.borderColor = borderColor.cgColor
}
}
#IBInspectable public var borderWidth: CGFloat = 0 {
didSet {
layer.borderWidth = borderWidth
}
}
#IBInspectable public var cornerRadius: CGFloat = 0 {
didSet {
layer.cornerRadius = cornerRadius
}
}
#IBInspectable var pulseDelay: Double = 0.0
#IBInspectable var popIn: Bool = false
#IBInspectable var popInDelay: Double = 0.4
// MARK: - Shadow
#IBInspectable public var shadowOpacity: CGFloat = 0 {
didSet {
//layer.shadowOpacity = Float(shadowOpacity)
}
}
#IBInspectable public var shadowColor: UIColor = UIColor.clear {
didSet {
//layer.shadowColor = shadowColor.cgColor
}
}
#IBInspectable public var shadowRadius: CGFloat = 0 {
didSet {
//layer.shadowRadius = shadowRadius
}
}
#IBInspectable public var shadowOffsetY: CGFloat = 0 {
didSet {
//layer.shadowOffset.height = shadowOffsetY
}
}
// MARK: - FUNCTIONS
override func layoutSubviews() {
// super.layoutSubviews()
// layer.shadowColor = shadowColor.cgColor
// layer.shadowOpacity = Float(shadowOpacity)
// layer.shadowRadius = shadowRadius
// layer.masksToBounds = false
// layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).cgPath
}
override func draw(_ rect: CGRect) {
if clipsToBounds && shadowOpacity > 0 {
layer.masksToBounds = true
layer.cornerRadius = cornerRadius
// Outer UIView to hold the Shadow
let shadow = UIView(frame: rect)
shadow.layer.cornerRadius = cornerRadius
shadow.layer.masksToBounds = false
shadow.layer.shadowOpacity = Float(shadowOpacity)
shadow.layer.shadowColor = shadowColor.cgColor
shadow.layer.shadowRadius = shadowRadius
shadow.layer.shadowOffset.height = shadowOffsetY
shadow.layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).cgPath
shadow.addSubview(self)
}
}
override func awakeFromNib() {
if pulseDelay > 0 {
UIView.animate(withDuration: 1, delay: pulseDelay, usingSpringWithDamping: 0.4, initialSpringVelocity: 0, options: [], animations: {
self.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
self.transform = CGAffineTransform.identity
}, completion: nil)
}
if popIn {
transform = CGAffineTransform(scaleX: 0.01, y: 0.01)
UIView.animate(withDuration: 0.8, delay: popInDelay, usingSpringWithDamping: 0.5, initialSpringVelocity: 0, options: .allowUserInteraction, animations: {
self.transform = CGAffineTransform.identity
}, completion: nil)
}
}
}
Step2:
Set custom class in storyboard like above image.
Step3:
After this you can see the corner radius properties of imageview in Attribute section.
Increase and decrease the corner radius then you will got the desire result
You can round an imageView using the CALayer, use this class to do it in the storyboard:
#IBDesignable class RoundImageView: UIImageView
{
#IBInspectable var cornerRadius: CGFloat = 0 {
didSet {
layer.cornerRadius = cornerRadius
}
}
#IBInspectable var borderColor: UIColor? = nil
{
didSet {
layer.borderColor = borderColor?.cgColor
}
}
#IBInspectable var borderWidth: CGFloat = 0 {
didSet {
layer.borderWidth = borderWidth
}
}
#IBInspectable var dropShadowOffset: CGSize = CGSize(width: 0, height: 0) {
didSet {
layer.shadowOffset = dropShadowOffset
}
}
#IBInspectable var maskToBounds: Bool = true {
didSet{
layer.masksToBounds = maskToBounds
}
}
#IBInspectable var dropShadowColor: UIColor? {
didSet {
layer.shadowColor = dropShadowColor?.cgColor
}
}
#IBInspectable var dropShadowRadius: CGFloat = 0 {
didSet {
layer.shadowRadius = dropShadowRadius
}
}
required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
}
override init(frame: CGRect)
{
super.init(frame: frame)
}
}
I'm new at using Xcode. My question is regarding "How to set corner.Radius for UIButtons (collection) instead of doing 1 by 1. Once the collection is created i'm using the following line:
self.myButtons.layer.cornerRadius = 10
but that is for a single button. Is it possible to do this for a "collection" of buttons?
enter image description here
any help is greatly appreciated.
#IBOutlet var myButtons: [UIButton]!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.myButtons.layer.conerRadius = 10
A few options:
Iterate through them yourself:
myButtons.forEach { $0.layer.cornerRadius = 10 }
Use NSArray and its setValue(_:forKey:)
(myButtons as NSArray).setValue(10, forKey: "cornerRadius")
I’d lean towards the former, but the latter is the old Objective-C way of doing it (which is why we had to bridge to NSArray).
The other approach is to define your own UIButton subclass, e.g. RoundedButton that does this for you. Just set the base class for your button in IB to be your custom subclass.
E.g. for fixed corner radius (which you can also adjust right in IB):
#IBDesignable
class RoundedButton: UIButton {
#IBInspectable var cornerRadius: CGFloat = 10 {
didSet {
layer.cornerRadius = cornerRadius
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configure()
}
override init(frame: CGRect = .zero) {
super.init(frame: frame)
configure()
}
}
private extension RoundedButton {
func configure() {
layer.cornerRadius = cornerRadius
}
}
Or, if you want dynamic rounding based upon the height:
#IBDesignable
class RoundedButton: UIButton {
override func layoutSubviews() {
super.layoutSubviews()
let radius = min(bounds.width, bounds.height) / 2
layer.cornerRadius = radius
}
}
The virtue of this approach is that you can see your rounded buttons rendered right in IB.
Follow this below steps -
1.Choose UIButton from the object library
2.Drag to your storyboard
3.Choose border style as none.
4.Create a Swift file and add this below extension -
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 {
return UIColor(cgColor: layer.borderColor!)
}
set {
layer.borderColor = newValue?.cgColor
}
}
}
extension UIButton {
func roundedButton(){
let maskPAth1 = UIBezierPath(roundedRect: self.bounds,
byRoundingCorners: [.topLeft , .topRight],
cornerRadii:CGSize(width:8.0, height:8.0))
let maskLayer1 = CAShapeLayer()
maskLayer1.frame = self.bounds
maskLayer1.path = maskPAth1.cgPath
self.layer.mask = maskLayer1
}
}
extension UITextField {
func setLeftPaddingPoints(_ amount:CGFloat){
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: amount, height: self.frame.size.height))
self.leftView = paddingView
self.leftViewMode = .always
}
func setRightPaddingPoints(_ amount:CGFloat) {
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: amount, height: self.frame.size.height))
self.rightView = paddingView
self.rightViewMode = .always
}
}
extension UITextField {
#IBInspectable var maxLength: Int {
get {
if let length = objc_getAssociatedObject(self, &kAssociationKeyMaxLength) as? Int {
return length
} else {
return Int.max
}
}
set {
objc_setAssociatedObject(self, &kAssociationKeyMaxLength, newValue, .OBJC_ASSOCIATION_RETAIN)
addTarget(self, action: #selector(checkMaxLength), for: .editingChanged)
}
}
#objc func checkMaxLength(textField: UITextField) {
guard let prospectiveText = self.text,
prospectiveText.count > maxLength
else {
return
}
let selection = selectedTextRange
let indexEndOfText = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
let substring = prospectiveText[..<indexEndOfText]
text = String(substring)
selectedTextRange = selection
}
}
5.Now you can access this extensions either from storyboard or from code to change the values and see the effects.
6.You can change the corner radius, border width, border colour for UIView,UIButton,UITexfield.Try this Method.
Hope this method also helps.
/// Other way to set Corner radius of view; also inspectable from Storyboard.
public extension UIView {
#IBInspectable public var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
// layer.masksToBounds = true
layer.cornerRadius = abs(CGFloat(Int(newValue * 100)) / 100)
}
}}
By usisng this you can set border radius from storyboard
OR
for btn in yourbuttonCollectionName {btn.cornerRadius = 10.0}
You can do this in interface builder. Select your button and then tap the "Identity Inspector" (3rd tab on the right). Under "User Defined Runtime Attributes" hit the plus button. and type layer.conerRadius for the key and 1 for the value. This will set the corner radius by KVO. you can now copy this button or duplicate it with alt+drag and the copies will also have the corner radius (note it doesn't show in the preview window, but it will show at run time).
Alternatively in code:
myButtons.forEach { button in
button.layer.cornerRadius = 1
}
If you are using an outlet collection you can do this in a didSet since that will be called when iOS sets the outlet from the nib file/ storyboard.
extension UIView {
func addCornerRadius(_ radius: CGFloat) {
self.layer.cornerRadius = radius
}
func applyBorder(_ width: CGFloat, borderColor: UIColor) {
self.layer.borderWidth = width
self.layer.borderColor = borderColor.cgColor
}
func addShadow(color: UIColor, opacity: Float, offset: CGSize, radius: CGFloat) {
self.layer.shadowColor = color.cgColor
self.layer.shadowOpacity = opacity
self.layer.shadowOffset = offset
self.layer.shadowRadius = radius
}
func displayToast(message: String) {
let style = CSToastStyle(defaultStyle: ())
style?.backgroundColor = UIColor.black
style?.titleColor = UIColor.white
style?.messageColor = UIColor.white
makeToast(message, duration: 3.0, position: CSToastPositionTop, style: style)
} }
Use As Below :
self.view.addCornerRadius(10)
self.view.addShadow(color: .lightGray, opacity: 1.0, offset: CGSize(width: 1, height: 1), radius: 2)