[Résolu] applyTransform sur scale d'une view ne fonctionne pas?

LouLou Membre
avril 2015 modifié dans API UIKit #1

Salut,


 


j'aimerais déplacer un rectangle bleu dans un rectangle arrondi aux bords orange. J'ai un problème avec le scale du rectangle bleu, j'aimerais le mettre à  100% par défaut, puis jouer sur son scale, avec une animation.


 


Pour l'instant, le applyTransform ne fonctionne pas, j'ai testé de mettre le .fill() après le applyTransform mais il n'apparaà®t plus dans ce cas là .


 


Si je laisse tel quel, le rectangle bleu ne prend pas en compte le scale. Sauriez-vous pourquoi?



override func drawRect(rect: CGRect) {
let w = self.frame.size.width
let h = self.frame.size.height
var orange = UIBezierPath(roundedRect:
CGRectMake(w/2, h/2, 100, 40),
cornerRadius: 20)
orange.lineWidth = 10
UIColor.orangeColor().setStroke()
orange.stroke()

orange.addClip()

blue = UIBezierPath(rect: CGRectMake(w/2, h/2, 200, 80))
UIColor.blueColor().setFill()
blue.fill()

let scale : CGFloat = 0.5
blue.applyTransform(CGAffineTransformMakeScale(scale, scale))
//blue.fill()

}

Merci :)


Réponses

  • CéroceCéroce Membre, Modérateur
    avril 2015 modifié #2

    Salut,
     
    j'aimerais déplacer un rectangle bleu dans un rectangle arrondi aux bords orange. J'ai un problème avec le scale du rectangle bleu, j'aimerais le mettre à  100% par défaut, puis jouer sur son scale, avec une animation.

    C'est une très mauvaise idée de faire ça dans drawRect:, pour des questions de performance. Et comment vas-tu l'animer par la suite ?
     
    Crée une deuxième UIView enfant ou une CALayer enfant. Tu pourras facilement et efficacement l'animer avec les méthodes de UIView, ou avec Core Animation.
     

    Pour l'instant, le applyTransform ne fonctionne pas, j'ai testé de mettre le .fill() après le applyTransform mais il n'apparaà®t plus dans ce cas là .

    Normal. fill() remplit le BézierPath. Donc, si tu le fais après, forcément, ça ne marche pas!
     

    Si je laisse tel quel, le rectangle bleu ne prend pas en compte le scale. Sauriez-vous pourquoi?

    Non. La syntaxe me semble correcte.
  • LouLou Membre

    Merci Céroce, comment ferais-tu les classes avec le drawRect? Pour l'instant, le rectangle ne se met pas à  la frame du parent, le 0,0 est en haut gauche de l'écran plutôt que d'être dans la view orange (qui se trouve au centre), et le rectangle arrondi orange n'est plus visible. Voici le code des 3 classes :



    //class Orange
    class MyView : UIView {

    override init(frame:CGRect){
    super.init(frame: frame)
    }

    required init(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
    }

    override func drawRect(rect: CGRect) {
    let w = self.frame.size.width
    let h = self.frame.size.height
    var orange = UIBezierPath(roundedRect:
    CGRectMake(w/2, h/2, 100, 40),
    cornerRadius: 20)
    orange.lineWidth = 10
    UIColor.orangeColor().setStroke()
    orange.stroke()

    orange.addClip()
    }
    }


    //class Blue
    import UIKit

    class BlueView : UIView {

    var blue : UIBezierPath!

    override init(frame:CGRect){
    super.init(frame: frame)
    }

    required init(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
    }

    override func drawRect(rect: CGRect) {
    blue = UIBezierPath(rect: CGRectMake(0,0, 20, 20))
    UIColor.blueColor().setFill()
    blue.fill()
    }
    }



    //viewDidLoad
    mView = MyView(frame: self.frame)
    var blueView = BlueView(frame: self.frame) //ou mView.frame

    mView.addSubview(blueView)
    self.view!.addSubview(mView)
  • CéroceCéroce Membre, Modérateur
    J'ai créé un Storyboard pour essayer.
    Le problème est que les deux vues ont exactement la même frame.
    Ceci crée deux problèmes:

    1) la frame est relative à  la vue parente
    C'est à  dire que si tu écris frame = 100, 100, 300, 200
    alors la vue enfant commence en 100, 100, _relativement_ à  la vue parente.

    2) le fond de la vue est noir
    Quand tu vas ajouter la vue fille, son fond noir va masquer ce qui est dessiné dans la vue parente.

    Solution: faire en sorte que les vues remplissent entièrement leur rectangle bounds (et non frame). Régler les frames, et pas les coordonnées passées à  UIBezierPath. De toute façon, c'est la frame que tu animeras ensuite.
  • LouLou Membre
    avril 2015 modifié #5

    Merci, j'ai réussi à  m'en sortir avec le code suivant. Pas sûr d'avoir compris l'histoire avec les bounds, mais en effet en jouant sur la frame et en bougeant la vue bleu, ça marche :) Avec un offset pour les cornerRadius aussi. Et bien vu pour le background color ;) En mettant en clearColor ça marche bien. Voici le code :



    let w = self.frame.size.width
    let h = self.frame.size.height

    var orangeView = OrangeView(frame: self.frame)
    orangeView.frame = CGRectMake(w/2, h/2, 150, 80)
    self.view!.addSubview(orangeView)

    var maskView = MaskView(frame : self.frame)
    maskView.frame = CGRectMake(w/2, h/2, 150, 50)
    self.view!.addSubview(maskView)

    blueView = BlueView(frame: self.frame)
    blueView.frame = CGRectMake(0, 0, 20,200)
    maskView.addSubview(blueView)



    class MaskView : UIView {
    override init(frame:CGRect){
    super.init(frame: frame)
    self.backgroundColor = UIColor.clearColor()
    }
    required init(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
    }

    var widthOrange: CGFloat = 100.0 - 10.0
    var heightOrange : CGFloat = 40.0 - 10.0
    var radius : CGFloat = 0

    override func drawRect(rect: CGRect) {
    createMask()
    }
    func createMask(){
    radius = heightOrange * 0.5
    let maskLayer = CAShapeLayer()
    var path = CGPathCreateMutable()
    var orange = UIBezierPath(roundedRect:
    CGRectMake(15,15,
    widthOrange, heightOrange),
    cornerRadius: radius)
    orange.lineWidth = 10
    maskLayer.path = orange.CGPath;
    self.layer.mask = maskLayer
    self.clipsToBounds = true
    }
    }

  • AliGatorAliGator Membre, Modérateur
    Oulà ... Qu'est ce que du code qui ne fait appel à  aucune méthode de CoreGraphics, comme la méthode createMask, vient faire dans drawRect() ?!

    drawRect ne doit absolument servir qu'à  dessiner sur le contexte graphique, genre avec des méthodes de CGContextXXX()

    Si au lieu de ça tu veux faire des formes avec des CALayer, c'est tout à  fait possible, mais ça n'a rien à  faire dans le drawRect() (qui est appelé à  chaque frame ayant à  être dessiné). Assembler des CALayer comme tu le fais ici, avec des CAShapeLayer et tout c'est très bien, mais c'est un peu comme quand on ajoute des UIViews en subview à  d'autres UIView : c'est à  faire une fois pour toutes (genre dans le init() par exemple) à  la création de ta vue ; certainement pas à  faire dans le drawRect, ce n'est pas sa place.
  • LouLou Membre

    OK, bien noté 


Connectez-vous ou Inscrivez-vous pour répondre.