[SWIFT] Extension UITextField, problème de z-index ?

InsouInsou Membre
mai 2018 modifié dans API UIKit #1

Bonjour tout le monde,

Je galère avec un truc qui a l'air tout bête mais je ne m'en sort pas..
Je m'explique, j'essaie de créer une extension à UITextField pour pouvoir placer une image (à droite ou à gauche) du champs, histoire de faire plus beau

Voila mon code :

extension UITextField {

enum Direction {
    case Left
    case Right
}

// met une image dans un textfield
func withImage(direction: Direction, image: UIImage, colorSeparator: UIColor, colorBorder: UIColor){

    let imageView = UIImageView(image: image)
    imageView.contentMode = .scaleAspectFit
    imageView.frame = CGRect(x: 12.0, y: 10.0, width: 24.0, height: 24.0)
    imageView.layer.zPosition = 1000
    let view = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 45))
    view.layer.cornerRadius = 5
    view.layer.borderWidth = 0.5
    view.layer.borderColor = colorBorder.cgColor // ici : noir
    view.backgroundColor = .white
    view.layer.zPosition = 0

    if(Direction.Left == direction){ // image left
        let seperatorView = UIView(frame: CGRect(x: 45, y: 0, width: 5, height: 50))
        seperatorView.backgroundColor = colorSeparator
        view.addSubview(seperatorView)
        self.leftViewMode = .always
        view.addSubview(imageView)
        self.leftViewMode = UITextFieldViewMode.always
        self.leftView = view
    }
    else{ // image right
        let seperatorView = UIView(frame: CGRect(x: 0, y: 0, width: 5, height: 50))
        seperatorView.backgroundColor = colorSeparator
        view.addSubview(seperatorView)
        self.rightViewMode = .always
        view.addSubview(imageView)
        self.rightViewMode = UITextFieldViewMode.always
        self.rightView = view
    }

    self.layer.borderColor = colorBorder.cgColor // ne fonctionne pas :/

}

}

et voila le résultat :

J'ai mis en noir le contour de ma "view" pour bien qu'on voit qu'il passe par dessus le séparateur (orange).

J'ai bien essayé de mettre des z-index (zPosition) mais ça ne change pas le soucis, le orange reste toujours en dessous alors que j'aimerai qu'il soit au dessus..

Une idée de comment faire ? :)

Mots clés:
«1

