programing

모서리가 둥글고 그림자가 드리워진 UIView?

lovejava 2023. 5. 14. 09:57

모서리가 둥글고 그림자가 드리워진 UIView?

저는 몇 년 동안 애플리케이션을 연구해 왔고 간단한 디자인 요청을 받았습니다. UI 뷰에서 모서리를 둥글게 만들고 드롭 섀도우를 추가하세요.하기에 따라 하기.

나는 커스텀을 원합니다.UIView: 저는 둥근 모서리가 있는 빈 흰색 뷰와 밝은 드롭 섀도우(조명 효과 없음)를 원했습니다.나는 그것들을 하나씩 할 수 있지만 보통.clipToBounds/maskToBounds충돌이 발생합니다.

여기에 이미지 설명 입력

스위프트

여기에 이미지 설명 입력

// corner radius
blueView.layer.cornerRadius = 10

// border
blueView.layer.borderWidth = 1.0
blueView.layer.borderColor = UIColor.black.cgColor

// shadow
blueView.layer.shadowColor = UIColor.black.cgColor
blueView.layer.shadowOffset = CGSize(width: 3, height: 3)
blueView.layer.shadowOpacity = 0.7
blueView.layer.shadowRadius = 4.0

옵션 탐색

여기에 이미지 설명 입력

여기에 이미지 설명 입력

여기에 이미지 설명 입력

여기에 이미지 설명 입력

여기에 이미지 설명 입력

문제 1: 섀도가 잘립니다.

보기의 범위에 내용을 클리핑하려는 하위 계층 또는 하위 뷰(이미지와 같은)가 있는 경우 어떻게 해야 합니까?

여기에 이미지 설명 입력

우리는 이것을 성취할 수 있습니다.

blueView.layer.masksToBounds = true

, (또는,는,blueView.clipsToBounds = true동일한 결과를 제공합니다.)

여기에 이미지 설명 입력

하지만, 이런!그림자도 범위를 벗어났기 때문에 그림자가 잘렸습니다!무엇을 해야 하나?무엇을 해야 하나?

해결책

그림자와 테두리에 대해 별도의 뷰를 사용합니다.기본 보기는 투명하며 그림자가 있습니다.테두리 보기는 테두리에 있는 다른 하위 내용을 클리핑합니다.

// add the shadow to the base view
baseView.backgroundColor = UIColor.clear
baseView.layer.shadowColor = UIColor.black.cgColor
baseView.layer.shadowOffset = CGSize(width: 3, height: 3)
baseView.layer.shadowOpacity = 0.7
baseView.layer.shadowRadius = 4.0

// add the border to subview
let borderView = UIView()
borderView.frame = baseView.bounds
borderView.layer.cornerRadius = 10
borderView.layer.borderColor = UIColor.black.cgColor
borderView.layer.borderWidth = 1.0
borderView.layer.masksToBounds = true
baseView.addSubview(borderView)

// add any other subcontent that you want clipped
let otherSubContent = UIImageView()
otherSubContent.image = UIImage(named: "lion")
otherSubContent.frame = borderView.bounds
borderView.addSubview(otherSubContent)

그러면 다음과 같은 결과가 나타납니다.

여기에 이미지 설명 입력

문제 2: 성능 저하

둥근 모서리와 그림자를 추가하면 성능이 크게 향상될 수 있습니다.섀도에 대해 미리 정의된 경로를 사용하고 래스터화하도록 지정하여 성능을 향상시킬 수 있습니다.위의 예에 다음 코드를 추가할 수 있습니다.

baseView.layer.shadowPath = UIBezierPath(roundedRect: baseView.bounds, cornerRadius: 10).cgPath
baseView.layer.shouldRasterize = true
baseView.layer.rasterizationScale = UIScreen.main.scale

자세한 내용은 이 게시물을 참조하십시오.여기도 보고 여기도 보세요.

이 답변은 Swift 4와 Xcode 9로 테스트되었습니다.

은 테두리, 반지름 및다음코조각리테은두드다및다추가니음합에섀를도드롭에 합니다.v,aUIView:

// border radius
[v.layer setCornerRadius:30.0f];

// border
[v.layer setBorderColor:[UIColor lightGrayColor].CGColor];
[v.layer setBorderWidth:1.5f];

// drop shadow
[v.layer setShadowColor:[UIColor blackColor].CGColor];
[v.layer setShadowOpacity:0.8];
[v.layer setShadowRadius:3.0];
[v.layer setShadowOffset:CGSizeMake(2.0, 2.0)];

Swift 5 버전:

// border radius
v.layer.cornerRadius = 30.0

// border
v.layer.borderColor = UIColor.lightGray.cgColor
v.layer.borderWidth = 1.5

// drop shadow
v.layer.shadowColor = UIColor.black.cgColor
v.layer.shadowOpacity = 0.8
v.layer.shadowRadius = 3.0
v.layer.shadowOffset = CGSize(width: 2.0, height: 2.0)

필요에 따라 설정을 조정할 수 있습니다.

또한 QuartzCore 프레임워크를 프로젝트에 추가하고 다음을 수행합니다.

#import <QuartzCore/QuartzCore.h>

관련된 다른 답변 보기masksToBounds.


메모

일부 경우에는 작동하지 않을 수 있습니다.이 방법이 수행 중인 다른 그리기 작업을 방해하는 경우 다음 답변을 참조하십시오.

GitHub에서 예제 프로젝트를 확인하여 구성 요소를 올바르게 사용하는지 확인하십시오.

추가적인 하위 보기 또는 하위 분류가 없는 간단한 Swift 5 솔루션:

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

        let backgroundCGColor = backgroundColor?.cgColor
        backgroundColor = nil
        layer.backgroundColor =  backgroundCGColor
    }
}

호출하기 에 모서리 반지름 및 기타 속성으로 보기를 설정해야 합니다. addShadow.

그 후에, 그냥 이것을 전화하세요.viewDidLoad다음과 같이:

