Button Border with Transparent Background in Swift - swift

How can I make a UIButton border to look alike in the below image (the "Getting Started") button with a transparent background?
How should I achieve this using storyboard or how to do it programmatically?

Setting the backgroundColor to clearColor makes the button transparent.Try the code below for example. You can configure and vary the borderAlpha,cornerRadius and colours as your want.
let borderAlpha : CGFloat = 0.7
let cornerRadius : CGFloat = 5.0
button.frame = CGRectMake(100, 100, 200, 40)
button.setTitle("Get Started", forState: UIControlState.Normal)
button.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
button.backgroundColor = UIColor.clearColor()
button.layer.borderWidth = 1.0
button.layer.borderColor = UIColor(white: 1.0, alpha: borderAlpha).CGColor
button.layer.cornerRadius = cornerRadius

Swift 5
Similar to #rakeshbs, but in Swift 5:
let borderAlpha : CGFloat = 0.7
let cornerRadius : CGFloat = 5.0
self.frame = CGRect(x: 100, y: 100, width: 200, height: 40)
self.setTitle("Login", for: UIControl.State.normal)
self.setTitleColor(UIColor.white, for: UIControl.State.normal)
self.backgroundColor = UIColor.clear
self.layer.borderWidth = 1.0
self.layer.borderColor = UIColor(white: 1.0, alpha: borderAlpha).cgColor
self.layer.cornerRadius = cornerRadius

using Extension:
extension UIButton
{
func setUpLayer(sampleButton: UIButton?) {
sampleButton!.setTitle("GET STARTED", forState: UIControlState.Normal)
sampleButton?.tintColor = UIColor.whiteColor()
sampleButton!.frame = CGRect(x:50, y:500, width:170, height:40)
sampleButton!.layer.borderWidth = 1.0
sampleButton!.layer.borderColor = UIColor.whiteColor().colorWithAlphaComponent(0.5).CGColor
sampleButton!.layer.cornerRadius = 5.0
sampleButton!.layer.shadowRadius = 3.0
sampleButton!.layer.shadowColor = UIColor.whiteColor().CGColor
sampleButton!.layer.shadowOpacity = 0.3
}
}
Usage:
let sampleUIButton = UIButton()
sampleUIButton.setUpLayer(sampleUIButton)
self.view.addSubview(sampleUIButton)

Using Swift 3, for Storyboard, just add this subclass to your project, then in the Identity Inspector, make this the class for the UIButton on your storyboard. You should then be able to adjust the boarder color and width.
#IBDesignable class CustomButton: UIButton {
#IBInspectable var borderColor: UIColor = UIColor.white {
didSet {
layer.borderColor = borderColor.cgColor
}
}
#IBInspectable var borderWidth: CGFloat = 2.0 {
didSet {
layer.borderWidth = borderWidth
}
}
override public func layoutSubviews() {
super.layoutSubviews()
clipsToBounds = true
}
}

Related

UIKit - How to prevent default blur and focus background of UITextField?

