Comment centrer une sous-vue d'UIView


128

J'ai UIViewun UIViewm intérieur et je veux que l'intérieur UIViewsoit toujours centré à l'intérieur de l'extérieur, sans qu'il soit nécessaire de redimensionner la largeur et la hauteur.

J'ai défini les entretoises et les ressorts de manière à ce qu'ils soient en haut / gauche / droite / bas sans définir le redimensionnement. Mais cela ne se concentre toujours pas. Une idée?


2
La réponse acceptée est fausse et plantera. La réponse de Hejazi fonctionne très bien.
Fattie

Réponses:


209

Objectif c

yourSubView.center = CGPointMake(yourView.frame.size.width  / 2, 
                                 yourView.frame.size.height / 2);

Rapide

yourSubView.center = CGPoint(x: yourView.frame.size.width  / 2,
                             y: yourView.frame.size.height / 2)

51
Vous devez utiliser le boundset non le frame, car le framen'est pas défini si la vue a un transform.
omz

1
En fait, cela ne changera rien dans ce cas, car seul sizeest utilisé.
Peter DeWeese

1
Cela n'a pas d'importance, la framepropriété entière n'est pas définie si la vue a une transformqui n'est pas la transformation d'identité; lisez la documentation sur la propriété frame de UIView .
omz

6
Malheureusement, cette réponse est en fait fausse . Utilisez simplement la bonne réponse de Heja.
Fattie

@Fattie qu'est-ce qui ne va pas ici? Je l'ai utilisé pour centrer une ImageView dans une vue et cela fonctionne.
jreft56 du

284

Vous pouvez le faire et cela fonctionnera toujours:

child.center = [parent convertPoint:parent.center fromView:parent.superview];

Et pour Swift:

child.center = parent.convert(parent.center, from:parent.superview)

1
et n'oubliez pas après, child.frame = CGRectIntegral (child.frame);
Fattie

