I wrote the below code to make the textfield only have bottom line,
the result show as the below image (the bottom line is not long enough to the right edge.)
func setBottomBorder() {
self.borderStyle = .none
self.layer.backgroundColor = UIColor.clear.cgColor
self.attributedPlaceholder = NSAttributedString(string:self.placeholder != nil ? self.placeholder! : "", attributes: [NSAttributedStringKey.foregroundColor: UIColor.white])
let border = CALayer()
let width = CGFloat(2.0)
border.borderColor = UIColor.white.cgColor
border.frame = CGRect(x: 0, y: self.frame.size.height - width, width: self.frame.size.width, height: self.frame.size.height)
border.borderWidth = width
self.layer.addSublayer(border)
self.layer.masksToBounds = true
}
As per My suggestion instead of progrmatically.
you should set it using StoryBoard:
A textfield with Hidden Border.
Below that you can take a label with white background and it is done.
Note:- Do not forget to give correct constraints to both so that it looks good
Related
I have a UITextView which changes size depending on the text the user inputs (the purple box), which is inside another UIView (the red box).
But when using a handwritten style font like this, the end character sometimes gets cut off at the edge:
I have tried used text1.clipsToBounds = false but that didn't show the edge of the character. Is there a way to show the full character without changing the width of the text view?
Also here is the code I am using to set up the text view:
let text1 = UITextView()
text1.text = ""
text1.font = UIFont(name: "Gotcha", size: 27)
text1.frame = CGRect(x: 10, y: 5, width: 70, height: 50)
text1.isScrollEnabled = false
text1.delegate = self
text1.textAlignment = .center
text1.isEditable = false
text1.isSelectable = false
holdingView.addSubview(text1)
The frame then gets updated with this function, and whenever the text is changed:
func adjustTextViewSize(_ textView: UITextView) {
let maxWidth = 300
let newSize = textView.sizeThatFits(CGSize(width: maxWidth, height: CGFloat.greatestFiniteMagnitude))
textView.frame = CGRect(x: (textView.frame.minX), y: (textView.frame.minY), width: newSize.width, height: newSize.height)
}
Thanks!
Update:
I solved this by adding an extra 30px to newSize.width for any font that is handwritten:
if fontFile?.isHandwritten == true {
currentView.widthConstraint?.constant = newSize.width + 30
currentTextHoldingView.widthConstraint?.constant = newSize.width + 30
}
call this function for get height according to string length
extension String {
func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin,
attributes: [NSAttributedString.Key.font: font], context: nil)
return ceil(boundingBox.height)
}
}
I wanted to recreate the AppStore's "today" cards with rounded corners and a light drop shadow.
I created a path, a maskLayer and a separate shadowLayer, which – according to several sources – is the way of doing it.
The problem, however, is that my lovely rounded rectangle with a shadow has got some gray strokes at it corners. How can I solve this? I tried different shadow opacities and different radii. It didn't solve my problem.
Here you can see my screenshots and my code below.
override func loadView() {
let view = UIView()
view.backgroundColor = .white
self.view = view
// create sample view and add to view hierarchy
let bigTeaser = UIView(frame: CGRect(x: 16, y: 200, width: 343, height: 267))
bigTeaser.backgroundColor = UIColor.white
view.addSubview(bigTeaser)
// create the path for the rounded corners and the shadow
let roundPath = UIBezierPath(roundedRect: bigTeaser.bounds, cornerRadius: 20)
// create maskLayer
let maskLayer = CAShapeLayer()
maskLayer.frame = bigTeaser.bounds
maskLayer.path = roundPath.cgPath
bigTeaser.layer.mask = maskLayer
// create shadowLayer
let shadowLayer = CAShapeLayer()
shadowLayer.path = roundPath.cgPath
shadowLayer.frame = bigTeaser.frame
shadowLayer.shadowOpacity = 0.3
shadowLayer.shadowRadius = 24
shadowLayer.shadowColor = UIColor.black.cgColor
shadowLayer.shadowOffset = CGSize(width: 0, height: 2)
// insert layers
bigTeaser.superview!.layer.insertSublayer(shadowLayer, below: bigTeaser.layer)
}
If you replace:
shadowLayer.path = roundPath.cgPath
to
shadowLayer.shadowPath = roundPath.cgPath
The ugly borders will magically disappear.
Hi there,
I have a class CardButton: UIButton . In the draw method of this CardButton, I would like to add and center(vertically and horizontally) NSAttributed String, which is basically just one Emoji, inside of it. The result would look something like this:
However, NSAttributedString can be only aligned to center in horizontal dimension inside the container.
My idea for solution:
create a containerView inside of CardButton
center containerView both vertically and horizontally in it's container(which is CardButton)
add NSAttributedString inside the containerView and size containerView to fit the string's font.
So the result would look something like this:
My attempt for this to happen looks like this:
class CardButton: UIButton {
override func draw(){
//succesfully drawing the CardButton
let stringToDraw = attributedString(symbol, fontSize: symbolFontSize) //custom method to create attributed string
let containerView = UIView()
containerView.backgroundColor = //green
addSubview(containerView)
containerView.translatesAutoresizingMaskIntoConstraints = false
let centerXConstraint = containerView.centerXAnchor.constraint(equalTo: (self.centerXAnchor)).isActive = true
let centerYConstraint = containerView.centerYAnchor.constraint(equalTo: (self.centerYAnchor)).isActive = true
stringToDraw.draw(in: containerView.bounds)
containerView.sizeToFit()
}
}
Long story short, I failed terribly. I first tried to add containerView to cardButton, made the background green, gave it fixed width and height jut to make sure that it got properly added as a subview. It did. But once I try to active constraints on it, it totally disappears.
Any idea how to approach this?
There is always more than one way to achieve any particular UI design goal, but the procedure below is relatively simple and has been adapted to suit the requirements as presented and understood in your question.
The UIButton.setImage method allows an image to be assigned to a UIButton without the need for creating a container explicitly.
The UIGraphicsImageRenderer method allows an image to be made from various components including NSAttributedText, and a host of custom shapes.
The process utilising these two tools to provide the rudiments for your project will be to:
Render an image with the appropriate components & size
Assign the rendered image to the button
A class could be created for this functionality, but that has not been explored here.
Additionally, your question mentions that when applying constraints the content disappears. This effect can be observed when image dimensions are too large for the container, constraints are positioning the content out of view and possibly a raft of other conditions.
The following code produces the above image:
func drawRectangleWithEmoji() -> UIImage {
let renderer = UIGraphicsImageRenderer(size: CGSize(width: 512, height: 512))
let img = renderer.image { (ctx) in
// Create the outer square:
var rectangle = CGRect(x: 0, y: 0, width: 512, height: 512).insetBy(dx: 7.5, dy: 7.5)
var roundedRect = UIBezierPath(roundedRect: rectangle, cornerRadius: 50).cgPath
// MARK: .cgPath creates a CG representation of the path
ctx.cgContext.setFillColor(UIColor.white.cgColor)
ctx.cgContext.setStrokeColor(UIColor.blue.cgColor)
ctx.cgContext.setLineWidth(15)
ctx.cgContext.addPath(roundedRect)
ctx.cgContext.drawPath(using: .fillStroke)
// Create the inner square:
rectangle = CGRect(x: 0, y: 0, width: 512, height: 512).insetBy(dx: 180, dy: 180)
roundedRect = UIBezierPath(roundedRect: rectangle, cornerRadius: 10).cgPath
ctx.cgContext.setFillColor(UIColor.green.cgColor)
ctx.cgContext.setStrokeColor(UIColor.green.cgColor)
ctx.cgContext.setLineWidth(15)
ctx.cgContext.addPath(roundedRect)
ctx.cgContext.drawPath(using: .fillStroke)
// Add emoji:
var fontSize: CGFloat = 144
var attrs: [NSAttributedString.Key: Any] = [
.font: UIFont.systemFont(ofSize: fontSize)//,
//.backgroundColor: UIColor.gray //uncomment to see emoji background bounds
]
var string = "❤️"
var attributedString = NSAttributedString(string: string, attributes: attrs)
let strWidth = attributedString.size().width
let strHeight = attributedString.size().height
attributedString.draw(at: CGPoint(x: 256 - strWidth / 2, y: 256 - strHeight / 2))
// Add NSAttributedString:
fontSize = 56
attrs = [
.font: UIFont.systemFont(ofSize: fontSize),
.foregroundColor: UIColor.brown
]
string = "NSAttributedString"
attributedString = NSAttributedString(string: string, attributes: attrs)
let textWidth = attributedString.size().width
let textHeight = attributedString.size().height
attributedString.draw(at: CGPoint(x: 256 - textWidth / 2, y: 384 - textHeight / 2))
}
return img
}
Activate the NSLayoutContraints and then the new image can be set for the button:
override func viewDidLoad() {
super.viewDidLoad()
view = UIView()
view.backgroundColor = .white
let buttonsView = UIView()
buttonsView.translatesAutoresizingMaskIntoConstraints = false
// buttonsView.backgroundColor = UIColor.gray
view.addSubview(buttonsView)
NSLayoutConstraint.activate([
buttonsView.widthAnchor.constraint(equalToConstant: CGFloat(buttonWidth)),
buttonsView.heightAnchor.constraint(equalToConstant: CGFloat(buttonWidth)),
buttonsView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
buttonsView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
let cardButton = UIButton(type: .custom)
cardButton.contentEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
cardButton.setImage(drawRectangleWithEmoji(), for: .normal)
let frame = CGRect(x: 0, y: 0, width: buttonWidth, height: buttonWidth)
cardButton.frame = frame
buttonsView.addSubview(cardButton)
}
Your comments will be appreciated as would constructive review of the code provided.
I want to set corner radius on bottom left and right side with border on UIView. here is code. **issue is it's not display SHARP in 1.5 border **
class BorderView: UIView {
override func draw(_ rect: CGRect) {
let color = UIColor.red
let color2 = UIColor.brown
//// Rectangle Drawing
let rectanglePath = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: 200, height: 200), byRoundingCorners: [.bottomRight, .bottomLeft], cornerRadii: CGSize(width: 10, height: 10))
rectanglePath.close()
color2.setFill()
rectanglePath.fill()
color.set()
rectanglePath.lineWidth = 1.5
rectanglePath.stroke()
}
}
OutPut
expected output
If you use the border and corner properties on CALayer, it should do it all for you.
// Probably inside init
layer.borderWidth = 1.5
layer.borderColor = UIColor.red.cgColor
layer.cornerRadius = 10
layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
This is what I'm getting with this code
private func setupBorders(){
let path = UIBezierPath(roundedRect: mainTableView.bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: 20, height: 20))
let maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath
mainTableView.layer.mask = maskLayer
mainTableView.layer.borderColor = UIColor.darkGray.cgColor
mainTableView.layer.borderWidth = 1.0
}
MainTableView is a uiview containing the notepad table and the table header. If I can get it to work for any UIView then it will work for this one. Much appreciation to anyone who can help!
Edit: In case its not clear, the problem is the border disappears on the rounded corners.
A mask layer is not enough to solve your requirement, because the layer border will not respect to the layer mask. Instead you should create a view for drawing the backgound and the border, and it should clip its contents along the border, too.
In storyboard drag a UIView to your ViewController, set constrains as you want, link it to NewView and try this,
import UIKit
import QuartzCore
class ViewController: UIViewController{
#IBOutlet var NewView :UIView!
override func viewDidLoad() {
super.viewDidLoad()
let screenSize: CGRect = UIScreen.mainScreen().bounds
let HeightFloat :CGFloat = screenSize.height - 60
let WidthFloat :CGFloat = screenSize.width - 50
let NewRect :CGRect = CGRectMake(10, 20, WidthFloat, HeightFloat)
let maskPath = UIBezierPath(roundedRect: NewRect,
byRoundingCorners: [.TopLeft, .TopRight],
cornerRadii: CGSize(width: 10, height: 10))
let shape = CAShapeLayer()
shape.path = maskPath.CGPath
shape.fillColor = UIColor.clearColor().CGColor
shape.strokeColor = UIColor.darkGrayColor().CGColor
shape.lineWidth = 2
shape.lineJoin = kCALineJoinRound
NewView.layer.mask = shape
}
}
You will get your output,