web-dev-qa-db-fra.com

Dessiner une ombre uniquement de 3 côtés de UIView

J'ai implémenté avec succès le dessin d'une ombre autour de ma UIView comme ceci:

block1.layer.masksToBounds = NO;
block1.layer.shadowOffset = CGSizeMake(0, 0);
block1.layer.shadowRadius = 1;
block1.layer.shadowOpacity = 0.7;

Ce qui se passe maintenant, c’est que j’ai une UIView rectangulaire et je voudrais tracer l’ombre autour de celle-ci sur trois côtés, en laissant le côté bas sans l’ombre. 

Je sais que je dois spécifier le block1.layer.shadowPath en créant une nouvelle UIBezierPath mais je ne sais pas comment le faire.

De toute évidence, régler layer.shadowOffset ne me convient pas.

Merci d'avance!

21
Sergey Grischyov

Je sais que vous dites que le réglage de layer.shadowOffset ne fonctionnera pas pour vous, mais que vous êtes autorisé à entrer des valeurs négatives. Le réglage de layer.shadowOffset = CGSizeMake(0.0, -2.0) se rapprocherait donc de l’effet recherché, mais bien sûr, je pense que vous voulez que ce soit le même trois côtés.

Alors on y va avec layer.shadowPath!

UIView *block1 = [[UIView alloc] initWithFrame:CGRectMake(32.0, 32.0, 128.0, 128.0)];
[block1 setBackgroundColor:[UIColor orangeColor]];
[self.view addSubview:block1];

block1.layer.masksToBounds = NO;
block1.layer.shadowOffset = CGSizeMake(0, 0);
block1.layer.shadowRadius = 1;
block1.layer.shadowOpacity = 0.7;

UIBezierPath *path = [UIBezierPath bezierPath];

// Start at the Top Left Corner
[path moveToPoint:CGPointMake(0.0, 0.0)];

// Move to the Top Right Corner
[path addLineToPoint:CGPointMake(CGRectGetWidth(block1.frame), 0.0)];

// Move to the Bottom Right Corner
[path addLineToPoint:CGPointMake(CGRectGetWidth(block1.frame), CGRectGetHeight(block1.frame))];

// This is the extra point in the middle :) Its the secret sauce.
[path addLineToPoint:CGPointMake(CGRectGetWidth(block1.frame) / 2.0, CGRectGetHeight(block1.frame) / 2.0)];

// Move to the Bottom Left Corner
[path addLineToPoint:CGPointMake(0.0, CGRectGetHeight(block1.frame))];

// Move to the Close the Path
[path closePath];

block1.layer.shadowPath = path.CGPath;

Et pour vous donner une idée de ce qui se passe, voici le chemin de l'ombre que vous venez de dessiner :)

enter image description here

Il est possible de simplement déplacer ce point médian supplémentaire avant ou après les autres lignes pour choisir le côté qui sera omis.

49
Ryan Poolos

Un peu d'amélioration pour d'autres réponses, merci à Ashok R pour le code Swift.

Comme nous étions en train de créer une vue triangulaire à l'arrière-plan de la vue avec des ombres sur tous les côtés, un triangle blanc sur les côtés ne nécessite pas d'ombre.

Il casse en cas de vues avec une largeur comparativement plus grande que la hauteur.

 image with triangle shadow

Une solution de contournement consistera à déplacer le chemin de la ligne où l'ombre n'est pas nécessaire un peu vers ce côté de la vue, au lieu de créer la vue triangulaire Chemin complètement .

J'ai créé une extension pour ça - 

extension UIView {
    func addshadow(top: Bool,
                   left: Bool,
                   bottom: Bool,
                   right: Bool,
                   shadowRadius: CGFloat = 2.0) {

        self.layer.masksToBounds = false
        self.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)
        self.layer.shadowRadius = shadowRadius
        self.layer.shadowOpacity = 1.0

