2017-06-03 1 views
0

Je tente d'ajouter un dégradé sur un UIBView @IBDesignable. Tout allait bien dans Simulator, mais quand je l'ai exécuté sur un périphérique physique, le dégradé ne remplit pas l'écran. J'ai mon code de gradient dans une extension UIView:Dégradé non rempli IBDesignable UIView

extension UIView { 
    func gradientFrom(_ colors: [UIColor]) { 
     let cgColors = colors.map({return $0.cgColor}) 
     let gradient = CAGradientLayer() 
     gradient.frame = self.bounds 
     gradient.locations = [0.0, 1.0] 
     gradient.colors = cgColors 
     self.layer.insertSublayer(gradient, at: 0) 
    } 
} 

Ensuite, mon gradient centré sur le code de mon UIView:

@IBDesignable class MyCustomView: UIView { 

    var view = UIView() 

    // MARK: - IBOutlets 
    @IBOutlet weak var label: UILabel! 
    @IBOutlet weak var textView: UITextView! 

    fileprivate var gradientColors: [UIColor] = [] 

    @IBInspectable var gradientColor0: UIColor = UIColor.flatWhite { 
     didSet { 
      gradientColors.remove(at: 0) 
      gradientColors.insert(gradientColor0, at: 0) 
     } 
    } 

    @IBInspectable var gradientColor1: UIColor = UIColor.flatWhiteDark { 
     didSet { 
      gradientColors.remove(at: 1) 
      gradientColors.insert(gradientColor1, at: 1) 
     } 
    } 

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

    required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
     xibSetup() 
     setup() 
    } 

    override func prepareForInterfaceBuilder() { 
     super.prepareForInterfaceBuilder() 
     setup() 
    } 

    func setup() { 
     textView.scrollRangeToVisible(NSMakeRange(0, 0)) 
     [gradientColor0, gradientColor1].forEach({gradientColors.append($0)}) 
     view.gradientFrom(gradientColors) 
     label.textColor = labelFontColor 
     label.backgroundColor = UIColor.clear 
     textView.backgroundColor = UIColor.clear 
     textView.textColor = textViewFontColor 
    } 

    // MARK: - Nib handlers 

    fileprivate func xibSetup() { 
     view = loadViewFromNib() 
     view.frame = bounds 
     view.autoresizingMask = [.flexibleWidth, .flexibleHeight] 
     addSubview(view) 
    } 

    fileprivate func loadViewFromNib() -> UIView { 
     let bundle = Bundle(for: type(of: self)) 
     let nib = UINib(nibName: "AttributionView", bundle: bundle) 
     let view = nib.instantiate(withOwner: self, options: nil).first as! UIView 
     return view 
    } 

    public func applyBackgroundGradient() {   
     view.gradientFrom(gradientColors) 
    } 

    func resizeView() { 
     textView.sizeToFit() 
     textView.scrollRangeToVisible(NSMakeRange(0, 0)) 
    } 
} 

Sur MyViewController, j'ajouter un UIView, définissez sa sous-classe à MyCustomView . Interface Builder remplit, mais quand je vais l'exécuter sur un périphérique physique, le dégradé dans MyCustomView ne remplit pas l'écran entier.

J'ai essayé de courir applyBackgroundGradient de l » viewDidLoadMyViewController, viewDidLayoutSubviews, viewDidAppear, aucun de ceux qui semblent faire le travail.

Toutes les suggestions pour résoudre ce problème sont grandement appréciées. Merci pour la lecture.

+0

Avez-vous défini des contraintes sur MyCustomView afin qu'il remplisse tout l'écran? – vacawama

+0

Oui. J'ai obtenu les résultats souhaités dans Simulator. Je rencontre ce problème sur un périphérique physique. – Adrian

+0

Vous obtenez les résultats souhaités sur le simulateur pour toutes les tailles d'appareils? – vacawama

Répondre

1

essayer de remplacer

gradient.frame = self.bounds 

avec

gradient.frame.size = self.frame.size 
gradient.frame.origin = CGPoint(x: 0.0, y: 0.0) 

et vous devriez certainement l'appeler comme

var didLayoutSubviews = false 

override func viewDidLayoutSubviews() { 
    super.viewDidLayoutSubviews() 
    if !self.didLayoutSubviews { 
     self.didLayoutSubviews = true 
     //apply gradient 
     //you can also try to execute drawing inside `DispatchQueue.main.async {}` 
    } 
} 

Addendum de OP:

Une partie de mon problème provient de mes appels didSet sur les couleurs du dégradé. Au lieu de déraper en configurant le tableau dans didSet, j'ai déplacé le code pour remplir le tableau gradientColors jusqu'à la méthode applyBackgroundGradient.

@IBInspectable var gradientColor0: UIColor = UIColor.flatWhite { 
    didSet { 
     applyBackgroundGradient() 
    } 
} 

@IBInspectable var gradientColor1: UIColor = UIColor.flatWhiteDark { 
    didSet { 
     applyBackgroundGradient() 
    } 
} 

... et le code de dégradé sur MyCustomView ressemble à ceci:

public func applyBackgroundGradient() { 
    gradientColors = [gradientColor0, gradientColor1] 
    self.view.gradientFrom(gradientColors) 
} 
+0

Merci! Une partie de mon problème était le cadre. L'autre partie était la façon dont j'appliquais le dégradé. Je faisais trop de travail dans les didSets des couleurs dégradées. Au lieu de cela, j'ai déplacé le code de population de tableau vers 'applyBackgroundGradient()'. Je vais ajouter au bas de votre réponse. – Adrian

+1

@Adrian, 'gradientColors = [gradientColor0, gradientColor1]' devrait suffire. – vacawama

+0

Ajout du dégradé dans viewDidLayoutSubviews était le correctif pour moi! Merci! – Phil