UIView에서 두 모서리 라운드


82

얼마 전에 뷰의 두 모서리 만 둥글게 하는 것에 대한 질문을 올렸고 훌륭한 응답을 받았지만 구현하는 데 문제가 있습니다. 내 drawRect : 메서드는 다음과 같습니다.

- (void)drawRect:(CGRect)rect {
    //[super drawRect:rect]; <------Should I uncomment this?
    int radius = 5;
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextBeginPath(context);
    CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + rect.size.height - radius, radius, M_PI, M_PI / 2, 1);
    CGContextAddArc(context, rect.origin.x + rect.size.width - radius, rect.origin.y + rect.size.height - radius, radius, M_PI / 2, 0.0f, 1);
    CGContextClosePath(context);
    CGContextClip(context);
}

메서드가 호출되고 있지만 뷰의 결과에 영향을주지 않는 것 같습니다. 이유는 무엇입니까?

답변:


103

CACornerMask는 , 뷰 레이어에서 오른쪽 아래를, 좌상 정의 topright, bottomleft하는 데 도움이 아이폰 OS (11)에 소개했다. 아래는 사용 예입니다.

여기에서는 상단 모서리 두 개만 둥글게 만들려고합니다.

myView.clipsToBounds = true
myView.layer.cornerRadius = 10
myView.layer.maskedCorners = [.layerMinXMinYCorner,.layerMaxXMinYCorner]

FYI 참조 :


이것은 지금 이것을하는 관용적 인 방법처럼 보입니다. 잘 잡아!
— Jumhyn

2
뷰의 너비 / 높이는 여전히 모서리 반경의 두 배 이상이어야합니다. 그렇지 않으면 이상한 아티팩트가 나타납니다. 예를 들어 하단 모서리 만 둥글게, 반경 20, 높이 30 만하면 셀이 눈에 띄게 좁아집니다 (1 픽셀 또는 2 픽셀).
— Graham Perks

보기가 (- 내 경우로 인해 확장 UITextView에 수의 프레임을 변경하는 경우이 올바른 방법이라고 주 stackoverflow.com/questions/50926215/... ). UIBezierPath를 설정하면 프레임이 변경 될 때 자동으로 업데이트되지 않습니다.
— thomers

이 아이폰 OS 11 이상에서만 사용할 수주의if #available(iOS 11.0, *) { }
— 트라이 Ngo의 호치민

2
좋은 대답입니다. 설정 밝혀 clipsToBounds으로는 true필요하지 않습니다. 당신은 모서리 마스크 때 레이어에 그림자를 추가 할 수 clipsToBounds있습니다 false. 나를 위해 편리하게 왔습니다.
— Au Ris

72


내가 아는 한, 하위 뷰도 CALayer마스킹 해야하는 경우 마스킹을 사용할 수 있습니다 . 이를 수행하는 두 가지 방법이 있습니다. 첫 번째는 좀 더 우아하고 두 번째는 해결 방법입니다. :-)하지만 빠릅니다. 둘 다 CALayer마스킹을 기반으로 합니다. 작년에 몇 개의 프로젝트에서 두 가지 방법을 모두 사용했으며 유용한 것을 찾을 수 있기를 바랍니다.

해결책 1

우선, UIImage필요한 둥근 모서리가 있는 즉석에서 이미지 마스크 ( ) 를 생성하기 위해이 함수를 만들었습니다 . 이 함수에는 기본적으로 5 개의 매개 변수가 필요합니다 : 이미지의 경계와 4 개의 코너 반경 (왼쪽 상단, 오른쪽 상단, 왼쪽 하단 및 오른쪽 하단).


