Dans ma candidature, quatre boutons sont nommés comme suit:
Au-dessus des boutons se trouve une vue d’image (ou une vue UIV).
Supposons maintenant qu'un utilisateur appuie sur le bouton - en haut à gauche. L'image/vue ci-dessus doit être arrondie à ce coin particulier.
J'ai quelques difficultés à appliquer des angles arrondis à UIView.
En ce moment, j'utilise le code suivant pour appliquer les angles arrondis à chaque vue:
// 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]];
Le code ci-dessus applique l’arrondi à chacun des coins de la vue fournie. Au lieu de cela, je voulais juste appliquer de la rondeur aux coins sélectionnés comme - haut/haut + gauche/bas + droite etc.
C'est possible? Comment?
J'ai utilisé la réponse à Comment créer un UILabel aux angles arrondis sur l'iPhone? et le code de Comment une vue rectangle arrondie avec transparence est-elle réalisée sur un iphone? faire ce code.
Ensuite, j'ai réalisé que j'avais répondu à la mauvaise question (j'ai donné un UILabel arrondi au lieu de UIImage) et j'ai donc utilisé ce code pour le changer:
http://discussions.Apple.com/thread.jspa?threadID=1683876
Créez un projet iPhone avec le modèle Voir. Dans le contrôleur de vue, ajoutez ceci:
- (void)viewDidLoad
{
CGRect rect = CGRectMake(10, 10, 200, 100);
MyView *myView = [[MyView alloc] initWithFrame:rect];
[self.view addSubview:myView];
[super viewDidLoad];
}
MyView
est simplement une UIImageView
sous-classe:
@interface MyView : UIImageView
{
}
Je n'avais jamais utilisé de contextes graphiques auparavant, mais j'ai réussi à bricoler ce code. Il manque le code pour deux des coins. Si vous lisez le code, vous pouvez voir comment je l'ai implémenté (en supprimant certains des appels CGContextAddArc
et en supprimant certaines valeurs de rayon dans le code. Le code pour tous les coins est là, alors utilisez-le comme point de départ et supprimez les pièces qui créent des coins inutiles Notez que vous pouvez aussi créer des rectangles avec 2 ou 3 coins arrondis si vous le souhaitez.
Le code n'est pas parfait, mais je suis sûr que vous pouvez le ranger un peu.
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 text http://nevan.net/skitch/skitched-20100224-092237.png
N'oubliez pas que vous aurez besoin d'inclure le framework QuartzCore pour que cela fonctionne.
À partir de iOS 3.2, vous pouvez utiliser la fonctionnalité de UIBezierPath
s pour créer un rectangle arrondi prêt à l'emploi (où seuls les coins que vous spécifiez sont arrondis). Vous pouvez ensuite l'utiliser comme chemin d'une variable CAShapeLayer
et l'utiliser comme masque pour le calque de votre vue:
// 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;
Et c'est tout - pas de déconner de définir manuellement des formes dans Core Graphics, pas de créer des images de masquage dans Photoshop. La couche n'a même pas besoin d'être invalidée. Appliquer le coin arrondi ou changer de coin est aussi simple que de définir une nouvelle UIBezierPath
et d’utiliser sa CGPath
comme chemin du calque de masque. Le paramètre corners
de la méthode bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:
est un masque de bits. Il est donc possible d'arrondir plusieurs angles en ouvrant la propriété OU ensemble .
Si vous souhaitez ajouter une ombre à cela, un peu plus de travail est nécessaire.
Parce que "imageView.layer.mask = maskLayer
" applique un masque, une ombre ne sera normalement pas affichée en dehors de celui-ci. L'astuce consiste à utiliser une vue transparente, puis à ajouter deux sous-couches (CALayer
s) à la couche de la vue: shadowLayer
et roundedLayer
. Les deux doivent utiliser la variable UIBezierPath
. L'image est ajoutée en tant que contenu de 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];
J'ai utilisé ce code à plusieurs endroits dans mon code et cela fonctionne à 100% correctement. Vous pouvez modifier n’importe quel câble en modifiant une propriété "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];
Dans iOS 11, nous ne pouvons désormais arrondir que certains coins
let view = UIView()
view.clipsToBounds = true
view.layer.cornerRadius = 8
view.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]
Stuarts, par exemple, pour arrondir des angles spécifiques fonctionne très bien. Si vous voulez arrondir plusieurs coins comme en haut à gauche et à droite, voici comment procéder.
// 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;
Merci d'avoir partagé. J'aimerais ici partager la solution sur Swift 2.0 pour une référence ultérieure sur ce sujet. (pour se conformer au protocole 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
Extension CALayer avec Swift 3 et supérieur syntaxe
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
}
}
Il peut être utilisé comme:
let layer: CALayer = yourView.layer
layer.round(roundedRect: yourView.bounds, byRoundingCorners: [.bottomLeft, .topLeft], cornerRadii: CGSize(width: 5, height: 5))
il existe une réponse plus simple et plus rapide qui peut fonctionner en fonction de vos besoins et fonctionne également avec des ombres. vous pouvez définir maskToBounds sur la supercouche sur true et décaler les calques enfants afin que deux de leurs coins soient en dehors des limites de la supercouche, coupant ainsi les coins arrondis des deux côtés.
bien sûr, cela ne fonctionne que lorsque vous souhaitez avoir seulement 2 coins arrondis du même côté et que le contenu du calque est identique lorsque vous coupez quelques pixels d'un côté. fonctionne très bien pour avoir des graphiques à barres arrondis uniquement sur la face supérieure.
Voir cette question connexe . Vous devrez dessiner votre propre rectangle à une CGPath
avec certains coins arrondis, ajouter la CGPath
à votre CGContext
et y couper un clip en utilisant CGContextClip
.
Vous pouvez également tracer le rectangle arrondi avec les valeurs alpha sur une image, puis utiliser cette image pour créer un nouveau calque que vous définissez comme propriété mask
de votre calque ( voir la documentation Apple ).
Arrondir seulement certains coins ne jouera pas Nice avec redimensionnement automatique ou mise en page automatique.
Une autre option consiste donc à utiliser la variable normale cornerRadius
et à masquer les coins non souhaités sous une autre vue ou en dehors de ses limites supérieures de vue, en vous assurant qu'elle est définie pour en couper le contenu.
Une demi-décennie de retard, mais je pense que la façon dont les gens font cela actuellement n’est pas correcte à 100%. De nombreuses personnes ont eu le problème suivant: l'utilisation de la méthode UIBezierPath + CAShapeLayer interfère avec la mise en page automatique, notamment lorsqu'elle est définie sur le scénarimage. Aucune réponse ne va à ce sujet, alors j'ai décidé d'ajouter la mienne.
Il existe un moyen très simple de contourner cela: Tracez les coins arrondis dans la fonction drawRect(rect: CGRect)
.
Par exemple, si je souhaitais utiliser les angles supérieurs arrondis pour UIView, je sous-classerais UIView, puis l’utiliserais chaque fois que nécessaire.
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
}
}
C'est la meilleure façon de résoudre le problème et ne prend aucun temps pour s'y adapter.
Pour ajouter à answer et à addition , j'ai créé une simple variable UIView
dans Swift. En fonction de votre cas d'utilisation, vous souhaiterez peut-être apporter des modifications (éviter de créer des objets sur chaque mise en page, etc.), mais je souhaitais le garder aussi simple que possible. L'extension vous permet de l'appliquer à d'autres vues (ex. UIImageView
) plus facilement si vous n'aimez pas les sous-classes.
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)
}
}
Voici comment vous l'appliqueriez à une 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)
}
}
Je suggère de définir un masque de calque. Le masque lui-même devrait être un objet CAShapeLayer
avec un chemin dédié. Vous pouvez utiliser la prochaine extension 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
}
}
Pour conclure la réponse de Stuart, vous pouvez utiliser la méthode suivante:
@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
Donc, pour appliquer le coin arrondi, vous faites simplement:
[self.imageView applyRoundCorners:UIRectCornerTopRight|UIRectCornerTopLeft radius:10];