Réponses

  • Tu mets ton séparateurView à l'intérieur de ta view et le contenu ne pourra pas être au dessus du "border color" du contenant.

  • InsouInsou Membre

    Euhmmm.. j'dois avoir le cerveau qui fume parce que j'ai pas compris ce que tu voulais dire :/

    Pour moi j'ai une vue (view) et je lui ai rajouté 2 vues dedans (imageView & seperatorView).
    Et cette première vue (view), je l'a met à droite ou à gauche du textfield.

    Du coup, mon seperatorView est déjà dans la vue (view) nan ?

    T'as un bout de code pour que je test ce que tu veux dire de mon côté ? ^^

  • Toi tu veux que ton rectangle orange soit au-dessus du bord noir ?

  • InsouInsou Membre

    Yes, c'est ça :)

  • JérémyJérémy Membre
    mai 2018 modifié #6

    En l'état ça ne pourra pas fonctionner car ton seperatorView est à l'intérieur de la vue qui a le bord noir. Il faudrait que tu fasses une stack comme ça :

    -- LeftView
    -- View -> (pas de border)
    ---- SeparatorView
    ---- ImageView -> (borderColor, borderWidth et corner radius)
    -------- UIImage

    En gros dans ton code :

    imageView.layer.cornerRadius = 5
    imageView.layer.borderWidth = 0.5
    imageView.layer.borderColor = colorBorder.cgColor

    et tu dégages les lignes :

    view.layer.cornerRadius = 5
    view.layer.borderWidth = 0.5
    view.layer.borderColor = colorBorder.cgColor

  • InsouInsou Membre

    @Jérémy a dit :
    En l'état ça ne pourra pas fonctionner car ton seperatorView est à l'intérieur de la vue qui a le bord noir. Il faudrait que tu fasses une stack comme ça :

    -- LeftView
    -- View -> (pas de border)
    ---- SeparatorView
    ---- ImageView -> (borderColor, borderWidth et corner radius)
    -------- UIImage

    En faite c'est ça que j'arrive pas à faire via le code :/

  • Tu copies colles le code que je t'ai filé, ça devrait pas être très loin du résultat que tu cherches. :smile:

  • func withImage(direction: Direction, image: UIImage, colorSeparator: UIColor, colorBorder: UIColor){
    
        let imageView = UIImageView(image: image)
        imageView.contentMode = .scaleAspectFit
        imageView.frame = CGRect(x: 12.0, y: 10.0, width: 24.0, height: 24.0)
        imageView.layer.cornerRadius = 5
        imageView.layer.borderWidth = 0.5
        imageView.layer.borderColor = colorBorder.cgColor
    
        let view = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 45))
        view.backgroundColor = .white
        if(Direction.Left == direction){
            self.leftViewMode = .always
            view.addSubview(imageView)
            let seperatorView = UIView(frame: CGRect(x: 45, y: 0, width: 5, height: 50))
            seperatorView.backgroundColor = colorSeparator
            view.addSubview(seperatorView)
            self.leftView = view
        } else { // image right
            self.rightViewMode = .always
            seperatorView.backgroundColor = colorSeparator
            view.addSubview(imageView)
            let seperatorView = UIView(frame: CGRect(x: 0, y: 0, width: 5, height: 50))
            view.addSubview(seperatorView)
           self.rightView = view
       }
    self.layer.borderColor = colorBorder.cgColor // ne fonctionne pas :/
    }
    

    Le code n'est pas du tout optimisé (on peut faire bien plus court) mais tu devrais avoir quelque chose qui correspond à ce que tu cherches. J'ai codé directement sur le forum, je n'ai pas testé ce que je te donne.

    Peace

  • PyrohPyroh Membre

    Et on arrêterai pas d'utiliser des views pour utiliser des layers à place ?

  • @Pyroh a dit :
    Et on arrêterai pas d'utiliser des views pour utiliser des layers à place ?

    Si si si, d'où ma phrase => "Le code n'est pas du tout optimisé".

  • InsouInsou Membre
    mai 2018 modifié #12

    Jérémy >> Ah bah c'est bien ce que j'avais fait alors..
    Je pensais avoir mal compris un truc mais on a sensiblement le même code et voila le résultat :

    Le trait fait le tour de l'image maintenant :(

    Pyroh >> Si t'as une solution plus propre, c'est pas de refus :p

  • JérémyJérémy Membre
    mai 2018 modifié #13

    Ah mince ! J'avais pas vu que ton image était plus petite... :neutral:

    Je t'ai apporté un correctif qui se base encore sur les UIView afin de voir si ça s'approche de ce que tu cherches. Si c'est okay, on passera par des Layers. :smile:

    N'ayant pas de Xcode sous la main, je ne sais pas si le code compile... :D

    func withImage(direction: Direction, image: UIImage, colorSeparator: UIColor, colorBorder: UIColor){
        let mainView = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 45))
        mainView.backgroundColor = .white
    
        let view = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 45))
        view.layer.cornerRadius = 5
        view.layer.borderWidth = 0.5
        view.layer.borderColor = colorBorder.cgColor
        mainView.addSubView(view)
    
        let imageView = UIImageView(image: image)
        imageView.contentMode = .scaleAspectFit
        imageView.frame = CGRect(x: 12.0, y: 10.0, width: 24.0, height: 24.0)
        main.addSubView(imageView)
    
        let seperatorView = UIView()
        seperatorView.backgroundColor = colorSeparator
        mainView.addSubview(seperatorView)
    
        if(Direction.Left == direction){
            seperatorView.frame = CGRect(x: 45, y: 0, width: 5, height: 50)
            self.leftViewMode = .always
            self.rightView = mainView
        } else {
            seperatorView.frame = CGRect(x: 0, y: 0, width: 5, height: 50)
            self.rightViewMode = .always
            self.rightView = mainView
       }
    }
    
  • InsouInsou Membre

    J'ai corrigé pour que ça compile mais maintenant il n'y a plus rien, juste l'UITextField :(

    Les corrections étaient simples (ouf lol) :
    addSubView = addSubview
    main.addSubView(imageView) = mainView.addSubview(imageView)

  • Je vais faire des tests en entrant chez moi. Coder sur le forum c’est pas simple. Je te tiens au jus. :)

  • Tu peux me filer le code de l’extension que tu as créé ?

  • InsouInsou Membre

    Ca marche ^^
    Merci de prendre le temps de regarder en tout cas :)

    extension UITextField {
    
    enum Direction {
        case Left
        case Right
    }
    
    func withImage(direction: Direction, image: UIImage, colorSeparator: UIColor, colorBorder: UIColor){
        let mainView = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 45))
        mainView.backgroundColor = .white
    
        let view = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 45))
        view.layer.cornerRadius = 5
        view.layer.borderWidth = 0.5
        view.layer.borderColor = colorBorder.cgColor
        mainView.addSubview(view)
    
        let imageView = UIImageView(image: image)
        imageView.contentMode = .scaleAspectFit
        imageView.frame = CGRect(x: 12.0, y: 10.0, width: 24.0, height: 24.0)
        mainView.addSubview(imageView)
    
        let seperatorView = UIView()
        seperatorView.backgroundColor = colorSeparator
        mainView.addSubview(seperatorView)
    
        if(Direction.Left == direction){
            seperatorView.frame = CGRect(x: 45, y: 0, width: 5, height: 50)
            self.leftViewMode = .always
            self.rightView = mainView
        } else {
            seperatorView.frame = CGRect(x: 0, y: 0, width: 5, height: 50)
            self.rightViewMode = .always
            self.rightView = mainView
        }
    }
    
    }
    
  • De rien :)

  • JérémyJérémy Membre
    mai 2018 modifié #19

    J'ai apporté les correctifs nécessaires, tu devrais obtenir quelque chose qui s'apparente à ce que tu recherches. Je ne te cache pas, comme l'a dit @Pyroh, qu'il serait plus léger de passer par des layers, du moins pour le cadre noir et la barre de séparation. Je te laisse prendre le soin de tester le code ci-dessous. ;)

    func withImage(direction: Direction, image: UIImage, colorSeparator: UIColor, colorBorder: UIColor){
        let mainView = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 45))
        mainView.layer.cornerRadius = 5
    
        let view = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 45))
        view.backgroundColor = .white
        view.clipsToBounds = true
        view.layer.cornerRadius = 5
        view.layer.borderWidth = 0.5
        view.layer.borderColor = colorBorder.cgColor
        mainView.addSubview(view)
    
        let imageView = UIImageView(image: image)
        imageView.contentMode = .scaleAspectFit
        imageView.frame = CGRect(x: 12.0, y: 10.0, width: 24.0, height: 24.0)
        view.addSubview(imageView)
    
        let seperatorView = UIView()
        seperatorView.backgroundColor = colorSeparator
        mainView.addSubview(seperatorView)
    
        if(Direction.Left == direction){
            seperatorView.frame = CGRect(x: 45, y: 0, width: 5, height: 45)
            self.leftViewMode = .always
            self.leftView = mainView
        } else {
            seperatorView.frame = CGRect(x: 0, y: 0, width: 5, height: 45)
            self.rightViewMode = .always
            self.rightView = mainView
        }
    }
    
  • InsouInsou Membre
    mai 2018 modifié #20

    Je viens de tester et ça fonctionne parfaitement, merci ^^

    Et le code et compréhensible, il fallait rajouter une vue principale (mainView) qui contient une vue (view) qui elle même contient l'image (imageView) et le séparateur va dans la vue principale (mainView) .. nickel ^^

    Histoire d'être pointilleux et de rendre ça cohérent.. Comment je peux faire pour que la couleur du cadre noir (colorBorder), s'applique aussi au TextField ?
    J'ai essayé un truc comme :

    self.layer.borderColor = colorBorder
    

    Mais sans grand succès.. je dois louper un truc..

  • C'est bien cette propriété qu'il faut utiliser pour appliquer une couleur sur le contour du TextField. Mais tu n'as pas du setter une largeur au "border" (self.layer.borderWidth = CGFloat(0.5)). Mais attention, ton séparateur ne sera pas au dessus (tu auras forcément un trait noir en bas et en haut de la vue seperatorView).

  • PyrohPyroh Membre

    Je suis en train de te faire une petite playground (Xcode 9.4b vu que Xcode 9.3 casse les PG) qui explique tout.
    Stay tuned.

  • JérémyJérémy Membre
    mai 2018 modifié #23

    @Pyroh a dit :
    Je suis en train de te faire une petite playground

    Je ne sais pas si ça vient du fait que ma machine est trop vieille mais de mon côté ça ne fonctionne pas du tout.

  • InsouInsou Membre
    mai 2018 modifié #24

    @Jérémy a dit :
    C'est bien cette propriété qu'il faut utiliser pour appliquer une couleur sur le contour du TextField. Mais tu n'as pas du setter une largeur au "border" (self.layer.borderWidth = CGFloat(0.5)). Mais attention, ton séparateur ne sera pas au dessus (tu auras forcément un trait noir en bas et en haut de la vue seperatorView).

    Ah bah oui, j'avais bien loupé un truc.. vu que la bordure était visible, je pensais qu'elle avait déjà une largeur.. en faite nan.. c'était une illusion d'optique lol
    Bon c'est résolu, c'est pas grave si ça passe pas au dessus du séparateur.. ça rend très bien comme ça ^^

    Merci encore ^^

    @Pyroh Ok, on stay tuned :p
    (il faut obligatoirement Xcode 9.4b pour tester ce que tu nous prépare ?)

  • JérémyJérémy Membre
    mai 2018 modifié #25

    @Insou a dit :
    Merci encore ^^

    Il n'y a pas de quoi ! :)

    @Insou a dit :
    @Pyroh Ok, on stay tuned :p
    (il faut obligatoirement Xcode 9.4b pour tester ce que tu nous prépare ?)

    Non non non, tu pourras tester. Mais je te conseille de passer par les layers. Si @Pyroh ne te file pas la solution, je t'en donnerai une ce weekend. :)

  • InsouInsou Membre

    ça change quoi concrètement de passer par des layers ?
    Qu'est ce que tu entendais quand tu disais que c'est plus "léger" de passer par des layers ?
    Plus léger = moins de code ?

  • JérémyJérémy Membre
    mai 2018 modifié #27

    En gros le rectangle noir et la ligne de séparation n'ont pas d’intérêt d'être sous forme de view. Chaque vue encapsule un layer et tu n'utilises que ce dernier. Moralité, tu te retrouves à employer des classes (plus lourde d'un point de vue mémoire vive) avec tout t'un tas de propriétés que tu n'utilises pas. D'un point de vue graphique ça ne change rien, c'est juste pas très optimisé.

  • InsouInsou Membre

    Ok je vois, rendu visuel c'est pareil mais niveau consommation c'est moins gourmand.. alors autant utilisé des layers si on peut ^^

  • Oui enfin bon il faut tout de même relativiser. Il est vrai que tu vas y gagner mais ça ne sera pas non plus le jour et la nuit. Peut être en vitesse de chargement, et encore, ça se chiffrera en micro secondes.

  • PyrohPyroh Membre

    Emprunte mémoire surtout. C'est pas énorme sur un contrôle de ce type mais sur une application complète ça commence à faire. Puis y'a pas de mal à faire les choses proprement 😉

    Quand ma journée de travail est terminée j'en profite pour finir la playground (mais elle termine tard...)

  • JérémyJérémy Membre
    mai 2018 modifié #31

    @Pyroh a dit :
    Emprunte mémoire surtout. C'est pas énorme sur un contrôle de ce type mais sur une application complète ça commence à faire.

    +1 B)

    @Pyroh a dit :
    Puis y'a pas de mal à faire les choses proprement 😉

    +1000 B)

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