static inline UIImage* MTDContextCreateRoundedMask( CGRect rect, CGFloat radius_tl, CGFloat radius_tr, CGFloat radius_bl, CGFloat radius_br ) {  

    CGContextRef context;
    CGColorSpaceRef colorSpace;

    colorSpace = CGColorSpaceCreateDeviceRGB();

    // create a bitmap graphics context the size of the image
    context = CGBitmapContextCreate( NULL, rect.size.width, rect.size.height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast );

    // free the rgb colorspace
    CGColorSpaceRelease(colorSpace);    

    if ( context == NULL ) {
        return NULL;
    }

    // cerate mask

    CGFloat minx = CGRectGetMinX( rect ), midx = CGRectGetMidX( rect ), maxx = CGRectGetMaxX( rect );
    CGFloat miny = CGRectGetMinY( rect ), midy = CGRectGetMidY( rect ), maxy = CGRectGetMaxY( rect );

    CGContextBeginPath( context );
    CGContextSetGrayFillColor( context, 1.0, 0.0 );
    CGContextAddRect( context, rect );
    CGContextClosePath( context );
    CGContextDrawPath( context, kCGPathFill );

    CGContextSetGrayFillColor( context, 1.0, 1.0 );
    CGContextBeginPath( context );
    CGContextMoveToPoint( context, minx, midy );
    CGContextAddArcToPoint( context, minx, miny, midx, miny, radius_bl );
    CGContextAddArcToPoint( context, maxx, miny, maxx, midy, radius_br );
    CGContextAddArcToPoint( context, maxx, maxy, midx, maxy, radius_tr );
    CGContextAddArcToPoint( context, minx, maxy, minx, midy, radius_tl );
    CGContextClosePath( context );
    CGContextDrawPath( context, kCGPathFill );

    // Create CGImageRef of the main view bitmap content, and then
    // release that bitmap context
    CGImageRef bitmapContext = CGBitmapContextCreateImage( context );
    CGContextRelease( context );

    // convert the finished resized image to a UIImage 
    UIImage *theImage = [UIImage imageWithCGImage:bitmapContext];
    // image is retained by the property setting above, so we can 
    // release the original
    CGImageRelease(bitmapContext);

    // return the image
    return theImage;
}  

이제 몇 줄의 코드 만 있으면됩니다. viewDidLoad더 빠르기 때문에 viewController 메서드 에 항목을 넣었 지만 예제 UIView의 layoutSubviews메서드를 사용하여 사용자 정의에서도 사용할 수 있습니다 .



- (void)viewDidLoad {

    // Create the mask image you need calling the previous function
    UIImage *mask = MTDContextCreateRoundedMask( self.view.bounds, 50.0, 50.0, 0.0, 0.0 );
    // Create a new layer that will work as a mask
    CALayer *layerMask = [CALayer layer];
    layerMask.frame = self.view.bounds;       
    // Put the mask image as content of the layer
    layerMask.contents = (id)mask.CGImage;       
    // set the mask layer as mask of the view layer
    self.view.layer.mask = layerMask;              

    // Add a backaground color just to check if it works
    self.view.backgroundColor = [UIColor redColor];
    // Add a test view to verify the correct mask clipping
    UIView *testView = [[UIView alloc] initWithFrame:CGRectMake( 0.0, 0.0, 50.0, 50.0 )];
    testView.backgroundColor = [UIColor blueColor];
    [self.view addSubview:testView];
    [testView release];

    [super viewDidLoad];
}

해결 방법 2

이 솔루션은 좀 더 "더럽습니다". 기본적으로 필요한 둥근 모서리 (모든 모서리)로 마스크 레이어를 만들 수 있습니다. 그런 다음 모서리 반경 값만큼 마스크 레이어의 높이를 늘려야합니다. 이런 식으로 하단의 둥근 모서리가 숨겨지고 상단의 둥근 모서리 만 볼 수 있습니다. viewDidLoad더 빠르기 때문에 메서드에 코드를 넣었 지만 예제 UIView의 layoutSubviews메서드를 사용하여 사용자 정의에서도 사용할 수 있습니다 .

  

- (void)viewDidLoad {

    // set the radius
    CGFloat radius = 50.0;
    // set the mask frame, and increase the height by the 
    // corner radius to hide bottom corners
    CGRect maskFrame = self.view.bounds;
    maskFrame.size.height += radius;
    // create the mask layer
    CALayer *maskLayer = [CALayer layer];
    maskLayer.cornerRadius = radius;
    maskLayer.backgroundColor = [UIColor blackColor].CGColor;
    maskLayer.frame = maskFrame;

    // set the mask
    self.view.layer.mask = maskLayer;

    // Add a backaground color just to check if it works
    self.view.backgroundColor = [UIColor redColor];
    // Add a test view to verify the correct mask clipping
    UIView *testView = [[UIView alloc] initWithFrame:CGRectMake( 0.0, 0.0, 50.0, 50.0 )];
    testView.backgroundColor = [UIColor blueColor];
    [self.view addSubview:testView];
    [testView release];

    [super viewDidLoad];
}