        let path = UIBezierPath()
        var x: CGFloat = 0
        var y: CGFloat = 0
        var viewWidth = self.frame.width
        var viewHeight = self.frame.height

        // here x, y, viewWidth, and viewHeight can be changed in
        // order to play around with the shadow paths.
        if (!top) {
            y+=(shadowRadius+1)
        }
        if (!bottom) {
            viewHeight-=(shadowRadius+1)
        }
        if (!left) {
            x+=(shadowRadius+1)
        }
        if (!right) {
            viewWidth-=(shadowRadius+1)
        }
        // selecting top most point
        path.move(to: CGPoint(x: x, y: y))
        // Move to the Bottom Left Corner, this will cover left edges
        /*
         |☐
         */
        path.addLine(to: CGPoint(x: x, y: viewHeight))
        // Move to the Bottom Right Corner, this will cover bottom Edge
        /*
         ☐
         -
         */
        path.addLine(to: CGPoint(x: viewWidth, y: viewHeight))
        // Move to the Top Right Corner, this will cover right Edge
        /*
         ☐|
         */
        path.addLine(to: CGPoint(x: viewWidth, y: y))
        // Move back to the initial point, this will cover the top Edge
        /*
         _
         ☐
         */        
        path.close()
        self.layer.shadowPath = path.cgPath
    }

et réglez la valeur booléenne sur le côté où vous souhaitez que l'ombre apparaisse

myView.addshadow(top: false, left: true, bottom: true, right: true, shadowRadius: 2.0)

// le rayon de l'ombre est facultatif ci-dessus et est défini par défaut à 2.0

 enter image description here

ou myView.addshadow(top: true, left: true, bottom: true, right: true, shadowRadius: 2.0)

 enter image description here

ou myView.addshadow(top: false, left: false, bottom: true, right: true, shadowRadius: 2.0)

 enter image description here

7
Saurabh Yadav

Mise à jourRyan PoolosRéponse à Swift 3.0

Merci àRyan Poolos

class sampleViewController: UIViewController {
    var block1: UIView! = nil

    override func viewDidLoad() {

        super.viewDidLoad()
        block1 = UIView(frame: CGRect(x: 32.0, y: 32.0, width: 128.0, height: 128.0))
        block1.backgroundColor = UIColor.orange
        self.view.addSubview(block1)

        block1.layer.masksToBounds = false
        block1.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)
        block1.layer.shadowRadius = 1.0
        block1.layer.shadowOpacity = 0.7

        let path = UIBezierPath()

        // Start at the Top Left Corner
        path.move(to: CGPoint(x: 0.0, y: 0.0))

        // Move to the Top Right Corner
        path.addLine(to: CGPoint(x: block1.frame.size.width, y: 0.0))

        // Move to the Bottom Right Corner
        path.addLine(to: CGPoint(x: block1.frame.size.width, y: block1.frame.size.height))

        // This is the extra point in the middle :) Its the secret sauce.
        path.addLine(to: CGPoint(x: block1.frame.size.width/2.0, y: block1.frame.size.height/2.0))

        // Move to the Bottom Left Corner
        path.addLine(to: CGPoint(x: 0.0, y: block1.frame.size.height))

        path.close()

        block1.layer.shadowPath = path.cgPath
    }
}

Résultat: 

 image

3
Ashok R

Essaye ça 

extension CALayer {
func applySketchShadow(color: UIColor, alpha: CGFloat, x: CGFloat, y: CGFloat, blur: CGFloat, spread: CGFloat)
{
    shadowColor = color.cgColor
    shadowOpacity = alpha
    shadowOffset = CGSize(width: x, height: y)
    shadowRadius = blur / 2.0
    if spread == 0 {
        shadowPath = nil
    } else {
        let dx = -spread
        let rect = bounds.insetBy(dx: dx, dy: dx)
        shadowPath = UIBezierPath(rect: rect).cgPath
    }
}
0
roopesh chowdary