Skorzystałem z odpowiedzi w artykule Jak utworzyć zaokrąglony UILabel na iPhonie? i kod z Jak wygląda zaokrąglony prostokąt z przezroczystością na iPhonie? aby stworzyć ten kod.
Potem zdałem sobie sprawę, że odpowiedziałem na złe pytanie (podałem zaokrąglony UILabel zamiast UIImage), więc użyłem tego kodu, aby to zmienić:
http://discussions.apple.com/thread.jspa?threadID=1683876
Utwórz projekt na telefon iPhone za pomocą szablonu widoku. W kontrolerze widoku dodaj to:
- (void)viewDidLoad
{
CGRect rect = CGRectMake(10, 10, 200, 100);
MyView *myView = [[MyView alloc] initWithFrame:rect];
[self.view addSubview:myView];
[super viewDidLoad];
}
MyView
to tylko UIImageView
podklasa:
@interface MyView : UIImageView
{
}
Nigdy wcześniej nie korzystałem z kontekstów graficznych, ale udało mi się utykać razem ten kod. Brakuje kodu dla dwóch rogów. Jeśli czytasz kod, możesz zobaczyć, jak to zaimplementowałem (usuwając niektóre CGContextAddArc
wywołania i niektóre wartości promienia w kodzie. Kod dla wszystkich rogów jest tam, więc użyj go jako punktu wyjścia i usuń części, które tworzą rogi, których nie potrzebujesz. Pamiętaj, że możesz również tworzyć prostokąty z 2 lub 3 zaokrąglonymi rogami, jeśli chcesz.
Kod nie jest doskonały, ale jestem pewien, że możesz go trochę uporządkować.
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];
}
tekst alternatywny http://nevan.net/skitch/skitched-20100224-092237.png
Nie zapominaj, że musisz mieć tam strukturę QuartzCore, aby to działało.
Począwszy od iOS 3.2, możesz użyć funkcji
UIBezierPath
s, aby utworzyć gotowy prostokąt z zaokrągleniem (gdzie tylko określone rogi są zaokrąglane). Możesz następnie użyć tego jako ścieżki aCAShapeLayer
i użyć tego jako maski dla warstwy widoku:I to wszystko - bez majstrowania przy ręcznym definiowaniu kształtów w Core Graphics, bez tworzenia maskujących obrazów w Photoshopie. Warstwa nie wymaga nawet unieważnienia. Zastosowanie zaokrąglonego narożnika lub zmiana na nowy jest tak proste, jak zdefiniowanie nowego
UIBezierPath
i użycie goCGPath
jako ścieżki warstwy maski.corners
ParametrembezierPathWithRoundedRect:byRoundingCorners:cornerRadii:
sposobu jest maską bitów, a więc wiele rogi mogą być zaokrąglone przez Oring je razem.EDYCJA: dodawanie cienia
Jeśli chcesz dodać do tego cień, potrzeba trochę więcej pracy.
Ponieważ "
imageView.layer.mask = maskLayer
" nakłada maskę, zwykle cień nie będzie widoczny poza nią. Sztuczka polega na użyciu przezroczystego widoku, a następnie dodaniu dwóch podwarstwCALayer
do warstwy widoku:shadowLayer
iroundedLayer
. Oba muszą korzystać zUIBezierPath
. Obraz zostanie dodany jako zawartośćroundedLayer
.źródło
Użyłem tego kodu w wielu miejscach w moim kodzie i działa on w 100% poprawnie. Możesz zmienić dowolny corder, zmieniając jedną właściwość „byRoundingCorners: UIRectCornerBottomLeft”
źródło
UITableView
-subviews (np.UITableViewCell
S lubUITableViewHeaderFooterView
s) skutkuje złą płynnością podczas przewijania . Innym podejściem do tego zastosowania jest to rozwiązanie z lepszą wydajnością (dodaje cornerRadius do wszystkich rogów). Aby „pokazać” tylko określone rogi zaokrąglone (jak górne i dolne prawe rogi) dodałem widok podrzędny z ujemną wartościąframe.origin.x
i przypisałem cornerRadius do jego warstwy. Jeśli ktoś znalazł lepsze rozwiązanie, jestem zainteresowany.W iOS 11 możemy teraz zaokrąglić tylko niektóre rogi
źródło
Rozszerzenie CALayer ze składnią Swift 3+
Może być używany jak:
źródło
Przykład Stuarta do zaokrąglania określonych rogów sprawdza się świetnie. Jeśli chcesz zaokrąglić wiele rogów, takich jak lewy górny i prawy, oto jak to zrobić
źródło
UITableView
-subviews (np.UITableViewCell
S lubUITableViewHeaderFooterView
s) skutkuje złą płynnością podczas przewijania . Innym podejściem do tego zastosowania jest to rozwiązanie z lepszą wydajnością (dodaje cornerRadius do wszystkich rogów). Aby „pokazać” tylko określone rogi zaokrąglone (jak górne i dolne prawe rogi) dodałem widok podrzędny z ujemną wartościąframe.origin.x
i przypisałem cornerRadius do jego warstwy. Jeśli ktoś znalazł lepsze rozwiązanie, jestem zainteresowany.Dzięki za udostępnienie. Tutaj chciałbym podzielić się rozwiązaniem na swift 2.0, aby uzyskać dalsze informacje na ten temat. (w celu zgodności z protokołem UIRectCorner)
źródło
istnieje łatwiejsza i szybsza odpowiedź, która może działać w zależności od Twoich potrzeb, a także działa z cieniami. możesz ustawić maskToBounds w superwarstwie na true i przesunąć warstwy potomne tak, aby 2 z ich rogów znajdowały się poza granicami superwarstwy, skutecznie odcinając zaokrąglone rogi z 2 stron.
oczywiście działa to tylko wtedy, gdy chcesz mieć tylko 2 zaokrąglone rogi po tej samej stronie, a zawartość warstwy wygląda tak samo, gdy odetniesz kilka pikseli z jednej strony. doskonale sprawdza się w przypadku wykresów słupkowych zaokrąglonych tylko na górze.
źródło
Zobacz to powiązane pytanie . Będziesz musiał narysować własny prostokąt
CGPath
z kilkoma zaokrąglonymi rogami, dodaćCGPath
do swojego,CGContext
a następnie przyciąć do niego za pomocąCGContextClip
.Możesz również narysować zaokrąglony prostokąt z wartościami alfa na obrazie, a następnie użyć tego obrazu do utworzenia nowej warstwy, którą ustawisz jako
mask
właściwość warstwy ( zobacz dokumentację Apple ).źródło
Pół dekady późno, ale myślę, że obecny sposób, w jaki ludzie to robią, nie jest w 100% prawidłowy. Wiele osób miało problem, że użycie metody UIBezierPath + CAShapeLayer koliduje z automatycznym układem, zwłaszcza gdy jest ustawiony na Storyboard. Żadne odpowiedzi nie przekraczają tego, więc zdecydowałem się dodać własne.
Jest bardzo łatwy sposób na obejście tego: Narysuj zaokrąglone rogi w
drawRect(rect: CGRect)
funkcji.Na przykład, jeśli chciałbym mieć zaokrąglone górne rogi dla UIView, podklasę podklasę UIView użyłbym wtedy, gdy jest to konieczne.
To najlepszy sposób na pokonanie problemu i dostosowanie się do niego nie zajmuje dużo czasu.
źródło
drawRect(_:)
wtedy, gdy robisz niestandardowy rysunek w swoim widoku (np. Z Core Graphics), w przeciwnym razie nawet pusta implementacja może wpłynąć na wydajność. Tworzenie nowej warstwy maski za każdym razem również nie jest konieczne. Wszystko, co musisz zrobić, to zaktualizować właściwość warstwy maski,path
gdy zmienią się granice widoku, a miejsce do zrobienia tego znajduje się w zastąpieniulayoutSubviews()
metody.Zaokrąglanie tylko niektórych rogów nie będzie dobrze działać z automatyczną zmianą rozmiaru lub automatycznym układem.
Więc inną opcją jest użycie zwykłych
cornerRadius
i ukrycie rogów, których nie chcesz, pod innym widokiem lub poza jego granicami nadzoru, upewniając się, że jest ustawiona na przycinanie zawartości.źródło
Aby dodać do odpowiedzi i uzupełnienia , stworzyłem prosty, wielokrotnego użytku
UIView
w Swift. W zależności od przypadku użycia możesz chcieć wprowadzić modyfikacje (unikaj tworzenia obiektów na każdym układzie itp.), Ale chciałem, aby było to tak proste, jak to tylko możliwe. Rozszerzenie umożliwiaUIImageView
łatwiejsze zastosowanie tego do innych widoków (np. ), Jeśli nie lubisz tworzenia podklas.Oto jak można to zastosować do
UIViewController
:źródło
Podsumowując odpowiedź Stuarta, możesz zastosować metodę zaokrąglania narożników w następujący sposób:
Aby zastosować zaokrąglenie narożnika, po prostu wykonaj:
źródło
Sugerowałbym zdefiniowanie maski warstwy. Sama maska powinna być
CAShapeLayer
obiektem z dedykowaną ścieżką. Możesz użyć następnego rozszerzenia UIView (Swift 4.2):źródło