도움이 되었기를 바랍니다. 챠오!


마침내 작동했습니다! 정말 고마워! 다른 것보다 하나의 장점은 무엇입니까?
— Jumhyn

어쨌든 CAShapeLayer 솔루션조차도 완벽합니다. UIBezierPath (3.2 이상 필요)를 사용하거나 CGPath 메소드 (CGPathMoveToPoint, CGPathAddQuadCurveToPoint 등)를 사용하여 CGPath를 그릴 수 있습니다.
— lomanf

1
세로에서 가로로 회전 한 후 마스크 크기를 자동으로 조정하려면 어떻게해야합니까?
— chourobin

YES = layer.masksToBounds를 추가하는 것을 잊지 마세요
— 드미트리 Salnikov

오른쪽 상단 및 하단 모서리 만 둥글게 만들려면 어떻게해야합니까?
— PLOW

69

몇 가지 답변 및 의견을 통해 빗질, 내가 사용하는 것을 발견 UIBezierPath bezierPathWithRoundedRect하고 CAShapeLayer가장 단순하고 정직 방법. 매우 복잡한 경우에는 적합하지 않을 수 있지만 가끔 모서리를 둥글게하는 경우에는 빠르고 원활하게 작동합니다.

마스크에 적절한 모서리를 설정하는 간단한 도우미를 만들었습니다.

-(void) setMaskTo:(UIView*)view byRoundingCorners:(UIRectCorner)corners
{
    UIBezierPath* rounded = [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(10.0, 10.0)];

    CAShapeLayer* shape = [[CAShapeLayer alloc] init];
    [shape setPath:rounded.CGPath];

    view.layer.mask = shape;
}

이를 사용하려면 적절한 UIRectCorner 열거 형으로 호출하기 만하면됩니다. 예 :

[self setMaskTo:self.photoView byRoundingCorners:UIRectCornerTopLeft|UIRectCornerBottomLeft];

저에게는 그룹화 된 UITableViewCell에서 사진의 모서리를 둥글게하는 데 사용합니다. 적절한 값을 변경해야하는 경우 10.0 반경이 잘 작동합니다.

편집 : 이전에 이것과 매우 유사하게 답변 한 것을 주목하십시오 ( 링크 ). 필요한 경우이 답변을 추가 편의 기능으로 계속 사용할 수 있습니다.


편집 : Swift 3의 UIView 확장과 동일한 코드

extension UIView {
    func maskByRoundingCorners(_ masks:UIRectCorner, withRadii radii:CGSize = CGSize(width: 10, height: 10)) {
        let rounded = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: masks, cornerRadii: radii)

        let shape = CAShapeLayer()
        shape.path = rounded.cgPath

        self.layer.mask = shape
    }
}

사용하려면 다음 maskByRoundingCorner중 하나를 호출 하면됩니다 UIView.

view.maskByRoundingCorners([.topLeft, .bottomLeft])

여전히 테두리를 추가하는 동안 가능합니까?
— Unome

2
나는 단지 하나의 모서리가 둥근있어 때문에 DispatchQueue.main.async {}로 함수 호출을 넣어했다 ...
— 막심 Kniazev

1
@MaksimKniazev 예, 메인 (UI) 스레드에서 호출해야합니다. 이 규칙은 UI를 건 드리는 모든 작업에 적용되며, 기본 스레드에서 호출해야합니다. 그렇지 않으면 이상한 일이 발생할 수 있습니다.
— PL

1
한쪽 모서리 만 둥글게 보입니다. @MaksimKniazev 솔루션을 시도했지만 작동하지 않았습니다.
— Gustavo_fringe

