2016-06-07 4 views
11

Я поднял голову, но не смог найти, как добавить внутреннюю тень в UIView, только сверху (сверху вниз) для Swift. Каков наилучший способ добавить внутренний круг в Свифт?Добавление внутренней тени вверху UIView

Редактировать: Я нашел несколько вопросов & ответы на SO, однако они либо в obj-c, либо выглядят настолько сложными. Я просто искал более Swifty образом, если есть какие-либо

То, что я хочу добиться:

enter image description here

+2

Взял меня 2 секунды: https://github.com/inamiy/YIInnerShadowView – Arbitur

+0

@gotnull Я нашел этот вопрос, однако я не мог понять, как добавить его только сверху. Кроме того, Arbitur, ваша ссылка в объективе-c, которую я не мог перевести. В своем SO-ответе он выглядит довольно сложным куском кода и всех его сторон. Он также не использует что-то простое, как 'CGSizeMake', поэтому я хотел спросить об этом. Я просто искал более Swifty way – senty

+1

Если вы хотите, чтобы тень оставалась только вдоль верхней границы, независимо от размытия/смещения размытия и т. Д.и не будет кровоточить в другие границы, лучше всего добавить «UIImageView» в качестве детского вида, прикрепленного к верхней границе и растянувшегося по всей ширине. Если вам нужно специальное лечение на боковых краях (как кажется, кажется, ваш скриншот), возможно, растягиваемое изображение с вставками сделает трюк. –

ответ

-2

Используйте следующую библиотеку:

https://github.com/nlampi/UIView-InnerShadow

// Add a shadow to the top of the view only 
[exampleView addInnerShadowWithRadius:3.0f 
          andColor:[UIColor colorWithWhite:0 alpha:0.45f] 
          inDirection:NLInnerShadowDirectionTop]; 

Я сделал все возможное, чтобы преобразовать расширение библиотеки в Swift (это непроверено, поэтому я не могу гарантировать, что он будет работать). Тем не менее, это должно сделать вас на правильном пути.

import UIKit 

extension UIView { 

    struct NLInnerShadowDirection: OptionSetType { 
     let rawValue: Int 

     static let None = NLInnerShadowDirection(rawValue: 0) 
     static let Left = NLInnerShadowDirection(rawValue: 1 << 0) 
     static let Right = NLInnerShadowDirection(rawValue: 1 << 1) 
     static let Top = NLInnerShadowDirection(rawValue: 1 << 2) 
     static let Bottom = NLInnerShadowDirection(rawValue: 1 << 3) 
     static let All = NLInnerShadowDirection(rawValue: 15) 
    } 

    func removeInnerShadow() { 
     for view in self.subviews { 
      if (view.tag == 2639) { 
       view.removeFromSuperview() 
       break 
      } 
     } 
    } 

    func addInnerShadow() { 
     let c = UIColor() 
     let color = c.colorWithAlphaComponent(0.5) 

     self.addInnerShadowWithRadius(3.0, color: color, inDirection: NLInnerShadowDirection.All) 
    } 

    func addInnerShadowWithRadius(radius: CGFloat, andAlpha: CGFloat) { 
     let c = UIColor() 
     let color = c.colorWithAlphaComponent(alpha) 

     self.addInnerShadowWithRadius(radius, color: color, inDirection: NLInnerShadowDirection.All) 
    } 

    func addInnerShadowWithRadius(radius: CGFloat, andColor: UIColor) { 
     self.addInnerShadowWithRadius(radius, color: andColor, inDirection: NLInnerShadowDirection.All) 
    } 

    func addInnerShadowWithRadius(radius: CGFloat, color: UIColor, inDirection: NLInnerShadowDirection) { 
     self.removeInnerShadow() 

     let shadowView = self.createShadowViewWithRadius(radius, andColor: color, direction: inDirection) 

     self.addSubview(shadowView) 
    } 

    func createShadowViewWithRadius(radius: CGFloat, andColor: UIColor, direction: NLInnerShadowDirection) -> UIView { 
     let shadowView = UIView(frame: CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)) 
     shadowView.backgroundColor = UIColor.clearColor() 
     shadowView.tag = 2639 

