UIView'de iki köşeyi yuvarlayın


83

Bir süre önce , bir görünümün sadece iki köşesini yuvarlamakla ilgili bir soru yayınladım ve harika bir yanıt aldım, ancak onu uygularken sorunlar yaşıyorum. İşte drawRect: yöntemim:

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

Yöntem çağrılıyor, ancak görüşün sonucunu etkilemiyor gibi görünüyor. Herhangi bir fikriniz neden?

Yanıtlar:


104

İOS 11'de sunulan CACornerMask, görünüm katmanında üst sol, üst sağ, alt sol, sağ alt tanımlamaya yardımcı olur. Kullanılacak örnek aşağıdadır.

Burada sadece iki üst köşeyi yuvarlatmaya çalışıyorum:

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

FYI Ref:


Bunu şimdi yapmanın deyimsel yolu bu gibi görünüyor. İyi yakalama!
Jumhyn

3
Görünümün genişliğinin / yüksekliğinin yine de köşe yarıçapının en az iki katı olması gerektiğini veya garip kusurların göründüğünü unutmayın. örneğin sadece alt köşelerin yuvarlanması, 20'lik bir yarıçap ve yalnızca 30'luk bir yükseklik, gözle görülür şekilde daha dar bir hücreye (bir veya iki piksel) neden olur.
Graham Perks

Görünümünüz çerçevesini değiştirdiğinde bunun doğru yol olduğunu unutmayın (benim durumumda olduğu gibi genişleyen bir UITextView nedeniyle mümkündür - stackoverflow.com/questions/50926215/… ). Bir UIBezierPath ayarlarsanız, çerçeve değiştiğinde otomatik olarak güncellenmez.
thomers

Yalnızca iOS 11 ve üzeri sürümlerde kullanılabildiğine dikkat çekildiif #available(iOS 11.0, *) { }
Tri Ngo Minh

2
Mükemmel cevap. Belirleyerek bunları Dönüşler clipsToBoundsiçin truegerekli değildir. Sen köşeleri maskelemek ve ne zaman katmana gölge ekleyebilirsiniz clipsToBoundsolduğunu false. Benim için kullanışlı oldu.
Au Ris

72


Bildiğim kadarıyla alt görünümleri de CALayermaskelemeniz gerekiyorsa maskelemeyi kullanabilirsiniz . Bunu yapmanın 2 yolu var. İlki biraz daha zarif, ikincisi geçici bir çözüm :-) ama aynı zamanda hızlı. Her ikisi de CALayermaskelemeye dayanmaktadır . Geçen yıl birkaç projede her iki yöntemi de kullandım, umarım faydalı bir şeyler bulursunuz.

1.Çözüm

Öncelikle, UIImageihtiyacım olan yuvarlak köşeyle anında ( ) bir görüntü maskesi oluşturmak için bu işlevi yarattım . Bu fonksiyon temelde 5 parametreye ihtiyaç duyar: görüntünün sınırları ve 4 köşe yarıçapı (sol üst, sağ üst, sol alt ve sağ alt).


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;
}  

Şimdi sadece birkaç satır koda ihtiyacınız var. Benim viewController şeyler koymak viewDidLoaddaha da hızlı ancak özel de kullanabilirsiniz, çünkü yöntemle UIViewbirlikte layoutSubviewsörnekteki yöntemle.



- (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.Çözüm

Bu çözüm biraz daha "kirli". Esasen ihtiyacınız olan yuvarlatılmış köşeye (tüm köşelere) sahip bir maske katmanı oluşturabilirsiniz. Daha sonra maske katmanının yüksekliğini köşe yarıçapının değeri kadar artırmalısınız. Bu şekilde alt yuvarlatılmış köşeler gizlenir ve yalnızca üst yuvarlatılmış köşeyi görebilirsiniz. Sadece kod koymak viewDidLoaddaha hızlı olduğu için yöntemin ancak özel de kullanabilirsiniz UIViewile layoutSubviewsörnekteki yöntemle.

  

- (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];
}

Bu yardımcı olur umarım. Ciao!


Sonunda çalıştı! Çok teşekkürler! Birinin diğerine göre avantajı nedir?
Jumhyn