button.addShadow(offset: CGSize.init(width: 0, height: 3), color: UIColor.black, radius: 2.0, opacity: 0.35)

최종 결과:

결과

매우 쉽고 간단합니다!

한 가지 방법은 모서리가 둥근 뷰를 드롭 그림자가 있는 뷰에 배치하는 것입니다.

UIView* roundedView = [[UIView alloc] initWithFrame: frame];
roundedView.layer.cornerRadius = 5.0;
roundedView.layer.masksToBounds = YES;

UIView* shadowView = [[UIView alloc] initWithFrame: frame];
shadowView.layer.shadowColor = [UIColor blackColor].CGColor;
shadowView.layer.shadowRadius = 5.0;
shadowView.layer.shadowOffset = CGSizeMake(3.0, 3.0);
shadowView.layer.shadowOpacity = 1.0;
[shadowView addSubview: roundedView];

그런 다음 원하는 곳에 섀도 뷰를 추가할 수 있습니다.

이것은 저에게 효과가 있었습니다.비결은 배경색을 주 뷰에서 레이어로 이동하는 것이었습니다.

CALayer *layer = view.layer;
layer.cornerRadius = 15.0f;
layer.masksToBounds = NO;

layer.shadowOffset = CGSizeMake(0, 3);
layer.shadowColor = [[UIColor blackColor] CGColor];
layer.shadowRadius = 2.0f;
layer.shadowOpacity = 0.35f;
layer.shadowPath = [[UIBezierPath bezierPathWithRoundedRect:layer.bounds cornerRadius:layer.cornerRadius] CGPath];

CGColorRef  bColor = view.backgroundColor.CGColor;
view.backgroundColor = nil;
layer.backgroundColor =  bColor ;

컨테이너 뷰에 섀도 경로를 할당할 때 다음과 같은 트릭을 사용하여 문제를 해결했습니다.

[UIBezierPath bezierPathWithRoundedRect:cell.bounds cornerRadius:12]

그림자에 지정된 경로는 셀에 포함된 배경과 동일한 모서리 반지름을 가진 둥근 직사각형입니다.

//this is the border for the UIView that is added to a cell
cell.backgroundView.layer.cornerRadius = 12;
cell.backgroundView.layer.masksToBounds = YES;
cell.backgroundView.layer.borderColor = [UIColor darkGrayColor].CGColor;
cell.backgroundView.layer.borderWidth = 1;

//this is the shadow around the cell itself (cannot have round corners with borders and shadow, need to use two views
cell.layer.shadowRadius = 2;
cell.layer.cornerRadius = 12;
cell.layer.masksToBounds = NO;
[[cell layer] setShadowColor:[[UIColor darkGrayColor] CGColor]];

[[cell layer] setShadowOffset:CGSizeMake(0.0,0.0)];
[[cell layer] setShadowOpacity:1.0];

UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:cell.bounds cornerRadius:12];
[[cell layer] setShadowPath:[path CGPath]];

은.corners대 대subviews대 대masksToBounds그런 다음 내 기능을 사용해 보십시오.

- (UIView*)putView:(UIView*)view insideShadowWithColor:(UIColor*)color andRadius:(CGFloat)shadowRadius andOffset:(CGSize)shadowOffset andOpacity:(CGFloat)shadowOpacity
{
    CGRect shadowFrame; // Modify this if needed
    shadowFrame.size.width = 0.f;
    shadowFrame.size.height = 0.f;
    shadowFrame.origin.x = 0.f;
    shadowFrame.origin.y = 0.f;
    UIView * shadow = [[UIView alloc] initWithFrame:shadowFrame];
    shadow.userInteractionEnabled = NO; // Modify this if needed
    shadow.layer.shadowColor = color.CGColor;
    shadow.layer.shadowOffset = shadowOffset;
    shadow.layer.shadowRadius = shadowRadius;
    shadow.layer.masksToBounds = NO;
    shadow.clipsToBounds = NO;
    shadow.layer.shadowOpacity = shadowOpacity;
    [view.superview insertSubview:shadow belowSubview:view];
    [shadow addSubview:view];
    return shadow;
}

당신이 보기에 그렇게 생각합니다.보기가 둥근 모서리를 가지든, 크기와 모양에 관계없이 멋진 그림자가 그려집니다.

때할 수 예: 테이블을예수때함있참반수다유값니환의합지만록도할사조용제거할예▁just▁so▁of▁function▁((다▁the).insertSubview:aboveView:)

Swift 4와 Xcode 9를 사용하여 다음과 같이 반올림합니다.ImageView그림자가 드리워져 있고, 테두리가 있습니다.

    //set dimensions and position of image (in this case, centered)
    let imageHeight: CGFloat = 150, imageWidth: CGFloat = 150
    let xPosition = (self.view.frame.width / 2) - (imageWidth / 2)
    let yPosition = (self.view.frame.height / 2) - (imageHeight / 2)

    //set desired corner radius
    let cornerRadius: CGFloat = 20

    //create container for the image
    let imageContainer = UIView(frame: CGRect(x: xPosition, y: yPosition, width: imageWidth, height: imageHeight))

    //configure the container
    imageContainer.clipsToBounds = false
    imageContainer.layer.shadowColor = UIColor.black.cgColor
    imageContainer.layer.shadowOpacity = 1
    imageContainer.layer.shadowOffset = CGSize(width: 3.0, height: 3.0)
    imageContainer.layer.shadowRadius = 5
    imageContainer.layer.shadowPath = UIBezierPath(roundedRect: imageContainer.bounds, cornerRadius: cornerRadius).cgPath

    //create imageView
    let imageView = UIImageView(frame: imageContainer.bounds)

    //configure the imageView
    imageView.clipsToBounds = true
    imageView.layer.cornerRadius = cornerRadius
    //add a border (if required)
    imageView.layer.borderColor = UIColor.black.cgColor
    imageView.layer.borderWidth = 1.0
    //set the image
    imageView.image = UIImage(named: "bird")

    //add the views to the superview
    view.addSubview(imageContainer)
    imageContainer.addSubview(imageView)

