How to set the corner radius to 50% [duplicate] - ios

This question already has answers here:
Set UIView's corner radius to half of the view's width automatically
(3 answers)
Closed 11 months ago.
I have an image view inside a collection view cell. I would like to set the corner radius of the image to 50% of its width (so it's a circle). How can I do this?
Here's my code so far
//
// CategoryCell.swift
// UICollectionViewDemo
//
import UIKit
final class Category3Cell: UICollectionViewCell {
private enum Constants {
// MARK: contentView layout constants
static let contentViewCornerRadius: CGFloat = 0.0
// MARK: imageView layout constants
static let imageWidth: CGFloat = 90.0
static let imageHeight: CGFloat = 90.0
// MARK: Generic layout constants
static let verticalSpacing: CGFloat = 10.0
static let horizontalPadding: CGFloat = 16.0
static let nameImagePadding: CGFloat = 20.0
}
public var categoryKey : String = "";
private let imageView: UIImageView = {
let imageView = UIImageView(frame: .zero)
imageView.contentMode = .scaleAspectFit
imageView.layer.cornerRadius = 45
imageView.layer.masksToBounds = true
return imageView
}()
private let name: UILabel = {
let label = UILabel(frame: .zero)
label.textAlignment = .center
label.numberOfLines = 0
label.font = UIFont(name: "CeraPro-Regular", size: 17);
return label
}()
override init(frame: CGRect) {
super.init(frame: .zero)
setupViews()
setupLayouts()
}
private func setupViews() {
contentView.clipsToBounds = true
contentView.layer.cornerRadius = Constants.contentViewCornerRadius
contentView.backgroundColor = .clear
contentView.isUserInteractionEnabled = true
contentView.addSubview(imageView)
contentView.addSubview(name)
}
private func setupLayouts() {
imageView.translatesAutoresizingMaskIntoConstraints = false
name.translatesAutoresizingMaskIntoConstraints = false
// Layout constraints for `imageView`
NSLayoutConstraint.activate([
imageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
imageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
imageView.topAnchor.constraint(equalTo: contentView.topAnchor),
imageView.heightAnchor.constraint(equalToConstant: Constants.imageWidth),
imageView.heightAnchor.constraint(equalToConstant: Constants.imageHeight)
])
// Layout constraints for `usernameLabel`
NSLayoutConstraint.activate([
name.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: Constants.horizontalPadding),
name.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -Constants.horizontalPadding),
name.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: Constants.nameImagePadding)
])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setup(image: String, nameOf: String, key: String) {
imageView.image = UIImage.init(named: image)
name.text = nameOf
categoryKey = key
}
}
extension Category3Cell: ReusableView {
static var identifier: String {
return String(describing: self)
}
}

you need first the clipsToBounds set to true and then if you know the image size, you can set its layer.cornerRadius to half of that size.
Alternatively you can use the layoutSubviews method, and in its override access the imageView bounds.height and use half of this for the corner radius.
Try this code:
imageView.layer.cornerRadius = imageView.frame.height / 2

Set width and height at first, then set imageView.layer.cornerRadius = imageView.frame.height / 2.
class ViewController: UIViewController {
private let imageView: UIImageView = {
let imageView = UIImageView(frame: .zero)
imageView.contentMode = .scaleAspectFit
return imageView
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
imageView.frame = CGRect(x: 100, y: 100, width: 100, height: 100);
imageView.layer.cornerRadius = 45
imageView.layer.masksToBounds = true
self.view.addSubview(imageView)
imageView.image = UIImage.init(named: "+")
}
}

Related

Portion of UIlabel clipped