Her neyse, CAShapeLayer çözümü bile mükemmel. CGPath'i UIBezierPath'i (3.2+ gerekir) veya sadece CGPath yöntemleriyle (CGPathMoveToPoint, CGPathAddQuadCurveToPoint vb.)
Kullanarak çizebilirsiniz

1
Dikeyden yataya döndürdükten sonra maskenin otomatik olarak yeniden boyutlandırılmasını nasıl sağlayabilirim?
chourobin

Layer.masksToBounds = EVET
Dmitry Salnikov

sadece sağ üst ve alt köşeleri yuvarlatmak için nasıl yapılır?
PLOW

69

Birkaç cevabı ve yorumu tarayarak, kullanmanın UIBezierPath bezierPathWithRoundedRectve CAShapeLayeren basit ve en basit yolu buldum . Çok karmaşık durumlar için uygun olmayabilir, ancak ara sıra köşelerin yuvarlanmasında benim için hızlı ve sorunsuz çalışıyor.

Maskede uygun köşeyi ayarlayan basitleştirilmiş bir yardımcı yaratmıştım:

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

Kullanmak için uygun UIRectCorner numaralandırması ile aramanız yeterlidir, örneğin:

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

Lütfen benim için bunu gruplanmış bir UITableViewCell'deki fotoğrafların köşelerini yuvarlamak için kullandığımı, 10.0 yarıçapının, değeri uygun şekilde değiştirmem gerekirse benim için iyi çalıştığını unutmayın.

DÜZENLEME: daha önce buna çok benzer bir yanıt ( bağlantı ) dikkat edin. Gerekirse bu yanıtı ek bir kolaylık işlevi olarak kullanmaya devam edebilirsiniz.


DÜZENLE: Swift 3'teki UIView uzantısı ile aynı kod

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

Kullanmak maskByRoundingCorneriçin herhangi birine basit bir çağrı yapın UIView:

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

Bu hala bir sınır eklerken mümkün mü?
Unome

2
DispatchQueue.main.async {} 'e işlev çağrısı koymak zorunda kaldım çünkü yalnızca bir köşe yuvarlandı ...
Maksim Kniazev

1
@MaksimKniazev evet, bu ana (UI) iş parçacığından çağrılmalıdır. Bu kural, kullanıcı arayüzüne dokunan tüm eylemler için geçerlidir, ana iş parçacığından çağrılmalıdırlar aksi halde bazı tuhaf şeyler olabilir.
PL

1
sadece bir köşe dönüyor gibi görünüyor. @MaksimKniazev çözümü de işe yaramadı.
Gustavo_fringe

@Gustavo_fringe ile aynı sorunu yaşıyorum, burada sağ üst köşenin bir xib görünümünün içindeki sınırlara kırpılmadığı / maskelenmediği (yeniden boyutlandırıldığı), henüz nasıl düzeltileceğinden emin değilim.
CyberMew

57

Tüm bunları @ lomanf'ın cevabına yapılan bir yoruma sığdıramadım. Bu yüzden bunu bir cevap olarak ekliyorum.

@Lomanf'ın dediği gibi, alt katmanların yolunuzun sınırlarının dışına çıkmasını önlemek için bir katman maskesi eklemeniz gerekir. Şimdi yapmak çok daha kolay. İOS 3.2 veya üstünü hedeflediğiniz sürece, kuvars ile bir görüntü oluşturmanıza ve bunu maske olarak ayarlamanıza gerek yoktur. Basitçe a CAShapeLayerile bir oluşturabilir UIBezierPathve bunu maske olarak kullanabilirsiniz.

Ayrıca, katman maskelerini kullanırken, maskeyi eklediğinizde maskelediğiniz katmanın herhangi bir katman hiyerarşisinin parçası olmadığından emin olun. Aksi takdirde davranış tanımsızdır. Görünümünüz zaten hiyerarşide ise, onu gözetim görünümünden kaldırmanız, maskelemeniz ve ardından olduğu yere geri koymanız gerekir.

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 oluşturma işleminin çalışma şekli nedeniyle maskeleme nispeten yavaş bir işlemdir. Her maske fazladan bir oluşturma geçişi gerektirir. Bu yüzden maskeleri idareli kullanın.