@Gustavo_fringe와 동일한 문제가 있는데, 오른쪽 상단 모서리가 xib 뷰 내부의 경계로 잘 리거나 마스킹되지 않고 아직 수정하는 방법을 모르겠습니다.
— CyberMew

57

@lomanf의 답변에 대한 의견에이 모든 것을 넣을 수는 없습니다. 그래서 나는 그것을 대답으로 추가하고 있습니다.

@lomanf가 말했듯이 하위 레이어가 경로 경계를 벗어나는 것을 방지하려면 레이어 마스크를 추가해야합니다. 하지만 지금은 훨씬 더 쉽습니다. iOS 3.2 이상을 대상으로하는 한 석영으로 이미지를 만들고 마스크로 설정할 필요가 없습니다. 을 사용하여 CAShapeLayer를 만들고 UIBezierPath마스크로 사용할 수 있습니다 .

또한 레이어 마스크를 사용할 때 마스크를 추가 할 때 마스크 할 레이어가 레이어 계층의 일부가 아닌지 확인하십시오. 그렇지 않으면 동작이 정의되지 않습니다. 뷰가 이미 계층 구조에있는 경우 수퍼 뷰에서 제거하고 마스킹 한 다음 원래 위치로 되돌려 야합니다.

CAShapeLayer *maskLayer = [CAShapeLayer layer];
UIBezierPath *roundedPath = 
  [UIBezierPath bezierPathWithRoundedRect:maskLayer.bounds
                        byRoundingCorners:UIRectCornerTopLeft |
                                          UIRectCornerBottomRight
                              cornerRadii:CGSizeMake(16.f, 16.f)];    
maskLayer.fillColor = [[UIColor whiteColor] CGColor];
maskLayer.backgroundColor = [[UIColor clearColor] CGColor];
maskLayer.path = [roundedPath CGPath];

//Don't add masks to layers already in the hierarchy!
UIView *superview = [self.view superview];
[self.view removeFromSuperview];
self.view.layer.mask = maskLayer;
[superview addSubview:self.view];

Core Animation 렌더링이 작동하는 방식으로 인해 마스킹은 상대적으로 느린 작업입니다. 각 마스크에는 추가 렌더링 패스가 필요합니다. 따라서 마스크를 아껴 사용하십시오.

이 접근 방식의 가장 좋은 부분 중 하나는 더 이상 사용자 지정 UIView을 만들고을 재정의 할 필요가 없다는 것 drawRect:입니다. 이렇게하면 코드가 더 간단하고 더 빨라질 것입니다.


유망 해 보이지만보기가 나타나지 않습니다. 이유는 무엇입니까?
— Jumhyn

10
maskLayer.bounds를 사용하여 UIBezierPath의 크기를 조정하고 있지만 경계 값은 CGRectZero입니다. maskLayer.frame = self.view.bounds와 같은 두 번째 코드 줄 (CAShapeLayer 초기화 직후)을 추가해야합니다.
— lomanf

1
네 말이 맞아. 모양 레이어가 이미 존재하는 다른 예제에서 해당 코드를 추출했습니다. 미안합니다.
— Nathan Eror

완벽하게 작동합니다! 위에서 언급했듯이 maskLayer.frame = self.view.bounds를 추가하면 make가 작동합니다. 그렇지 않으면보기가 표시되지 않습니다.
— Daniel Ribeiro

+1 이것은 아주 잘 작동합니다. 사실 저는 lomanf의 # 2 솔루션보다이 방법을 선호한다고 생각합니다. 이 방법을 사용하면 반대쪽 모서리 (예 : 오른쪽 위 + 왼쪽 아래)에 호를 쉽게 추가 할 수 있으며 lomanf의 첫 번째 솔루션보다 확실히 짧습니다. 위대한 코드 Nathan!
— FreeAsInBeer 2013 년

30

나는 Nathan의 예를 들어 UIViewDRY 원칙을 고수 할 수 있도록 카테고리를 만들었습니다 . 더 이상 고민하지 않고 :

UIView + Roundify.h

#import <UIKit/UIKit.h>

@interface UIView (Roundify)

-(void)addRoundedCorners:(UIRectCorner)corners withRadii:(CGSize)radii;
-(CALayer*)maskForRoundedCorners:(UIRectCorner)corners withRadii:(CGSize)radii;