As you can see in the image, the UITextField (only on tvOS?) by default has these behaviors:
A translucent overlay (make the background and the white text grey in the second button)
A white background and bigger size when it's focused (the first button)
How do I remove/change these behaviors?
What did I do?
I tried to change all color related property (except text color) in Interface Builder to Clear color
I used these code to build the view programmatically
let view = UITextField()
view.backgroundColor = .clear
view.translatesAutoresizingMaskIntoConstraints = false
view.font = view.font?.withSize(16)
view.textAlignment = .center
view.borderStyle = .none
view.tintColor = .clear
view.tintAdjustmentMode = .normal
view.accessibilityIgnoresInvertColors = true
view.textColor = .white
view.disabledBackground = .none
view.background = .none
view.layer.backgroundColor = CGColor(gray: 0.0, alpha: 0.0)
view.layer.shadowColor = CGColor(gray: 0.0, alpha: 0.0)
view.layer.borderColor = CGColor(gray: 0.0, alpha: 0.0)
view.layer.shadowOpacity = 0.0
Additional Information
A new tvOS app project, created with XCode 12.2 in macOS 10.15.7
Run on Apple TV simulator
No additional libraries/pods used
Actually we always can inherit UIKit classes and do whatever layout/style we want. Here is very raw demo of how this can be done.
Prepared & tested with Xcode 12.1 / tvOS 14.0
So just substitute custom subclass of UITextField class
class MyTextField: UITextField {
lazy var textLayer = CATextLayer()
override func didMoveToSuperview() {
super.didMoveToSuperview()
layer.backgroundColor = UIColor.clear.cgColor
textLayer.font = self.font
textLayer.fontSize = 36
textLayer.foregroundColor = UIColor.white.cgColor
textLayer.alignmentMode = .center
textLayer.frame = layer.bounds
layer.addSublayer(textLayer)
layer.borderWidth = 2
}
override func layoutSublayers(of layer: CALayer) {
layer.borderColor = self.isFocused ? UIColor.black.cgColor : UIColor.clear.cgColor
textLayer.frame = layer.bounds
textLayer.string = self.text?.isEmpty ?? true ? self.placeholder : self.text
}
override func addSubview(_ view: UIView) {
// blocks standard styling
}
}

How to have a button call a method programmatically in a class in swift?

I want the button to slide off the screen when it's hit, but that part of the code (buttonPressed) isn't working. When the method buttonPressed is inside the class, nothing happens when the button is pressed. Move the method outside of the brackets (to right before viewDidLoad) and the code executes. However, then it slides the entire view as opposed to just the tutorial window. I either need to find a way to make buttonPressed work as a method of the Tutorial class, or find a way to make it refer to the specific instance of "view" that's called in the class.
I'm new to coding and very new to methods, so any help is appreciated!
class Tutorial{
var label = UILabel()
var view = UIView()
var button = UIButton()
init (text: String){
view = UIView()
label = UILabel(frame: CGRect(x: 10, y: 10, width: 180, height: 90))
button = UIButton(frame: CGRect(x: 50, y: 110, width: 100, height: 30))
view.backgroundColor = .white
view.layer.cornerRadius = 15
view.translatesAutoresizingMaskIntoConstraints = false
label.textAlignment = .center
label.text = text
label.numberOfLines = 10
label.backgroundColor = .white
label.textColor = UIColor(red:0.12, green:0.15, blue:0.23, alpha:1.0)
button.backgroundColor = UIColor(red:0.23, green:0.72, blue:0.44, alpha:1.0)
button.setTitleColor(.white, for: .normal)
button.setTitle("Got it!", for: .normal)
button.layer.cornerRadius = 15
view.addSubview(label)
view.addSubview(button)
button.addTarget(self, action: #selector(buttonPressed), for: UIControlEvents.touchUpInside)
}
func setConstraints(height: CGFloat){
view.centerXAnchor.constraint(equalTo: view.superview!.centerXAnchor).isActive = true
view.topAnchor.constraint(equalTo: view.superview!.topAnchor, constant: UIScreen.main.bounds.height-300).isActive = true
view.widthAnchor.constraint(equalToConstant: 200).isActive = true
view.heightAnchor.constraint(equalToConstant: height).isActive = true
UIView.animate(withDuration: 0.5, delay: 0.2, options: [], animations: {
self.view.center.x -= UIScreen.main.bounds.width
})
}
#objc func buttonPressed(){
print("Pressed")
UIView.animate(withDuration: 0.5, delay: 0.0, options: [], animations: {
self.view.center.x -= UIScreen.main.bounds.width
},
completion: { (finished: Bool) in
self.view.isHidden = true
})
}
}
override func viewDidLoad() {
super.viewDidLoad()
let tutorial1 = Tutorial(text: "Click and hold to see the anatomy overlay")
self.view.addSubview(tutorial1.view)
tutorial1.setConstraints(height: 150)
Try using Interface Builder Constants. Here is the Apple Documentation. https://developer.apple.com/documentation/appkit/constants/interface_builder_constants?language=objc
make an IBOutlet and an IBAction for your button.

Swift - Customizing UISearchBar design programmatically

I'm trying to customize UISearchBar design programmatically. I tried adding a bunch of codes but only a few places are changed.
This is the design I want to create.
And this is how it looks now.
I screen-captured the second image from the simulator so it's bigger.
Anyways, I'm trying to make my search bar has
Lighter background color
Shorter textfield in height
Textfield to have less corner radious
Here are my codes:
let searchBar = UISearchBar(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 60))
[In viewDidLoad()]
searchBar.delegate = self
searchBar.isTranslucent = false
searchBar.placeholder = "Search the phrase"
searchBar.tintColor = UIColor(red:0.73, green:0.76, blue:0.78, alpha:1.0)
searchBar.setImage(UIImage(named: "search"), for: .search, state: .normal)
let forTextField = searchBar.value(forKey: "searchField") as? UITextField
forTextField?.textColor = UIColor(red:0.31, green:0.31, blue:0.31, alpha:1.0)
forTextField?.font = UIFont(name: "HelveticaNeue-Light", size: 14)
forTextField?.clipsToBounds = true
forTextField?.layer.cornerRadius = 5
forTextField?.frame.size.height = 30
I would appreciate your help!
Here is the way you can achieve that:
class ViewController: UIViewController, UISearchBarDelegate {
let searchBar = UISearchBar(frame: CGRect(x: 0, y: 20, width: UIScreen.main.bounds.width, height: 60))
override func viewDidLoad() {
super.viewDidLoad()
searchBar.delegate = self
searchBar.isTranslucent = false
searchBar.placeholder = "Search the phrase"
searchBar.tintColor = UIColor(red:0.73, green:0.76, blue:0.78, alpha:1.0)
//1. Lighter background color
searchBar.barTintColor = UIColor(netHex: 0xE6E6E6)
self.view.addSubview(searchBar)
}
override func viewDidAppear(_ animated: Bool) {
for subView in searchBar.subviews {
for subsubView in subView.subviews {
if let textField = subsubView as? UITextField {
var bounds: CGRect
bounds = textField.frame
//2. Shorter textfield in height
bounds.size.height = 28
textField.bounds = bounds
//3. Textfield to have less corner radious
textField.layer.cornerRadius = 5 //Probably you can play with this and see the changes.
textField.clipsToBounds = true
}
}
}
}
}
extension UIColor {
convenience init(r: Int, g: Int, b: Int, a: Int = 255) {
self.init(red: CGFloat(r) / 255.0, green: CGFloat(g) / 255.0, blue: CGFloat(b) / 255.0, alpha: CGFloat(a) / 255.0)
}
convenience init(netHex:Int) {
self.init(r:(netHex >> 16) & 0xff, g:(netHex >> 8) & 0xff, b:netHex & 0xff)
}
}

