Add shadow at bottom of UIview - ios

Actually, I want shadow at bottom of UIView.
I had tried some code but getting shadow from top side only and I am using swift 3 currently.
Please follow below code :
let horizontalLine = UIView()
horizontalLine.frame = CGRect.zero
horizontalLine.backgroundColor = .lightGray
self.addSubview(horizontalLine)
horizontalLine.layer.shadowColor = UIColor.gray.cgColor
horizontalLine.layer.shadowOpacity = 0.5
horizontalLine.layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
horizontalLine.layer.masksToBounds = false
horizontalLine.backgroundColor = .lightGray
horizontalLine.layer.shadowRadius = 5
Also I am using snapkit library for UI Setting:
horizontalLine.snp.makeConstraints{ (make) in
make.height.equalTo(5)
make.width.equalTo(self.snp.width)
make.left.equalTo(self.snp.left)
make.right.equalTo(self.snp.right)
make.bottom.equalTo(self.snp.bottom)
}
How it looks now:
Also, I do have collection view just down that.
And we have one more collection view just backside of that line.
Please guide me guys.
Thanks in advance.

Based on the image you show, it looks like the "shadow" you are seeing is in the cell content of the collection view above your horizontalLine view.
It also looks like the shadow on your horizontalLine view is not visible at all - because its superview is clipping it.
Try this:
// new line
self.clipsToBounds = false
// rest of your code...
let horizontalLine = UIView()

try this..
let horizontalLine = UIView()
horizontalLine.frame = CGRect(x: 150, y: 350, width: 150, height: 150)
horizontalLine.backgroundColor = .lightGray
self.view.addSubview(horizontalLine)
horizontalLine.layer.shadowColor = UIColor.red.cgColor
horizontalLine.layer.shadowOffset = CGSize(width: 0.0, height: 3.0)
horizontalLine.layer.shadowOpacity = 1.0
horizontalLine.layer.shadowRadius = 0.0
horizontalLine.layer.masksToBounds = false
horizontalLine.layer.cornerRadius = 4.0

Related

UIScrollView Subviews being misplaced when scaled down and Subviews not showing up when rounded

