Border not getting applied to full view - ios

I am setting up the dashed border to my UIView it is getting applied in iPhone 6,7,8. But if open in iPhone XR it is coming like this.
My view is named as camerauiview
The border I am setting up in this function by calling it in viewdidload().
func setupBorder(){
let dashedborder = CAShapeLayer()
dashedborder.strokeColor = #colorLiteral(red: 0.4076032743, green: 0.1454663677, blue: 0.9795397903, alpha: 1)
dashedborder.lineWidth = 2
dashedborder.lineDashPattern = [7 , 7]
dashedborder.frame = camerauiview.bounds
dashedborder.fillColor = nil
dashedborder.path = UIBezierPath(rect: camerauiview.bounds).cgPath
camerauiview.layer.addSublayer(dashedborder)
}
This is coming like this.
For reference, I have given background color as grey just to showcase how much area it is covering.

Use func viewDidLayoutSubviews()
When the bounds change for a view controller's view, the view adjusts the positions of its subviews and then the system calls this method. However, this method being called does not indicate that the individual layouts of the view's subviews have been adjusted. Each subview is responsible for adjusting its own layout.
Your view controller can override this method to make changes after the view lays out its subviews. The default implementation of this method does nothing.
Use your func setupBorder() in override func viewDidLayoutSubviews() Method like:
override func viewDidLayoutSubviews() {
setupBorder()
}

Related

Swift UITableViewCell Shadow not appearing

I am trying to create custom table view cell which works fine in my other UIViewControllers. However, in one of my controllers, the shadow is not growing, I can barely see the shadow.
Here is an image of the shadow being shown in red, you can see it is barely visible.
My cell has a UIView added inside the contentView to creating floating cell effects - the same code and same storyboard layouts are being used across my controllers but this is the only table view where the shadow issue is occurring - so I must be missing something.
My addShadow extension:
extension UIView {
func addShadow(offset: CGSize, color: UIColor, radius: CGFloat, opacity: Float) {
layer.masksToBounds = false
layer.shadowOffset = offset
layer.shadowColor = color.cgColor
layer.shadowRadius = radius
layer.shadowOpacity = opacity
}
}
My awakeFromNib on the custom cell:
:: cellContentView is my UIView added to the base contentView of the cell.
override func awakeFromNib() {
super.awakeFromNib()
self.backgroundColor = .clear
self.selectionStyle = .none
cellContentView?.layer.masksToBounds = true
cellContentView?.round(corners: [.topLeft, .topRight, .bottomLeft, .bottomRight], radius: 10)
cellContentView?.addShadow(offset: CGSize(width: 40, height: 60), color: UIColor.red, radius: 10, opacity: 1)
cellContentView?.layer.shouldRasterize = true
}
Note: The .round is an extension being used on all my cells.
No matter what radius or offset I add for this shadow, it does not get bigger than the image. Also, none of my other cells in the their controllers require the shouldRasterize property to be set, but this does.
Does anyone know what is happening here?
Thanks :)
Edit
Strangely, if I add constraints around my view to keep the gaps large between my view and the cell content view, the background colour disappears - this is set to white in the storyboard.
You should call in the layoutSubviews method. because shadow should add after the view is uploaded
override func awakeFromNib() {
super.awakeFromNib()
//init methods
}
override public func layoutSubviews() {
super.layoutSubviews()
//Added shadow
self.reloadLayers()
}
private func reloadLayers() {
self.layer.cornerRadius = 5
self.addShadow(.TransactionCell)
}
I hope it helps
Content view will fill you cell, so you need to add shadow to view inside content view which has all your components inside it. Then add constraints to it with gap between that view and content view. Second, 40 and 60 properties for shadow is likely too large, when I said too large I mean unbelievable large, because gap between content views in cells are no more than 15 - 30 even less. so try it with much less values, while radius can remain 10 but you will see what value fit the best. If cell content view is your custom view just values will did the job if your view is not kind of transparent or any inside it, in that case it won't, and there is hard to fix that, I tried many libraries and custom codes and it is never ok.
squircleView.layer.cornerRadius = 40
squircleView.layer.cornerCurve = CALayerCornerCurve.continuous
squircleView.layer.shadowColor = UIColor.systemGray.cgColor
squircleView.layer.shadowOpacity = 0.7
squircleView.layer.shadowOffset = CGSize(width: 0, height: 0.5)
squircleView.layer.shadowRadius = 5

