I make UIView like this. but I want to use this in UIViewController
What should I do?
import UIKit
class CardView: UIView {
#IBInspectable var cornerRadius: CGFloat = 2
#IBInspectable var shadowOffsetWidth: Int = 0
#IBInspectable var shadowOffsetHeight: Int = 3
#IBInspectable var shadowColor: UIColor? = UIColor.black
#IBInspectable var shadowOpacity: Float = 0.5
override func layoutSubviews() {
layer.cornerRadius = cornerRadius
let shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius)
layer.masksToBounds = false
layer.shadowColor = shadowColor?.cgColor
layer.shadowOffset = CGSize(width: shadowOffsetWidth, height: shadowOffsetHeight);
layer.shadowOpacity = shadowOpacity
layer.shadowPath = shadowPath.cgPath
}
}
If you want to add it in your viewController you have several options:
Add it directly in storyboard (best option):
drag a view in viewController via inspector/object library on the bottom right side in xCode
UIView object screenshot
add constraints, then tap on the view in
Constraints screenshot
and pick your custom class in identity inspector/custom class field
You can also use a view loaded from xib
Google different way to load from xib.
You can add it in code. It's a little bit harder:
Create a lazy property:
lazy var cardView: CardView = {
let cardView = CardView(frame: CGRect(x: 0, y: 0, width: 100, height: 200))
cardView.backgroundColor = .gray
cardView.layer.cornerRadius = 16.0
return cardView
}()
Add custom view in viewDidLoad for example:
override func viewDidLoad() {
super.viewDidLoad()
/* Adding subview to the VC */
view.addSubview(cardView)
}
Then add constraints. You can center it vertically/horizontally and then set custom height/width. It depends on what you want...
Check this out:
Swift | Adding constraints programmatically
I advise you to read Apple's documentation rather then just copy pasting code.
Should definitely read "documentation/UserExperience/Conceptual/AutolayoutPG/ProgrammaticallyCreatingConstraints.html" if you still haven't.
Add a new uiview to your storyboard or xib file and set its class as CardView as shown
Related
I am working on a project which has all views embedded in a view container like this:
Today, I have to make one of these containers grow vertically in a animatable way when a stack view is showing its arranged subviews. So, the first problem was that the shadow border of this container is not being animated and I realized that the shadow path should be animated in another way and not just in a UIView.animate block.
I have isolated the problem in a small project:
As you can see, I am trying to deploy/undeploy the container view depending on the inner stackview arranged subviews. The problem is the shadow path, which I am already trying to understand how it works.
Can you help me to understand how to manage a UIView shadow layer when you need to update the height of an UIView in an animation block?
Container Shadow view code:
import UIKit
#IBDesignable final class ShadowView: UIView {
#IBInspectable var cornerRadius: CGFloat = 0.0 {
didSet {
setNeedsLayout()
}
}
#IBInspectable var shadowColor: UIColor = UIColor.darkGray {
didSet {
setNeedsLayout()
}
}
#IBInspectable var shadowOffsetWidth: CGFloat = 0.0 {
didSet {
setNeedsLayout()
}
}
#IBInspectable var shadowOffsetHeight: CGFloat = 1.8 {
didSet {
setNeedsLayout()
}
}
#IBInspectable var shadowOpacity: Float = 0.30 {
didSet {
setNeedsLayout()
}
}
#IBInspectable var shadowRadius: CGFloat = 3.0 {
didSet {
setNeedsLayout()
}
}
#IBInspectable var isAnimatable: Bool = false
private var shadowLayer: CAShapeLayer = CAShapeLayer() {
didSet {
setNeedsLayout()
}
}
private var previousPat: CGPath = CGPath(rect: CGRect(x: 0, y: 0, width: 0, height: 0), transform: .none)
override func layoutSubviews() {
super.layoutSubviews()
layer.cornerRadius = cornerRadius
shadowLayer.path = UIBezierPath(roundedRect: bounds,
cornerRadius: cornerRadius).cgPath
shadowLayer.fillColor = backgroundColor?.cgColor
shadowLayer.shadowColor = shadowColor.cgColor
shadowLayer.shadowPath = shadowLayer.path
shadowLayer.shadowOffset = CGSize(width: shadowOffsetWidth,
height: shadowOffsetHeight)
shadowLayer.shadowOpacity = shadowOpacity
shadowLayer.shadowRadius = shadowRadius
if isAnimatable {
let animation = CABasicAnimation(keyPath: "shadowPath")
animation.fromValue = previousPat
animation.toValue = shadowLayer.path
animation.autoreverses = false
animation.duration = 0.8
shadowLayer.add(animation, forKey: "pathAnimation")
}
layer.insertSublayer(shadowLayer, at: 0)
previousPat = shadowLayer.path!
}
}
Main ViewController code:
final class ViewController: UIViewController {
#IBOutlet weak var stack: UIStackView!
#IBOutlet weak var redContainerLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func animateAction(_ sender: Any) {
UIView.animate(withDuration: 0.8) {
self.redContainerLabel.alpha = self.redContainerLabel.alpha == 0 ? 1 : 0
self.stack.arrangedSubviews.forEach {
$0.isHidden.toggle()
}
}
}
}
View structure:
I was looking for an answer to exactly this problem and encountered this post here, which I believe is what you're looking for:
Animating CALayer shadow simultaneously as UITableviewCell height animates
The solution is a bit verbose (I'm surprised the use-case is so rare as to not prompt apple to fix(?) it) and a few years old at this point, but the most recent I could find. Ultimately I decided to work around it by fading out my shadows before resizing, but you might find it useful!
A couple of other, older posts I've found appear to corroborated the level of effort required for this effect (again, Apple's got a weird list of things it decides are your problem), so that first post is probably your best bet.
https://petosoft.wordpress.com/2012/10/24/shadowpath-not-animating-with-standard-uiview-animations-on-ipad/
Smoothly rotate and change size of UIView with shadow
UIView: How to animate CALayer frame with shadow?
If you've managed to find a more straightforward solution, by all means let me know; in the mean-time I hope this helps.
I have a tableview cell with view inside and I want to add shadow to it.
For this reason I add this code:
self.PrimaView.layer.shadowPath = UIBezierPath(rect: self.PrimaView.bounds).cgPath
self.PrimaView.layer.shadowRadius = 3
self.PrimaView.layer.shadowOffset = .zero
self.PrimaView.layer.shadowOpacity = 3
This is tableview cell structure:
My problem is this:
when I execute code on simulator I get this (this is what I want to get):
but when I execute the same code on the real device I get this:
Why is it different than the previous image?
#Sulthan is right or may be you have safe area issue as well if you have same device if not.
Then you can use this code for shadow
import UIKit
#IBDesignable
class CardViewMaterial: UIView {
// #IBInspectable var cornerRadius: CGFloat = 2
#IBInspectable var shadowOffsetWidth: Int = 0
#IBInspectable var shadowOffsetHeight: Int = 3
#IBInspectable var shadowColor: UIColor? = UIColor.black
#IBInspectable var shadowOpacity: Float = 0.5
override func layoutSubviews() {
layer.cornerRadius = cornerRadius
let shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius)
layer.masksToBounds = false
layer.shadowColor = shadowColor?.cgColor
layer.shadowOffset = CGSize(width: shadowOffsetWidth, height: shadowOffsetHeight);
layer.shadowOpacity = shadowOpacity
layer.shadowPath = shadowPath.cgPath
}
}
I have been creating an app which has a View as that of AppStore (iOS 11) - {Today} view.
Just want to know how do I approach that view. Yet, I think the approach is to create a UIViewController with extensions of UITableViewDataSource and -Delegate, I can get the number of rows and data in my ViewController. And In the dequeReusableCell, I have created a UITableViewCell class in which I have created a UIView Programmatically but that's not working.
class MyTableViewCell: UITableViewCell {
let cellView:UIView = {
let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
view.layer.cornerRadius = 15
view.backgroundColor = UIColor.clear
view.layer.shadowColor = UIColor.black.cgColor
view.layer.shadowOpacity = 1
view.layer.shadowOffset = CGSize.zero
view.layer.shadowRadius = 5
return view
}()
}
In the above class snippet, there is no way to insert my UIView in the main view.
There is no method to add views(obviously) because it's under UIViewController rather than UITableViewCell.
So my question is how do I get UIView inside a tableViewCell
Or Is there any other approach to get exact view cells as ios 11 Today tab view? This is what I want ->
I have upgraded my Question, please have a look [here]1: How to nest a UICollectionViewCell inside another one?
You can add customView to uitableviewcell like this.
class MyTableViewCell: UITableViewCell {
let cellView: UIView = {
let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
view.layer.cornerRadius = 15
view.backgroundColor = UIColor.white
view.layer.shadowColor = UIColor.black.cgColor
view.layer.shadowOpacity = 1
view.layer.shadowOffset = CGSize.zero
view.layer.shadowRadius = 5
return view
}()
override func awakeFromNib() {
super.awakeFromNib()
addSubview(cellView)
}
}
have a look at this git project this will help you :)
https://github.com/phillfarrugia/appstore-clone
For making a circular UIView I am using the cornerRadius property.
I have a UIView with dimension 79*158.
redView.layer.cornerRadius = redView.frame.size.height/2
redView.layer.masksToBounds = true
It shows elipse instead of circle:
Any workaround or does it only work with square type (eg. UIView(100*100))?
I am ok if it resizes dynamically.
use this...
func makeCircle (view: UIView) {
view.clipsToBounds = true
let height = view.frame.size.height
let width = view.frame.size.width
let newHeight = min(height, width) // use "max" if you want big circle
var rectFrame = view.frame
rectFrame.size.height = newHeight
rectFrame.size.width = newHeight
view.frame = rectFrame
view.layer.cornerRadius = newHeight/2
}
use like this:
#IBOutlet var rectView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
makeCircle(view: rectView)
}
You have a UIView with dimension 79*158.So that is wrong. You should have exactly same height and width for rounding exact a view to circle shape.
E.g.
redView.frame.size.height = 79.0
redView.frame.size.width = 79.0
or
redView.frame.size.height = 158.0
redView.frame.size.width = 158.0
And apply corner radius like:
redView.clipsToBounds = true
redView.layer.cornerRadius = redView.frame.size.height / 2.0
Result:
Note: Check your constrains also If you are using Auto Layout. Be sure view frame doesn't change.
If you are using constraints then changing the frame/bounds of the view is not a good idea. Instead you should do the following.
If the view is contained in a UIViewController then set the cornerRadius in viewDidLayoutSubviews method
And if the view is itself a subclass of UIView the set the cornerRadius in layoutSubviews method
Only Squire view make a perfect circle. For example, if your view size is (10*10),(50*50),(100*100), etc. then your view becomes perfect squire else not.
Using IBDesignable, you can display without project run in storyboard ox .XIB #simple way
Step 1. Subclass UIView:
#IBDesignable class RoundedCornerView: UIView {
#IBInspectable var borderWidth:CGFloat = 2 {
didSet {
layer.borderWidth = borderWidth
}
}
#IBInspectable var borderColor:UIColor = UIColor.orangeGradientLight {
didSet {
layer.borderColor = borderColor.cgColor
}
}
override func layoutSubviews() {
super.layoutSubviews()
layer.cornerRadius = frame.height/2
layer.masksToBounds = true
layer.borderColor = borderColor.cgColor
layer.borderWidth = borderWidth
}
}
Step 2. Set custom class in identity inspector:
can't.
Try resize UIView to square: 79*79 OR 158*158
And set:
redView.layer.cornerRadius = redView.frame.size.height/2
I am trying to create some a circular image in every row of my table view. I have followed tutorials but my image is turning out to be a diamond shape and not a circular one. What am I doing wrong:
var cellImage = UIImage(named: pic)
cell.imageView!.image = cellImage
cell.imageView!.layer.frame = CGRectMake(0, 0, 190, 190)
cell.imageView!.layer.borderWidth = 0.5
cell.imageView!.layer.masksToBounds = false
cell.imageView!.layer.borderColor = UIColor.blueColor().CGColor
cell.imageView!.layer.cornerRadius = cell.imageView!.layer.frame.height/2
cell.imageView!.clipsToBounds = true
If you are creating your own imageView, it's better to set the cornerRadius inside the custom TableViewCell.
class CircularTableViewCell: UITableViewCell {
#IBOutlet weak var circularImageView: UIImageView!
override func layoutSubviews() {
circularImageView.layer.cornerRadius = circularImageView.bounds.height / 2
circularImageView.clipsToBounds = true
}
}
Note the cornerRadius property can't guarantee that the view will be absolutely round unless you set the imageView's width and height ratio to be 1:1. Another approach to create round view is using Mask.
public extension UIView {
public func round() {
let width = bounds.width < bounds.height ? bounds.width : bounds.height
let mask = CAShapeLayer()
mask.path = UIBezierPath(ovalInRect: CGRectMake(bounds.midX - width / 2, bounds.midY - width / 2, width, width)).CGPath
self.layer.mask = mask
}
}
This will allow you to call round() with any UIView and make sure the view is always round. e.g.
class CircularTableViewCell: UITableViewCell {
#IBOutlet weak var circularImageView: UIImageView!
override func layoutSubviews() {
circularImageView.round()
}
}
Try giving the static value(half of width or height) as corner radius.This may solve your problem.