여기에 이미지 설명 입력

영상을 원형으로 표시하려면: (그리고 테두리 없이 표시됨)

let cornerRadius = imageWidth / 2

여기에 이미지 설명 입력

사해야합다를 .shadowView그리고.roundView

여기에 이미지 설명 입력

섀도 뷰

  • 배경색이 있어야 합니다.
  • 뒤에 .roundView
  • 을 만드는 것입니다.shadowView약간의 내부, 그리고 그것의 그림자는 빛을 발해야 합니다.을 합니다.insets 그 록도하록shadowView뒤로는 전혀 보이지 않습니다.roundView

원경

  • 하위 뷰를 클립해야 합니다.

코드

addSubviews(shadowView, roundView)
roundView.addSubviews(titleLabel, subtitleLabel, imageView)

// need inset
shadowView.pinEdges(view: self, inset: UIEdgeInsets(constraintInsets: 2))
roundView.pinEdges(view: self)

do {
  shadowView.backgroundColor = .white // need background
  let layer = shadowView.layer
  layer.shadowColor = UIColor.black.cgColor
  layer.shadowRadius = 3
  layer.shadowOffset = CGSize(width: 3, height: 3)
  layer.shadowOpacity = 0.7
  layer.shouldRasterize = true
}

do {
  roundView.backgroundColor = .white
  let layer = roundView.layer
  layer.masksToBounds = true
  layer.cornerRadius = 5
}

또는 아래와 같이 지정하지 않고 수행할 수 있습니다.clipToBounds/maskToBounds

layer.shadowColor = UIColor.gray.cgColor
layer.shadowOffset = CGSize(width: 3, height: 3)
layer.shadowOpacity = 0.8

여기 확실히 작동할 수 있는 해결책이 있습니다!

아래와 같이 섀도를 적용하기 위해 필요한 가장자리가 있는 UIView 확장을 만들었습니다.


enum AIEdge:Int {
    case
    Top,
    Left,
    Bottom,
    Right,
    Top_Left,
    Top_Right,
    Bottom_Left,
    Bottom_Right,
    All,
    None
}

extension UIView {
        
    func applyShadowWithCornerRadius(color:UIColor, opacity:Float, radius: CGFloat, edge:AIEdge, shadowSpace:CGFloat, cornerRadius: CGFloat)    {

        var sizeOffset:CGSize = CGSize.zero
        
        switch edge {
        case .Top:
            sizeOffset = CGSize(width: 0, height: -shadowSpace)
        case .Left:
            sizeOffset = CGSize(width: -shadowSpace, height: 0)
        case .Bottom:
            sizeOffset = CGSize(width: 0, height: shadowSpace)
        case .Right:
            sizeOffset = CGSize(width: shadowSpace, height: 0)
            
            
        case .Top_Left:
            sizeOffset = CGSize(width: -shadowSpace, height: -shadowSpace)
        case .Top_Right:
            sizeOffset = CGSize(width: shadowSpace, height: -shadowSpace)
        case .Bottom_Left:
            sizeOffset = CGSize(width: -shadowSpace, height: shadowSpace)
        case .Bottom_Right:
            sizeOffset = CGSize(width: shadowSpace, height: shadowSpace)
            
            
        case .All:
            sizeOffset = CGSize(width: 0, height: 0)
        case .None:
            sizeOffset = CGSize.zero
        }

        self.layer.cornerRadius = cornerRadius
        self.layer.masksToBounds = true

        self.layer.shadowColor = color.cgColor
        self.layer.shadowOpacity = opacity
        self.layer.shadowOffset = sizeOffset
        self.layer.shadowRadius = radius
        self.layer.masksToBounds = false

        self.layer.shadowPath = UIBezierPath(roundedRect:self.bounds, cornerRadius:self.layer.cornerRadius).cgPath
    }
}

마지막으로, 당신은 당신의 모든 UIView 하위 클래스에 대해 아래와 같이 그림자 함수를 호출할 수 있고, 또한 그림자를 적용할 에지를 지정할 수 있으며, 아래 메소드 호출의 필요에 따라 다양한 변형을 시도할 수 있습니다.

viewRoundedToBeShadowedAsWell.applyShadowWithCornerRadius(color: .gray, opacity: 1, radius: 15, edge: AIEdge.All, shadowSpace: 15)

참고: 그래도 작동하지 않으면 주 스레드에서 호출해 보십시오.

DispatchQueue.main.async {
   viewRoundedToBeShadowedAsWell.applyShadowWithCornerRadius(color: .gray, opacity: 1, radius: 15, edge: AIEdge.All, shadowSpace: 15)
}

누군가 이것이 유용하다고 생각하기를 바랍니다!

다음은 결과 영상입니다.

여기에 이미지 설명 입력

여기에 이미지 설명 입력

여기에 이미지 설명 입력

UIView에서 도우미를 만들었습니다.

@interface UIView (Helper)

- (void)roundCornerswithRadius:(float)cornerRadius
               andShadowOffset:(float)shadowOffset;
@end

당신은 이렇게 부를 수 있습니다.

[self.view roundCornerswithRadius:5 andShadowOffset:5];

구현 내용은 다음과 같습니다.

- (void)roundCornerswithRadius:(float)cornerRadius
               andShadowOffset:(float)shadowOffset
{
    const float CORNER_RADIUS = cornerRadius;
    const float SHADOW_OFFSET = shadowOffset;
    const float SHADOW_OPACITY = 0.5;
    const float SHADOW_RADIUS = 3.0;

    UIView *superView = self.superview;

    CGRect oldBackgroundFrame = self.frame;
    [self removeFromSuperview];

    CGRect frameForShadowView = CGRectMake(0, 0, oldBackgroundFrame.size.width, oldBackgroundFrame.size.height);
    UIView *shadowView = [[UIView alloc] initWithFrame:frameForShadowView];
    [shadowView.layer setShadowOpacity:SHADOW_OPACITY];
    [shadowView.layer setShadowRadius:SHADOW_RADIUS];
    [shadowView.layer setShadowOffset:CGSizeMake(SHADOW_OFFSET, SHADOW_OFFSET)];

    [self.layer setCornerRadius:CORNER_RADIUS];
    [self.layer setMasksToBounds:YES];

    [shadowView addSubview:self];
    [superView addSubview:shadowView];

}