     let colorsArray: Array = [ andColor.CGColor, UIColor.clearColor().CGColor ] 

     if direction.contains(.Top) { 
      let xOffset: CGFloat = 0.0 
      let topWidth = self.bounds.size.width 

      let shadow = CAGradientLayer() 
      shadow.colors = colorsArray 
      shadow.startPoint = CGPointMake(0.5, 0.0) 
      shadow.endPoint = CGPointMake(0.5, 1.0) 
      shadow.frame = CGRectMake(xOffset, 0, topWidth, radius) 
      shadowView.layer.insertSublayer(shadow, atIndex: 0) 
     } 

     if direction.contains(.Bottom) { 
      let xOffset: CGFloat = 0.0 
      let bottomWidth = self.bounds.size.width 

      let shadow = CAGradientLayer() 
      shadow.colors = colorsArray 
      shadow.startPoint = CGPointMake(0.5, 1.0) 
      shadow.endPoint = CGPointMake(0.5, 0.0) 
      shadow.frame = CGRectMake(xOffset, self.bounds.size.height - radius, bottomWidth, radius) 
      shadowView.layer.insertSublayer(shadow, atIndex: 0) 
     } 

     if direction.contains(.Left) { 
      let yOffset: CGFloat = 0.0 
      let leftHeight = self.bounds.size.height 

      let shadow = CAGradientLayer() 
      shadow.colors = colorsArray 
      shadow.frame = CGRectMake(0, yOffset, radius, leftHeight) 
      shadow.startPoint = CGPointMake(0.0, 0.5) 
      shadow.endPoint = CGPointMake(1.0, 0.5) 
      shadowView.layer.insertSublayer(shadow, atIndex: 0) 
     } 

     if direction.contains(.Right) { 
      let yOffset: CGFloat = 0.0 
      let rightHeight = self.bounds.size.height 

      let shadow = CAGradientLayer() 
      shadow.colors = colorsArray 
      shadow.frame = CGRectMake(self.bounds.size.width - radius, yOffset, radius, rightHeight) 
      shadow.startPoint = CGPointMake(1.0, 0.5) 
      shadow.endPoint = CGPointMake(0.0, 0.5) 
      shadowView.layer.insertSublayer(shadow, atIndex: 0) 
     } 

     return shadowView 
    } 
} 
+0

Спасибо, что ответили. Нужно ли мне создавать для этого заголовок мостов? Есть ли способ добиться этого на Свифт? Я был бы признателен – senty

+0

@senty: Да, самым простым способом было бы создать заголовок моста, поскольку в Objective-C есть много кода. – fuzz

+0

Я стесняюсь использовать мост, потому что каждый раз, когда я пытаюсь, он продолжает ломаться. Если у вас есть время, можете ли вы рассказать мне, какие бит необходимы, чтобы я мог заставить его работать исключительно в Swift? Это было бы очень полезно для всех – senty

9

Я использовал внутреннюю тень для UIView, используя Objective-C. Я пытаюсь перевести код в быстрый. Пожалуйста, простите меня за мой плохой стремительной синтаксис

вы можете вызвать функцию ниже в 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) 
    } 
} 
+1

Безусловно лучший ответ. ИМХО. Другие ответы используют градиенты, которые не являются тем, как тени рисуются в Core Graphics. – beyowulf

+0

@beyowulf Спасибо за исправление моего кода. –

+0

Откуда берется 'self.shadowLayer'? –

16

Вот чистый 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) 
view.layer.addSublayer(topShadow) 

Обратите внимание, что по умолчанию используется градиент от черного до белого, который имеет глубину 20 пикселей.

Полный код с образцом UIViewController, который позволяет вам переключать тени на все четыре угла обзора, находится на https://github.com/jrtibbetts/Tenebrae. Я также полностью документировал EdgeShadowLayer.

3

я переписал @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) 
    } 
} 
0

я обновил @ ответ NRitH и сделал расширение из него также модифицирована таким образом, что вы можете манипулировать несколько ребер в один идти

использование

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() 
      } 
     } 
    } 

} 

Shadow

Смежные вопросы