Bu yaklaşımın en iyi kısımlarından biri, artık bir özel oluşturmanıza UIViewve geçersiz kılmanıza gerek kalmamasıdır drawRect:. Bu, kodunuzu daha basit ve belki daha da hızlı hale getirmelidir.


Umut verici görünüyor, ancak manzara görünmüyor. Herhangi bir fikriniz neden?
Jumhyn

10
UIBezierPath'i boyutlandırmak için maskLayer.bounds'u kullanıyorsunuz, ancak sınırların değeri CGRectZero'dur. MaskLayer.frame = self.view.bounds gibi ikinci bir kod satırı eklemeniz gerekir (CAShapeLayer başlatıldıktan hemen sonra);
lomanf

1
Evet haklısın. Bu kodu, şekil katmanının zaten var olduğu başka bir örnekten çıkardım. Bunun için üzgünüm.
Nathan Eror

Mükemmel çalışıyor! MaskLayer.frame = self.view.bounds eklemek, yukarıda belirtildiği gibi, make çalışmadır. Aksi takdirde görünümler gösterilmez.
Daniel Ribeiro

+1 Bu oldukça iyi çalışıyor. Aslında bu yöntemi Lomanf'ın 2 numaralı çözümüne tercih ettiğimi düşünüyorum. Bu yöntem, zıt köşelere kolayca yay eklemenize izin verir (örneğin: Sağ Üst + Alt Sol) ve kesinlikle lomanf'ın ilk çözümünden daha kısadır. Harika kod Nathan!
FreeAsInBeer

30

Nathan'ın örneğini aldım ve UIViewDRY ilkelerine bağlı kalmasına izin vermek için bir kategori oluşturdum . Daha fazla uzatmadan:

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

Aramak:

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

2
<QuartzCore / QuatzCore.h> dosyasını .m dosyasına aktarmayı ve ayrıca projeye QuartzCore.framework eklemeyi unutmayın
DEzra

+1 Harika şeyler, bir soru var, görünümü kaldırmanın / süpervizör görünümüne okumanın amacı nedir?
eladleb

@eladleb: Buradaki temel kod Nathan'dan geldi, basitçe onu biraz optimize ettim. Yaptığım araştırmadan, katman maskesini uygulamadan önce görünümü kaldırmak için geçerli bir neden bulamıyorum. Bu nedenle, bu kodu atlamanın güvenli olduğuna inanıyorum.
FreeAsInBeer

@FreeAsInBeer - Kabul ediyorum, sonra onu kaldırmak için oy kullanırım, bu aslında görünüm z sırasını değiştirir ve daha fazla sorun yaratabilir ..
eladleb

TableView'e yuvarlatılmış köşeler ekleyerek yaşadığım sorunu çözdüm: Bir başlık ekledim, yuvarlak köşeleri yuvarladım ve yuvarlatılmış alt köşeleri olan bir altbilgi ekledim. Teşekkürler.
23'te gece sabitlendi

24

PL'nin cevabını biraz genişletmek için yöntemi, gibi belirli nesneleri UIButtondoğru şekilde yuvarlamadığı gibi yeniden yazdım.

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

Ve onu çağır

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

12

Swift ile yapmak istiyorsanız, bir UIView. Bunu yaparak, tüm alt sınıflar aşağıdaki yöntemi kullanabilecektir:

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

Örnek kullanım:

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

3

Kabul edilen cevabı genişleterek, ona geriye dönük uyumluluk ekleyelim. İOS 11'den önce, view.layer.maskedCorners mevcut değildir. Böylece bunu yapabiliriz

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'ı bir UIView uzantısı olarak yazdık, böylece kodun yeniden kullanımını iyileştirir.

@SachinVsSachin ve @PL kredileri :) Kodlarını daha iyi hale getirmek için birleştirdim.


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" ı ihtiyacınıza göre değiştirin .


peki bunu UIView'de yapmanız gerekiyor mu yoksa bu UIViewController'da yapılabilir mi? UIBezierPath'i yaptıktan sonra ne yaparsınız? Teşekkürler.
StoneBreaker

2

Sağlanan tüm çözümler hedefe ulaşır. Ama UIConstraintsbazen bunu havaya uçurabilir.