swift 4에서 빠르게 테스트된 것.

import UIKit

extension UIView {
    @IBInspectable var dropShadow: Bool {
        set{
            if newValue {
                layer.shadowColor = UIColor.black.cgColor
                layer.shadowOpacity = 0.4
                layer.shadowRadius = 1
                layer.shadowOffset = CGSize.zero
            } else {
                layer.shadowColor = UIColor.clear.cgColor
                layer.shadowOpacity = 0
                layer.shadowRadius = 0
                layer.shadowOffset = CGSize.zero
            }
        }
        get {
            return layer.shadowOpacity > 0
        }
    }
}

프로듀스

여기에 이미지 설명 입력

이렇게 Inspector에서 활성화하면 다음과 같습니다.

여기에 이미지 설명 입력

User Defined Runtime 특성이 추가되어 다음과 같은 결과가 발생합니다.

여기에 이미지 설명 입력

(에 (이전에추내용은한가▁previous내)를 추가했습니다cornerRadius = 8)

:)

그림자가 있는 둥근 코너 뷰를 하루 종일 조사한 후, 저는 여기에 제 커스텀 뷰 클래스를 게시하게 되어 기쁩니다. 이 질문을 마치기를 바랍니다.

둥근 모서리 그림자 뷰.h

#import <UIKit/UIKit.h>

@interface RoundCornerShadowView : UIView

@end

둥근 모서리 그림자 뷰

#import "RoundCornerShadowView.h"

@implementation RoundCornerShadowView

// *** must override this method, not the other method ***
// otherwise, the background corner doesn't disappear....
// @2015/05/29
-(void) layoutSubviews {
    [super layoutSubviews];//is must to ensure rightly layout children view

    //1. first, create Inner layer with content
    CALayer *innerView = [CALayer layer];
    innerView.frame = CGRectMake(0,0,self.bounds.size.width,self.bounds.size.height);
    //instead of: innerView.frame = self.frame;
    innerView.borderWidth = 1.0f;
    innerView.cornerRadius = 6.0f;
    innerView.masksToBounds = YES;
    innerView.borderColor = [[UIColor lightGrayColor] CGColor];
    innerView.backgroundColor = [[UIColor whiteColor] CGColor];
    //put the layer to the BOTTOM of layers is also a MUST step...
    //otherwise this layer will overlay the sub uiviews in current uiview...
    [self.layer insertSublayer:innerView atIndex:0];

    //2. then, create shadow with self layer
    self.layer.masksToBounds = NO;
    self.layer.shadowColor = [[UIColor darkGrayColor] CGColor];
    self.layer.shadowOpacity = 0.4f;
    //shadow length
    self.layer.shadowRadius = 2.0f;
    //no offset
    self.layer.shadowOffset = CGSizeMake(0, 0);
    //right down shadow
    //[self.layer setShadowOffset: CGSizeMake(1.0f, 1.0f)];

    //3. last but important, MUST clear current view background color, or the color will show in the corner!
    self.backgroundColor = [UIColor clearColor];
}

@end

따라서 뷰에서 하위 뷰를 추가하거나 대상 뷰에서 하위 뷰를 추가할 필요가 없습니다. 현재 뷰에서 레이어를 하나 추가하기만 하면 3단계를 수행하여 완료할 수 있습니다!

코드의 주석을 자세히 살펴보십시오. 구성 요소를 이해하는 데 도움이 됩니다!

Swift 3 & IB 검사 불가능한 솔루션:
Ade의 솔루션에서 영감을 얻음

먼저 UIView 확장을 만듭니다.

//
//  UIView-Extension.swift
//  

import Foundation
import UIKit

@IBDesignable
extension UIView {
     // Shadow
     @IBInspectable var shadow: Bool {
          get {
               return layer.shadowOpacity > 0.0
          }
          set {
               if newValue == true {
                    self.addShadow()
               }
          }
     }

     fileprivate func addShadow(shadowColor: CGColor = UIColor.black.cgColor, shadowOffset: CGSize = CGSize(width: 3.0, height: 3.0), shadowOpacity: Float = 0.35, shadowRadius: CGFloat = 5.0) {
          let layer = self.layer
          layer.masksToBounds = false

          layer.shadowColor = shadowColor
          layer.shadowOffset = shadowOffset
          layer.shadowRadius = shadowRadius
          layer.shadowOpacity = shadowOpacity
          layer.shadowPath = UIBezierPath(roundedRect: layer.bounds, cornerRadius: layer.cornerRadius).cgPath

          let backgroundColor = self.backgroundColor?.cgColor
          self.backgroundColor = nil
          layer.backgroundColor =  backgroundColor
     }


     // Corner radius
     @IBInspectable var circle: Bool {
          get {
               return layer.cornerRadius == self.bounds.width*0.5
          }
          set {
               if newValue == true {
                    self.cornerRadius = self.bounds.width*0.5
               }
          }
     }

     @IBInspectable var cornerRadius: CGFloat {
          get {
               return self.layer.cornerRadius
          }

          set {
               self.layer.cornerRadius = newValue
          }
     }


     // Borders
     // Border width
     @IBInspectable
     public var borderWidth: CGFloat {
          set {
               layer.borderWidth = newValue
          }

          get {
               return layer.borderWidth
          }
     }

     // Border color
     @IBInspectable
     public var borderColor: UIColor? {
          set {
               layer.borderColor = newValue?.cgColor
          }

          get {
               if let borderColor = layer.borderColor {
                    return UIColor(cgColor: borderColor)
               }
               return nil
          }
     }
}

