칼레이어를 사용한 반올림된 UI 보기 - 일부 코너만 - 어떻게?
내 응용 프로그램에는 다음과 같은 이름의 네 개의 버튼이 있습니다.
- 위 - 왼쪽
- 아래 - 왼쪽
- 오른쪽 위
- 오른쪽 아래
버튼 위에는 영상 보기(또는 UI 보기)가 있습니다.
이제 사용자가 왼쪽 위 버튼을 탭한다고 가정해 보겠습니다.위의 이미지/보기는 해당 특정 모서리에서 반올림해야 합니다.
UIView에 둥근 모서리를 적용하는 데 어려움을 겪고 있습니다.
현재 다음 코드를 사용하여 둥근 모서리를 각 보기에 적용하고 있습니다.
// imgVUserImg is a image view on IB.
imgVUserImg.image=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"any Url Here"];
CALayer *l = [imgVUserImg layer];
[l setMasksToBounds:YES];
[l setCornerRadius:5.0];
[l setBorderWidth:2.0];
[l setBorderColor:[[UIColor darkGrayColor] CGColor]];
위의 코드는 제공된 뷰의 각 모서리에 라운드니스를 적용하는 것입니다.대신에 저는 상단 / 상단 + 왼쪽 / 하단 + 오른쪽 등과 같은 선택된 모서리에 라운드를 적용하고 싶었습니다.
가능할까요? 어떻게요?
3부터는 iOS 3.2의 할 수 .UIBezierPath
s - 즉시 사용할 수 있는 반올림된 직사각형(지정한 모서리만 반올림됨)을 만듭니다.그런 다음 이것을 다음 경로로 사용할 수 있습니다.CAShapeLayer
이를 뷰 도면층의 마스크로 사용합니다.
// Create the path (with only the top-left corner rounded)
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:imageView.bounds
byRoundingCorners:UIRectCornerTopLeft
cornerRadii:CGSizeMake(10.0, 10.0)];
// Create the shape layer and set its path
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = imageView.bounds;
maskLayer.path = maskPath.CGPath;
// Set the newly created shape layer as the mask for the image view's layer
imageView.layer.mask = maskLayer;
그리고 그것이 바로 코어 그래픽에서 도형을 수동으로 정의하는 데 방해가 되지 않으며 포토샵에서 마스킹 이미지를 만들지 않습니다.계층은 무효화할 필요도 없습니다.둥근 모서리를 적용하거나 새 모서리로 변경하는 것은 새 모서리를 정의하는 것만큼 간단합니다.UIBezierPath
그리고 그것을 사용합니다.CGPath
마스크 계층의 경로로 사용됩니다. 그corners
의 파라미터bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:
메소드는 비트 마스크이므로 OR링을 통해 여러 모서리를 반올림할 수 있습니다.
편집: 그림자 추가
여기에 그림자를 추가하려면 작업이 조금 더 필요합니다.
하면냐왜" 때문입니다.imageView.layer.mask = maskLayer
마스크를 적용하면 일반적으로 마스크 외부에 그림자가 표시되지 않습니다.뷰를 두개의 레이어를 입니다.CALayer
으로: 뷰의도으로층:shadowLayer
그리고.roundedLayer
다 ▁of를 사용해야 합니다.UIBezierPath
는 이지가다추가다니됩의 됩니다.roundedLayer
.
// Create a transparent view
UIView *theView = [[UIView alloc] initWithFrame:theFrame];
[theView setBackgroundColor:[UIColor clearColor]];
// Create the path (with only the top-left corner rounded)
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:theView.bounds
byRoundingCorners:UIRectCornerTopLeft
cornerRadii:CGSizeMake(10.0f, 10.0f)];
// Create the shadow layer
CAShapeLayer *shadowLayer = [CAShapeLayer layer];
[shadowLayer setFrame:theView.bounds];
[shadowLayer setMasksToBounds:NO];
[shadowLayer setShadowPath:maskPath.CGPath];
// ...
// Set the shadowColor, shadowOffset, shadowOpacity & shadowRadius as required
// ...
// Create the rounded layer, and mask it using the rounded mask layer
CALayer *roundedLayer = [CALayer layer];
[roundedLayer setFrame:theView.bounds];
[roundedLayer setContents:(id)theImage.CGImage];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
[maskLayer setFrame:theView.bounds];
[maskLayer setPath:maskPath.CGPath];
roundedLayer.mask = maskLayer;
// Add these two layers as sublayers to the view
[theView.layer addSublayer:shadowLayer];
[theView.layer addSublayer:roundedLayer];
저는 아이폰에서 어떻게 둥근 모서리의 UI 레이블을 만들 수 있습니까? 그리고 아이폰에서 투명도가 있는 둥근 직선 뷰는 어떻게 됩니까?에서 답변을 사용했습니다.이 코드를 만드는 것.
그런 다음 잘못된 질문에 답했다는 것을 깨닫고(UIImage 대신 둥근 UI 레이블을 지정) 이 코드를 사용하여 변경했습니다.
http://discussions.apple.com/thread.jspa?threadID=1683876
View 템플릿으로 iPhone 프로젝트를 만듭니다.보기 컨트롤러에서 다음을 추가합니다.
- (void)viewDidLoad
{
CGRect rect = CGRectMake(10, 10, 200, 100);
MyView *myView = [[MyView alloc] initWithFrame:rect];
[self.view addSubview:myView];
[super viewDidLoad];
}
MyView
냥그입니다.UIImageView
하위 클래스:
@interface MyView : UIImageView
{
}
저는 그래픽 콘텍스트를 사용해 본 적이 없지만, 이 코드를 간신히 연결할 수 있었습니다.모서리 두 개에 대한 코드가 누락되었습니다. 제가 이걸 구현했는지 알 수 .CGContextAddArc
호출 및 코드에서 반지름 값의 일부를 삭제합니다.모든 코너의 코드는 거기에 있으므로 이 코드를 시작점으로 사용하고 필요 없는 코너를 만드는 부분은 삭제하십시오.원하는 경우 두 개 또는 세 개의 둥근 모서리가 있는 직사각형도 만들 수 있습니다.
코드가 완벽하지는 않지만, 당신이 그것을 조금 정리할 수 있다고 확신합니다.
static void addRoundedRectToPath(CGContextRef context, CGRect rect, float radius, int roundedCornerPosition)
{
// all corners rounded
// CGContextMoveToPoint(context, rect.origin.x, rect.origin.y + radius);
// CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + rect.size.height - radius);
// CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + rect.size.height - radius,
// radius, M_PI / 4, M_PI / 2, 1);
// CGContextAddLineToPoint(context, rect.origin.x + rect.size.width - radius,
// rect.origin.y + rect.size.height);
// 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 + radius);
// CGContextAddArc(context, rect.origin.x + rect.size.width - radius, rect.origin.y + radius,
// radius, 0.0f, -M_PI / 2, 1);
// CGContextAddLineToPoint(context, rect.origin.x + radius, rect.origin.y);
// CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + radius, radius,
// -M_PI / 2, M_PI, 1);
// top left
if (roundedCornerPosition == 1) {
CGContextMoveToPoint(context, rect.origin.x, rect.origin.y + radius);
CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + rect.size.height - radius);
CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + rect.size.height - radius,
radius, M_PI / 4, M_PI / 2, 1);
CGContextAddLineToPoint(context, rect.origin.x + rect.size.width,
rect.origin.y + rect.size.height);
CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y);
CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y);
}
// bottom left
if (roundedCornerPosition == 2) {
CGContextMoveToPoint(context, rect.origin.x, rect.origin.y);
CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + rect.size.height);
CGContextAddLineToPoint(context, rect.origin.x + rect.size.width,
rect.origin.y + rect.size.height);
CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y);
CGContextAddLineToPoint(context, rect.origin.x + radius, rect.origin.y);
CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + radius, radius,
-M_PI / 2, M_PI, 1);
}
// add the other corners here
CGContextClosePath(context);
CGContextRestoreGState(context);
}
-(UIImage *)setImage
{
UIImage *img = [UIImage imageNamed:@"my_image.png"];
int w = img.size.width;
int h = img.size.height;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);
CGContextBeginPath(context);
CGRect rect = CGRectMake(0, 0, w, h);
addRoundedRectToPath(context, rect, 50, 1);
CGContextClosePath(context);
CGContextClip(context);
CGContextDrawImage(context, rect, img.CGImage);
CGImageRef imageMasked = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
[img release];
return [UIImage imageWithCGImage:imageMasked];
}
alt 텍스트 http://nevan.net/skitch/skitched-20100224-092237.png
이 작업을 수행하려면 QuartzCore 프레임워크가 필요합니다.
나는 이 코드를 내 코드의 여러 곳에서 사용해왔고 100% 올바르게 작동합니다.하나의 특성을 "원형 코너별"로 변경하여 임의의 코더를 변경할 수 있습니다.UIRect 코너 왼쪽 하단"
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:UIRectCornerBottomLeft cornerRadii:CGSizeMake(10.0, 10.0)];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = view.bounds;
maskLayer.path = maskPath.CGPath;
view.layer.mask = maskLayer;
[maskLayer release];
iOS 11에서는 이제 일부 코너만 라운드할 수 있습니다.
let view = UIView()
view.clipsToBounds = true
view.layer.cornerRadius = 8
view.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]
Swift 3+ 구문을 사용하는 CAL 계층 확장
extension CALayer {
func round(roundedRect rect: CGRect, byRoundingCorners corners: UIRectCorner, cornerRadii: CGSize) -> Void {
let bp = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: cornerRadii)
let sl = CAShapeLayer()
sl.frame = self.bounds
sl.path = bp.cgPath
self.mask = sl
}
}
다음과 같이 사용할 수 있습니다.
let layer: CALayer = yourView.layer
layer.round(roundedRect: yourView.bounds, byRoundingCorners: [.bottomLeft, .topLeft], cornerRadii: CGSize(width: 5, height: 5))
특정 모서리를 반올림하는 스터트 예제는 유용합니다.여러 모서리를 왼쪽 위와 오른쪽 위처럼 반올림하려면 이 방법을 사용합니다.
// Create the path (with only the top-left corner rounded)
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:imageview
byRoundingCorners:UIRectCornerTopLeft|UIRectCornerTopRight
cornerRadii:CGSizeMake(10.0, 10.0)];
// Create the shape layer and set its path
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = imageview.bounds;
maskLayer.path = maskPath.CGPath;
// Set the newly created shape layer as the mask for the image view's layer
imageview.layer.mask = maskLayer;
필요에 따라 작동할 수 있고 그림자에도 작동할 수 있는 더 쉽고 빠른 대답이 있습니다.수퍼레이어에서 maskToBounds를 true로 설정하고 하위 레이어의 모서리 2개가 수퍼레이어 경계 밖에 있도록 오프셋하여 두 변의 둥근 모서리를 효과적으로 잘라낼 수 있습니다.
물론 이것은 같은 면에 두 개의 둥근 모서리만 있고 한 면에서 몇 개의 픽셀을 잘라낼 때 레이어의 내용이 동일하게 보일 때만 작동합니다.막대 차트를 위쪽에서만 반올림할 수 있습니다.
공유해 주셔서 감사합니다.이 문제에 대한 추가 참조를 위해 swift 2.0에 대한 솔루션을 공유하고자 합니다.(UIRectCorner의 프로토콜을 준수
let mp = UIBezierPath(roundedRect: cell.bounds, byRoundingCorners: [.bottomLeft, .TopLeft], cornerRadii: CGSize(width: 10, height: 10))
let ml = CAShapeLayer()
ml.frame = self.bounds
ml.path = mp.CGPath
self.layer.mask = ml
이 관련 질문을 참조하십시오.당신은 당신 자신의 직사각형을 그려야 할 것입니다.CGPath
약간의 둥근 모서리와 함께, 추가합니다.CGPath
당신에게CGContext
다음을 사용하여 클립으로 고정합니다.CGContextClip
.
또한 알파 값을 사용하여 반올림한 직선을 이미지에 그린 다음 해당 이미지를 사용하여 레이어 값으로 설정한 새 레이어를 만들 수 있습니다.mask
속성(Apple 설명서 참조).
5년 후의 일이지만, 저는 사람들이 이것을 하는 현재의 방식이 100% 옳지 않다고 생각합니다.많은 사람들이 UIBizerPath + CASapeLayer 메서드를 사용하면 자동 레이아웃이 특히 스토리보드에 설정되어 있을 때 자동 레이아웃을 방해한다는 문제를 가지고 있습니다.이 문제에 대한 답은 없습니다. 그래서 저는 제 것을 추가하기로 결정했습니다.
이를 피하기 위한 매우 쉬운 방법이 있습니다. 즉, 모서리의 둥근 부분을 그립니다.drawRect(rect: CGRect)
기능.
예를 들어, UIView의 모서리를 반올림하려면 UIView를 하위 클래스로 분류한 다음 해당 하위 클래스를 사용합니다.
import UIKit
class TopRoundedView: UIView {
override func drawRect(rect: CGRect) {
super.drawRect(rect)
var maskPath = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: UIRectCorner.TopLeft | UIRectCorner.TopRight, cornerRadii: CGSizeMake(5.0, 5.0))
var maskLayer = CAShapeLayer()
maskLayer.frame = self.bounds
maskLayer.path = maskPath.CGPath
self.layer.mask = maskLayer
}
}
이것은 문제를 극복하는 가장 좋은 방법이며 적응하는 데 전혀 시간이 걸리지 않습니다.
자동 크기 조정 또는 자동 레이아웃에서는 일부 모서리만 반올림하면 제대로 재생되지 않습니다.
그래서 또 다른 옵션은 일반적으로 사용하는 것입니다.cornerRadius
다른 뷰 아래 또는 수퍼뷰 경계 밖에서 원하지 않는 모서리를 숨겨 콘텐츠를 클리핑하도록 설정합니다.
답변과 추가 사항에 추가하기 위해 단순하고 재사용 가능한 솔루션을 만들었습니다.UIView
사례에 것을)하고 , 한 하고 싶었습니다.사용 사례에 따라 수정(모든 레이아웃에 개체를 만들지 않음)할 수도 있지만 가능한 한 단순하게 유지하고 싶었습니다.하면 다른(예: 확사면다예보른기하용장에 이 을 적용할 수 .UIImageView
하위 분류를 좋아하지 않는 경우 더 쉽습니다.
extension UIView {
func roundCorners(_ roundedCorners: UIRectCorner, toRadius radius: CGFloat) {
roundCorners(roundedCorners, toRadii: CGSize(width: radius, height: radius))
}
func roundCorners(_ roundedCorners: UIRectCorner, toRadii cornerRadii: CGSize) {
let maskBezierPath = UIBezierPath(
roundedRect: bounds,
byRoundingCorners: roundedCorners,
cornerRadii: cornerRadii)
let maskShapeLayer = CAShapeLayer()
maskShapeLayer.frame = bounds
maskShapeLayer.path = maskBezierPath.cgPath
layer.mask = maskShapeLayer
}
}
class RoundedCornerView: UIView {
var roundedCorners: UIRectCorner = UIRectCorner.allCorners
var roundedCornerRadii: CGSize = CGSize(width: 10.0, height: 10.0)
override func layoutSubviews() {
super.layoutSubviews()
roundCorners(roundedCorners, toRadii: roundedCornerRadii)
}
}
다음은 에 적용하는 방법입니다.UIViewController
:
class MyViewController: UIViewController {
private var _view: RoundedCornerView {
return view as! RoundedCornerView
}
override func loadView() {
view = RoundedCornerView()
}
override func viewDidLoad() {
super.viewDidLoad()
_view.roundedCorners = [.topLeft, .topRight]
_view.roundedCornerRadii = CGSize(width: 10.0, height: 10.0)
}
}
스튜어트의 답변을 마무리하면 다음과 같은 반올림 코너 방법을 사용할 수 있습니다.
@implementation UIView (RoundCorners)
- (void)applyRoundCorners:(UIRectCorner)corners radius:(CGFloat)radius {
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(radius, radius)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = self.bounds;
maskLayer.path = maskPath.CGPath;
self.layer.mask = maskLayer;
}
@end
따라서 반올림 모서리를 적용하려면 다음 작업을 수행합니다.
[self.imageView applyRoundCorners:UIRectCornerTopRight|UIRectCornerTopLeft radius:10];
레이어의 마스크를 정의하는 것이 좋습니다.마스크 자체는 다음과 같아야 합니다.CAShapeLayer
전용 경로가 있는 개체입니다.다음 UIView 확장(Swift 4.2)을 사용할 수 있습니다.
extension UIView {
func round(corners: UIRectCorner, with radius: CGFloat) {
let maskLayer = CAShapeLayer()
maskLayer.frame = bounds
maskLayer.path = UIBezierPath(
roundedRect: bounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius)
).cgPath
layer.mask = maskLayer
}
}
언급URL : https://stackoverflow.com/questions/2264083/rounded-uiview-using-calayers-only-some-corners-how
'programing' 카테고리의 다른 글
MongoDb c# 드라이버 필드 값으로 배열에서 항목 찾기 (0) | 2023.05.06 |
---|---|
Git를 사용하지 않고 GitHub 저장소 내에 폴더 만들기 (0) | 2023.05.01 |
긴 길을 위한 "에일리어스"를 만드는 방법은? (0) | 2023.05.01 |
비동기 코루틴으로 동기 함수를 래핑하려면 어떻게 해야 합니까? (0) | 2023.05.01 |
이클립스의 모든 파일에서 문자열 바꾸기 (0) | 2023.05.01 |