Come centrare una sottoview di UIView


128

Ho un UIViewinterno a UIViewme voglio che l'interno UIViewsia sempre centrato all'interno di quello esterno, senza che sia necessario ridimensionare la larghezza e l'altezza.

Ho impostato i montanti e le molle in modo che sia in alto / a sinistra / a destra / in basso senza impostare il ridimensionamento. Ma non centra ancora. Qualche idea?


2
La risposta accettata è sbagliata e andrà in crash. La risposta di Hejazi funziona alla grande.
Fattie,

Risposte:


209

Objective-C

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

veloce

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

51
È necessario utilizzare il boundse non il frame, poiché framenon è definito se la vista ha a transform.
omz,

1
In realtà non farà nulla di diverso in questo caso, poiché sizeviene utilizzato solo.
Peter DeWeese,

1
Non importa, l'intera frameproprietà non è definita se la vista ha una transformtrasformazione non identitaria; leggi la documentazione sulla proprietà frame di UIView .
omz,

6
Purtroppo questa risposta è in realtà sbagliata . Usa semplicemente la risposta corretta di Heja.
Fattie,

@Fattie cosa c'è che non va qui? L'ho usato per centrare un ImageView all'interno di una vista e funziona.
jreft56,

284

Puoi farlo e funzionerà sempre:

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

E per Swift:

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

1
e non dimenticare in seguito, child.frame = CGRectIntegral (child.frame);
Fattie,

8
Uno: funziona solo se non hai modificato il centro / la posizione della vista principale. Secondo: se stai usando questo metodo non c'è bisogno di convertire il punto (è già nel formato corretto) basta usare child.center = parent.center. Vorrei usare `child.center = CGPointMake (parent.bounds.height / 2, parent.bounds.width / 2) '. In questo modo la tua subview sarà centrata indipendentemente da ciò su cui è impostato il tuo centro di visualizzazione principale.
Vecchio nome

1
Non è inoltre utile se la vista non è stata ancora aggiunta alla gerarchia della vista (come quando si entra nell'oggetto)
Victor Jalencas

1
@Hejazi Sarebbe bello aggiungere anche una risposta rapida;)
Milad Faridnia

1
@Soumen No, c'è una differenza. UIView.boundsè relativo alla vista stessa (e quindi bounds.origininizialmente è zero), mentre UIView.centerè specificato nel sistema di coordinate della superview .
Hejazi,

41

Prima di iniziare, ricordiamo solo che il punto di origine è l'angolo in alto a sinistra CGPointdi una vista. Una cosa importante da capire su punti di vista e genitori.

Diamo un'occhiata a questo semplice codice, un controller di visualizzazione che aggiunge alla sua visualizzazione un quadrato nero:

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()
    }

}

Questo creerà questa vista: l'origine e il centro del rettangolo nero si adattano alle stesse coordinate del genitore

inserisci qui la descrizione dell'immagine

Ora proviamo ad aggiungere subView un altro SubSubView e dando a subSubview la stessa origine di subView, ma facciamo di subSubView una vista figlio di subView

Aggiungeremo questo codice:

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

E questo è il risultato:

inserisci qui la descrizione dell'immagine

A causa di questa linea:

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

Ti aspetti che l'origine del rettangolo viola sia la stessa del suo genitore (il rettangolo nero) ma ci passa sotto e perché? Perché quando aggiungi una vista a un'altra vista, il frame "world" di subView ora è il RECTANGLE RILEVATO padre, se hai una vista che la sua origine nella schermata principale è a coords (15,15) per tutte le sue viste secondarie, il l'angolo in alto a sinistra sarà (0,0)

Questo è il motivo per cui devi sempre fare riferimento a un genitore per il suo rettangolo rilegato, che è il "mondo" delle sue viste secondarie, consente di correggere questa riga su:

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

E vedi la magia, il subSubview ora si trova esattamente nella sua origine padre:

inserisci qui la descrizione dell'immagine

Quindi, ti piace "ok, volevo solo centrare la mia visione con quella dei miei genitori, qual è il grosso problema?" beh, non è un grosso problema, devi solo "tradurre" il punto centrale del genitore che viene preso dalla sua cornice al centro dei limiti del genitore facendo questo:

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

In realtà gli stai dicendo "prendi il centro di visualizzazione dei genitori e convertilo nel mondo subSubView".