그런 다음 아래와 같이 인터페이스 작성기 설정 그림자 켜기 및 모서리 반지름에서 UIView를 선택합니다.

UI 보기 선택

섀도 ON & 코너 반지름 설정

결과!

결과

iOS 그림자 및 모서리 반지름

[iOS CALayer]

[iOS 마스크 경계로]

[iOS 디버그 렌더링]

은 다을사용섀설수있습다니정할도를을 사용하여 그림자를 할 수 .layer

//shadow
view1.layer.shadowColor = UIColor.magenta.cgColor

view1.layer.shadowOffset = CGSize(width: 0, height: 0)
view1.layer.shadowOpacity = 1
view1.layer.shadowRadius = 5

//cornerRadius
view1.layer.cornerRadius = 5

시각화

1.그림자 오프셋.너비, 2.그림자 간격띄우기.높이, 3.그림자 불투명도, 4.그림자 반지름

  • 그림자 간격띄우기 너비 및 높이는 임의입니다.
  • shadowOpacity ~ ~ 1µm입니다.
  • shadowRadius는 00에서입니다.

간단한 작업이 아닙니다.

섀도는 다음을 기준으로만 계산되지 않습니다.boundaries그리고.cornerRaduis그림자를 만드는 동안 다음 항목이 고려됩니다.

  • 하위 뷰 도면층
  • 서브레이어
  • content(Backing Image)
view1.backgroundColor = .clear
view1.layer.contents = UIImage(named: "ring")?.cgImage
view1.layer.contentsScale = UIScreen.main.scale

축척 계수(contentsScale,rasterizationScale - 은 1) - 기값은 1.0니다입니다.

currentBitmapSize = layerSize * scaleFactor

//non retina
1 point == 1x pixels

//Retina
1 point == 2x pixels
//or
1 point == 3x pixels

//For example to draw line 
point(width: 4, height: 2) == 1x pixels(width: 4, height: 2)(8 pixels) == 2x pixels(width: 8, height: 4)(32 pixels)

사용하다UIScreen.main.scale

[iOS 픽셀 대 포인트 대 유닛]

성능

용사를 합니다.layer.cornerRadius,shadow 정도 영향을 .

에 대해서는layer.cornerRadius성능:

하기 용하기적.color blending사용됨 [자세히 읽어보기]

에 대해서는shadowXcode 힌트:

The layer is using dynamic shadows which are expensive to render. If possible try setting shadowPath, or pre-rendering the shadow into an image and putting it under the layer

로 용사가를 합니다.shadowPath

내부 정적 계층에 사용됩니다.기본적으로 다음과 같습니다.nil그렇기 때문에 UIKit은 화면 밖에서 보기를 생성하고 이 정보를 기반으로 그림자를 생성해야 합니다.따라서 경로를 미리 정의하고 설정할 수 있습니다.또 다른 장점은 원하는 대로 사용자 정의 섀도를 만들 수 있다는 것입니다.

view1.layer.shadowPath = UIBezierPath(roundedRect: view1.bounds, cornerRadius: 50).cgPath

단점 - 동적이지 않습니다.뷰가 경계(폭, 높이, 모서리 반지름...)를 변경하는 경우 그림자는 이전 경계(이전 경계) 그대로 유지됩니다.보기의 위치가 변경된 경우(이동, 스크롤됨)shadowPath입니다.

캐시 래스터라이즈

[iOS를 래스터라이즈해야 함]

여기 maskToBounds 충돌 문제에 대한 해결책이 있습니다. 저에게 효과가 있습니다.

코더 Radius/borderColor/shadow 등을 설정한 후 maskToBounds를 NO로 설정합니다.

v.layer.masksToBounds = NO;

+ 반지름 + 모서리 반지름 + 모서리 반지름여기에 이미지 설명 입력

    scrollview.backgroundColor = [UIColor whiteColor]; 
    CALayer *ScrlViewLayer = [scrollview layer];
    [ScrlViewLayer setMasksToBounds:NO ];
    [ScrlViewLayer setShadowColor:[[UIColor lightGrayColor] CGColor]];
    [ScrlViewLayer setShadowOpacity:1.0 ];
    [ScrlViewLayer setShadowRadius:6.0 ];
    [ScrlViewLayer setShadowOffset:CGSizeMake( 0 , 0 )];
    [ScrlViewLayer setShouldRasterize:YES];
    [ScrlViewLayer setCornerRadius:5.0];
    [ScrlViewLayer setBorderColor:[UIColor lightGrayColor].CGColor];
    [ScrlViewLayer setBorderWidth:1.0];
    [ScrlViewLayer setShadowPath:[UIBezierPath bezierPathWithRect:scrollview.bounds].CGPath];

이것은 UIView용 Swift 3 버전입니다.

let corners:UIRectCorner = [.bottomLeft, .topRight]
let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()

mask.path = path.cgPath
mask.fillColor = UIColor.white.cgColor

let shadowLayer = CAShapeLayer()
shadowLayer.shadowColor = UIColor.black.cgColor
shadowLayer.shadowOffset = CGSize(width: 0.0, height: 4.0)
shadowLayer.shadowRadius = 6.0
shadowLayer.shadowOpacity = 0.25
shadowLayer.shadowPath = mask.path

self.layer.insertSublayer(shadowLayer, at: 0)
self.layer.insertSublayer(mask, at: 1)

Swift 4: UIView의 하위 클래스 만들기

class ShadowView: UIView {

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        // corner radius
        self.layer.cornerRadius = 10

        // border
        self.layer.borderWidth = 1.0
        self.layer.borderColor = UIColor.black.cgColor

        // shadow
        self.layer.shadowColor = UIColor.black.cgColor
        self.layer.shadowOffset = CGSize(width: 3, height: 3)
        self.layer.shadowOpacity = 0.7
        self.layer.shadowRadius = 4.0
    }

}

사용 중...

클래스 섀도 뷰 사용

