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")
}}
Related
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: "+")
}
}
I am new to swift - I want to add a label ONTO the ui image view image in a collectionview, however i am having some issues. The text sits below the image view, how can i adjust it so it stays in the middle of the image. I want to do this in code and not use storyboards or a nib file. I believe it may be due to my frames i have set:
import UIKit
class ExploreCollectionViewCell: UICollectionViewCell {
static let identifier = "ExploreCollectionViewCell"
private let label: UILabel = {
let label = UILabel()
label.textColor = .white
label.font = UIFont(name: Settings.shared.MAIN_APP_FONT_BOLD, size: 13)
return label
}()
private let imageView: UIImageView = {
let imageView = UIImageView()
imageView.clipsToBounds = true
imageView.layer.cornerRadius = 0
imageView.contentMode = .scaleAspectFill
return imageView
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(label)
contentView.addSubview(imageView)
}
required init?(coder: NSCoder) {
fatalError()
}
override func layoutSubviews() {
super.layoutSubviews()
label.frame = CGRect(x: 5, y: 0, width: contentView.frame.size.width-10, height: 50)
//imageView.frame = contentView.bounds
imageView.frame = CGRect(x: 0, y: 0, width: 250, height: 250)
}
override func prepareForReuse() {
super.prepareForReuse()
imageView.image = nil
}
func configure(with urlString: String, label: String) {
guard let url = URL(string: urlString) else {
return
}
let task = URLSession.shared.dataTask(with: url) { [weak self] data, _, error in
guard let data = data, error == nil else {
return
}
DispatchQueue.main.async {
self?.label.text = label
let image = UIImage(data: data)
self?.imageView.image = image
}
}
task.resume()
}
}
First, add the imageView before adding the label, so that it will be shown behind the label:
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(imageView) // behind
contentView.addSubview(label) // front
}
Second, it would be easier to use auto layout:
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.widthAnchor.constraint(equalToConstant: 250).isActive = true
imageView.heightAnchor.constraint(equalToConstant: 250).isActive = true
label.translatesAutoresizingMaskIntoConstraints = false
label.centerYAnchor.constraint(equalTo: imageView.centerYAnchor).isActive = true
label.widthAnchor.constraint(equalTo: imageView.widthAnchor).isActive = true
private let label: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = .white
label.font = UIFont(name: Settings.shared.MAIN_APP_FONT_BOLD, size: 13)
return label
}()
private let imageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.clipsToBounds = true
imageView.layer.cornerRadius = 0
imageView.contentMode = .scaleAspectFill
return imageView
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(label)
contentView.addSubview(imageView)
imageView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 0).isActive = true
imageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0).isActive = true
imageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 0).isActive = true
imageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: 0).isActive = true
label.heightAnchor.constraint(equalToConstant: 50).isActive = true
label.centerYAnchor.constraint(contentView.centerYAnchor).isActive = true
label.centerXAnchor.constraint(contentView.centerXAnchor).isActive = true
label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 5).isActive = true
label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -5).isActive = true
}
required init?(coder: NSCoder) {
fatalError()
}
Currently, I implement multiple corner radii on my bubbleView which is a UIView by doing something along the lines of:
// First create the bubble view
bubbleView = UIView()
bubbleView.layer.cornerRadius = 4 // set the corner radius of the "smaller" corner style
bubbleView.layer.cornerCurve = .continuous
bubbleView.clipsToBounds = true
bubbleView.backgroundColor = UIColor.systemBlue
// ...
// Update the "mask" of the bubble view to give another type of rounded corners
let maskPath = UIBezierPath(roundedRect:bubbleView.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: 17.0, height: 0.0))
let maskLayer = CAShapeLayer()
maskLayer.path = maskPath.cgPath
bubbleView.layer.mask = maskLayer // updates the mask
My issue is I am setting the mask, self.bubbleView.layer.mask = maskLayer, of the bubbleView in the func layoutSubviews() function, which causes a noticable delay, for example, when the device rotates from portrait to landscape mode.
Is there a faster, more efficient way to implement different corner radii for a UIView that responds faster than simply updating the mask in layoutSubviews() ?
You could try using a subview with the larger radius corners...
custom view
clear background
all 4 corners set to Radius of 4
subView with desired background color
set Radius of 17 on desired corners of subView
Here's some sample code:
class MyCustomView: UIView {
// self's background will be .clear
// so we use a custom property to set the
// background of the subView
public var viewColor: UIColor = .clear {
didSet {
subView.backgroundColor = viewColor
}
}
// corners to use larger radius
public var corners: CACornerMask = [] {
didSet {
subView.layer.maskedCorners = corners
}
}
public var smallRadius: CGFloat = 0 {
didSet {
layer.cornerRadius = smallRadius
}
}
public var bigRadius: CGFloat = 0 {
didSet {
subView.layer.cornerRadius = bigRadius
}
}
private let subView = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
addSubview(subView)
subView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
subView.topAnchor.constraint(equalTo: topAnchor),
subView.leadingAnchor.constraint(equalTo: leadingAnchor),
subView.trailingAnchor.constraint(equalTo: trailingAnchor),
subView.bottomAnchor.constraint(equalTo: bottomAnchor),
])
// round all 4 corners of self's layer with the small radius
layer.masksToBounds = true
layer.cornerRadius = smallRadius
layer.cornerCurve = .continuous
// subview only specified corners with bigger radius
subView.layer.masksToBounds = true
subView.layer.cornerRadius = bigRadius
subView.layer.cornerCurve = .continuous
subView.layer.maskedCorners = corners
}
}
and a test view controller to demo it:
class TestViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let v = MyCustomView()
v.viewColor = .systemBlue
v.smallRadius = 4
v.bigRadius = 17
// set top-left, top-right, bottom-left to use larger radius
v.corners = [.layerMinXMinYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner]
v.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(v)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
v.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 60.0),
v.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -60.0),
v.heightAnchor.constraint(equalToConstant: 120.0),
v.centerYAnchor.constraint(equalTo: g.centerYAnchor),
])
}
}
Greetings stack overflow.
I am trying to build a "bullseye" type view, using coloured subviews and the corner radius. The problem I have is, only my first subview's corners are getting rounded and the inner views are still squares. The black view is a subview of my custom view. The red view is it's subview, and they yellow view the subview of that. Pretty simple hierarchy.
The result looks like this:
I add the views and set their constraints manually. My test app just has the ThreeCircleView dead center of a view controller with the X,Y centered and the width, height constant. I do the actual rounding of the corners in didLayoutSubViews because the size of the view might change, so the corners would have to be resized.
I wrote a test view to isolate this, here it is
class ThreeCircleView: UIView {
var outerCircle: UIView = UIView()
var middleCircle: UIView = UIView()
var innerCircle: UIView = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
translatesAutoresizingMaskIntoConstraints = false
addSubViews()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
translatesAutoresizingMaskIntoConstraints = false
addSubViews()
}
func addSubViews() {
outerCircle.backgroundColor = .black
middleCircle.backgroundColor = .red
innerCircle.backgroundColor = .yellow
self.addSubview(outerCircle)
outerCircle.addSubview(middleCircle)
middleCircle.addSubview(innerCircle)
let outerCenterY = outerCircle.centerYAnchor.constraint(equalTo: self.centerYAnchor)
let outerCenterX = outerCircle.centerXAnchor.constraint(equalTo: self.centerXAnchor)
let outerCenterWidth = outerCircle.widthAnchor.constraint(equalTo: self.widthAnchor, constant: -50.0 )
let outerCenterHeight = outerCircle.heightAnchor.constraint(equalTo: self.heightAnchor, constant: -50.0 )
outerCircle.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([outerCenterY,outerCenterX,outerCenterWidth,outerCenterHeight])
self.setNeedsLayout()
let middleCenterY = middleCircle.centerYAnchor.constraint(equalTo: self.centerYAnchor)
let middleCenterX = middleCircle.centerXAnchor.constraint(equalTo: self.centerXAnchor)
let middleCenterWidth = middleCircle.widthAnchor.constraint(equalTo: self.widthAnchor, constant: -100.0 )
let middleCenterHeight = middleCircle.heightAnchor.constraint(equalTo: self.heightAnchor, constant: -100.0 )
middleCircle.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([middleCenterY,middleCenterX,middleCenterWidth,middleCenterHeight])
let innerCenterY = innerCircle.centerYAnchor.constraint(equalTo: self.centerYAnchor)
let innerCenterX = innerCircle.centerXAnchor.constraint(equalTo: self.centerXAnchor)
let innerCenterWidth = innerCircle.widthAnchor.constraint(equalTo: self.widthAnchor, constant: -150.0 )
let innerCenterHeight = innerCircle.heightAnchor.constraint(equalTo: self.heightAnchor, constant: -150.0 )
innerCircle.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([innerCenterY,innerCenterX,innerCenterWidth,innerCenterHeight])
}
func makeCircle(v:UIView) {
v.layer.cornerRadius = v.frame.size.width * 0.50
v.clipsToBounds = true
}
override func layoutSubviews() {
super.layoutSubviews()
makeCircle(v: outerCircle)
makeCircle(v: middleCircle)
makeCircle(v: innerCircle)
}
}
An easy way to make it look as expected is to add layoutIfNeeded() call inside your makeCircle(v:UIView) method. This will make you sure that all views' frames are updated correctly before applying visual changes:
func makeCircle(v:UIView) {
v.layoutIfNeeded()
v.layer.cornerRadius = v.frame.size.width * 0.50
v.clipsToBounds = true
}
I'm trying to set a cornerRadius and a shadow(bottom + right) to my UICollectionViewCell but my code doesn't work. Neither the cornerRadius nor the shadow does appear..
Here's my code:
class MainWishlistCell: UICollectionViewCell {
let wishlistImage: UIImageView = {
let v = UIImageView()
v.translatesAutoresizingMaskIntoConstraints = false
v.image = UIImage(named: "logoGroß")
return v
}()
let wishlistLabel: UILabel = {
let v = UILabel()
v.translatesAutoresizingMaskIntoConstraints = false
v.text = "Main Wishlist"
v.font = UIFont(name: "AvenirNext-DemiBold", size: 18)
v.textColor = .darkGray
v.textAlignment = .center
return v
}()
func addShadow() {
let cornerRadius: CGFloat = 5
self.wishlistImage.layer.shadowPath = UIBezierPath(roundedRect: self.wishlistImage.bounds, cornerRadius: cornerRadius).cgPath
self.wishlistImage.layer.shadowRadius = cornerRadius
self.wishlistImage.layer.shadowOffset = .zero
self.wishlistImage.layer.shadowOpacity = 0.3
self.wishlistImage.layer.shadowRadius = 10
self.wishlistImage.layer.cornerRadius = cornerRadius
self.wishlistImage.layer.shadowColor = UIColor.black.cgColor
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
addShadow()
contentView.addSubview(wishlistImage)
contentView.addSubview(wishlistLabel)
// constrain view to all 4 sides
NSLayoutConstraint.activate([
wishlistImage.topAnchor.constraint(equalTo: contentView.topAnchor),
wishlistImage.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
wishlistImage.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
wishlistImage.heightAnchor.constraint(equalToConstant:150),
wishlistLabel.topAnchor.constraint(equalTo: wishlistImage.bottomAnchor,constant: 1),
wishlistLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
wishlistLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
wishlistLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
])
}
}
Just add one line of code into addShadow() function:
layer.masksToBounds = false ---> which set the shadow of the view's layer.
Then add corner radius to your cell:
contentview.clipsToBounds = true
The problem is at that point
addShadow()
contentView.addSubview(wishlistImage)
contentView.addSubview(wishlistLabel)
The image bounds is zero
self.wishlistImage.layer.shadowPath = UIBezierPath(roundedRect:
self.wishlistImage.bounds,
cornerRadius: cornerRadius).cgPath
So you need
var once = true
override func layoutSubviews() {
super.layoutSubviews()
if once {
addShadow()
once = false
}
}