How to make an IBDesignable component that has an angle: CGFloat property that rotates the view
import UIKit
#IBDesignable
class MyB: UIButton {
#IBInspectable
var angle: CGFloat = 0 {
didSet {
//What to put here?
}
}
override init(frame: CGRect) {
super.init(frame: frame)
// Initialization code
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
I tried
self.transform = CGAffineTransformMakeRotation(angle)
but it doesn't work
You should create CustomButton inherited from UIButton
import UIKit
#IBDesignable
class CustomButton: UIButton {
#IBInspectable var rotation: Double = 0 {
didSet {
rotateButton(rotation: rotation)
}
}
func rotateButton(rotation: Double) {
self.transform = CGAffineTransform(rotationAngle: CGFloat(.pi/2 + rotation))
}
}
You will get following output,
Related
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
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
}
}
}
So I've got two views, both added to the superview programmatically:
//First added view to my superView (baseView)
let imageViewOne = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
baseView.addSubview(imageViewOne)
//Second added view to my superView (baseView)
let imageViewTwo = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
baseView.addSubview(imageViewTwo)
I want to bring one of them to the front when it is selected because when you add a new view, it overlaps the previous one. Something that works with "selected" or "touched".
Use this:
baseView.bringSubview(toFront: imageViewOne)
You can do this by UITapGestureRecognizer by setting Restoration ID from the interface builder
func tapOneAct(sender: UITapGestureRecognizer) {
if(sender.view!.restorationIdentifier == "view1")
// view1 is `Restoration ID` of imageViewOne
{
view.bringSubview(toFront: imageViewOne)
}
if(sender.view!.restorationIdentifier == "view2")
// view2 is `Restoration ID` of 2nd view
{
view.bringSubview(toFront: imageViewTwo)
}
}
If I understand correctly then you would like to check the status of selected view and bring it to the front of the view hierarchy.
In this case you have to do following things:
1) track selection state, let it will be var isSelected: Bool in code snippet
2) hold a callback for an action when view is selected (you can use for example UIButton to observe tap event)
In following code snippet you can check the selection state when the view is touched.
BaseView implements logic for checking the state of SelectionView.
import UIKit
final class SelectionView<T: UIView>: UIView {
var onTap: ((_ isSelected: Bool) -> ())?
// MARK: - Private
private let view: T
private let button = UIButton(type: .custom)
private var isSelected: Bool = false
// MARK: - Init
init(view: T) {
self.view = view
super.init(frame: .zero)
setUp()
}
// MARK: - Private
private func setUp() {
addSubview(view)
addSubview(button)
button.addTarget(self, action: #selector(onButtonTap), for: .touchUpInside)
}
#objc private func onButtonTap() {
isSelected = !isSelected
onTap?(isSelected)
}
// MARK: - Layout
override func layoutSubviews() {
super.layoutSubviews()
view.frame = bounds
button.frame = bounds
}
override func sizeThatFits(_ size: CGSize) -> CGSize {
return view.sizeThatFits(size)
}
// MARK: - Unused
override init(frame: CGRect) {
fatalError("init(frame:) has not been implemented")
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
final class BaseView: UIView {
init() {
super.init(frame: .zero)
let views = [SelectionView(view: UIView()), SelectionView(view: UIView())]
for view in views {
view.onTap = { [weak self, weak view] isSelected in
guard let selectedView = view
else { return }
if isSelected {
self?.bringSubview(toFront: selectedView)
}
}
}
}
// MARK: - Unused
override init(frame: CGRect) {
fatalError("init(frame:) has not been implemented")
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
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
}
}
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