만약 당신이 David C의 제안대로 당신의 닙과 보기 계층을 바꾸고 싶지 않다면, 이 방법이 당신을 위해 그것을 할 것입니다.UIImageView에 둥근 모서리와 그림자를 추가하려면 다음과 같은 방법을 사용합니다.

[Utils roundCornersForImageView:myImageView withCornerRadius:6.0 
andShadowOffset:2.0];

(!) 성능상의 이유로 UITableView와 같은 곳에서 이 코드를 사용하는 것은 좋은 생각이 아니라고 생각합니다. 이 코드는 보기 계층을 변경하기 때문입니다.그래서 저는 당신의 닙을 변경하고 섀도우 효과를 위한 컨테이너 뷰를 추가하고 데이비드 C. 코드를 사용하는 것을 제안하겠습니다.

+ (void)roundCornersForImageView:(UIImageView *)imageView 
withCornerRadius:(float)cornerRadius andShadowOffset:(float)shadowOffset
{
    const float CORNER_RADIUS = cornerRadius;
    const float BORDER_WIDTH = 1.0; 
    const float SHADOW_OFFSET = shadowOffset;
    const float SHADOW_OPACITY = 0.8;
    const float SHADOW_RADIUS = 3.0;

    //Our old image now is just background image view with shadow
    UIImageView *backgroundImageView = imageView;
    UIView *superView = backgroundImageView.superview;

    //Make wider actual visible rect taking into account shadow
    //offset
    CGRect oldBackgroundFrame = backgroundImageView.frame;
    CGRect newBackgroundFrame = CGRectMake(oldBackgroundFrame.origin.x, oldBackgroundFrame.origin.y, oldBackgroundFrame.size.width + SHADOW_OFFSET, oldBackgroundFrame.size.height + SHADOW_OFFSET);
    [backgroundImageView removeFromSuperview];
    backgroundImageView.frame = newBackgroundFrame;        

    //Make new UIImageView with rounded corners and put our old image
    CGRect frameForRoundedImageView = CGRectMake(0, 0, oldBackgroundFrame.size.width, oldBackgroundFrame.size.height);
    UIImageView *roundedImageView = [[UIImageView alloc]initWithFrame:frameForRoundedImageView];
    roundedImageView.image = imageView.image;
    [roundedImageView.layer setCornerRadius:CORNER_RADIUS];
    [roundedImageView.layer setBorderColor:[UIColor lightGrayColor].CGColor];        
    [roundedImageView.layer setBorderWidth:BORDER_WIDTH]; 
    [roundedImageView.layer setMasksToBounds:YES];

    //Set shadow preferences
    [backgroundImageView setImage:nil];
    [backgroundImageView.layer setShadowColor:[UIColor blackColor].CGColor];
    [backgroundImageView.layer setShadowOpacity:SHADOW_OPACITY];
    [backgroundImageView.layer setShadowRadius:SHADOW_RADIUS];
    [backgroundImageView.layer setShadowOffset:CGSizeMake(SHADOW_OFFSET, SHADOW_OFFSET)];   

    //Add out two image views back to the view hierarchy.
    [backgroundImageView addSubview:roundedImageView];
    [superView addSubview:backgroundImageView];   
}    

이전 스레드가 여전히 현재 상태입니다...

Daniel Gindi의 방법을 편집하여 버튼 등으로도 사용할 수 있도록 하였습니다.둥근 모서리가 필요하거나 둥근 모서리와 테두리를 결합하려는 사용자는 이 방법으로 전달되는 뷰의 도면층에 설정해야 합니다.또한 래스터라이제이션을 설정하여 속도를 조금 높였습니다.

+ (UIView*)putView:(UIView*)view insideShadowWithColor:(CGColorRef)color 
                                 andRadius:(CGFloat)shadowRadius 
                                 andOffset:(CGSize)shadowOffset 
                                 andOpacity:(CGFloat)shadowOpacity
{
    // Must have same position like "view"
    UIView *shadow = [[UIView alloc] initWithFrame:view.frame]; 

    shadow.layer.contentsScale = [UIScreen mainScreen].scale;
    shadow.userInteractionEnabled = YES; // Modify this if needed
    shadow.layer.shadowColor = color;
    shadow.layer.shadowOffset = shadowOffset;
    shadow.layer.shadowRadius = shadowRadius;
    shadow.layer.masksToBounds = NO;
    shadow.clipsToBounds = NO;
    shadow.layer.shadowOpacity = shadowOpacity;
    shadow.layer.rasterizationScale = [UIScreen mainScreen].scale;
    shadow.layer.shouldRasterize = YES;

    [view.superview insertSubview:shadow belowSubview:view];
    [shadow addSubview:view];

    // Move view to the top left corner inside the shadowview 
    // ---> Buttons etc are working again :)
    view.frame = CGRectMake(0, 0, view.frame.size.width, view.frame.size.height);

    return shadow;
}

다음은 나에게 가장 잘 작동했습니다(이 코드는 UIView 확장자에 있으므로 self는 그림자와 둥근 모서리를 추가해야 하는 일부 UIView를 나타냅니다).