8
Un: cela ne fonctionne que si vous n'avez pas changé le centre / l'emplacement de votre vue parent. Deuxièmement: si vous utilisez cette méthode, il n'est pas nécessaire de convertir le point (il est déjà dans le format correct), utilisez simplement child.center = parent.center. J'utiliserais `child.center = CGPointMake (parent.bounds.height / 2, parent.bounds.width / 2) '. Votre sous-vue sera toujours centrée, quel que soit le réglage de votre centre de vue parent.
Ancien nom

1
Ce n'est pas non plus utile si la vue n'a pas encore été ajoutée à la hiérarchie des vues (comme lors de la saisie de l'objet)
Victor Jalencas

1
@Hejazi Ce serait bien d'ajouter une réponse rapide aussi;)
Milad Faridnia

1
@Soumen Non, il y a une différence. UIView.boundsest relatif à la vue elle-même (et bounds.originest donc initialement zéro), tandis que UIView.centerest spécifié dans le système de coordonnées de la vue de supervision .
Hejazi

41

Avant de commencer, rappelons simplement que le point d'origine est le coin supérieur gauche CGPointd'une vue. Une chose importante à comprendre sur les opinions et les parents.

Jetons un œil à ce code simple, un contrôleur de vue qui ajoute à sa vue un carré noir:

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        createDummyView()
        super.view.backgroundColor = UIColor.cyanColor();
    }

    func createDummyView(){
        var subView = UIView(frame: CGRect(x: 15, y: 50, width: 50 , height: 50));
        super.view.addSubview(subView);
        view.backgroundColor = UIColor.blackColor()
    }

}

Cela créera cette vue: l'origine et le centre du rectangle noir correspondent aux mêmes coordonnées que son parent

entrez la description de l'image ici

Essayons maintenant d'ajouter une sous-vue à une autre sous-vue, et en donnant à la sous-vue la même origine que la sous-vue, mais en faisant de la sous-vue une vue enfant de la sous-vue

Nous ajouterons ce code:

var subSubView = UIView();
subSubView.frame.origin = subView.frame.origin;
subSubView.frame.size = CGSizeMake(20, 20);
subSubView.backgroundColor = UIColor.purpleColor()
subView.addSubview(subSubView)

Et voici le résultat:

entrez la description de l'image ici

En raison de cette ligne:

subSubView.frame.origin = subView.frame.origin;

Vous vous attendez à ce que l'origine du rectangle violet soit la même que son parent (le rectangle noir), mais il passe en dessous, et pourquoi? Parce que lorsque vous ajoutez une vue à une autre vue, le cadre de sous-vue "monde" est maintenant son parent BOUND RECTANGLE, si vous avez une vue dont l'origine sur l'écran principal est aux coordonnées (15,15) pour toutes ses sous-vues, le le coin supérieur gauche sera (0,0)

C'est pourquoi vous devez toujours faire référence à un parent par son rectangle lié, qui est le "monde" de ses sous-vues, fixons cette ligne à:

subSubView.frame.origin = subView.bounds.origin;

Et voyez la magie, la sous-vue est maintenant située exactement dans son origine parent:

entrez la description de l'image ici

Alors, vous aimez "ok, je voulais seulement centrer mon point de vue sur le point de vue de mes parents, quel est le problème?" eh bien, ce n'est pas grave, vous avez juste besoin de "traduire" le point central parent qui est pris de son cadre au centre des limites du parent en faisant ceci:

subSubView.center = subView.convertPoint(subView.center, fromView: subSubView);

Vous lui dites en fait "prenez le centre de vue des parents et convertissez-le en monde subSubView".

Et vous obtiendrez ce résultat:

entrez la description de l'image ici


Où la ligne «subSubView.center = subView.convertPoint (subView.center, fromView: subSubView)» doit-elle être placée?
Thamarai T

26

J'utiliserais:

self.childView.center = CGPointMake(CGRectGetMidX(self.parentView.bounds),
                                    CGRectGetMidY(self.parentView.bounds));

J'aime utiliser les CGRectoptions ...

SWIFT 3:

self.childView.center = CGPoint(x: self.parentView.bounds.midX,
                                        y: self.parentView.bounds.midY);

19

1. Si vous avez activé la mise en page automatique:

  • Conseil: pour centrer une vue sur une autre vue avec mise en page automatique, vous pouvez utiliser le même code pour deux vues partageant au moins une vue parent.

Tout d'abord désactiver la redimensionnement automatique des vues enfants

UIView *view1, *view2;
[childview setTranslatesAutoresizingMaskIntoConstraints:NO];
  1. Si vous êtes UIView + Autolayout ou Purelayout :

    [view1 autoAlignAxis:ALAxisHorizontal toSameAxisOfView:view2];
    [view1 autoAlignAxis:ALAxisVertical toSameAxisOfView:view2];
  2. Si vous n'utilisez que des méthodes de mise en page automatique de niveau UIKit:

    [view1 addConstraints:({
        @[ [NSLayoutConstraint
           constraintWithItem:view1
           attribute:NSLayoutAttributeCenterX
           relatedBy:NSLayoutRelationEqual
           toItem:view2
           attribute:NSLayoutAttributeCenterX
           multiplier:1.f constant:0.f],
    
           [NSLayoutConstraint
            constraintWithItem:view1
            attribute:NSLayoutAttributeCenterY
            relatedBy:NSLayoutRelationEqual
            toItem:view2
            attribute:NSLayoutAttributeCenterY
            multiplier:1.f constant:0.f] ];
    })];

2. Sans mise en page automatique:

Je préfère:

UIView *parentView, *childView;
[childView setFrame:({
    CGRect frame = childView.frame;

    frame.origin.x = (parentView.frame.size.width - frame.size.width) / 2.0;
    frame.origin.y = (parentView.frame.size.height - frame.size.height) / 2.0;

    CGRectIntegral(frame);
})];

6
Il convient de noter que, contrairement à la réponse acceptée, cette solution s'alignera proprement sur les limites des pixels et empêchera le flou de la vue pour certaines largeurs.
Brad Larson

1
Si je ne me trompe pas, child.frame = CGRectIntegral (child.frame); est une sorte élégante de solution fourre-tout / à utiliser n'importe où au problème décrit par BL.
Fattie

1
@JoeBlow: Merci pour la mise en garde. J'adorais arrondir mais avec le style bloc, c'est plus élégant à utiliserCGRectIntegral
Cemal Eker

Pourriez-vous expliquer la syntaxe que vous utilisez pour définir le cadre, je ne l'ai jamais vue auparavant. Est-ce toujours la dernière déclaration dans la «fermeture» qui est attribuée à la propriété? Et où puis-je le trouver dans la documentation Apple?
Johannes

"Si vous n'utilisez que des méthodes de mise en page automatique de niveau UIKit:" entraîne des erreurs.
Jonny

13

Le moyen le plus simple:

child.center = parent.center

Ce que je veux dire, c'est que vous devriez ajouter plus d'explications / description de la façon dont cela fonctionne.
Tushar

J'ai cherché beaucoup de réponses de ce type, cette simple a fait l'affaire pour moi. Merci.
gbossa le

9

entrez la description de l'image ici

Réglez ce masque de redimensionnement automatique sur votre vue intérieure.


1
Avec la mise en page automatique, il n'y a pas de fenêtre de dimensionnement automatique.
Allen

@Allen vous devez désactiver la mise en page automatique si vous souhaitez utiliser la redimensionnement automatique.
Mayank Jain

8

Avec IOS9, vous pouvez utiliser l'API d'ancrage de mise en page.

Le code ressemblerait à ceci:

childview.centerXAnchor.constraintEqualToAnchor(parentView.centerXAnchor).active = true
childview.centerYAnchor.constraintEqualToAnchor(parentView.centerYAnchor).active = true

L'avantage de ceci par rapport à CGPointMakeou CGRectest qu'avec ces méthodes, vous définissez le centre de la vue sur une constante, mais avec cette technique, vous définissez une relation entre les deux vues qui durera pour toujours, quelle que soit la façon dont les parentviewchangements.

Assurez-vous simplement avant de faire ceci:

        self.view.addSubview(parentView)
        self.view.addSubView(chidview)

et pour définir le translatesAutoresizingMaskIntoConstraintsfor each view sur false.

Cela empêchera les plantages et la mise en page automatique d'interférer.


8

Vous pouvez utiliser

yourView.center = CGPointMake(CGRectGetMidX(superview.bounds), CGRectGetMidY(superview.bounds))

Et dans Swift 3.0

yourView.center = CGPoint(x: superview.bounds.midX, y: superview.bounds.midY)

1
Le deuxième exemple de code fonctionne parfaitement dans swift 4. GREAT 👍🏻!
iGhost

OUI! Merci enfin. Je ne savais pas pour ce truc midX / midY. Perfecto.
Dave Y

5

Utiliser le même centre dans la vue et la sous-vue est le moyen le plus simple de le faire. Tu peux faire quelque chose comme ça,

UIView *innerView = ....;
innerView.view.center = self.view.center;
[self.view addSubView:innerView];

Cela centrera la vue secondaire par rapport à la super vue de vue. Dans le cas ci-dessus, cela fonctionne car l'origine est à (0, 0).
Abdurrahman Mubeen Ali

3

Une autre solution avec PureLayout utilisant autoCenterInSuperview.

// ...
UIView *innerView = [UIView newAutoLayoutView];
innerView.backgroundColor = [UIColor greenColor];
[innerView autoSetDimensionsToSize:CGSizeMake(100, 30)];

[outerview addSubview:innerView];

[innerView autoCenterInSuperview];

Voici à quoi ça ressemble:

Centre avec PureLayout


2

En c # ou Xamarin.ios, nous pouvons utiliser comme ceci

imageView.Center = nouveau CGPoint (tempView.Frame.Size.Width / 2, tempView.Frame.Size.Height / 2);


1

J'utiliserais:

child.center = CGPointMake(parent.bounds.height / 2, parent.bounds.width / 2)

C'est simple, court et doux. Si vous utilisez la réponse de @ Hejazi ci-dessus et parent.centerest réglé sur autre chose que (0,0)votre sous-vue ne sera pas centrée!


0
func callAlertView() {

    UIView.animate(withDuration: 0, animations: {
        let H = self.view.frame.height * 0.4
        let W = self.view.frame.width * 0.9
        let X = self.view.bounds.midX - (W/2)
        let Y = self.view.bounds.midY - (H/2)
        self.alertView.frame = CGRect(x:X, y: Y, width: W, height: H)
        self.alertView.layer.borderWidth = 1
        self.alertView.layer.borderColor = UIColor.red.cgColor
        self.alertView.layer.cornerRadius = 16
        self.alertView.layer.masksToBounds = true
        self.view.addSubview(self.alertView)

    })


}// calculation works adjust H and W according to your requirement
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.