@end

UIView + Roundify.m

#import "UIView+Roundify.h"

@implementation UIView (Roundify)

-(void)addRoundedCorners:(UIRectCorner)corners withRadii:(CGSize)radii {
    CALayer *tMaskLayer = [self maskForRoundedCorners:corners withRadii:radii];
    self.layer.mask = tMaskLayer;
}

-(CALayer*)maskForRoundedCorners:(UIRectCorner)corners withRadii:(CGSize)radii {
    CAShapeLayer *maskLayer = [CAShapeLayer layer];
    maskLayer.frame = self.bounds;

    UIBezierPath *roundedPath = [UIBezierPath bezierPathWithRoundedRect:
        maskLayer.bounds byRoundingCorners:corners cornerRadii:radii];
    maskLayer.fillColor = [[UIColor whiteColor] CGColor];
    maskLayer.backgroundColor = [[UIColor clearColor] CGColor];
    maskLayer.path = [roundedPath CGPath];

    return maskLayer;
}

@end

전화하려면 :

[myView addRoundedCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight
                withRadii:CGSizeMake(20.0f, 20.0f)];

2
.m 파일에서 <QuartzCore / QuatzCore.h>를 가져 와서 QuartzCore.framework를 프로젝트에 추가하는 것을
— 잊지 마십시오

+1 멋진 것, 한 가지 질문입니다. 뷰를 수퍼 뷰로 제거 / 읽는 목적은 무엇입니까?
— eladleb

@eladleb : 여기에있는 기본 코드는 Nathan이 만든 것입니다. 간단히 약간 최적화했습니다. 내가 한 연구에서 레이어 마스크를 적용하기 전에 뷰를 제거해야하는 유효한 이유를 찾을 수 없습니다. 따라서 해당 코드를 생략하는 것이 안전하다고 생각합니다.
— FreeAsInBeer 2013-08-13

@FreeAsInBeer는 - 그때 내가 그것을 제거하기 위해 투표 것, 동의,이 사실은 ..보기 z 순서를 변경하고 더 많은 문제를 만들 수 있습니다
— eladleb

TableView에 둥근 모서리를 추가 할 때 발생한 문제를 해결했습니다. 머리글, 둥근 홑 모서리를 추가하고 둥근 하단 모서리가있는 바닥 글을 추가했습니다. 감사.
— nightfixed

24

PL의 답변을 조금 확장하기 위해 UIButton정확하게 같은 특정 객체를 반올림하지 않도록 방법을 다시 작성했습니다.

- (void)setMaskTo:(id)sender byRoundingCorners:(UIRectCorner)corners withCornerRadii:(CGSize)radii
{
    // UIButton requires this
    [sender layer].cornerRadius = 0.0;

    UIBezierPath *shapePath = [UIBezierPath bezierPathWithRoundedRect:[sender bounds]
                                                byRoundingCorners:corners
                                                cornerRadii:radii];

    CAShapeLayer *newCornerLayer = [CAShapeLayer layer];
    newCornerLayer.frame = [sender bounds];
    newCornerLayer.path = shapePath.CGPath;
    [sender layer].mask = newCornerLayer;
}

그리고 그것을 부르십시오

[self setMaskTo:self.continueButton byRoundingCorners:UIRectCornerBottomLeft|UIRectCornerBottomRight withCornerRadii:CGSizeMake(3.0, 3.0)];

12

Swift에서하고 싶다면 UIView. 이렇게하면 모든 하위 클래스에서 다음 메서드를 사용할 수 있습니다.

import QuartzCore

extension UIView {
    func roundCorner(corners: UIRectCorner, radius: CGFloat) {
        let maskPath = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
        let maskLayer = CAShapeLayer()
        maskLayer.frame = bounds
        maskLayer.path = maskPath.CGPath
        layer.mask = maskLayer
    }
}    

사용 예 :

self.anImageView.roundCorner(.topRight, radius: 10)

3

허용되는 답변을 확장하여 이전 버전과의 호환성을 추가하겠습니다. iOS 11 이전에는 view.layer.maskedCorners를 사용할 수 없습니다. 그래서 우리는 이렇게 할 수 있습니다