- (void)addShadowViewWithCornerRadius:(CGFloat)radius {

UIView *container = self.superview;

if (!container) {
    return;
}

UIView *shadowView = [[UIView alloc] init];
shadowView.translatesAutoresizingMaskIntoConstraints = NO;
shadowView.backgroundColor = [UIColor lightGrayColor];
shadowView.layer.cornerRadius = radius;
shadowView.layer.masksToBounds = YES;

[container addSubview:shadowView];
[container bringSubviewToFront:shadowView];

[container addConstraint:[NSLayoutConstraint constraintWithItem:shadowView
                                                      attribute:NSLayoutAttributeWidth
                                                      relatedBy:NSLayoutRelationEqual
                                                         toItem:self
                                                      attribute:NSLayoutAttributeWidth
                                                     multiplier:1.0
                                                       constant:0.0]];
[container addConstraint:[NSLayoutConstraint constraintWithItem:shadowView
                                                      attribute:NSLayoutAttributeLeading
                                                      relatedBy:NSLayoutRelationEqual
                                                         toItem:self
                                                      attribute:NSLayoutAttributeLeading
                                                     multiplier:1.0
                                                       constant:2.0]];

[container addConstraint:[NSLayoutConstraint constraintWithItem:shadowView
                                                      attribute:NSLayoutAttributeHeight
                                                      relatedBy:NSLayoutRelationEqual
                                                         toItem:self
                                                      attribute:NSLayoutAttributeHeight
                                                     multiplier:1.0
                                                       constant:0.0]];
[container addConstraint:[NSLayoutConstraint constraintWithItem:shadowView
                                                      attribute:NSLayoutAttributeTop
                                                      relatedBy:NSLayoutRelationEqual
                                                         toItem:self
                                                      attribute:NSLayoutAttributeTop
                                                     multiplier:1.0
                                                       constant:2.0]];
[container sendSubviewToBack:shadowView];
}

이것과 다른 코드 샘플의 주요 차이점은 현재 뷰를 섀도 뷰의 하위 뷰로 추가하는 것과 달리 섀도 뷰를 형제 뷰로 추가하므로 기존 뷰 계층 구조를 수정할 필요가 없습니다.

확장과 합병증 없이 UICollectionViewCell을 원형으로 만들고 그림자를 추가하는 Swift 4 솔루션 :)

참고: 버튼과 같은 간단한 보기용입니다.이 게시물의 @suragch's Answer를 참조하십시오.https://stackoverflow.com/a/34984063/7698092 .버튼 테스트 성공

여전히 코너를 돌면서 동시에 그림자를 더하기 위해 고군분투하는 사람이 있다면 말입니다.이 솔루션은 UICollectionViewCell과 함께 작동하지만 모든 보기로 일반화할 수 있습니다.

이 기술은 저에게 아무런 확장이나 복잡한 것 없이 효과가 있었습니다.저는 storyBoard와 함께 일하고 있습니다.

기술.

스토리보드의 UICollectionViewCell 내에 UIView("containerView"라고 가정)를 추가하고 이 컨테이너View 내에 필요한 모든 뷰(버튼, 이미지 등)를 추가해야 합니다.스크린샷을 참조하십시오.셀의 구조

containerView용 콘센트를 연결합니다.Cell for ItemAtIndexPath 대리 함수에 다음 코드 행을 추가합니다.

//adds shadow to the layer of cell

cell.layer.cornerRadius = 3.0
    cell.layer.masksToBounds = false
    cell.layer.shadowColor = UIColor.black.cgColor
    cell.layer.shadowOffset = CGSize(width: 0, height: 0)
    cell.layer.shadowOpacity = 0.6

//makes the cell round 

let containerView = cell.containerView!
    containerView.layer.cornerRadius = 8
    containerView.clipsToBounds = true

산출량

시뮬레이터 스크린샷 참조

daniel.gindi의 위의 대답은 나에게 효과가 있었습니다! (+1 daniel)하지만 저는 섀도우 프레임 크기를 뷰의 프레임 크기와 동일하게 변경하고 사용자 상호 작용을 활성화하는 등 사소한 조정을 해야 했습니다.다음은 업데이트된 코드입니다.

+ (UIView*)putView:(UIView*)view insideShadowWithColor:(UIColor*)color andRadius:(CGFloat)shadowRadius andOffset:(CGSize)shadowOffset andOpacity:(CGFloat)shadowOpacity
{
    CGRect shadowFrame; // Modify this if needed

    // Modified this line
    shadowFrame.size = CGSizeMake(view.frame.size.width, view.frame.size.height);

    shadowFrame.origin.x = 0.f;
    shadowFrame.origin.y = 0.f;
    UIView * shadow = [[UIView alloc] initWithFrame:shadowFrame];

    // Modified this line
    shadow.userInteractionEnabled = YES;
    shadow.layer.shadowColor = color.CGColor;
    shadow.layer.shadowOffset = shadowOffset;
    shadow.layer.shadowRadius = shadowRadius;
    shadow.layer.masksToBounds = NO;
    shadow.clipsToBounds = NO;
    shadow.layer.shadowOpacity = shadowOpacity;

    [shadow addSubview:view];
    return shadow;
}

제 경우에는 타사 보기 컨트롤러에 이 정보를 추가하려고 했습니다.나는 코드를 직접 제어할 수 없었습니다.위의 기능을 사용한 방법은 다음과 같습니다.

UIView *shadow = [self putView:vc.view 
         insideShadowWithColor:[UIColor blackColor]
                     andRadius:5.0 
                     andOffset:CGSizeMake(0.0, 0.0) 
                    andOpacity:1.0];
vc.view = shadow;
vc.view.layer.cornerRadius = 5.0;
vc.view.layer.masksToBounds = YES;

daniel.gindi의 코드를 약간 변경했습니다.

이것이 당신이 그것을 작동시키기 위해 필요한 전부입니다.

+ (void)putView:(UIView*)view insideShadowWithColor:(UIColor*)color andBlur:         (CGFloat)blur andOffset:(CGSize)shadowOffset andOpacity:(CGFloat)shadowOpacity
{
    CGRect shadowFrame = view.frame;
    UIView * shadow = [[UIView alloc] initWithFrame:shadowFrame];
    shadow.backgroundColor = [UIColor redColor];
    shadow.userInteractionEnabled = YES; // Modify this if needed
    shadow.layer.shadowColor = color.CGColor;
    shadow.layer.shadowOffset = shadowOffset;
    shadow.layer.shadowRadius = blur;
    shadow.layer.cornerRadius = view.layer.cornerRadius;
    shadow.layer.masksToBounds = NO;
    shadow.clipsToBounds = NO;
    shadow.layer.shadowOpacity = shadowOpacity;
    [view.superview insertSubview:shadow belowSubview:view];
}

