Округленный UIView с использованием CALayers-только некоторые углы-как?
в моем приложении - есть четыре кнопки названы следующим образом:
- верхний левый
- нижний - левый
- верхний правый
- нижний правый
над кнопками есть вид изображения (или UIView).
теперь предположим, что пользователь нажимает на верхнюю левую кнопку. Выше изображение / вид должны быть закруглены в этом конкретном углу.
У меня возникли некоторые трудности в применении скругленных углов к Наследник 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]];
выше код применяет округлость к каждому из углов поставляемого вида. Вместо этого я просто хотел применить округлость к выбранным углам, таким как - top / top+left / bottom+right и т. д.
это возможно? Как?
13 ответов:
я использовал ответ на как создать круглый угловой UILabel на iPhone? и код как округлый прямой вид с прозрачностью делается на iphone? чтобы сделать этот код.
затем я понял, что ответил на неправильный вопрос (дал округленный UILabel вместо UIImage), поэтому я использовал этот код, чтобы изменить его:
http://discussions.apple.com/thread.jspa?threadID=1683876
сделать 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вызовы и удаление некоторых значений радиуса в коде. Код для всех углов есть, так что используйте это как начальная точка и удалите детали, которые создают углы, которые вам не нужны. Обратите внимание, что вы можете сделать прямоугольники с 2 или 3 закругленными углами тоже, если хотите.код не идеален, но я уверен, что вы можете убирать его немного.
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 там для этого, чтобы работать.
начиная с iOS 3.2, вы можете использовать функциональность
UIBezierPaths, чтобы создать прямоугольную закругленную прямую (где закруглены только заданные углы). Затем вы можете использовать это как путь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;и это все - не возиться с ручным определением фигур в основной графике, не создавать маскирующие изображения в Photoshop. Слой даже не нуждается в аннулировании. Применение закругленного угла или изменение на новый углу так же просто, как определение нового
UIBezierPathи с помощьюCGPathкак путь слоя маски. ЭлементcornersпараметрbezierPathWithRoundedRect:byRoundingCorners:cornerRadii:метод является битовой маской,и поэтому несколько углов могут быть скруглены путем их объединения.
EDIT: добавление тени
если вы хотите, чтобы добавить тень к этому, требуется немного больше работы.
потому что "
imageView.layer.mask = maskLayer" применяет маску, тень обычно не будет отображаться за ее пределами. Фокус в том, что чтобы использовать прозрачный вид, а затем добавить два подуровня (CALayers) к слою представления:shadowLayerиroundedLayer. Оба должны использовать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];
я использовал этот код в мой код и он работает правильно на 100%. Вы можете изменить любой Кордер, изменив одно свойство "byRoundingCorners:UIRectCornerBottomLeft"
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];
пример Стюарта для округления определенных углов отлично работает. Если вы хотите закруглить несколько углов, таких как верхний левый и правый, это как это сделать
// 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;
Спасибо за обмен. Здесь я хотел бы поделиться решением на 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
есть более простой и быстрее ответ, который может работать в зависимости от ваших потребностей, а также работает с тенями. вы можете установить maskToBounds на суперслое в true и смещать дочерние слои так, чтобы 2 их угла находились за пределами границ суперслоя, эффективно вырезая закругленные углы с двух сторон.
конечно, это работает только тогда, когда вы хотите иметь только 2 закругленных угла на одной стороне, и содержимое слоя выглядит одинаково, когда вы отрезаете несколько пикселей от одна сторона. отлично подходит для того, чтобы гистограммы округлялись только с верхней стороны.
расширение CALayer с Swift 3 и выше синтаксис
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))
в iOS 11 теперь мы можем только закруглить некоторые углы
let view = UIView() view.clipsToBounds = true view.layer.cornerRadius = 8 view.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]
посмотреть этот вопрос. Вам придется нарисовать свой собственный прямоугольник в
CGPathс некоторые закругленные углы, добавитьCGPathнаCGContextа затем клип к нему с помощьюCGContextClip.вы также можете нарисовать округлый прямоугольник с Альфа-значениями на изображении, а затем использовать это изображение для создания нового слоя, который вы установили в качестве
maskсобственность (смотрите документацию Apple).
полтора десятилетия поздно, но я думаю, что сейчас люди делают это не на 100% прав. У многих людей была проблема, что использование метода UIBezierPath + CAShapeLayer мешает автоматической компоновке, особенно когда она установлена на раскадровке. Никаких ответов на это нет, поэтому я решил добавить свой собственный.
есть очень простой способ обойти это: нарисуйте закругленные углы в
округление только некоторых углов не будет хорошо играть с автоматическим изменением размера или автоматической компоновкой.
другой вариант-использовать обычный
cornerRadiusи скрыть углы, которые вы не хотите под другим видом или за пределами его границ супервизора, убедившись, что он установлен для обрезки его содержимого.
чтобы добавить к ответ и дополнение Я создал простой, многоразовые
UIViewв Swift. В зависимости от вашего варианта использования вы можете внести изменения (избегайте создания объектов на каждом макете и т. д.), но я хотел, чтобы это было как можно проще. Расширение позволяет применить это к другим представлениям (например.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];
Comments