iphone - top - what is safe area ios




UIView arredondada usando CALayers-apenas alguns cantos-Como? (10)

A partir do iOS 3.2, você pode usar a funcionalidade do UIBezierPath s para criar um UIBezierPath para o uso (onde apenas os cantos especificados são arredondados). Você pode usar isso como o caminho de um CAShapeLayer e usá-lo como uma máscara para a camada de visualização:

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

E é isso - sem mexer manualmente definindo formas no Core Graphics, sem criar imagens de mascaramento no Photoshop. A camada nem precisa invalidar. Aplicar o canto arredondado ou mudar para um novo canto é tão simples quanto definir um novo UIBezierPath e usar seu CGPath como o caminho da camada de máscara. O parâmetro de corners do bezierPathWithRoundedRect:byRoundingCorners:cornerRadii: é um bitmask e, portanto, vários cantos podem ser arredondados, reunindo-os.

EDIT: Adicionando uma sombra

Se você quer adicionar uma sombra a isso, é necessário um pouco mais de trabalho.

Como " imageView.layer.mask = maskLayer " aplica uma máscara, uma sombra normalmente não será mostrada fora dela. O truque é usar uma visão transparente e adicionar duas subcamadas ( CALayer s) à camada da view: shadowLayer e roundedLayer . Ambos precisam fazer uso do UIBezierPath . A imagem é adicionada como o conteúdo 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];

Na minha aplicação - existem quatro botões com o seguinte nome:

  • Superior esquerdo
  • Inferior esquerdo
  • Canto superior direito
  • Canto inferior direito

Acima dos botões, há uma visualização de imagem (ou um UIView).

Agora, suponha que um usuário toque no botão esquerdo. A imagem / vista acima deve ser arredondada nesse canto específico.

Estou tendo alguma dificuldade em aplicar cantos arredondados ao UIView.

No momento, estou usando o seguinte código para aplicar os cantos arredondados a cada exibição:

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

O código acima está aplicando a redondeza a cada um dos cantos da visualização fornecida. Em vez disso, eu só queria aplicar a redondeza aos cantos selecionados como - superior / superior + esquerda / inferior + direita etc.

É possível? Como?


Arredondar apenas alguns cantos não funciona com redimensionamento automático ou layout automático.

Portanto, outra opção é usar o cornerRadius regular e ocultar os cantos que você não deseja sob outra visualização ou fora dos limites de superview, certificando-se de que esteja definido para recortar seu conteúdo.


Eu usei a resposta no Como faço para criar um UILabel arredondado no iPhone? e o código de Como é uma visão retangular com transparência feita no iphone? para fazer este código.

Então percebi que tinha respondido a pergunta errada (dei uma UILabel arredondada em vez de UIImage) então usei este código para alterá-lo:

http://discussions.apple.com/thread.jspa?threadID=1683876

Faça um projeto do iPhone com o modelo Exibir. No controlador de visualização, adicione isto:

- (void)viewDidLoad
{
    CGRect rect = CGRectMake(10, 10, 200, 100);
    MyView *myView = [[MyView alloc] initWithFrame:rect];
    [self.view addSubview:myView];
    [super viewDidLoad];
}

MyView é apenas uma subclasse UIImageView :

@interface MyView : UIImageView
{
}

Eu nunca usei contextos gráficos antes, mas consegui manejar juntos esse código. Está faltando o código para dois dos cantos. Se você ler o código, você pode ver como eu implementei isso (excluindo algumas das chamadas CGContextAddArc e excluindo alguns dos valores do raio no código. O código para todos os cantos está lá, então use isso como ponto de partida e delete). as partes que criam cantos que você não precisa Observe que você pode fazer retângulos com 2 ou 3 cantos arredondados também se quiser.

O código não é perfeito, mas tenho certeza que você pode arrumar um pouco.

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

texto alternativo http://nevan.net/skitch/skitched-20100224-092237.png

Não se esqueça de que você precisará instalar o framework QuartzCore para que isso funcione.


Eu usei este código em muitos lugares no meu código e funciona 100% corretamente. Você pode alterar qualquer corder por uma propriedade alterada "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];

Meia década atrasada, mas acho que a maneira atual como as pessoas fazem isso não é 100% correta. Muitas pessoas tiveram o problema de que o uso do método UIBezierPath + CAShapeLayer interfere no layout automático, especialmente quando ele é definido no Storyboard. Nenhuma resposta passa por isso, então decidi adicionar a minha.

Existe uma maneira muito fácil de contornar isso: Desenhe os cantos arredondados na função drawRect(rect: CGRect) .

Por exemplo, se eu quisesse cantos arredondados para um UIView, eu subclassificaria o UIView e usaria essa subclasse sempre que fosse apropriado.

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

Essa é a melhor maneira de vencer o problema e não precisa de tempo para se adaptar.


No iOS 11, agora podemos arredondar apenas alguns cantos

let view = UIView()

view.clipsToBounds = true
view.layer.cornerRadius = 8
view.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]

Obrigado por compartilhar. Aqui eu gostaria de compartilhar a solução no swift 2.0 para mais referências sobre esse assunto. (para conformar o protocolo do 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

Para adicionar a answer e a addition , criei um UIView simples e reutilizável no Swift. Dependendo do seu caso de uso, você pode querer fazer modificações (evite criar objetos em todos os layouts etc.), mas eu queria mantê-lo o mais simples possível. A extensão permite que você aplique isso a outras visualizações (ex. UIImageView ) mais facilmente se você não gosta de subclassificação.

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

Veja como você aplicaria isso a um 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)
    }
}

Veja esta questão relacionada . Você terá que desenhar seu próprio retângulo em um CGPath com alguns cantos arredondados, adicionar o CGPath ao seu CGContext e então CGContext -lo usando CGContextClip .

Você também pode desenhar o retângulo com valores alfa em uma imagem e, em seguida, usar essa imagem para criar uma nova camada definida como a propriedade de mask da camada ( consulte a documentação da Apple ).


existe uma resposta mais fácil e rápida que pode funcionar dependendo das suas necessidades e também funciona com sombras. você pode definir maskToBounds na superlayer como true e compensar as camadas filho de modo que 2 dos seus cantos fiquem fora dos limites da super camada, cortando efetivamente os cantos arredondados em 2 lados.

é claro que isso só funciona quando você quer ter apenas 2 cantos arredondados no mesmo lado e o conteúdo da camada parece o mesmo quando você corta alguns pixels de um lado. funciona muito bem para ter gráficos de barras arredondados apenas no lado superior.







calayer