Swift - How to create this form bubble effect - swift

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 .

Related

Sizing UIButton depending on length of titleLabel

So I have a UIButton and I'm setting the title in it to a string that is dynamic in length. I want the width of the titleLabel to be half of the screen width. I've tried using .sizeToFit() but this causes the button to use the CGSize before the constraint was applied to the titleLabel. I tried using .sizeThatFits(button.titleLabel?.intrinsicContentSize) but this also didn't work. I think the important functions below are the init() & presentCallout(), but I'm showing the entire class just for a more complete understanding. The class I'm playing with looks like:
class CustomCalloutView: UIView, MGLCalloutView {
var representedObject: MGLAnnotation
// Allow the callout to remain open during panning.
let dismissesAutomatically: Bool = false
let isAnchoredToAnnotation: Bool = true
// https://github.com/mapbox/mapbox-gl-native/issues/9228
override var center: CGPoint {
set {
var newCenter = newValue
newCenter.y -= bounds.midY
super.center = newCenter
}
get {
return super.center
}
}
lazy var leftAccessoryView = UIView() /* unused */
lazy var rightAccessoryView = UIView() /* unused */
weak var delegate: MGLCalloutViewDelegate?
let tipHeight: CGFloat = 10.0
let tipWidth: CGFloat = 20.0
let mainBody: UIButton
required init(representedObject: MGLAnnotation) {
self.representedObject = representedObject
self.mainBody = UIButton(type: .system)
super.init(frame: .zero)
backgroundColor = .clear
mainBody.backgroundColor = .white
mainBody.tintColor = .black
mainBody.contentEdgeInsets = UIEdgeInsets(top: 10.0, left: 10.0, bottom: 10.0, right: 10.0)
mainBody.layer.cornerRadius = 4.0
addSubview(mainBody)
// I thought this would work, but it doesn't.
// mainBody.translatesAutoresizingMaskIntoConstraints = false
// mainBody.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
// mainBody.leftAnchor.constraint(equalTo: self.rightAnchor).isActive = true
// mainBody.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
// mainBody.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
}
required init?(coder decoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - MGLCalloutView API
func presentCallout(from rect: CGRect, in view: UIView, constrainedTo constrainedRect: CGRect, animated: Bool) {
delegate?.calloutViewWillAppear?(self)
view.addSubview(self)
// Prepare title label.
mainBody.setTitle(representedObject.title!, for: .normal)
mainBody.titleLabel?.lineBreakMode = .byWordWrapping
mainBody.titleLabel?.numberOfLines = 0
mainBody.sizeToFit()
if isCalloutTappable() {
// Handle taps and eventually try to send them to the delegate (usually the map view).
mainBody.addTarget(self, action: #selector(CustomCalloutView.calloutTapped), for: .touchUpInside)
} else {
// Disable tapping and highlighting.
mainBody.isUserInteractionEnabled = false
}
// Prepare our frame, adding extra space at the bottom for the tip.
let frameWidth = mainBody.bounds.size.width
let frameHeight = mainBody.bounds.size.height + tipHeight
let frameOriginX = rect.origin.x + (rect.size.width/2.0) - (frameWidth/2.0)
let frameOriginY = rect.origin.y - frameHeight
frame = CGRect(x: frameOriginX, y: frameOriginY, width: frameWidth, height: frameHeight)
if animated {
alpha = 0
UIView.animate(withDuration: 0.2) { [weak self] in
guard let strongSelf = self else {
return
}
strongSelf.alpha = 1
strongSelf.delegate?.calloutViewDidAppear?(strongSelf)
}
} else {
delegate?.calloutViewDidAppear?(self)
}
}
func dismissCallout(animated: Bool) {
if (superview != nil) {
if animated {
UIView.animate(withDuration: 0.2, animations: { [weak self] in
self?.alpha = 0
}, completion: { [weak self] _ in
self?.removeFromSuperview()
})
} else {
removeFromSuperview()
}
}
}
// MARK: - Callout interaction handlers
func isCalloutTappable() -> Bool {
if let delegate = delegate {
if delegate.responds(to: #selector(MGLCalloutViewDelegate.calloutViewShouldHighlight)) {
return delegate.calloutViewShouldHighlight!(self)
}
}
return false
}
#objc func calloutTapped() {
if isCalloutTappable() && delegate!.responds(to: #selector(MGLCalloutViewDelegate.calloutViewTapped)) {
delegate!.calloutViewTapped!(self)
}
}
// MARK: - Custom view styling
override func draw(_ rect: CGRect) {
// Draw the pointed tip at the bottom.
let fillColor: UIColor = .white
let tipLeft = rect.origin.x + (rect.size.width / 2.0) - (tipWidth / 2.0)
let tipBottom = CGPoint(x: rect.origin.x + (rect.size.width / 2.0), y: rect.origin.y + rect.size.height)
let heightWithoutTip = rect.size.height - tipHeight - 1
let currentContext = UIGraphicsGetCurrentContext()!
let tipPath = CGMutablePath()
tipPath.move(to: CGPoint(x: tipLeft, y: heightWithoutTip))
tipPath.addLine(to: CGPoint(x: tipBottom.x, y: tipBottom.y))
tipPath.addLine(to: CGPoint(x: tipLeft + tipWidth, y: heightWithoutTip))
tipPath.closeSubpath()
fillColor.setFill()
currentContext.addPath(tipPath)
currentContext.fillPath()
}
}
This is what it looks like for a short title and a long title. When the title gets too long, I want the text to wrap and the bubble to get a taller height. As you can see in the image set below, the first 'Short Name' works fine as a map annotation bubble. When the name gets super long though, it just widens the bubble to the point it goes off the screen.
https://imgur.com/a/I5z0zUd
Any help on how to fix is much appreciated. Thanks!
To enable word-wrapping to multiple lines in a UIButton, you need to create your own button subclass.
For example:
class MultilineTitleButton: UIButton {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
func commonInit() -> Void {
self.titleLabel?.numberOfLines = 0
self.titleLabel?.textAlignment = .center
self.setContentHuggingPriority(UILayoutPriority.defaultLow + 1, for: .vertical)
self.setContentHuggingPriority(UILayoutPriority.defaultLow + 1, for: .horizontal)
}
override var intrinsicContentSize: CGSize {
let size = self.titleLabel!.intrinsicContentSize
return CGSize(width: size.width + contentEdgeInsets.left + contentEdgeInsets.right, height: size.height + contentEdgeInsets.top + contentEdgeInsets.bottom)
}
override func layoutSubviews() {
super.layoutSubviews()
titleLabel?.preferredMaxLayoutWidth = self.titleLabel!.frame.size.width
}
}
That button will wrap the title onto multiple lines, cooperating with auto-layout / constraints.
I don't have any projects with MapBox, but here is an example using a modified version of your CustomCalloutView. I commented out any MapBox specific code. You may be able to un-comment those lines and use this as-is:
class CustomCalloutView: UIView { //}, MGLCalloutView {
//var representedObject: MGLAnnotation
var repTitle: String = ""
// Allow the callout to remain open during panning.
let dismissesAutomatically: Bool = false
let isAnchoredToAnnotation: Bool = true
// https://github.com/mapbox/mapbox-gl-native/issues/9228
// NOTE: this causes a vertical shift when NOT using MapBox
// override var center: CGPoint {
// set {
// var newCenter = newValue
// newCenter.y -= bounds.midY
// super.center = newCenter
// }
// get {
// return super.center
// }
// }
lazy var leftAccessoryView = UIView() /* unused */
lazy var rightAccessoryView = UIView() /* unused */
//weak var delegate: MGLCalloutViewDelegate?
let tipHeight: CGFloat = 10.0
let tipWidth: CGFloat = 20.0
let mainBody: UIButton
var anchorView: UIView!
override func willMove(toSuperview newSuperview: UIView?) {
if newSuperview == nil {
anchorView.removeFromSuperview()
}
}
//required init(representedObject: MGLAnnotation) {
required init(title: String) {
self.repTitle = title
self.mainBody = MultilineTitleButton()
super.init(frame: .zero)
backgroundColor = .clear
mainBody.backgroundColor = .white
mainBody.setTitleColor(.black, for: [])
mainBody.tintColor = .black
mainBody.contentEdgeInsets = UIEdgeInsets(top: 10.0, left: 10.0, bottom: 10.0, right: 10.0)
mainBody.layer.cornerRadius = 4.0
addSubview(mainBody)
mainBody.translatesAutoresizingMaskIntoConstraints = false
let padding: CGFloat = 8.0
NSLayoutConstraint.activate([
mainBody.topAnchor.constraint(equalTo: self.topAnchor, constant: padding),
mainBody.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: padding),
mainBody.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -padding),
mainBody.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -padding),
])
}
required init?(coder decoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - MGLCalloutView API
func presentCallout(from rect: CGRect, in view: UIView, constrainedTo constrainedRect: CGRect, animated: Bool) {
//delegate?.calloutViewWillAppear?(self)
// since we'll be using auto-layout for the mutli-line button
// we'll add an "anchor view" to the superview
// it will be removed when self is removed
anchorView = UIView(frame: rect)
anchorView.isUserInteractionEnabled = false
anchorView.backgroundColor = .clear
view.addSubview(anchorView)
view.addSubview(self)
// Prepare title label.
//mainBody.setTitle(representedObject.title!, for: .normal)
mainBody.setTitle(self.repTitle, for: .normal)
// if isCalloutTappable() {
// // Handle taps and eventually try to send them to the delegate (usually the map view).
// mainBody.addTarget(self, action: #selector(CustomCalloutView.calloutTapped), for: .touchUpInside)
// } else {
// // Disable tapping and highlighting.
// mainBody.isUserInteractionEnabled = false
// }
self.translatesAutoresizingMaskIntoConstraints = false
anchorView.autoresizingMask = [.flexibleTopMargin, .flexibleLeftMargin, .flexibleRightMargin, .flexibleBottomMargin]
NSLayoutConstraint.activate([
self.centerXAnchor.constraint(equalTo: anchorView.centerXAnchor),
self.bottomAnchor.constraint(equalTo: anchorView.topAnchor),
self.widthAnchor.constraint(lessThanOrEqualToConstant: constrainedRect.width),
])
if animated {
alpha = 0
UIView.animate(withDuration: 0.2) { [weak self] in
guard let strongSelf = self else {
return
}
strongSelf.alpha = 1
//strongSelf.delegate?.calloutViewDidAppear?(strongSelf)
}
} else {
//delegate?.calloutViewDidAppear?(self)
}
}
func dismissCallout(animated: Bool) {
if (superview != nil) {
if animated {
UIView.animate(withDuration: 0.2, animations: { [weak self] in
self?.alpha = 0
}, completion: { [weak self] _ in
self?.removeFromSuperview()
})
} else {
removeFromSuperview()
}
}
}
// MARK: - Callout interaction handlers
// func isCalloutTappable() -> Bool {
// if let delegate = delegate {
// if delegate.responds(to: #selector(MGLCalloutViewDelegate.calloutViewShouldHighlight)) {
// return delegate.calloutViewShouldHighlight!(self)
// }
// }
// return false
// }
//
// #objc func calloutTapped() {
// if isCalloutTappable() && delegate!.responds(to: #selector(MGLCalloutViewDelegate.calloutViewTapped)) {
// delegate!.calloutViewTapped!(self)
// }
// }
// MARK: - Custom view styling
override func draw(_ rect: CGRect) {
print(#function)
// Draw the pointed tip at the bottom.
let fillColor: UIColor = .red
let tipLeft = rect.origin.x + (rect.size.width / 2.0) - (tipWidth / 2.0)
let tipBottom = CGPoint(x: rect.origin.x + (rect.size.width / 2.0), y: rect.origin.y + rect.size.height)
let heightWithoutTip = rect.size.height - tipHeight - 1
let currentContext = UIGraphicsGetCurrentContext()!
let tipPath = CGMutablePath()
tipPath.move(to: CGPoint(x: tipLeft, y: heightWithoutTip))
tipPath.addLine(to: CGPoint(x: tipBottom.x, y: tipBottom.y))
tipPath.addLine(to: CGPoint(x: tipLeft + tipWidth, y: heightWithoutTip))
tipPath.closeSubpath()
fillColor.setFill()
currentContext.addPath(tipPath)
currentContext.fillPath()
}
}
Here is a sample view controller showing that "Callout View" with various length titles, restricted to 70% of the width of the view:
class CalloutTestVC: UIViewController {
let sampleTitles: [String] = [
"Short Title",
"Slightly Longer Title",
"A ridiculously long title that will need to wrap!",
]
var idx: Int = -1
let tapView = UIView()
var ccv: CustomCalloutView!
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(red: 0.8939146399, green: 0.8417750597, blue: 0.7458069921, alpha: 1)
tapView.backgroundColor = .systemBlue
tapView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tapView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
tapView.centerYAnchor.constraint(equalTo: g.centerYAnchor),
tapView.centerXAnchor.constraint(equalTo: g.centerXAnchor),
tapView.widthAnchor.constraint(equalToConstant: 60),
tapView.heightAnchor.constraint(equalTo: tapView.widthAnchor),
])
// tap the Blue View to cycle through Sample Titles for the Callout View
// using the Blue view as the "anchor rect"
let t = UITapGestureRecognizer(target: self, action: #selector(gotTap))
tapView.addGestureRecognizer(t)
}
#objc func gotTap() -> Void {
if ccv != nil {
ccv.removeFromSuperview()
}
// increment sampleTitles array index
// to cycle through the strings
idx += 1
let validIdx = idx % sampleTitles.count
let str = sampleTitles[validIdx]
// create a new Callout view
ccv = CustomCalloutView(title: str)
// to restrict the "callout view" width to less-than 1/2 the screen width
// use view.width * 0.5 for the constrainedTo width
// may look better restricting it to 70%
ccv.presentCallout(from: tapView.frame, in: self.view, constrainedTo: CGRect(x: 0, y: 0, width: view.frame.size.width * 0.7, height: 100), animated: false)
}
}
It looks like this:
The UIButton class owns the titleLabel and is going to position and set the constraints on that label itself. More likely than not you are going to have to create a subclass of UIButton and override its "updateConstraints" method to position the titleLabel where you want it to go.
Your code should probably not be basing the size of the button off the size of the screen. It might set the size of off some other view in your hierarchy that happens to be the size of the screen but grabbing the screen bounds in the middle of setting a view's size is unusual.

