web-dev-qa-db-fra.com

redessiner une vue personnalisée lors de la modification de l'orientation d'un périphérique

  1. Si je dessine mon tableau à l'intérieur de - (void)drawRect:(CGRect)rect, il suffit juste de définir [_chartView setContentMode:UIViewContentModeRedraw] et cette méthode sera appelée lorsque l'appareil change, c'est son changement et il est possible de calculer f.e. nouveau point central pour ma carte.
  2. Si je crée une vue comme une sous-vue à l'aide de - (id)initWithFrame:(CGRect)frame, puis l'ajoute dans le contrôleur de vue comme [self.view addSubview:chartView];. Comment dans ce cas je peux gérer la rotation pour redessiner mon graphique?
17
pvllnspk

Pour rendre votre graphique correctement rendu lorsque l'orientation du périphérique change, vous devez mettre à jour la présentation du graphique. Voici le code que vous devez ajouter à votre contrôleur de vue:

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    _chartView.frame = self.view.bounds;
    [_chartView strokeChart];
}
14
Keenle

Utilisation de .Redraw

L'appel par programme myView.contentMode = .Redraw lors de la création de la vue personnalisée devrait suffire. Il s’agit d’un indicateur unique dans IB et, en tant que tel, des lignes de code 0 préférées. Voir Stack Overflow Comment déclencher drawRect sur la sous-classe UIView .


Utilisation de setNeedsDisplay()

Si vous devez déclencher un rafraîchissement, faites-le dans setNeedsDisplay, qui à son tour appelle drawRect.
Pas besoin d'écouter les notifications ni de refactoriser le code.

Rapide

override func layoutSubviews() {
    super.layoutSubviews()
    self.setNeedsDisplay()
}

Objectif c

- (void)layoutSubviews {
    [super layoutSubviews];
    [self setNeedsDisplay];
}

Remarque:
layoutSubviews est une méthode UIView, pas une méthode UIViewController.

28
SwiftArchitect

Allez ici pour savoir comment recevoir des notifications lorsque l'orientation de l'appareil change. Lorsque l'orientation change, appelez simplement [chartView setNeedsDisplay]; pour que drawRect: soit appelé afin de pouvoir mettre à jour votre vue. J'espère que cela t'aides!

4
Aderis

Le code que vous allez ajouter à votre contrôleur de vue:

- (void)updateViewConstraints
{
    [super updateViewConstraints];
    [_chartView setNeedsDisplay];
}
2
2cupsOfTech

Malheureusement, certaines réponses suggèrent de remplacer les méthodes du contrôleur, mais certaines personnalités UITableViewCells avec une ombre entourant et faisant pivoter le périphérique étirent les cellules mais ne redessinent pas l'ombre. Donc, je ne veux pas mettre mon code dans un contrôleur pour (re) dessiner une sous-vue . La solution pour moi consiste à écouter une notification UIDeviceOrientationDidChange dans ma coutume UITableViewCell et ensuite appeler setNeedsDisplay() comme suggéré.

Exemple de code Swift 4.0 dans l'un de mes UITableViewCells personnalisés

override func awakeFromNib() {
    super.awakeFromNib()

    NotificationCenter.default.addObserver(self, selector: #selector(deviceOrientationDidChangeNotification), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
}

@objc func deviceOrientationDidChangeNotification(_ notification: Any) {
        Logger.info("Orientation changed: \(notification)")
        setNeedsLayout()
}

BTW: Logger est une typealias à SwiftyBeaver. Merci à @Aderis de me diriger dans la bonne direction.

0
Sal

J'ai essayé «setNeedsDisplay» de différentes manières et cela ne fonctionnait pas pour ajuster l'ombre d'une vue animée à une nouvelle position.

J'ai cependant résolu mon problème avec cela. Si votre ombre ne semble pas vouloir coopérer/mettre à jour, vous pouvez simplement définir l'ombre sur nil, puis la redéfinir:

    UIView.animateKeyframes(withDuration: 0.2 /*Total*/, delay: 0.0, options: UIViewKeyframeAnimationOptions(), animations: {
        UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 10/10, animations:{
            // Other things to animate

            //Set shadow to nil
            self.viewWithShadow.layer.shadowPath = nil
        })
    }, completion: { finished in
        if (!finished) { return }
        // When the view is moved, set the shadow again
        self.viewWithShadow.layer.shadowPath = UIBezierPath(rect: self.descTextView.bounds).cgPath
    })

Si vous n'avez même pas encore d'ombre et avez besoin de ce code, voici ce qui suit:

func addShadowTo (view: UIView) {
    view.layer.masksToBounds = false
    view.layer.shadowColor = UIColor.gray.cgColor
    view.layer.shadowOffset = CGSize( width: 1.0, height: 1.0)
    view.layer.shadowOpacity = 0.5
    view.layer.shadowRadius = 6.0
    view.layer.shadowPath = UIBezierPath(rect: view.bounds).cgPath
    view.layer.shouldRasterize = true
}
0
Dave G

Merci Keenle, pour la solution ObjC ci-dessus. Je m'amusais à créer des contraintes programmées toute la matinée, à tuer mon cerveau, sans comprendre pourquoi ils ne recompileraient/réaligneraient pas la vue. Je suppose que parce que j'avais créé UIView par programme en utilisant CGRect ... cela prenait le dessus.

Cependant, voici ma solution à Swift:

    override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    myUIView.center = CGPoint(x: (UIScreen.mainScreen().bounds.width / 2), y: (UIScreen.mainScreen().bounds.height / 2))

}

Tellement soulagé! :) 

0
David West