Hi,
I have collection view cell and it appears that some portion of label is clipped. Here is my code:
class FeedbackTagCell: BaseCollectionCell {
override func prepare() {
super.prepare()
setup()
setConstraints()
}
private let lbl: UILabel = {
let lbl = UILabel()
lbl.translatesAutoresizingMaskIntoConstraints = false
lbl.numberOfLines = 1
return lbl
}()
private let icon: UIImageView = {
let imgView = UIImageView()
imgView.translatesAutoresizingMaskIntoConstraints = false
imgView.contentMode = .scaleAspectFit
return imgView
}()
private func setup() {
contentView.layer.cornerRadius = 4.0
contentView.addSubview(lbl)
contentView.addSubview(icon)
}
private func setConstraints() {
let iconLeftOffset: CGFloat = 8
let iconRightOffset: CGFloat = 15
let lblVerticalOffset: CGFloat = 8
let lblLeftOffset: CGFloat = 16
let iconHeightWidth: CGFloat = 10
NSLayoutConstraint.activate([
lbl.leftAnchor.constraint(equalTo: leftAnchor, constant: lblLeftOffset),
lbl.rightAnchor.constraint(equalTo: icon.leftAnchor, constant: -iconLeftOffset),
lbl.topAnchor.constraint(equalTo: contentView.topAnchor, constant: lblVerticalOffset),
lbl.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -lblVerticalOffset),
icon.rightAnchor.constraint(equalTo: rightAnchor, constant: -iconRightOffset),
icon.centerYAnchor.constraint(equalTo: centerYAnchor),
icon.heightAnchor.constraint(equalToConstant: iconHeightWidth),
icon.widthAnchor.constraint(equalToConstant: iconHeightWidth)
])
}
}

Multiline UILabel on navigation bar title view