Multiple buttons on iPhone - Swift

I am trying to put multiple buttons on an iPhone app with an function, only when I run the function the 2nd time , does the button show. It doesn't show the two buttons which I have configured it to run.
class ViewController: UIViewController {
let button = UIButton.buttonWithType(UIButtonType.System) as UIButton
let screensize: CGRect = UIScreen.mainScreen().bounds
override func viewDidLoad() {
super.viewDidLoad()
println(screensize.size.height)
blur()
// add iphone 2 buttons
let rect : CGRect = CGRectMake(100, 50, 200, 50)
var rectObj = NSValue(CGRect: rect)
showButton("Hello", rect: rectObj, redvalue: 1.0, greenvalue: 0.5, bluevalue: 0.5, alphavalue: 1.0)
let rect1 : CGRect = CGRectMake(20, 50, 200, 50)
var rectObj1 = NSValue(CGRect: rect)
showButton("Good bye", rect: rectObj1, redvalue: 0.5, greenvalue: 0.5, bluevalue: 0.5, alphavalue: 1.0)
}
func showButton(title: String, rect: NSValue, redvalue : CGFloat, greenvalue: CGFloat, bluevalue: CGFloat, alphavalue : CGFloat)
{
var rectRestored : CGRect = rect.CGRectValue()
button.frame = CGRectMake(rectRestored.origin.x, rectRestored.origin.y, rectRestored.width, rectRestored.height)
button.backgroundColor = UIColor(red: redvalue , green: greenvalue, blue: bluevalue, alpha: alphavalue)
button.setTitle(title, forState: UIControlState.Normal)
self.view.addSubview(button)
}
func blur()
{
var blur = UIVisualEffectView(effect: UIBlurEffect(style: .Light)) as UIVisualEffectView
blur.frame = self.view.frame
self.view.addSubview(blur)
}
Does addSubView overwrite it ? If so I have tried insersubview : index and that doesn't seem to work either.
Try to call the method in viewWillAppear insted of viewDidLoad, because in viewDidLoad you still may not have the appropriate frame for main view.

Adding rounded corner and drop shadow to UICollectionViewCell

So I already went through various posts on adding 2nd view for adding shadow, but I still cannot get it to work if I want to add it in UICollectionViewCell. I subclassed UICollectionViewCell, and here is my code where I add various UI elements to the cell's content view and adding shadow to the layer:
[self.contentView setBackgroundColor:[UIColor whiteColor]];
self.layer.masksToBounds = NO;
self.layer.shadowOffset = CGSizeMake(0, 1);
self.layer.shadowRadius = 1.0;
self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowOpacity = 0.5;
[self.layer setShadowPath:[[UIBezierPath bezierPathWithRect:self.bounds] CGPath]];
I would like to know how to add rounded corner and shadow to UICollectionViewCell.
Neither of these solutions worked for me. If you place all your subviews into the UICollectionViewCell content view, which you probably are, you can set the shadow on the cell's layer and the border on the contentView's layer to achieve both results.
cell.contentView.layer.cornerRadius = 2.0f;
cell.contentView.layer.borderWidth = 1.0f;
cell.contentView.layer.borderColor = [UIColor clearColor].CGColor;
cell.contentView.layer.masksToBounds = YES;
cell.layer.shadowColor = [UIColor blackColor].CGColor;
cell.layer.shadowOffset = CGSizeMake(0, 2.0f);
cell.layer.shadowRadius = 2.0f;
cell.layer.shadowOpacity = 0.5f;
cell.layer.masksToBounds = NO;
cell.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds cornerRadius:cell.contentView.layer.cornerRadius].CGPath;
Swift 3.0
self.contentView.layer.cornerRadius = 2.0
self.contentView.layer.borderWidth = 1.0
self.contentView.layer.borderColor = UIColor.clear.cgColor
self.contentView.layer.masksToBounds = true
self.layer.shadowColor = UIColor.black.cgColor
self.layer.shadowOffset = CGSize(width: 0, height: 2.0)
self.layer.shadowRadius = 2.0
self.layer.shadowOpacity = 0.5
self.layer.masksToBounds = false
self.layer.shadowPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.contentView.layer.cornerRadius).cgPath
Swift 3 version:
cell.contentView.layer.cornerRadius = 10
cell.contentView.layer.borderWidth = 1.0
cell.contentView.layer.borderColor = UIColor.clear.cgColor
cell.contentView.layer.masksToBounds = true
cell.layer.shadowColor = UIColor.gray.cgColor
cell.layer.shadowOffset = CGSize(width: 0, height: 2.0)
cell.layer.shadowRadius = 2.0
cell.layer.shadowOpacity = 1.0
cell.layer.masksToBounds = false
cell.layer.shadowPath = UIBezierPath(roundedRect:cell.bounds, cornerRadius:cell.contentView.layer.cornerRadius).cgPath
In case it helps: Here is the swift for rounding the corners:
cell.layer.cornerRadius = 10
cell.layer.masksToBounds = true
with cell being a variable controlling the cell: often, you will use this in override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
Enjoy!
Here's my answer, close to the others, but I add a corner radius to the layer otherwise the corners won't fill in correctly. Also, this makes a nice little extension on UICollectionViewCell.
extension UICollectionViewCell {
func shadowDecorate() {
let radius: CGFloat = 10
contentView.layer.cornerRadius = radius
contentView.layer.borderWidth = 1
contentView.layer.borderColor = UIColor.clear.cgColor
contentView.layer.masksToBounds = true
layer.shadowColor = UIColor.black.cgColor
layer.shadowOffset = CGSize(width: 0, height: 1.0)
layer.shadowRadius = 2.0
layer.shadowOpacity = 0.5
layer.masksToBounds = false
layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: radius).cgPath
layer.cornerRadius = radius
}
}
You can call it in collectionView(_:cellForItemAt:) of the datasource once you dequeue your cell.
Here the Swift 4 solution, updated to round every corners and not only the top corners:
contentView.layer.cornerRadius = 6.0
contentView.layer.borderWidth = 1.0
contentView.layer.borderColor = UIColor.clear.cgColor
contentView.layer.masksToBounds = true
layer.shadowColor = UIColor.lightGray.cgColor
layer.shadowOffset = CGSize(width: 0, height: 2.0)
layer.shadowRadius = 6.0
layer.shadowOpacity = 1.0
layer.masksToBounds = false
layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: contentView.layer.cornerRadius).cgPath
layer.backgroundColor = UIColor.clear.cgColor
Set the layer attributes for the cell, not contentView.
CALayer * layer = [cell layer];
[layer setShadowOffset:CGSizeMake(0, 2)];
[layer setShadowRadius:1.0];
[layer setShadowColor:[UIColor redColor].CGColor] ;
[layer setShadowOpacity:0.5];
[layer setShadowPath:[[UIBezierPath bezierPathWithRect:cell.bounds] CGPath]];
SWIFT 4.2
One should add this in your custom cell or cellForItemAt:
If you are using the cellForItemAt: approach substitute self -> cell
self.layer.cornerRadius = 10
self.layer.borderWidth = 1.0
self.layer.borderColor = UIColor.lightGray.cgColor
self.layer.backgroundColor = UIColor.white.cgColor
self.layer.shadowColor = UIColor.gray.cgColor
self.layer.shadowOffset = CGSize(width: 2.0, height: 4.0)
self.layer.shadowRadius = 2.0
self.layer.shadowOpacity = 1.0
self.layer.masksToBounds = false
This will give you a cell with a rounded border and a drop shadow.
You simply need to (a) set cornerRadius and (b) set shadowPath to be a rounded rect with the same radius as cornerRadius:
self.layer.cornerRadius = 10;
self.layer.shadowPath = [[UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:self.layer.cornerRadius] CGPath];
Here's my take on the solution. It's similar to other answers, with one key difference. It doesn't create a path that's dependent on the bounds of the view. Anytime you create a path based on the bounds and provide it to the layer you can run into issues when it's resizing, and need to setup methods to update the path.
A simpler solution is to avoid using anything that is bounds dependent.
let radius: CGFloat = 10
self.contentView.layer.cornerRadius = radius
// Always mask the inside view
self.contentView.layer.masksToBounds = true
self.layer.shadowColor = UIColor.black.cgColor
self.layer.shadowOffset = CGSize(width: 0, height: 1.0)
self.layer.shadowRadius = 3.0
self.layer.shadowOpacity = 0.5
// Never mask the shadow as it falls outside the view
self.layer.masksToBounds = false
// Matching the contentView radius here will keep the shadow
// in sync with the contentView's rounded shape
self.layer.cornerRadius = radius
Now when ever the cells size change the view API will do all the work internally.
I had to make some slight changes for Swift:
cell.contentView.layer.cornerRadius = 2.0;
cell.contentView.layer.borderWidth = 1.0;
cell.contentView.layer.borderColor = UIColor.clearColor().CGColor;
cell.contentView.layer.masksToBounds = true;
cell.layer.shadowColor = UIColor.grayColor().CGColor;
cell.layer.shadowOffset = CGSizeMake(0, 2.0);
cell.layer.shadowRadius = 2.0;
cell.layer.shadowOpacity = 1.0;
cell.layer.masksToBounds = false;
cell.layer.shadowPath = UIBezierPath(roundedRect:cell.bounds, cornerRadius:cell.contentView.layer.cornerRadius).CGPath;
I use the following method to accomplish this kind of effect:
extension UICollectionViewCell {
/// Call this method from `prepareForReuse`, because the cell needs to be already rendered (and have a size) in order for this to work
func shadowDecorate(radius: CGFloat = 8,
shadowColor: UIColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.3),
shadowOffset: CGSize = CGSize(width: 0, height: 1.0),
shadowRadius: CGFloat = 3,
shadowOpacity: Float = 1) {
contentView.layer.cornerRadius = radius
contentView.layer.borderWidth = 1
contentView.layer.borderColor = UIColor.clear.cgColor
contentView.layer.masksToBounds = true
layer.shadowColor = shadowColor.cgColor
layer.shadowOffset = shadowOffset
layer.shadowRadius = shadowRadius
layer.shadowOpacity = shadowOpacity
layer.masksToBounds = false
layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: radius).cgPath
layer.cornerRadius = radius
}
}
The answer of Mike Sabatini works fine, if you configure the cell properties directly on the collectionView cellForItemAt, but if you try to set them in awakeFromNib() of a custom UICollectionViewCell subclass, you will end with a wrong bezierPath set on the devices that doesn't match the width and height previously set in your Storyboard (IB).
Solution for me was create a func inside the subclass of UICollectionViewCell and calling it from the cellForItemAt like this:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellID", for: indexPath) as? CustomCollectionViewCell{
cell.configure())
return cell
}
else {
return UICollectionViewCell()
}
}
And on the CustomCollectionViewCell.swift :
class CustomCollectionViewCell: UICollectionViewCell{
func configure() {
contentView.layer.cornerRadius = 20
contentView.layer.borderWidth = 1.0
contentView.layer.borderColor = UIColor.clear.cgColor
contentView.layer.masksToBounds = true
layer.shadowColor = UIColor.black.cgColor
layer.shadowOffset = CGSize(width: 0, height: 2.0)
layer.shadowRadius = 2.0
layer.shadowOpacity = 0.5
layer.masksToBounds = false
layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: contentView.layer.cornerRadius).cgPath}
}
This one worked for me
cell.contentView.layer.cornerRadius = 5.0
cell.contentView.layer.borderColor = UIColor.gray.withAlphaComponent(0.5).cgColor
cell.contentView.layer.borderWidth = 0.5
let border = CALayer()
let width = CGFloat(2.0)
border.borderColor = UIColor.darkGray.cgColor
border.frame = CGRect(x: 0, y: cell.contentView.frame.size.height - width, width: cell.contentView.frame.size.width, height: cell.contentView.frame.size.height)
border.borderWidth = width
cell.contentView.layer.addSublayer(border)
cell.contentView.layer.masksToBounds = true
cell.contentView.clipsToBounds = true
You can set shadow color, radius and offset in UICollectionViewDataSource method while creating a UICollectionViewCell
cell.layer.shadowColor = UIColor.gray.cgColor
cell.layer.shadowOffset = CGSize(width: 0, height: 2.0)
cell.layer.shadowRadius = 1.0
cell.layer.shadowOpacity = 0.5
cell.layer.masksToBounds = false
I found an important thing: the UICollectionViewCell must have the backgroundColor as clear color in order to make these above work.
Swift 5, Xcode 13, iOS 14
First config your collection as below:
self.collectionView.clipsToBounds = false
Then config your cell same as below:
override func awakeFromNib() {
super.awakeFromNib()
self.configView()
}
private func configView() {
self.clipsToBounds = false
self.backgroundColor = .systemBackground
self.layer.cornerRadius = 10
self.layer.shadowColor = UIColor.black.cgColor
self.layer.shadowOffset = CGSize(width: 0, height: 0.0)
self.layer.shadowRadius = 10
self.layer.shadowOpacity = 0.2
}
Note to those two "clipToBounds = false" commands.
Just that.