E otterrai questo risultato:

inserisci qui la descrizione dell'immagine


Dove si trova la riga "subSubView.center = subView.convertPoint (subView.center, fromView: subSubView)"?
Thamarai,

26

Io userei:

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

Mi piace usare le CGRectopzioni ...

SWIFT 3:

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

19

1. Se hai attivato il layout automatico:

  • Suggerimento: per centrare una vista su un'altra vista con autolayout è possibile utilizzare lo stesso codice per due viste qualsiasi che condividano almeno una vista padre.

Innanzitutto disabilita il ridimensionamento automatico delle viste figlio

UIView *view1, *view2;
[childview setTranslatesAutoresizingMaskIntoConstraints:NO];
  1. Se sei UIView + Autolayout o Purelayout :

    [view1 autoAlignAxis:ALAxisHorizontal toSameAxisOfView:view2];
    [view1 autoAlignAxis:ALAxisVertical toSameAxisOfView:view2];
  2. Se si utilizzano solo metodi di autolayout a livello di 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. Senza autolayout:

Preferisco:

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
Va notato che, a differenza della risposta accettata, questa soluzione si allineerà perfettamente sui confini dei pixel e impedirà la sfocatura della vista per determinate larghezze.
Brad Larson

1
Se non sbaglio, child.frame = CGRectIntegral (child.frame); è una sorta di soluzione catch-all / use ovunque elegante al problema descritto da BL.
Fattie,

1
@JoeBlow: grazie per l'heads up. Mi piaceva arrotondare ma con lo stile a blocchi è più elegante da usareCGRectIntegral
Cemal Eker

Potresti spiegare la sintassi che usi per impostare il frame, non l'ho mai visto prima. È sempre l'ultima istruzione nella "chiusura" che viene assegnata alla proprietà? E dove posso trovarlo nei documenti Apple?
Johannes,

"Se si utilizzano solo metodi di autolayout a livello di UIKit:" si verificano errori.
Jonny,

13

La via più facile:

child.center = parent.center

Quello che voglio dire è che dovresti aggiungere ulteriori spiegazioni / descrizioni di come funziona.
Tushar,

Ho cercato molte risposte di questo tipo, questa semplice ha fatto il trucco per me. Grazie.
gbossa,

9

inserisci qui la descrizione dell'immagine

Imposta questa maschera di ridimensionamento automatico sulla tua vista interiore.


1
Con il layout automatico, non esiste una finestra di ridimensionamento automatico.
Allen

@Tutti devi disabilitare il autolayout se vuoi usare il ridimensionamento automatico.
Mayank Jain,

8

Con IOS9 è possibile utilizzare l'API di ancoraggio del layout.

Il codice sarebbe simile al seguente:

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

Il vantaggio di questo più CGPointMakeo CGRectè che con questi metodi si sta impostando il centro della vista a una costante, ma con questa tecnica si sta impostando una relazione tra i due punti di vista che conterrà per sempre, non importa quanto il parentviewcambiamento.

Basta essere sicuri prima di fare questo per fare:

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

e per impostare il translatesAutoresizingMaskIntoConstraintsper ogni vista su falso.

Ciò eviterà l'arresto anomalo e l'interruzione automatica di interferenze.


8

Puoi usare

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

E in Swift 3.0

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

1
Il secondo esempio di codice funziona perfettamente in rapido 4. GRANDE 👍🏻!
iGhost

SÌ! Grazie, finalmente. Non sapevo di quella cosa midX / midY. Perfecto.
Dave Y

5

Usare lo stesso centro nella vista e nella sottoview è il modo più semplice per farlo. Puoi fare qualcosa del genere,

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

Questo centrerà la vista secondaria rispetto alla vista super vista. Nel caso precedente, funziona perché l'origine è su (0, 0).
Abdurrahman Mubeen Ali,

3

Un'altra soluzione con PureLayout utilizzando autoCenterInSuperview.

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

[outerview addSubview:innerView];

[innerView autoCenterInSuperview];

Ecco come appare:

Centro con PureLayout


2

In c # o Xamarin.ios, possiamo usare così

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


1

Io userei:

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

Questo è semplice, breve e dolce. Se usi la risposta di @ Hejazi sopra e sei parent.centerimpostato su qualcosa di diverso dalla (0,0)tua subview non sarà centrato!


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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.