Örneğin, alt köşelerin yuvarlatılması gerekiyor. Yükseklik veya alt aralık kısıtlaması, yuvarlanması gereken UIView olarak ayarlanmışsa, köşeleri yuvarlayan kod parçacıklarının viewDidLayoutSubviewsyönteme taşınması gerekir .

Vurgulama:

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

Yukarıdaki kod parçacığı, bu kod ayarlandığında yalnızca sağ üst köşeyi yuvarlayacaktır viewDidLoad. Çünkü roundedView.boundskısıtlamalar güncellendikten sonra değişecek UIView.



1

Kodunuzla başlayarak, aşağıdaki kod parçacığı gibi bir şeyle gidebilirsiniz.

Bunun peşinde olduğunuz türden bir sonuç olup olmadığından emin değilim. Ayrıca, sistem drawRect'i çağırırsa / çağırdığında: yine, düzeltmenin yalnızca bir kısmının yeniden çizilmesini istemek, bunun çok tuhaf davranacağını da belirtmek gerekir. Nevan'ın yukarıda belirtilen yaklaşımı , daha iyi bir yol olabilir.

 // 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);    
}

Yuvarlatılmış köşeleri olan bir görünüm üzerinde çalıştım, ancak alt görünümlerinden herhangi birini kırpamıyorum. Görüşümün kenarına kare köşeli bir manzara yerleştirirsem, yine de gözetimdeki yuvarlatılmış köşeleri kaplar. Bunun neden olduğu hakkında bir fikriniz var mı?
Jumhyn

Çünkü kırpmak -drawRect:yalnızca çizdiğiniz görünümü etkiler. Alt görünümleri, çiziminiz tamamlandıktan sonra bağımsız olarak çizilir.
Jonathan Grynspan

1

Biraz karmaşık, ancak nispeten basit (alt sınıflandırma, maskeleme vb. Yok) yolu, iki UIV görünümüne sahip olmaktır. İkisi de clipToBounds = YES. Alt görünümde yuvarlatılmış köşeler ayarlayın, ardından düz olmasını istediğiniz köşelerin kırpılması için ana görünümün içine yerleştirin.

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];

Çapraz olarak zıt iki köşenin yuvarlatılmasını istediğiniz durumu desteklemez.


1

Bezier yolu, benim için çalışan ek koda ihtiyacınız varsa, bunun için bir çözümdür: 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 çözümü.

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

Bu, yalnızca bazı şeyler doğru ayarlanmışsa işe yarayabilir:

  1. clipsToBounds, YES olarak ayarlanmalıdır
  2. opak HAYIR olmalı
  3. backgroundColor "clearColor" olmalıdır (bundan tam olarak emin değilim)
  4. drawRect sık sık çağrılmıyorsa, contentMode "UIContentModeRedraw" olmalıdır
  5. [super drawRect: rect], CGContextClip'ten sonra çağrılmalıdır
  6. Görünümünüz rastgele alt görünümler içeremez (bundan emin değilsiniz)
  7. Doğru ayarınızı tetiklemek için en az bir kez "needsDisplay:" ayarladığınızdan emin olun

0

Bir UITableView’un en üstteki iki köşesini yuvarlamaya çalıştığınızın farkındayım, ancak nedense en iyi çözümün kullanmak olduğunu buldum:

self.tableView.layer.cornerRadius = 10;

Programlı olarak dört köşeyi de yuvarlaması gerekir, ancak bir nedenle yalnızca ilk ikisini yuvarlar. ** Yukarıda yazdığım kodun etkisini görmek için lütfen aşağıdaki ekran görüntüsüne bakın.

Umarım bu yardımcı olur!

görüntü açıklamasını buraya girin


1
O her köşesine yuvarlama değilse UITableViewyapıyor o zaman olmalıdır kod başka bir yerde UITableViewaltındaki yapmadıysanız yuvarlatılmış köşeler, Belkide bir UIViewveya UILabelo alt kısmını kapsayan UITableView.
Josh Valdivieso

-1

Muhtemelen sınırlara kadar kırpmanız gerekiyor. Satırı ekleyin

self.clipsToBounds = YES

bu özelliği ayarlamak için kodda bir yere.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.