How to create the shadow of material-like table view cells?

I am trying to make my table view cells look "material". Here is something similar to what I want to do (source):
Note that there is a shadow around the whole table view in the above image. What I want is that shadow, but applied to each table view cell, instead of the whole table view.
I first designed my cell in an XIB file. I put a UIView called containerView as a subview of the content view. I added constraints so that the containerView has a top, bottom, left, right margin of 8. This is so that the containerView is a little smaller than the content view, so that the shadow I put on it will be visible.
I also added a UILabel called label as the subview of containerView to show some text.
This is the UITableViewCell subclass:
class QueueItemCell: UITableViewCell {
#IBOutlet var label: UILabel!
#IBOutlet var container: UIView!
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
...
}
override func setSelected(_ selected: Bool, animated: Bool) {
...
}
override func awakeFromNib() {
container.layer.shadowColor = UIColor.black.cgColor
container.layer.shadowOpacity = 0.7
container.layer.shadowOffset = CGSize(width: 3, height: 9)
container.layer.shadowRadius = 4
container.layer.cornerRadius = 4
container.layer.shadowPath = UIBezierPath(roundedRect: container.bounds, cornerRadius: 4).cgPath
selectionStyle = .none
}
}
There is nothing special about the data source and delegate methods except that I set the cells' height to 61 in heightForRowAt.
When I run the app, I got something like this:
The shadow on the bottom and left edges are quite good. But the right edge is a total disaster. The top edge also does not have a shadow, which is undesirable. I tried to do trial and error with shadowPath and shadowOffset but there's always one or two edges that looks bad.
How can I achieve a shadow on all edges of the cell, as shown in the first image?
in awakeFromNib you have wrong view size. You need to move container.layer.shadowPath = UIBezierPath(roundedRect: container.bounds, cornerRadius: 4).cgPath into layoutSubviews
or remove this code
container.layer.shadowPath = UIBezierPath(roundedRect: container.bounds, cornerRadius: 4).cgPath
so shadow will be configured automatically

How to correctly round edges of a table view cell with dynamic height

I am having a problem with one of my table views. I am writing a messaging page for my app that uses a table view to display the messages sent and received. The table cells need to change height based on each cells content. I have the sizing working correctly but I now need to round the cells edges to fit the UI design. The way that I have done this in the past with non-dynamic heights is by calling a function to round each corner in the override function "layoutSubViews()" in the tableViewCell:
func roundAllCorners(radius: CGFloat) {
let allCorners: UIRectCorner = [.topLeft, .bottomLeft, .bottomRight, .topRight]
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: allCorners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
}
If I try calling this function but the cell is dynamically sized then the left edge cuts off half a centimeter. If you scroll the cell off screen and back again though it fixes it. Hope you can find a solution to my problem, has been a pain in the neck for a while. Thanks.
It might be you also need to override the setter for frame and call it in there. Any any case this is not a good idea for multiple reasons. The thing is that table view cell has many views (including itself being a view) like content view and background view...
I suggest that you add yet another view on the content view which holds all your cell views. Then make this view a subclass and handle all the rounding in there. So from the storyboard perspective you would have something like:
- UITableViewCell
- contentView
- roundedContainer
- imageView
- button
- label
...
The rounded view has (or should have) constraints so layoutSubViews should be enough to override for setting up corner radius.
You can have a neat class you can use to round your view like:
class RoundedView: UIView {
#IBInspectable var cornerRadius: CGFloat = 0.0 {
didSet {
refresh()
}
}
#IBInspectable var fullyRounded: Bool = false {
didSet {
refresh()
}
}
override func layoutSubviews() {
super.layoutSubviews()
refresh()
}
private func refresh() {
layer.cornerRadius = fullyRounded ? min(bounds.width, bounds.height) : cornerRadius
}
}
As already mentioned by #iDeveloper it might be better to use cornerRadius of a layer. But if you need to use a shape layer you can do that as well in this class.
Make sure to clip bounds on this view.
Make sure you RELOAD THE TABLEVIEW after calling your function
yourTableView.reloadData()
You can use self sizing table view cell according to the content. Now you can follow the previous implementation for rounded corner cell.
Place the below code inside viewDidLoad.
tableView.estimatedRowHeight = YourEstimatedTableViewHeight
tableView.rowHeight = UITableViewAutomaticDimension
Note: You have to give the top and bottom constraints to the content properly.
For detailed implementation you can follow self-sizing-table-view-cells