How can I position these UIView elements from the right using CGRect to position

I have a UIView sub class that allows me to create a group of 'tags' for the footer of some content. At the moment however they are position aligned to the left edge, I would like them to be positioned from the right.
I have included a playground below that should run the screen shot you can see.
The position is set within the layoutSubviews method of CloudTagView.
I tried to play around with their position but have not been able to start them from the right however.
import UIKit
import PlaygroundSupport
// CLOUD VIEW WRAPPER - THIS IS THE CONTAINER FOR THE TAGS AND SETS UP THEIR FRAME
class CloudTagView: UIView {
weak var delegate: TagViewDelegate?
override var intrinsicContentSize: CGSize {
return frame.size
}
var removeOnDismiss = true
var resizeToFit = true
var tags = [TagView]() {
didSet {
layoutSubviews()
}
}
var padding = 5 {
didSet {
layoutSubviews()
}
}
var maxLengthPerTag = 0 {
didSet {
layoutSubviews()
}
}
public override init(frame: CGRect) {
super.init(frame: frame)
isUserInteractionEnabled = true
clipsToBounds = true
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
isUserInteractionEnabled = true
clipsToBounds = true
}
override func layoutSubviews() {
for tag in subviews {
tag.removeFromSuperview()
}
var xAxis = padding
var yAxis = padding
var maxHeight = 0
for (index, tag) in tags.enumerated() {
setMaxLengthIfNeededIn(tag)
tag.delegate = self
if index == 0 {
maxHeight = Int(tag.frame.height)
}else{
let expectedWidth = xAxis + Int(tag.frame.width) + padding
if expectedWidth > Int(frame.width) {
yAxis += maxHeight + padding
xAxis = padding
maxHeight = Int(tag.frame.height)
}
if Int(tag.frame.height) > maxHeight {
maxHeight = Int(tag.frame.height)
}
}
tag.frame = CGRect(x: xAxis, y: yAxis, width: Int(tag.frame.size.width), height: Int(tag.frame.size.height))
addSubview(tag)
tag.layoutIfNeeded()
xAxis += Int(tag.frame.width) + padding
}
if resizeToFit {
frame = CGRect(x: frame.origin.x, y: frame.origin.y, width: frame.size.width, height: CGFloat(yAxis + maxHeight + padding))
}
}
// MARK: Methods
fileprivate func setMaxLengthIfNeededIn(_ tag: TagView) {
if maxLengthPerTag > 0 && tag.maxLength != maxLengthPerTag {
tag.maxLength = maxLengthPerTag
}
}
}
// EVERYTHING BELOW HERE IS JUST SETUP / REQUIRED TO RUN IN PLAYGROUND
class ViewController:UIViewController{
let cloudView: CloudTagView = {
let view = CloudTagView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
let tags = ["these", "are", "my", "tags"]
tags.forEach { tag in
let t = TagView(text: tag)
t.backgroundColor = .darkGray
t.tintColor = .white
cloudView.tags.append(t)
}
view.backgroundColor = .white
view.addSubview(cloudView)
NSLayoutConstraint.activate([
cloudView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
cloudView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
cloudView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
cloudView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor)
])
}
}
// Tag View
class TagView: UIView {
weak var delegate: TagViewDelegate?
var text = "" {
didSet {
layoutSubviews()
}
}
var marginTop = 5 {
didSet {
layoutSubviews()
}
}
var marginLeft = 10 {
didSet {
layoutSubviews()
}
}
var iconImage = UIImage(named: "close_tag_2", in: Bundle(for: CloudTagView.self), compatibleWith: nil) {
didSet {
layoutSubviews()
}
}
var maxLength = 0 {
didSet {
layoutSubviews()
}
}
override var backgroundColor: UIColor? {
didSet {
layoutSubviews()
}
}
override var tintColor: UIColor? {
didSet {
layoutSubviews()
}
}
var font: UIFont = UIFont.systemFont(ofSize: 12) {
didSet {
layoutSubviews()
}
}
fileprivate let dismissView: UIView
fileprivate let icon: UIImageView
fileprivate let textLabel: UILabel
public override init(frame: CGRect) {
dismissView = UIView()
icon = UIImageView()
textLabel = UILabel()
super.init(frame: frame)
isUserInteractionEnabled = true
addSubview(textLabel)
addSubview(icon)
addSubview(dismissView)
dismissView.isUserInteractionEnabled = true
textLabel.isUserInteractionEnabled = true
dismissView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(TagView.iconTapped)))
textLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(TagView.labelTapped)))
backgroundColor = UIColor(white: 0.0, alpha: 0.6)
tintColor = UIColor.white
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public init(text: String) {
dismissView = UIView()
icon = UIImageView()
textLabel = UILabel()
super.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
isUserInteractionEnabled = true
addSubview(textLabel)
addSubview(icon)
addSubview(dismissView)
dismissView.isUserInteractionEnabled = true
textLabel.isUserInteractionEnabled = true
dismissView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(TagView.iconTapped)))
textLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(TagView.labelTapped)))
self.text = text
backgroundColor = UIColor(white: 0.0, alpha: 0.6)
tintColor = UIColor.white
}
override func layoutSubviews() {
icon.frame = CGRect(x: marginLeft, y: marginTop + 4, width: 8, height: 8)
icon.image = iconImage?.withRenderingMode(.alwaysTemplate)
icon.tintColor = tintColor
let textLeft: Int
if icon.image != nil {
dismissView.isUserInteractionEnabled = true
textLeft = marginLeft + Int(icon.frame.width ) + marginLeft / 2
} else {
dismissView.isUserInteractionEnabled = false
textLeft = marginLeft
}
textLabel.frame = CGRect(x: textLeft, y: marginTop, width: 100, height: 20)
textLabel.backgroundColor = UIColor(white: 0, alpha: 0.0)
if maxLength > 0 && text.count > maxLength {
textLabel.text = text.prefix(maxLength)+"..."
}else{
textLabel.text = text
}
textLabel.textAlignment = .center
textLabel.font = font
textLabel.textColor = tintColor
textLabel.sizeToFit()
let tagHeight = Int(max(textLabel.frame.height,14)) + marginTop * 2
let tagWidth = textLeft + Int(max(textLabel.frame.width,14)) + marginLeft
let dismissLeft = Int(icon.frame.origin.x) + Int(icon.frame.width) + marginLeft / 2
dismissView.frame = CGRect(x: 0, y: 0, width: dismissLeft, height: tagHeight)
frame = CGRect(x: Int(frame.origin.x), y: Int(frame.origin.y), width: tagWidth, height: tagHeight)
layer.cornerRadius = bounds.height / 2
}
// MARK: Actions
#objc func iconTapped(){
delegate?.tagDismissed?(self)
}
#objc func labelTapped(){
delegate?.tagTouched?(self)
}
}
// MARK: TagViewDelegate
#objc protocol TagViewDelegate {
#objc optional func tagTouched(_ tag: TagView)
#objc optional func tagDismissed(_ tag: TagView)
}
extension CloudTagView: TagViewDelegate {
public func tagDismissed(_ tag: TagView) {
delegate?.tagDismissed?(tag)
if removeOnDismiss {
if let index = tags.firstIndex(of: tag) {
tags.remove(at: index)
}
}
}
public func tagTouched(_ tag: TagView) {
delegate?.tagTouched?(tag)
}
}
let viewController = ViewController()
PlaygroundPage.current.liveView = viewController
PlaygroundPage.current.needsIndefiniteExecution = true
UIStackView can line subviews up in a row for you, including with trailing alignment. Here is a playground example:
import SwiftUI
import PlaygroundSupport
class V: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let tags = ["test", "testing", "test more"].map { word -> UIView in
let label = UILabel()
label.text = word
label.translatesAutoresizingMaskIntoConstraints = false
let background = UIView()
background.backgroundColor = .cyan
background.layer.cornerRadius = 8
background.clipsToBounds = true
background.addSubview(label)
NSLayoutConstraint.activate([
background.centerXAnchor.constraint(equalTo: label.centerXAnchor),
background.centerYAnchor.constraint(equalTo: label.centerYAnchor),
background.widthAnchor.constraint(equalTo: label.widthAnchor, constant: 16),
background.heightAnchor.constraint(equalTo: label.heightAnchor, constant: 16),
])
return background
}
let stack = UIStackView.init(arrangedSubviews: [UIView()] + tags)
stack.translatesAutoresizingMaskIntoConstraints = false
stack.axis = .horizontal
stack.alignment = .trailing
stack.spacing = 12
view.addSubview(stack)
NSLayoutConstraint.activate([
stack.topAnchor.constraint(equalTo: view.topAnchor),
stack.widthAnchor.constraint(equalTo: view.widthAnchor),
])
view.backgroundColor = .white
}
}
PlaygroundPage.current.liveView = V()

Make the UIImage to the rounded form? [closed]

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)
}
}

How to set corner radius to a collection of UIButtons

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)

Masking UIView/UIImageView to cutout transparent text

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