두 개를 사용해야 합니다.UIViews이를 위해하나.UIView그림자처럼 작동하고 다른 하나는 둥근 테두리에 작동합니다.

여기 코드 스니펫이 있습니다.Class Methodprotocol:

@implementation UIMethods

+ (UIView *)genComposeButton:(UIViewController <UIComposeButtonDelegate> *)observer;
{
    UIView *shadow = [[UIView alloc]init];
    shadow.layer.cornerRadius = 5.0;
    shadow.layer.shadowColor = [[UIColor blackColor] CGColor];
    shadow.layer.shadowOpacity = 1.0;
    shadow.layer.shadowRadius = 10.0;
    shadow.layer.shadowOffset = CGSizeMake(0.0f, -0.5f);

    UIButton *btnCompose = [[UIButton alloc]initWithFrame:CGRectMake(0, 0,60, 60)];
    [btnCompose setUserInteractionEnabled:YES];
    btnCompose.layer.cornerRadius = 30;
    btnCompose.layer.masksToBounds = YES;
    [btnCompose setImage:[UIImage imageNamed:@"60x60"] forState:UIControlStateNormal];
    [btnCompose addTarget:observer action:@selector(btnCompose_click:) forControlEvents:UIControlEventTouchUpInside];
    [shadow addSubview:btnCompose];
    return shadow;
}

btnCompose_click:▁a▁become다▁will니가 될 것입니다.@required버튼 클릭 시 실행되는 delegate 메서드입니다.

에 제 그고여기버추튼가다니습했을에리▁▁my▁button다▁a니▁and습▁added▁i추▁here가했그에 버튼을 추가했습니다.UIViewController다음과 같이:

UIView *btnCompose = [UIMethods genComposeButton:self];
btnCompose.frame = CGRectMake(self.view.frame.size.width - 75,
                          self.view.frame.size.height - 75,
                          60, 60);
[self.view addSubview:btnCompose];

결과는 다음과 같습니다.

여기에 이미지 설명 입력

저는 이 게시물에서 많은 해결책을 시도했고 결국 아래와 같은 해결책을 얻었습니다.선명한 색상 보기에 그림자를 놓을 필요가 없는 경우 이는 완전한 증명 솔루션입니다.

- (void)addShadowWithRadius:(CGFloat)shadowRadius withOpacity:(CGFloat)shadowOpacity withOffset:(CGSize)shadowOffset withColor:(UIColor *)shadowColor withCornerradius:(CGFloat)cornerRadius
{
    UIView *viewShadow = [[UIView alloc]initWithFrame:self.frame];
    viewShadow.backgroundColor = [UIColor whiteColor];
    viewShadow.layer.shadowColor = shadowColor.CGColor;
    viewShadow.layer.shadowOffset = shadowOffset;
    viewShadow.layer.shadowRadius = shadowRadius;
    viewShadow.layer.shadowOpacity = shadowOpacity;
    viewShadow.layer.cornerRadius = cornerRadius;
    viewShadow.layer.masksToBounds = NO;
    [self.superview insertSubview:viewShadow belowSubview:self];

    [viewShadow setTranslatesAutoresizingMaskIntoConstraints:NO];
    [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:viewShadow attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0]];
    [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:viewShadow attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0]];
    [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:viewShadow attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:viewShadow attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];
    [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:viewShadow attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:viewShadow attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0]];
    [self layoutIfNeeded];

    self.layer.cornerRadius = cornerRadius;
    self.layer.masksToBounds = YES;
}
import UIKit

extension UIView {

    func addShadow(shadowColor: UIColor, offSet: CGSize, opacity: Float, shadowRadius: CGFloat, cornerRadius: CGFloat, corners: UIRectCorner, fillColor: UIColor = .white) {

        let shadowLayer = CAShapeLayer()
        let size = CGSize(width: cornerRadius, height: cornerRadius)
        let cgPath = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: size).cgPath //1
        shadowLayer.path = cgPath //2
        shadowLayer.fillColor = fillColor.cgColor //3
        shadowLayer.shadowColor = shadowColor.cgColor //4
        shadowLayer.shadowPath = cgPath
        shadowLayer.shadowOffset = offSet //5
        shadowLayer.shadowOpacity = opacity
        shadowLayer.shadowRadius = shadowRadius
        self.layer.addSublayer(shadowLayer)
    }
}

Evan Mulawski가 제공한 답변은 완벽하게 작동할 것입니다.이 경우 뷰의 배경색을 clearColor로 설정하고 masksToBounds 속성을 NO로 설정해야 합니다.

보기에 원하는 색상을 설정할 수 있습니다.

v.layer.backgroundColor = your color;

이게 도움이 되길..

길을 가리지 않고 모서리가 둥글고 그림자가 둥근 것이 바로 이런 식으로 말이죠.

//Inner view with content
[imageView.layer setBorderColor:[[UIColor lightGrayColor] CGColor]];
[imageView.layer setBorderWidth:1.0f];
[imageView.layer setCornerRadius:8.0f];
[imageView.layer setMasksToBounds:YES];

//Outer view with shadow
UIView* shadowContainer = [[UIView alloc] initWithFrame:imageView.frame];
[shadowContainer.layer setMasksToBounds:NO];
[shadowContainer.layer setShadowColor:[[UIColor blackColor] CGColor]];
[shadowContainer.layer setShadowOpacity:0.6f];
[shadowContainer.layer setShadowRadius:2.0f];
[shadowContainer.layer setShadowOffset: CGSizeMake(0.0f, 2.0f)];

[shadowContainer addSubview:imageView];

내용이 있는 보기(내 경우 UIImageView)는 모서리 반지름을 가지고 있으므로 경계까지 마스크해야 합니다.

그림자에 대해 동일한 크기의 다른 보기를 만들고 maskToBounds를 NO로 설정한 다음 내용 보기를 컨테이너 보기(예: 그림자 컨테이너)에 추가합니다.

언급URL : https://stackoverflow.com/questions/4754392/uiview-with-rounded-corners-and-drop-shadow