UIView is not rounded - swift

I have a small problem and not sure why it is not working. I have a code:
func rounded(cornerRadius: CGFloat? = nil) {
if let cornerRadius = cornerRadius {
layer.cornerRadius = cornerRadius
} else {
layer.cornerRadius = min(frame.size.height, frame.size.width) / 2
}
clipsToBounds = true
}
And I am trying to use like this:
cameraImageContainer.rounded()
cameraImageContainer = UIView
The image is not really very rounded and it doesn't look good.
Any Suggestions please?

Since the frame can change, it's easier to implement the corner radius when the bounds are set. Give this a try:
class CircleView: UIView {
override var bounds: CGRect {
didSet {
self.layer.cornerRadius = min(bounds.size.height, bounds.size.width) / 2
}
}
override init(frame: CGRect) {
super.init(frame: frame)
self.commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
self.commonInit()
}
private func commonInit() {
clipsToBounds = true
}
}

Call the function to round the image in viewDidApper like this
override func viewDidAppear(_ animated: Bool) {
cameraImageContainer.rounded()
}
because the frames of the button will be set only after the view is loaded
if you waant to call it in viewDidLoad create a custom class for imageView and set it in the storybaord

Related

Swift - get random CGPoints from UIView

I am trying to get random CGPoints along the 'outer contour' of UIView so that I will be able to draw UIBezierPath line over obtained CGPoints. For example, get CGPoints from below red dots which I marked myself by hand. Any idea?
###Edit###
As per Sweeper's advice I am trying to add CAShapeLayer into my custom view but it returns nil when I am printing its path. Please could you point out what I am missing?
class ViewController: UIViewController {
let shapeLayer = CAShapeLayer()
override func viewDidLoad() {
super.viewDidLoad()
let view = BubbleView(frame: CGRect(x: self.view.frame.midX / 2, y: self.view.frame.midY/2, width: 150, height: 100))
view.backgroundColor = .gray
view.layer.cornerRadius = 30
self.view.addSubview(view)
}
}
class BubbleView: UIView {
var pathLayer: CAShapeLayer!
override func layoutSubviews() {
pathLayer = CAShapeLayer()
pathLayer.bounds = frame
self.layer.addSublayer(pathLayer)
print(pathLayer.path) // returns nil
}
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .clear
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

How to create this view with constraints programtically

I feel this is pretty simple to accomplish but I can't seem to figure it out. I'm fairly new to not using the storyboard and trying to learn how to set my constraints programatically for my views. I created the view that I want easily in storyboard but can't seem to get it programatically.
I have my view controller has my parent view, and then I call a container view. I imagine in the container view is where I setup my constraints but I can't get the height of my view to stay the same every-time I change to a different device
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var clariView = ClariContainerView()
view.addSubview(clariView)
}
}
This my view controller and then my ClariContainerView looks like this:
class ClariContainerView: UIView {
lazy var clariQuestionView: UIView = {
let containerView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 0))
containerView.backgroundColor = .blue
containerView.translatesAutoresizingMaskIntoConstraints = false
return containerView
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupView()
}
public func setupView() {
addSubview(clariQuestionView)
setupLayout()
}
public func setupLayout() {
NSLayoutConstraint.activate([
clariQuestionView.heightAnchor.constraint(equalToConstant: 169)
])
}
}
What I'm trying to recreate is this:
I need the height of the blue view to always be 169.
Here is how you would do that:
First, you don't need to define a frame for your containerView since the translatesAutoresizingMaskIntoConstraints = falsestatement is specifying that you'll be using auto-layout and therefore the frame will be ignored:
lazy var clariQuestionView: UIView = {
let containerView = UIView()
containerView.backgroundColor = .blue
containerView.translatesAutoresizingMaskIntoConstraints = false
return containerView
}()
And here is how you would define your constraints. You need to set height, but also need to pin the view to the bottom, the leading, and the trailing edges of self.view:
public func setupLayout() {
NSLayoutConstraint.activate([
clariQuestionView.heightAnchor.constraint(equalToConstant: 169),
clariQuestionView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
clariQuestionView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
clariQuestionView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor)
])
}
For such a basic layout you don't really need to add heightAnchor. Here is a simple way to achieve desired behavior + bonus — a code snippet to adjust height according to the device's safeAreaInsets.
class ClariContainerView: UIView {
lazy var clariQuestionView: UIView = {
let desiredContainerHeigh = 169
// If you want, you can use commented code to adjust height according to the device's safe area.
// This might be needed if you want to keep the same height over safe area on all devices.
// let safeAreaAdjustment = UIApplication.shared.keyWindow?.rootViewController?.view.safeAreaInsets.bottom ?? 0
let containerView = UIView(frame: CGRect(x: 0, y: UIScreen.main.bounds.height - 169, width: UIScreen.main.bounds.width, height: 169))
containerView.backgroundColor = .blue
containerView.translatesAutoresizingMaskIntoConstraints = true
return containerView
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupView()
}
public func setupView() {
addSubview(clariQuestionView)
}
}

