这是我迅速编写的纯Swift版本:
public class EdgeShadowLayer: CAGradientLayer {
public enum Edge {
case Top
case Left
case Bottom
case Right
}
public init(forView view: UIView,
edge: Edge = Edge.Top,
shadowRadius radius: CGFloat = 20.0,
toColor: UIColor = UIColor.white,
fromColor: UIColor = UIColor.black) {
super.init()
self.colors = [fromColor.cgColor, toColor.cgColor]
self.shadowRadius = radius
let viewFrame = view.frame
switch edge {
case .Top:
startPoint = CGPoint(x: 0.5, y: 0.0)
endPoint = CGPoint(x: 0.5, y: 1.0)
self.frame = CGRect(x: 0.0, y: 0.0, width: viewFrame.width, height: shadowRadius)
case .Bottom:
startPoint = CGPoint(x: 0.5, y: 1.0)
endPoint = CGPoint(x: 0.5, y: 0.0)
self.frame = CGRect(x: 0.0, y: viewFrame.height - shadowRadius, width: viewFrame.width, height: shadowRadius)
case .Left:
startPoint = CGPoint(x: 0.0, y: 0.5)
endPoint = CGPoint(x: 1.0, y: 0.5)
self.frame = CGRect(x: 0.0, y: 0.0, width: shadowRadius, height: viewFrame.height)
case .Right:
startPoint = CGPoint(x: 1.0, y: 0.5)
endPoint = CGPoint(x: 0.0, y: 0.5)
self.frame = CGRect(x: viewFrame.width - shadowRadius, y: 0.0, width: shadowRadius, height: viewFrame.height)
}
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
要使用它,
let topShadow = EdgeShadowLayer(forView: targetView, edge: .Top)
targetView.layer.addSublayer(topShadow)
请注意,默认情况下,它是一个深度为20点的从黑到白的渐变。UIViewController
,让您可以切换视图四个角落的阴影,可在https://github.com/jrtibbetts/Tenebrae找到。我还对EdgeShadowLayer
进行了相当详细的记录。targetView
和 view
在这里分别代表什么?它们不是一样的吗? - Nagendra RaoUIColor.clear
作为 toColor
,这样第二个颜色就会是透明的?这样它就可以独立于底层视图的颜色。 - Lou Valencia我曾经使用Objective-C实现过UIView的内部阴影效果,现在我正在尝试将这段代码翻译成Swift。请原谅我的Swift语法不是很好。
您可以在UIView.didMoveToSuperview中调用以下函数:
func drawShadow() {
if nil == self.shadowLayer {
let size = self.frame.size
self.clipsToBounds = true
let layer: CALayer = CALayer()
layer.backgroundColor = UIColor.lightGrayColor().CGColor
layer.position = CGPointMake(size.width / 2, -size.height / 2 + 0.5)
layer.bounds = CGRectMake(0, 0, size.width, size.height)
layer.shadowColor = UIColor.darkGrayColor().CGColor
layer.shadowOffset = CGSizeMake(0.5, 0.5)
layer.shadowOpacity = 0.8
layer.shadowRadius = 5.0
self.shadowLayer = layer
self.layer.addSublayer(layer)
}
}
self.shadowLayer
是从哪里来的? - Jon Vogel我对@anoop4real所做的修改进行了微调,将toColor
设置为清晰,并使界面更符合CALayer中阴影设置的默认值,但默认不透明度为0.0。我选择了0.6作为默认值,因为它看起来最自然。
extension UIView {
func addShadow(to edges: [UIRectEdge], radius: CGFloat = 3.0, opacity: Float = 0.6, color: CGColor = UIColor.black.cgColor) {
let fromColor = color
let toColor = UIColor.clear.cgColor
let viewFrame = self.frame
for edge in edges {
let gradientLayer = CAGradientLayer()
gradientLayer.colors = [fromColor, toColor]
gradientLayer.opacity = opacity
switch edge {
case .top:
gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.0)
gradientLayer.endPoint = CGPoint(x: 0.5, y: 1.0)
gradientLayer.frame = CGRect(x: 0.0, y: 0.0, width: viewFrame.width, height: radius)
case .bottom:
gradientLayer.startPoint = CGPoint(x: 0.5, y: 1.0)
gradientLayer.endPoint = CGPoint(x: 0.5, y: 0.0)
gradientLayer.frame = CGRect(x: 0.0, y: viewFrame.height - radius, width: viewFrame.width, height: radius)
case .left:
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
gradientLayer.frame = CGRect(x: 0.0, y: 0.0, width: radius, height: viewFrame.height)
case .right:
gradientLayer.startPoint = CGPoint(x: 1.0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 0.0, y: 0.5)
gradientLayer.frame = CGRect(x: viewFrame.width - radius, y: 0.0, width: radius, height: viewFrame.height)
default:
break
}
self.layer.addSublayer(gradientLayer)
}
}
func removeAllShadows() {
if let sublayers = self.layer.sublayers, !sublayers.isEmpty {
for sublayer in sublayers {
sublayer.removeFromSuperlayer()
}
}
}
}
默认情况下是顶视图,底部使用半径为5.0以更清晰地显示。
view1.addShadow([.top, .bottom, .left, .right])
view2.addShadow([.top, .bottom, .left, .right], radius: 5.0)
view2.backgroundColor = .orange
myview.addShadow(to: [.top,.bottom], radius: 15.0)
。此外,我还进行了修改以便使用更多边缘。extension UIView{
func addShadow(to edges:[UIRectEdge], radius:CGFloat){
let toColor = UIColor(colorLiteralRed: 235.0/255.0, green: 235.0/255.0, blue: 235.0/255.0, alpha: 1.0)
let fromColor = UIColor(colorLiteralRed: 188.0/255.0, green: 188.0/255.0, blue: 188.0/255.0, alpha: 1.0)
// Set up its frame.
let viewFrame = self.frame
for edge in edges{
let gradientlayer = CAGradientLayer()
gradientlayer.colors = [fromColor.cgColor,toColor.cgColor]
gradientlayer.shadowRadius = radius
switch edge {
case UIRectEdge.top:
gradientlayer.startPoint = CGPoint(x: 0.5, y: 0.0)
gradientlayer.endPoint = CGPoint(x: 0.5, y: 1.0)
gradientlayer.frame = CGRect(x: 0.0, y: 0.0, width: viewFrame.width, height: gradientlayer.shadowRadius)
case UIRectEdge.bottom:
gradientlayer.startPoint = CGPoint(x: 0.5, y: 1.0)
gradientlayer.endPoint = CGPoint(x: 0.5, y: 0.0)
gradientlayer.frame = CGRect(x: 0.0, y: viewFrame.height - gradientlayer.shadowRadius, width: viewFrame.width, height: gradientlayer.shadowRadius)
case UIRectEdge.left:
gradientlayer.startPoint = CGPoint(x: 0.0, y: 0.5)
gradientlayer.endPoint = CGPoint(x: 1.0, y: 0.5)
gradientlayer.frame = CGRect(x: 0.0, y: 0.0, width: gradientlayer.shadowRadius, height: viewFrame.height)
case UIRectEdge.right:
gradientlayer.startPoint = CGPoint(x: 1.0, y: 0.5)
gradientlayer.endPoint = CGPoint(x: 0.0, y: 0.5)
gradientlayer.frame = CGRect(x: viewFrame.width - gradientlayer.shadowRadius, y: 0.0, width: gradientlayer.shadowRadius, height: viewFrame.height)
default:
break
}
self.layer.addSublayer(gradientlayer)
}
}
func removeAllSublayers(){
if let sublayers = self.layer.sublayers, !sublayers.isEmpty{
for sublayer in sublayers{
sublayer.removeFromSuperlayer()
}
}
}
}
Swift 5扩展
extension UIView {
func addInnerShadow() {
let innerShadow = CALayer()
innerShadow.frame = bounds
// Shadow path (1pt ring around bounds)
let radius = self.layer.cornerRadius
let path = UIBezierPath(roundedRect: innerShadow.bounds.insetBy(dx: 2, dy:2), cornerRadius:radius)
let cutout = UIBezierPath(roundedRect: innerShadow.bounds, cornerRadius:radius).reversing()
path.append(cutout)
innerShadow.shadowPath = path.cgPath
innerShadow.masksToBounds = true
// Shadow properties
innerShadow.shadowColor = UIColor.black.cgColor
innerShadow.shadowOffset = CGSize(width: 0, height: 0)
innerShadow.shadowOpacity = 0.5
innerShadow.shadowRadius = 2
innerShadow.cornerRadius = self.layer.cornerRadius
layer.addSublayer(innerShadow)
}
}
我重写了@NRitH的Swift 3解决方案,并进行了轻微的重构:
final class SideShadowLayer: CAGradientLayer {
enum Side {
case top,
bottom,
left,
right
}
init(frame: CGRect, side: Side, shadowWidth: CGFloat,
fromColor: UIColor = .black,
toColor: UIColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0),
opacity: Float = 0.5) {
super.init()
colors = [fromColor.cgColor, toColor.cgColor]
self.opacity = opacity
switch side {
case .bottom:
startPoint = CGPoint(x: 0.5, y: 1.0)
endPoint = CGPoint(x: 0.5, y: 0.0)
self.frame = CGRect(x: 0, y: frame.height - shadowWidth, width: frame.width, height: shadowWidth)
case .top:
startPoint = CGPoint(x: 0.5, y: 0.0)
endPoint = CGPoint(x: 0.5, y: 1.0)
self.frame = CGRect(x: 0, y: 0, width: frame.width, height: shadowWidth)
case .left:
startPoint = CGPoint(x: 0.0, y: 0.5)
endPoint = CGPoint(x: 1.0, y: 0.5)
self.frame = CGRect(x: 0, y: 0, width: shadowWidth, height: frame.height)
case .right:
startPoint = CGPoint(x: 1.0, y: 0.5)
endPoint = CGPoint(x: 0.0, y: 0.5)
self.frame = CGRect(x: frame.width - shadowWidth, y: 0, width: shadowWidth, height: frame.height)
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
如果您不介意使用 clipsToBounds = true
,您可以创建一个新的CALayer
,将其偏移至视图边缘之外,并将阴影添加到该视图。这就是J.Hunter的答案所做的。
J.Hunter的代码添加了一个顶部阴影,这里我将其更新为Swift 5并添加到底部。
Swift 5:
override func draw(_ rect: CGRect) {
// Create Inner Shadow. Not sure about efficiency of this.
// You may want to create a shadowLayer property
// and only run this code if it hasn't been created yet.
let size = rect.size
clipsToBounds = true // Don't want to see your fake view layer
let innerShadowLayer: CALayer = CALayer()
// Need to set a backgroundColor or it doesn't work
innerShadowLayer.backgroundColor = UIColor.black.cgColor
// Position your shadow layer (anchor point is in the center)
// on the edge of where your shadow needs to be.
// In my case this moves the shadow layer to the
// bottom edge of my view
innerShadowLayer.position = CGPoint(x: size.width / 2, y: size.height + (size.height / 2))
// This could be smaller I think, just copying J.Hunter's code...
innerShadowLayer.bounds = CGRect(x: 0, y: 0, width: size.width, height: size.height)
// Normal shadow layer properties you'd use for an outer shadow
innerShadowLayer.shadowColor = UIColor.black.cgColor
innerShadowLayer.shadowOffset = CGSize(width: 0, height: 0)
innerShadowLayer.shadowOpacity = 0.3
innerShadowLayer.shadowRadius = 3
layer.addSublayer(innerShadowLayer)
}
CGSizeMake
这样简单的东西,这就是为什么我想问一下的原因。我只是在寻找一种更Swifty的方式。 - sentyUIImageView
作为子视图,粘贴到顶部边框并沿整个宽度拉伸。如果您需要在侧边缘进行特殊处理(就像您的屏幕截图所示),也许具有插图的可拉伸图像可以解决问题。 - Nicolas MiaridrawRect(_:)
并使用Core Graphics完成所有操作。没有多余的视图,不需要图像资源,但需要更高级的代码。 - Nicolas Miari