if #available(iOS 11.0, *) {
    myView.layer.maskedCorners = [.layerMinXMinYCorner,.layerMaxXMinYCorner]
} else {
    myView.maskByRoundingCorners([.topLeft, .topRight])
}

extension UIView{
    func maskByRoundingCorners(_ masks:UIRectCorner, withRadii radii:CGSize = CGSize(width: 10, height: 10)) {
        let rounded = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: masks, cornerRadii: radii)

        let shape = CAShapeLayer()
        shape.path = rounded.cgPath

        self.layer.mask = shape
    }
}

코드 재사용을 향상시키기 위해 maskByRoundingCorners를 UIView 확장으로 작성했습니다.

@SachinVsSachin 및 @PL에 대한 크레딧 :) 더 나은 코드를 만들기 위해 코드를 결합했습니다.


2
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(5, 5, self.bounds.size.width-10, self.bounds.size.height-10)
                                               byRoundingCorners:UIRectCornerAllCorners
                                                     cornerRadii:CGSizeMake(12.0, 12.0)];

필요에 따라 "AllCorners"를 변경 하십시오.


그래서 당신은 UIView에서 이것을해야합니까 아니면 UIViewController에서 이것을 할 수 있습니까? UIBezierPath를 만든 후에는 무엇을합니까? 감사.
— StoneBreaker 2012-06-07

2

제공된 모든 솔루션이 목표를 달성합니다. 그러나 UIConstraints때때로 이것을 날려 버릴 수 있습니다.

예를 들어, 하단 모서리는 둥글어야합니다. 반올림해야하는 UIView에 높이 또는 하단 간격 제약 조건이 설정된 경우 모서리를 반올림하는 코드 조각을 viewDidLayoutSubviews메서드 로 이동해야 합니다.

강조 :

UIBezierPath *maskPath = [UIBezierPath
    bezierPathWithRoundedRect:roundedView.bounds byRoundingCorners:
    (UIRectCornerTopRight | UIRectCornerBottomRight) cornerRadii:CGSizeMake(16.0, 16.0)];

위의 코드 스 니펫은이 코드가 viewDidLoad. 때문에 roundedView.bounds제약 후 변화에려고하고를 업데이트합니다 UIView.



1

코드로 시작하면 아래 스 니펫과 같은 것을 사용할 수 있습니다.

이것이 당신이 추구하는 결과인지 확실하지 않습니다. 또한 시스템이 drawRect :를 호출 할 때 rect의 일부만 다시 그려달라고 요청하면 매우 이상하게 동작 할 것입니다. 위에서 언급 한 Nevan의 접근 방식 이 더 나은 방법 일 수 있습니다.

 // make sure the view's background is set to [UIColor clearColor]
- (void)drawRect:(CGRect)rect
{
    CGFloat radius = 10.0;
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextTranslateCTM(context, rect.size.width/2, rect.size.height/2);
    CGContextRotateCTM(context, M_PI); // rotate so image appears right way up
    CGContextTranslateCTM(context, -rect.size.width/2, -rect.size.height/2);

    CGContextBeginPath(context);

    CGContextMoveToPoint(context, rect.origin.x, rect.origin.y);
    CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + rect.size.height - radius, radius, M_PI, M_PI / 2, 1);
    CGContextAddArc(context, rect.origin.x + rect.size.width - radius, rect.origin.y + rect.size.height - radius, radius, M_PI / 2, 0.0f, 1);
    CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y);
    CGContextClip(context); 

    // now do your drawing, e.g. draw an image
    CGImageRef anImage = [[UIImage imageNamed:@"image.jpg"] CGImage];
    CGContextDrawImage(context, rect, anImage);    
}

모서리가 둥근 뷰를 만들었지 만 하위 뷰를 잘라낼 수 없습니다. 내 뷰의 가장자리에 정사각형 모서리가있는 뷰를 배치해도 수퍼 뷰의 둥근 모서리가 여전히 덮입니다. 왜 이런 일이 일어나는지 아십니까?
— Jumhyn