I have a custom UIView which has 2 UILabel (same width) and one UIImageView (known width of 44pt). Width sizes are given as an example, they can change but It is exact that UILabels should has same width and UIImage has a 44 point width. I want to add this view to UINavigationBar' titleView BUT ImageView should be in the center of navigation bar.
(60 width) UILabel---UIImageView (44 width) ---UILabel (60 width)
I want is that UILabels to have maximum two line and adJustFontSizeToFitWidth true. I'm giving specific width and height to title view but labels get two line but their font size doesn't change even they don't fit the view.
How I add titleView:
navigationItem.titleView = myTitleView
let widthOfItem: CGFloat = 30.0
let pading: CGFloat = 40
let aWidth: CGFloat = (self.navigationController?.navigationBar.frame.width)! - CGFloat(1) * widthOfItem * 2.0 - pading
myTitleView { (make) in
make.width.equalTo(aWidth)
make.height.equalTo(44)
}
MyCustomView:
override func layoutSubviews() {
super.layoutSubviews()
let preferredWidth = (bounds.width / 2) - 56
firstLabel.preferredMaxLayoutWidth = preferredWidth
secondLabel.preferredMaxLayoutWidth = preferredWidth
}
private func setupViews() {
addSubview(firstLabel)
addSubview(myImageView)
addSubview(secondLabel)
firstLabel.font = .myFont(.bold, size: 36)
firstLabel.adjustsFontSizeToFitWidth = true
firstLabel.minimumScaleFactor = 0.5
firstLabel.textColor = .textPrimary
firstLabel.numberOfLines = 2
firstLabel.lineBreakMode = .byWordWrapping
firstLabel.textAlignment = .right
myImageView.contentMode = .scaleAspectFit
myImageView.clipsToBounds = true
myImageView.layer.minificationFilter = .trilinear
myImageView.layer.cornerRadius = currencyImageSize.height / 2
secondLabel.font = . myFont(.bold, size: 36)
secondLabel.translatesAutoresizingMaskIntoConstraints = false
secondLabel.textColor = .textPrimary
secondLabel.numberOfLines = 2
secondLabel.adjustsFontSizeToFitWidth = true
secondLabel.baselineAdjustment = .none
secondLabel.minimumScaleFactor = 0.5
secondLabel.lineBreakMode = .byWordWrapping
secondLabel.textAlignment = .left
firstLabel.snp.makeConstraints { (make) in
make.leading.equalToSuperview()
make.top.bottom.equalToSuperview()
make.trailing.equalTo(myImageView.snp.leading).offset(-12)
}
myImageView.snp.makeConstraints { (make) in
make.height.equalToSuperview()
make.width.equalTo(myImageView.snp.height)
make.centerX.equalToSuperview()
}
secondLabel.snp.makeConstraints { (make) in
make.top.bottom.equalToSuperview()
make.leading.equalTo(myImageView.snp.trailing).offset(12)
make.trailing.equalToSuperview()
}
}
Maybe this code will work?
class CustomNavClass: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setup_view()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setup_view()
}
private func setup_view() {
backgroundColor = .lightGray
let image = UIImageView(image: .init())
addSubview(image)
image.translatesAutoresizingMaskIntoConstraints = false
image.backgroundColor = .green
NSLayoutConstraint.activate([
image.centerXAnchor.constraint(equalTo: centerXAnchor),
image.widthAnchor.constraint(equalToConstant: 44),
image.heightAnchor.constraint(equalToConstant: 44),
image.topAnchor.constraint(equalTo: topAnchor, constant: 3),
image.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -3)
])
let leftLabel = UILabel()
leftLabel.text = "Label label left long label will go here, naturally"
leftLabel.numberOfLines = 2
leftLabel.adjustsFontSizeToFitWidth = true
leftLabel.backgroundColor = .red
addSubview(leftLabel)
leftLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
leftLabel.leadingAnchor.constraint(equalTo: leadingAnchor),
leftLabel.centerYAnchor.constraint(equalTo: centerYAnchor),
leftLabel.trailingAnchor.constraint(equalTo: image.leadingAnchor, constant: -10)
])
let rightLabel = UILabel()
rightLabel.text = "Label label right long label will go here, naturally"
rightLabel.numberOfLines = 2
rightLabel.adjustsFontSizeToFitWidth = true
rightLabel.backgroundColor = .blue
addSubview(rightLabel)
rightLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
rightLabel.trailingAnchor.constraint(equalTo: trailingAnchor),
rightLabel.centerYAnchor.constraint(equalTo: centerYAnchor),
rightLabel.leadingAnchor.constraint(equalTo: image.trailingAnchor, constant: 10)
])
}
}
The code does not use a UIStackView as its limited to its function (specifically, only one UIView can be stretched out on .fill distribution property.
This instead creates layout constraints:
UIImageView that is pegged at the center(with a 3 top and bottom constraint, optional, you can use centerY constraint or the like).
Leading UILabel is pegged to leading edge and trailing edge with UIImageView's leading edge.
Trailing UILabel is pegged to trailing edge and leading edge with UIImageView's trailing edge.

How to create a circular UIImageView

I am having issue creating a circular UIImageView. If I were to manually set the corderRadius to a value, eg. 50, it will have rounded corner. But when I try to set it as half of the frame's height or width (frame.width / 2 or frame.height / 2), it doesn't work. Somehow, the frame is (0, 0, 0, 0) when I try to print it.
And here is my code,
import UIKit
class TestIconController : UIViewController {
let icon: UIImageView = {
let imageView = UIImageView()
imageView.layer.cornerRadius = imageView.frame.width / 2
imageView.clipsToBounds = true
imageView.layer.masksToBounds = true
imageView.backgroundColor = .red
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
override func viewDidLoad() {
super.viewDidLoad()
loadLogo()
}
func loadLogo() {
view.addSubview(icon)
// Constraints
icon.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
icon.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
icon.heightAnchor.constraint(equalToConstant: 200).isActive = true
icon.widthAnchor.constraint(equalToConstant: 200).isActive = true
}
}
Override this function.
override func viewDidLayoutSubviews() {
icon.layer.cornerRadius = icon.bounds.size.width / 2
icon.clipsToBounds = true
icon.layer.masksToBounds = true
}
You may also make a base class for it for batter handling; Like
class UICirlceImageView : UIImageView {
override open func layoutSubviews() {
super.layoutSubviews();
let layer:CALayer = self.layer;
layer.cornerRadius = self.frame.size.width/2.0;
layer.masksToBounds = true;
}
}
then, do it like this
//let icon: UICirlceImageView = { // You may initialize like this as well
let icon: UIImageView = {
let imageView = UICirlceImageView()
imageView.backgroundColor = .red
//imageView.translatesAutoresizingMaskIntoConstraints = false // Don't know if it is needed
return imageView
}()
Note: The answer given by Rushabh is also correct.
You can create this extensions
extension UIImageView {
func setRounded() {
self.layer.cornerRadius = self.frame.width / 2
self.layer.masksToBounds = true
self.clipsToBounds = true
}
}
In your case you can inside viewDidLayoutSubviews call
icon.setRounded()

Add UILabel as subview of UITextField on top

I am in the process of implementing a UILabel as a subview of a UITextField which will be shown right above the UITextField itself. The UITextField has a rounded border and what I would like to achieve is the UILabel to be shown over the border.
Everything currently works as expected, but the UILabel is drawn behind the border of the UITextField. I want it to go "over" (above) the border so the white backgroundColor would be shown above part of the border and make the text more easily readible.
var priceTextField: CustomTextField = {
let priceTextField = CustomTextField()
priceTextField.layer.cornerRadius = 10.0
priceTextField.layer.borderWidth = 1.0
priceTextField.layer.borderColor = UIColor.darkGray.cgColor
priceTextField.translatesAutoresizingMaskIntoConstraints = false
priceTextField.font = UIFont.systemFont(ofSize: 15)
priceTextField.textColor = .black
priceTextField.text = "0"
priceTextField.suffix = "EUR"
priceTextField.suffixTextColor = .darkGray
priceTextField.suffixSpacing = 2.0
priceTextField.textAlignment = .center
priceTextField.labelText = "Price"
return priceTextField
}()
In my CustomTextField class (subclass of UITextField):
public var labelText: String?
var topLabel: UILabel = {
let topLabel = UILabel()
topLabel.translatesAutoresizingMaskIntoConstraints = false
topLabel.textAlignment = .center
topLabel.font = UIFont.systemFont(ofSize: 12)
topLabel.textColor = .lightGray
topLabel.backgroundColor = .white
topLabel.numberOfLines = 1
return topLabel
}()
func setupLabel() {
self.addSubview(topLabel)
topLabel.centerYAnchor.constraint(equalTo: self.topAnchor).isActive = true
topLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 20).isActive = true
topLabel.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20).isActive = true
topLabel.text = labelText
}
I call setupLabel() at the end of the draw(_ rect: CGRect) method of UITextField (because I work with this to show the EUR sign always behind the entered value).
I have tried to play around with bringSubviewToFront and changing the zPosition of the layer of the UILabel, without success.
It now looks like this:
How can I bring the text "above" the border on the top?
EDIT: Tried Sh_Khan's solution, but it's still hidden behind the border.
import Foundation
import UIKit
public class CustomTextView: UIView, UITextFieldDelegate {
public var labelText: String?
var customTextField: CustomTextField = {
let customTextField = CustomTextField()
customTextField.translatesAutoresizingMaskIntoConstraints = false
customTextField.font = UIFont.systemFont(ofSize: 15)
customTextField.textColor = .black
customTextField.textAlignment = .center
customTextField.text = "0"
customTextField.suffix = "EUR"
customTextField.suffixTextColor = .lightGray
customTextField.suffixSpacing = 2.0
return customTextField
}()
var topLabel: UILabel = {
let topLabel = UILabel()
topLabel.translatesAutoresizingMaskIntoConstraints = false
topLabel.font = UIFont.systemFont(ofSize: 12)
topLabel.textColor = .darkGray
topLabel.numberOfLines = 1
topLabel.backgroundColor = .red
topLabel.textAlignment = .center
return topLabel
}()
override public init(frame: CGRect) {
super.init(frame: frame)
setupBorders()
}
public override func layoutSubviews() {
setupViews()
}
func setupBorders() {
self.layer.cornerRadius = 10.0
self.layer.borderColor = UIColor.lightGray.cgColor
self.layer.borderWidth = 1.0
}
func setupViews() {
addSubview(topLabel)
// insertSubview(topLabel, aboveSubview: customTextField)
insertSubview(customTextField, belowSubview: topLabel)
customTextField.topAnchor.constraint(equalTo: topAnchor).isActive = true
customTextField.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
customTextField.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
customTextField.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
topLabel.centerYAnchor.constraint(equalTo: topAnchor).isActive = true
topLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10).isActive = true
topLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10).isActive = true
topLabel.text = labelText
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupViews()
}
}
You can try to organize it by creating a UIView subclass , so everything appear properly in it's order of adding
class CustomView: UIView {
var priceTextField: CustomTextField = {
let priceTextField = CustomTextField()
priceTextField.layer.cornerRadius = 10.0
priceTextField.layer.borderWidth = 1.0
priceTextField.layer.borderColor = UIColor.darkGray.cgColor
priceTextField.translatesAutoresizingMaskIntoConstraints = false
priceTextField.font = UIFont.systemFont(ofSize: 15)
priceTextField.textColor = .black
priceTextField.text = "0"
priceTextField.suffix = "EUR"
priceTextField.suffixTextColor = .darkGray
priceTextField.suffixSpacing = 2.0
priceTextField.textAlignment = .center
priceTextField.labelText = "Price"
return priceTextField
}()
var topLabel: UILabel = {
let topLabel = UILabel()
topLabel.translatesAutoresizingMaskIntoConstraints = false
topLabel.textAlignment = .center
topLabel.font = UIFont.systemFont(ofSize: 12)
topLabel.textColor = .lightGray
topLabel.backgroundColor = .white
topLabel.numberOfLines = 1
return topLabel
}()
var lableStr:String?
init(frame: CGRect,lblTex:String) {
super.init(frame: frame)
lableStr = lblTex
createSubviews()
}
override init(frame: CGRect) {
super.init(frame: frame)
createSubviews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
createSubviews()
}
func createSubviews() {
// all the layout code from above
// add the textfield then the label and set constraints properly
}
}
According to the Apple specification: It is composited above the receiver’s contents and sublayers.
So, the border will always be above all subviews, even if one brings the subview to the front and so on.
So one needs to make a background view to fake the border.
similar to Stackoverflow Question
Example:
Here self is "TextField"
activeborderView is "UiView"
activeborderView.frame = CGRect.init(x: -1, y: -1, width: self.frame.size.width+2, height: self.frame.size.height+2)
activeborderView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(activeborderView)
activeborderView.topAnchor.constraint(equalTo: self.topAnchor, constant:-1).isActive = true // Place our label 10 pts above the text field
activeborderView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: -1).isActive=true
activeborderView.heightAnchor.constraint(equalToConstant: self.frame.size.height+2).isActive=true
activeborderView.widthAnchor.constraint(equalToConstant: self.frame.size.width+2).isActive=true
activeborderView.layer.borderWidth = 3
activeborderView.layer.borderColor = CustomColor.blue().cgColor
activeborderView.layer.cornerRadius = 5
activeborderView.backgroundColor = .white
self.sendSubviewToBack(activeborderView)
self.setNeedsDisplay()