Adding an overlay view to UICollectionViewCell - keeps overlaying

I'm trying to add a 50% black alpha view on every collection view cell. The collection view cells have a background photograph and text on top. Would like the overlay view to be in between the two.
In my cellForItemAt method, I use the following:
let overlayView = UIView()
overlayView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5)
overlayView.frame = cell.bounds
cell.addSubview(overlayView)
The problem is as i scroll down, then up, the overlay keeps adding, making the alpha much darker than 50%. Additionally, the overlayView is being added on top of my text (I need it below the text.)
How can I prevent the overlay from adding multiple times, and adding it in between the correct layers of the cell?
UITableView has a method of reusing cells to make it more efficient (keeping only the required cells in memory). Because of this the reused cell may already have this subview, so calling addSubview again causes another view to be added on top of it.
Here is how to solve this:
Move addSubview(overlayView) to the layoutSubviews() method inside your cell subclass.
override func layoutSubviews() {
super.layoutSubviews()
addSubview(overlayView)
}
Remove the overlay view in the prepareForReuse() method inside your cell subclass.
override func prepareForReuse() {
super.prepareForReuse()
overlayView.removeFromSuperview()
}
Note that this requires you to define the overlay view in the cell's subclass (which you should probably do since the cell itself should be responsible for its own subviews).
This happens because your cells are dequeued and reused multiple times, therefore, you are adding multiple layers.
Put this code inside your cell's class
override func awakeFromNib() {
super.awakeFromNib()
let overlayView = UIView()
overlayView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5)
overlayView.frame = self.bounds
self.addSubview(overlayView)
}
Or if you want to achieve the same result you can set black backgroundColor and set imageView's alpha to 50%
cell.backgroundColor = .black
cell.imageView.alpha = 0.5
Avoid adding this in cellForItem. The cells are reused, hence if you keep adding the view it would add one top of another. On reusing the cell the previously added view is not removed. Instead you can add the view in Prototype cell or XIB and set its alpha to whatever you want. Or if you are creating the cell programatically you can it in awakeFromNib()

How can I prevent delay of layer clipsToBounds at page transition

I have a page which has radius corners.
When the page appear, corners are not rounded at first. After seconds, corners become rounded.
I want to make corners rounded from at first.
I set properties to view at custom view's initializer.
class ModalView: UIView {
init() {
super.init(frame: .zero)
self.backgroundColor = UIColor.whiteColor()
self.clipsToBounds = true
self.layer.cornerRadius = 10
}
}
class ViewController: UIViewController {
override func loadView() {
let customView = ModalView()
customView.frame = self.view.frame
self.view = customView
}
}
This problem was solved.
The situation was like below.
image
So, I set cornerRadius to navigation controller's view.
self.navigationController?.view.layer.cornerRadius = 10
self.navigationController?.view.clipsToBounds = true
Your code does not compile.
First, initWithCoder is missing, maybe you omitted it.
Secondly, in init you call super initWithFrame, which internally is calling again init, here is where the program crashes, i don't get how yours is working but this explains the delay.
And third, loadView is used for controllers purely made in code, if you have a xib you already have a view.
Four, UIViewController does not extend a UIView, i don't even understand what you wanted to do there, you can't redefine a class.

Resources