클리핑 -drawRect:은 그리는 뷰에만 영향을 미치기 때문입니다. 도면이 완료된 후 하위 뷰가 독립적으로 그려집니다.
— Jonathan Grynspan

1

약간 해키하지만 상대적으로 간단한 (서브 클래 싱, 마스킹 등이없는) 방법은 두 개의 UIView를 갖는 것입니다. 둘 다 clipToBounds = YES. 하위 뷰에 둥근 모서리를 설정 한 다음 똑바로 원하는 모서리가 잘 리도록 상위 뷰 내에 배치합니다.

UIView* parent = [[UIView alloc] initWithFrame:CGRectMake(10,10,100,100)];
parent.clipsToBounds = YES;

UIView* child = [[UIView alloc] new];
child.clipsToBounds = YES;
child.layer.cornerRadius = 3.0f;
child.backgroundColor = [UIColor redColor];
child.frame = CGRectOffset(parent.bounds, +4, -4);


[parent addSubView:child];

대각선으로 마주 보는 두 모서리를 둥글게하고 싶은 경우는 지원하지 않습니다.


1

추가 코드가 필요한 경우 Bezier 경로가 답입니다. https://stackoverflow.com/a/13163693/936957

UIBezierPath *maskPath;
maskPath = [UIBezierPath bezierPathWithRoundedRect:_backgroundImageView.bounds 
                                 byRoundingCorners:(UIRectCornerBottomLeft | UIRectCornerBottomRight) 
                                       cornerRadii:CGSizeMake(3.0, 3.0)];

CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = self.bounds;
maskLayer.path = maskPath.CGPath;
_backgroundImageView.layer.mask = maskLayer;
[maskLayer release];

1

UIBezierPath 솔루션.

- (void) drawRect:(CGRect)rect {

    [super drawRect:rect];

    //Create shape which we will draw. 
    CGRect rectangle = CGRectMake(2, 
                                  2, 
                                  rect.size.width - 4,
                                  rect.size.height - 4);

    //Create BezierPath with round corners
    UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:rectangle 
                                                   byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight 
                                                         cornerRadii:CGSizeMake(10.0, 10.0)];

    //Set path width
    [maskPath setLineWidth:2];

    //Set color
    [[UIColor redColor] setStroke];

    //Draw BezierPath to see it
    [maskPath stroke];
}

0

다음과 같이 올바르게 설정된 경우에만 작동 할 수 있습니다.

  1. clipsToBounds는 YES로 설정되어야합니다.
  2. 불투명은 NO 여야합니다.
  3. backgroundColor는 "clearColor"여야합니다 (확실하지 않음).
  4. drawRect는 그렇지 않은 경우 자주 호출되지 않으므로 contentMode는 "UIContentModeRedraw"여야합니다.
  5. [super drawRect : rect]는 CGContextClip 후에 호출되어야합니다.
  6. 보기에 임의의 하위보기가 포함되어 있지 않을 수 있습니다 (확실하지 않음)
  7. drawrect를 트리거하려면 "needsDisplay :"를 한 번 이상 설정해야합니다.

0

UITableView의 상단 두 모서리를 둥글게 만들려고한다는 것을 알고 있지만 어떤 이유로 가장 좋은 해결책은 다음을 사용하는 것입니다.

self.tableView.layer.cornerRadius = 10;

프로그래밍 방식으로 네 모서리를 모두 둥글게해야하지만 어떤 이유로 상단 2 개만 둥글게합니다. ** 위에 작성한 코드의 효과를 확인하려면 아래 스크린 샷을 참조하십시오.

이게 도움이 되길 바란다!

여기에 이미지 설명 입력


1
그것은 모든 모서리 라운딩되어 있지 않은 경우 UITableView제작되어 다음이 있어야 코드를 다른 곳에서 UITableView바닥에하지 않은 모서리를 둥글게, 또는 어쩌면 UIView나 UILabel그가의 하단 부분을 포함됩니다 UITableView.
— Josh Valdivieso

-1

경계에 맞게 클립해야 할 것입니다. 라인 추가

self.clipsToBounds = YES

코드의 어딘가에 해당 속성을 설정합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.