Make Image in rounded ImageView fit

I have a collectionviewCell with a rounded imageview which shows an icon.
Unfortunately the icons are too big. How can I fit them to fit into the rounded ImageView:
Code
func makeItCircle() {
self.imageView.layer.cornerRadius = self.imageView.frame.height/2
self.imageView.layer.masksToBounds = false
self.imageView.clipsToBounds = true
self.imageView.contentMode = .scaleAspectFit
}
Picture
You can wrap the image views inside container views (the cell views you already have should work) to add some padding: center the image view inside its container and constraint its width and height to about 0.75 of the container. Also you'll have to set the background and corner rounding on the container, not on the image view.
(100x100)
class CenterTab:UIView{
let container:UIView = {
let v = UIView()
v.backgroundColor = .white
v.layer.cornerRadius = 100/2
v.layer.shadowColor = UIColor.systemPurple.cgColor
v.layer.shadowOpacity = 0.4
v.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)
v.layer.shadowRadius = 7
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
let tabImg:UIImageView = {
let img = UIImageView()
img.contentMode = .scaleAspectFit
img.clipsToBounds = true
img.tintColor = .systemPurple
img.translatesAutoresizingMaskIntoConstraints = false
return img
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(tabImg)
self.addSubview(container)
}
override func layoutSubviews() {
super.layoutSubviews()
NSLayoutConstraint.activate([
container.topAnchor.constraint(equalTo: self.topAnchor),
container.leadingAnchor.constraint(equalTo: self.leadingAnchor),
container.trailingAnchor.constraint(equalTo: self.trailingAnchor),
container.bottomAnchor.constraint(equalTo: self.bottomAnchor),
tabImg.centerXAnchor.constraint(equalTo: container.centerXAnchor),
tabImg.centerYAnchor.constraint(equalTo: container.centerYAnchor),
tabImg.widthAnchor.constraint(equalTo: container.widthAnchor, multiplier: 0.60),
tabImg.heightAnchor.constraint(equalTo: container.widthAnchor)
])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}}

Resources