Swift: Rounded Buttons

I am following the following tutorial on how to round the sides of buttons:
https://blog.supereasyapps.com/how-to-create-round-buttons-using-ibdesignable-on-ios-11/
I have created a new Swift code file as it has suggested and entered the following code:
import Foundation
import UIKit
#IBDesignable class RoundButton: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
sharedInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
sharedInit()
}
override func prepareForInterfaceBuilder() {
sharedInit()
}
func sharedInit() {
refreshCorners(value: cornerRadius)
}
func refreshCorners(value: CGFloat) {
layer.cornerRadius = value
}
var cornerRadius: CGFloat = 15 {
didSet {
refreshCorners(value: cornerRadius)
}
}
}
I cannot see find the Corner Radius option in the "Identity Inspector" as shown in the animation on the website to create rounder buttons. Can someone please tell me what I did wrong? Greatly appreciate the help
You need to change the cornerRadius to the following, to include #IBInspectable:
#IBInspectable
var cornerRadius: CGFloat = 15 {
didSet {
refreshCorners(value: cornerRadius)
layer.masksToBounds = true // Could include this
}
}
#IBInspectable allows you to access the property within storyboards, the interface builder.
You could also include layer.masksToBounds = true, so the corners are sure to get rounded even if masksToBounds in the storyboard is unchecked. However, you cannot apply both rounded corners and a shadow at the same time, but there are many workarounds available.
You missed out adding the cornerRadius var:
#IBDesignable class RoundButton: UIButton {
#IBInspectable var cornerRadius: CGFloat = 15 { didSet { refreshCorners(value: cornerRadius) } }
override func awakeFromNib() {
super.awakeFromNib()
setupView()
}
.
.
.
.
}
It is my universal extension for UIView. You can move it to only for UIButton. Thus you can use 2 methods from interface to make rounded corners.
#IBDesignable extension UIView {
#IBInspectable var roundRadius : CGFloat {
set {
self.layer.cornerRadius = newValue
}
get {
return self.roundRadius
}
}
/// automatically set cornerRadius as half of height
#IBInspectable var isRounded : Bool {
set {
let radius = newValue ? self.frame.height/2 : 0
self.layer.cornerRadius = radius
}
get {
return self.isRounded
}
}
}

How to make custom rounded UIImageView subclass?

I want to make my custom round UIImageView and show it in storyboard.
I've done next:
#IBDesignable
class RoundedImageView: UIImageView {
override init(image: UIImage?) {
super.init(image: image)
super.layer.cornerRadius = super.frame.size.height / 2
self.layer.cornerRadius = self.frame.size.height / 2
}
override init(frame: CGRect) {
super.init(frame: frame)
super.layer.cornerRadius = super.frame.size.height / 2
self.layer.cornerRadius = self.frame.size.height / 2
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
super.layer.cornerRadius = super.frame.size.height / 2
self.layer.cornerRadius = self.frame.size.height / 2
}
}
And my imageView in storyboard is RoundedImageView class selected.
But in storyboard it's still showing as rectangle. How can I realize it?
When I'm running code its rounded.
Thanks
You should set radius after layouts have been applied.
#IBDesignable
class RoundedImageView: UIImageView {
override init(image: UIImage?) {
super.init(image: image)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func layoutSubviews() {
super.layoutSubviews()
self.layer.cornerRadius = self.frame.size.height / 2
self.clipsToBounds = true
}
}

customize UIPageControl dots

I'm currently trying to customize the UIPageControl so it will fit my needs. However I seem to be having a problem when implementing some logic in the draw
What I want to do is to be able to user IBInspectable variables to draw out the UIPageControl however those seem to still be nil when the draw method is being called and when I try to implement my logic in the awakeFromNib for instance it won't work.
What I did so far is the following
class BoardingPager: UIPageControl {
#IBInspectable var size: CGSize!
#IBInspectable var borderColor: UIColor!
#IBInspectable var borderWidth: CGFloat! = 1
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.pageIndicatorTintColor = UIColor.clear
}
override func draw(_ rect: CGRect) {
super.draw(rect)
setDots()
}
func setDots() {
for i in (0..<self.numberOfPages) {
let dot = self.subviews[i]
if size != nil {
let dotFrame = CGRect(x: size.width/2, y: size.height/2, width: size.width, height: size.height)
dot.frame = dotFrame
}
if i != self.currentPage {
dot.layer.cornerRadius = dot.frame.size.height / 2
dot.layer.borderColor = borderColor.cgColor
dot.layer.borderWidth = borderWidth
}
}
}
}
Another problem I'm facing is that I want to remove/add a border when the current page changes.
I'm hoping someone will be able to help me out