so I'm making my first Swift iOS app. I have two problems that I would like some help with.
First problem: I'm running into some issues with subviews that I created programmatically not being aligned properly when displayed on a small screen.
This first picture shows how I intend the scrollview to look. (iPhone 11 Pro Max)
However, this is what it looks like when it's on a smaller screen. (iPhone 8)
I think the issue is with me creating the subviews programmatically as the scrollview's size is what I want it to be.
Here's the swift code that I used inside viewDidLoad():
var districtNewsSize = 10;
var districtNewsFrame = CGRect(x:0,y:0,width:0,height:0);
// District News -----
districtNewsPageControl.numberOfPages = districtNewsSize;
for aIndex in 0..<districtNewsSize{
districtNewsFrame.origin.x = districtNewsScrollView.frame.size.width * CGFloat(aIndex);
districtNewsFrame.size = districtNewsScrollView.frame.size;
// create content in scrollview
let contentView = UIButton(frame: districtNewsFrame);
contentView.backgroundColor = makeColor(r: 147, g: 66, b: 78);
contentView.setTitle("titletext", for: .normal);
contentView.layer.cornerRadius = 20; // just to show how displaced the views are
// add contentview to scrollview
self.districtNewsScrollView.addSubview(contentView);
}
// change horizontal size of scrollview
districtNewsScrollView.contentSize = CGSize(width: districtNewsScrollView.frame.size.width * CGFloat(districtNewsSize), height: districtNewsScrollView.frame.size.height);
districtNewsScrollView.delegate = self;
Second Problem: When attempting to round the top two corners of the scrollview, the content inside the scrollview seems to disappear.
This is a picture of the first subview.
This is a picture of the second subview.
I also have a suspicion that this is caused by my function that I am using to round the top edges.
Here's the extension function I made for UIScrollView:
extension UIScrollView{
func setRoundedEdge(corners:UIRectCorner, radius: CGFloat){ // label.setRoundedEdge([.TopLeft, . TopRight], radius: 10)
let maskPath1 = UIBezierPath(roundedRect: bounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius))
let maskLayer1 = CAShapeLayer()
maskLayer1.frame = bounds
maskLayer1.path = maskPath1.cgPath
layer.mask = maskLayer1
}
}
This is how I'm calling the function in viewDidLoad():
districtNewsScrollView.setRoundedEdge(corners: [.topRight,.topLeft], radius: 30);
Any help will greatly be appreciated. I've been stuck on these two problems and can't find anything online (probably because I'm not wording it right but I don't know how to describe these issues). Thank you!
I assume you are using storyboard for scrollview and programmatically adding subviews in viewDidLoad,
districtNewsFrame.origin.x = districtNewsScrollView.frame.size.width * CGFloat(aIndex);
districtNewsFrame.size = districtNewsScrollView.frame.size;
Should be changed to
districtNewsFrame.origin.x = UIScreen.main.bounds.size.width * CGFloat(aIndex);
districtNewsFrame.size = UIScreen.main.bounds.frame.size;
Use screen's size on viewDidLoad since the views in storyboards are loaded but constraints in auto layout is not yet applied.
For second question,
change extension to
extension UIScrollView{
func setRoundedEdge(corners:UIRectCorner, radius: CGFloat){ // label.setRoundedEdge([.TopLeft, . TopRight], radius: 10)
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
layer.mask = mask
}
}
and view controller to
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews();
districtNewsScrollView.setRoundedEdge(corners: [.topRight,.topLeft], radius: 30);
}
Here's what I did to fix both issues:
// District News -----
districtNewsFrame.size = districtNewsScrollView.frame.size;
districtNewsFrame.size.width = UIScreen.main.bounds.size.width - 34;
for aIndex in 0..<districtNewsSize{
//districtNewsFrame.origin.x = (UIScreen.main.bounds.size.width-52) * CGFloat(aIndex);
//districtNewsFrame.size = UIScreen.main.bounds.size;
districtNewsFrame.origin.x = (districtNewsFrame.size.width * CGFloat(aIndex));
// create content in scrollview
let contentView = UIButton(frame: districtNewsFrame); // wrapper for article
//testButton.setImage(UIImage(named: "ahsldpi.png"), for: .normal);
contentView.backgroundColor = makeColor(r: 147, g: 66, b: 78);
// content inside contentView -------
let articleContentFrame = CGRect(x:0,y:0,width:districtNewsFrame.width,height:districtNewsFrame.height-60);
let articleContent = UIView(frame: articleContentFrame); // may be image?
articleContent.backgroundColor = makeColor(r: 138, g: 138, b: 138);
let articleLabelFrame = CGRect(x:0,y:districtNewsFrame.height-60,width:districtNewsFrame.width,height:60);
let articleLabel = UILabel(frame: articleLabelFrame);
articleLabel.text = " " + "Title";
articleLabel.backgroundColor = UIColor.white;
articleLabel.font = UIFont(name: "DINCondensed-Bold", size: 30);
// add content inside contentView to contentview
contentView.addSubview(articleContent);
contentView.addSubview(articleLabel);
// add contentview to scrollview
contentView.setRoundedEdge(corners: [.topRight,.topLeft,.bottomLeft,.bottomRight], radius: 30);
self.districtNewsScrollView.addSubview(contentView);
}
// change horizontal size of scrollview
districtNewsScrollView.contentSize = CGSize(width: (districtNewsFrame.size.width * CGFloat(districtNewsSize)), height: districtNewsScrollView.frame.size.height);
districtNewsScrollView.delegate = self;
```

iOS - Display a progress indicator at the center of the screen rather than the view

I want to display a progress indicator at the center of the screen, NOT the view. It should be the center of the view because the view is scrollable. Most answers only tells how to center it in the view. I have this code:
let screenBound = UIScreen.main.bounds
let progressIndc = UIActivityIndicatorView()
progressIndc.frame = CGRect(x: screenBound.width / 2 - 10,
y: screenBound.height / 2 - 10,
width: 20, height: 20)
progressIndc.hidesWhenStopped = true
progressIndc.color = UIColor.gray
progressIndc.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
// self.view is scroll view
self.view.addSubview(progressIndc)
progressIndc.startAnimating()
But it shown near the top in iPhone 7. What should be the right way? I can also do a blocking pop-up dialog with a progress indicator.
if you want to keep the indicator view at the center of screen while scrolling, you can add a overlay view to the current topmost UIWindow, then add your indicator view to the overlay view:
guard let topWindow = UIApplication.shared.windows.last else {return}
let overlayView = UIView(frame: topWindow.bounds)
overlayView.backgroundColor = UIColor.clear
topWindow.addSubview(overlayView)
let hudView = UIActivityIndicatorView()
hudView.bounds = CGRect(x: 0, y: 0, width: 20, height: 20)
overlayView.addSubview(hudView)
hudView.center = overlayView.center
you should do this after the topmost UIViewController's view was attached on the top UIWindow, for example, in viewDidAppearmethod.
you can use center property of UIView
progressIndc.center = self.view.center
for e.g
let screenBound = UIScreen.main.bounds
let progressIndc = UIActivityIndicatorView()
progressIndc.frame = CGRect(x: screenBound.width / 2 - 10,
y: screenBound.height / 2 - 10,
width: 20, height: 20)
progressIndc.hidesWhenStopped = true
progressIndc.color = UIColor.gray
progressIndc.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
// self.view is scroll view
progressIndc.center = self.view.center
self.view.addSubview(progressIndc)
progressIndc.startAnimating()
output
you can try this one to add you indicator on top of the screen. but it's not pretty solution -
AppDelegate.sharedInstance.window?.addSubview(progressIndc);

How to use preservesSuperviewLayoutMargins in nested views

I'm trying to make used of preservesSuperviewLayoutMargins through a nested view hierarchy but hitting a lot of issues with UIKit and wondering what I am doing wrong (or whether this is a genuine bug).
I'm trying to lay out a handful of views (some by the side of each other, some above each other) like so:
// Various combinations here will create different visual results (it will either work or won't)
let i1 = ImageView()
//let i1 = LabelView()
let i2 = ImageView()
//let i2 = LabelView()
let i3 = ImageView()
//let i3 = LabelView()
let view = LeftRight(left: i1, right: TopBottom(top: i2, bottom: i3))
//let view = LeftRight(left: TopBottom(top: i2, bottom: i3), right: i1)
With some layout's I can get it to work, shown below. You can see that the images on the right are correctly indented against the green view, which is in turn correctly indented against the white view.
But with others I am struggling:
Running code similar to this in an app I can get a complete lockup and memory runaway.
The indenting is done using layoutMargins like this:
let masterView = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
masterView.translatesAutoresizingMaskIntoConstraints = false
masterView.layoutMargins = UIEdgeInsets(top: 5.0, left: 5.0, bottom: 5.0, right: 5.0)
let subView = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
subView.translatesAutoresizingMaskIntoConstraints = false
subView.layoutMargins = UIEdgeInsets(top: 5.0, left: 5.0, bottom: 5.0, right: 5.0)
Here's a sample of the image layout from a playground. The full playground project can be found here and can easily be loaded up and ran in XCode to see what I mean.
class ImageView: UIView {
init() {
super.init(frame: CGRect(x: 0, y: 0, width: 1000, height: 1000))
self.preservesSuperviewLayoutMargins = true
self.layoutMargins = .zero
let imageView = UIImageView(image: UIImage(named: "jesus"))
imageView.contentMode = .center
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.clipsToBounds = true
self.clipsToBounds = true
imageView.backgroundColor = UIColor.red
self.addSubview(imageView)
imageView.leftAnchor.constraint(equalTo: self.layoutMarginsGuide.leftAnchor).isActive = true
imageView.rightAnchor.constraint(equalTo: self.layoutMarginsGuide.rightAnchor).isActive = true
imageView.topAnchor.constraint(equalTo: self.layoutMarginsGuide.topAnchor).isActive = true
imageView.bottomAnchor.constraint(equalTo: self.layoutMarginsGuide.bottomAnchor).isActive = true
}
}
I believe that you forgot something those are required.
Implementation of intrinsicContentSize on ImageView and Label
Missing constraints that make both subviews have the same width and height in those 2 UIView subclasses (TopBottom and LeftRight)
right view of view (LeftRight) still haven't been set its translatesAutoresizingMaskIntoConstraints property to false
Add the constraint for bottom of the outmost frame view
Call layoutIfNeeded() on frame view
top.widthAnchor.constraint(equalTo: bottom.widthAnchor).isActive = true
top.heightAnchor.constraint(equalTo: bottom.heightAnchor).isActive = true
Ok. Found your issue. Your master view and your subview have both a frame of size 500x500 and a marginLayout of 5 points per edge. If you instantiate those with a frame of .zero then everything should be fine.
Update
After taking a bit more time with your Playground I also added this to ImageView:
private var imageView: UIImageView!
override var intrinsicContentSize: CGSize {
return imageView?.intrinsicContentSize ?? .zero
}
and LabelView:
private var textLabel: UILabel!
override var intrinsicContentSize: CGSize {
return textLabel?.intrinsicContentSize ?? .zero
}
Now in your init methods of both ImageView and LabelView use these instance properties instead of a local variable. After doing so it seems that all possible combinations work. If you had one specific combination that you knew it didn't please let me know so I can test it.

Why is my table view shadow scrolling with my table view?

I added shadow to my table view but unfortunately when I scroll through the table view the shadow also moves with the table. The code for adding shadow is as follows:
func addShadow(to myView: UIView){
let shadowPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: uiView.frame.width, height: uiView.frame.height * 1.1))
uiView.layer.shadowColor = UIColor.black.cgColor
uiView.layer.shadowOffset = CGSize(width: 0.2, height: 0)
uiView.layer.shadowOpacity = 0.5
uiView.layer.shadowRadius = 5.0
uiView.layer.masksToBounds = false
uiView.layer.shadowPath = shadowPath.cgPath
}
Can you please explain to me why is this happening and how to make the shadow stick to its designated location?
Thank you in advance.
If you are adding shadow on tableView, it will scroll along with tableview data. To prevent that you have to add UIView first. Add tableview on that view. Add shadow for the UIView you have taken. It will stick to designated location.
This is my solution in Swift 3 with an UIView and a CAGradientLayer inside.
override func viewWillAppear(_ animated: Bool) {
addShadow(myView: myTab)
}
func addShadow(myView: UIView){
let shadowView = UIView()
shadowView.center = CGPoint(x: myView.frame.minX,y:myView.frame.minY - 15)
shadowView.frame.size = CGSize(width: myView.frame.width, height: 15)
let gradient = CAGradientLayer()
gradient.frame.size = shadowView.frame.size
let stopColor = UIColor.clear.cgColor
let startColor = UIColor.black.withAlphaComponent(0.8).cgColor
gradient.colors = [stopColor,startColor]
gradient.locations = [0.0,1.0]
shadowView.layer.addSublayer(gradient)
view.addSubview(shadowView)
}

Swift - UIView scaling

Question:
What is the appropriate to size a subview (or set of subviews) so that they fit (scale) to the appropriate bounds - or in this case make sure the blue circle fits inside the yellow square. Picture and playground code below!
import UIKit
let topLevelFrame = CGRectMake(0, 0, 400, 400)
let topView = UIView(frame: topLevelFrame)
topView.backgroundColor = UIColor.grayColor()
topView
let windowFrame = CGRectMake(20, 20, 300, 300)
let windowView = UIView(frame: windowFrame)
windowView.backgroundColor = UIColor.yellowColor()
topView.addSubview(windowView)
topView
let contentFrame = CGRectMake(-200, -200, 400, 400)
let contentView = UIView(frame: contentFrame)
//contentView.alpha = 5
contentView.layer.cornerRadius=200
contentView.backgroundColor = UIColor.blueColor()
contentView
windowView.clipsToBounds = true
windowView.addSubview(contentView)
windowView.bounds
windowView.frame
// How do I fit the blue circle to scale appropriately inside the yellow square?
topView
Try changing your code to the following:
let contentFrame = CGRectMake(windowFrame.origin.x, windowFrame.origin.y, windowFrame.size.width, windowFrame.size.height)
let contentView = UIView(frame: contentFrame)
contentView.layer.cornerRadius = windowFrame.size.height / 2.0
contentView.center = CGPoint(x:windowFrame.size.width / 2.0, y:windowFrame.size.height / 2.0)
contentView.backgroundColor = UIColor.blueColor()
contentView

Resources