Jak wyśrodkować widok częściowy UIView


128

Mam UIViewwewnętrzną UIViewm i chcę, aby wewnętrzna UIViewbyła zawsze wyśrodkowana wewnątrz zewnętrznej, bez konieczności zmiany rozmiaru i wysokości.

Ustawiłem rozpórki i sprężyny tak, aby znajdowały się na górze / po lewej / prawej / dolnej stronie bez zmiany rozmiaru. Ale nadal nie jest to centrum. Dowolny pomysł?


2
Zaakceptowana odpowiedź jest nieprawidłowa i ulegnie awarii. Odpowiedź Hejazi działa świetnie.
Fattie

Odpowiedzi:


214

Cel C

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

Szybki

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

51
Powinieneś używać, boundsa nie the frame, ponieważ framejest niezdefiniowane, jeśli widok ma transform.
omz

1
W tym przypadku właściwie nie będzie inaczej, ponieważ sizejest używany.
Peter DeWeese

1
To nie ma znaczenia, cała framewłaściwość jest niezdefiniowana, jeśli widok zawiera element, transformktóry nie jest transformacją tożsamości; przeczytaj dokumentację dotyczącą właściwości ramy UIView .
omz

6
Niestety ta odpowiedź jest w rzeczywistości błędna . Po prostu użyj poprawnej odpowiedzi Heji.
Fattie

@Fattie, co tu jest nie tak? Użyłem go do wyśrodkowania ImageView w widoku i działa.
jreft56

285

Możesz to zrobić i zawsze będzie działać:

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

A dla Swift:

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

1
i nie zapomnij później, child.frame = CGRectIntegral (child.frame);
Fattie

9
Po pierwsze: działa to tylko wtedy, gdy nie zmieniłeś środka / lokalizacji widoku rodzica. Po drugie: jeśli używasz tej metody, nie ma potrzeby konwertowania punktu (jest już w odpowiednim formacie), po prostu użyj child.center = parent.center. Użyłbym `child.center = CGPointMake (parent.bounds.height / 2, parent.bounds.width / 2) '. Spowoduje to zawsze wyśrodkowanie widoku podrzędnego, niezależnie od tego, na co jest ustawione centrum widoku nadrzędnego.
Stara nazwa

1
Nie jest to również przydatne, jeśli widok nie został jeszcze dodany do hierarchii widoków (na przykład podczas inicjowania obiektu)
Victor Jalencas,

1
@Hejazi Fajnie byłoby też dodać szybką odpowiedź;)
Milad Faridnia

1
@Soumen Nie, jest różnica. UIView.boundsodnosi się do samego widoku (i dlatego bounds.originpoczątkowo wynosi zero), podczas gdy UIView.centerjest określony w układzie współrzędnych superviewu .
Hejazi

41

Zanim zaczniemy, przypomnijmy tylko, że punkt początkowy to lewy górny róg CGPointwidoku. Ważna rzecz do zrozumienia o poglądach i rodzicach.

Przyjrzyjmy się temu prostemu kodowi, kontrolerowi widoku, który dodaje do widoku czarny kwadrat:

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

}

Stworzy to taki widok: początek i środek czarnego prostokąta pasują do tych samych współrzędnych, co jego rodzic

wprowadź opis obrazu tutaj

Teraz spróbujmy dodać subView inny SubSubView i nadając subSubview to samo źródło co subView, ale uczyń subSubView widokiem potomnym subView

Dodamy ten kod:

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

A oto wynik:

wprowadź opis obrazu tutaj

Z powodu tej linii:

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

Spodziewasz się, że pochodzenie fioletowego prostokąta będzie takie samo jak jego rodzic (czarny prostokąt), ale znajduje się pod nim, a dlaczego tak jest? Ponieważ kiedy dodajesz widok do innego widoku, „świat” ramki widoku podrzędnego jest teraz jego nadrzędnym PROSTOKĄTEM OGRANICZONYM. w lewym górnym rogu będzie (0,0)

Dlatego zawsze musisz odnosić się do rodzica przez powiązany prostokąt, który jest „światem” jego podwidoków, naprawmy tę linię tak, aby:

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

I zobacz magię, subSubview znajduje się teraz dokładnie w swoim nadrzędnym źródle:

wprowadź opis obrazu tutaj

Więc lubisz "ok, chciałem skupić się tylko na poglądach moich rodziców, o co chodzi?" cóż, to nic wielkiego, wystarczy "przetłumaczyć" nadrzędny punkt środkowy, który jest przenoszony z ramki do środka granic rodzica, wykonując następujące czynności:

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

Właściwie mówisz mu „weź centrum widoku rodziców i przekształć je w świat subSubView”.

Otrzymasz taki wynik:

wprowadź opis obrazu tutaj


Gdzie należy umieścić wiersz „subSubView.center = subView.convertPoint (subView.center, fromView: subSubView)”?
Thamarai T

26

Użyłbym:

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

Lubię korzystać z CGRectopcji ...

SWIFT 3:

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

19

1. Jeśli masz włączone automatyczne układanie:

  • Wskazówka: aby wyśrodkować widok na innym widoku z automatycznym układem, możesz użyć tego samego kodu dla dowolnych dwóch widoków, które współużytkują co najmniej jeden widok nadrzędny.

Przede wszystkim wyłącz autorezację widoków potomnych

UIView *view1, *view2;
[childview setTranslatesAutoresizingMaskIntoConstraints:NO];
  1. Jeśli jesteś UIView + Autolayout lub Purelayout :

    [view1 autoAlignAxis:ALAxisHorizontal toSameAxisOfView:view2];
    [view1 autoAlignAxis:ALAxisVertical toSameAxisOfView:view2];
    
  2. Jeśli używasz tylko metod autoukładu na poziomie 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. Bez automatycznego układu:

Wolę:

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
Należy zauważyć, że w przeciwieństwie do przyjętej odpowiedzi, rozwiązanie to wyrównuje się czysto na granicach pikseli i zapobiega rozmyciu widoku dla pewnych szerokości.
Brad Larson

1
Jeśli się nie mylę, child.frame = CGRectIntegral (child.frame); jest eleganckim rodzajem uniwersalnego rozwiązania problemu opisanego przez BL.
Fattie

1
@JoeBlow: Dzięki za ostrzeżenie. Lubiłem zaokrąglenia ale ze stylem bloku to bardziej elegancki w użyciuCGRectIntegral
Cemal Eker

Czy mógłbyś wyjaśnić składnię, której używasz do ustawiania ramki, nie widziałem tego wcześniej. Czy zawsze jest to ostatnie stwierdzenie w „zamknięciu” przypisane do nieruchomości? A gdzie mogę to znaleźć w dokumentach Apple?
Johannes

„Jeśli używasz tylko metod autoukładu na poziomie UIKit:” powoduje błędy.
Jonny,

13

Najłatwiejszy sposób:

child.center = parent.center

Chodzi mi o to, że powinieneś dodać więcej wyjaśnień / opisów, jak to działa.
Tushar

Przeszukałem wiele tego typu odpowiedzi, ta prosta załatwiła mi sprawę. Dzięki.
gbossa

9

wprowadź opis obrazu tutaj

Ustaw tę automatyczną maskę na swój widok wewnętrzny.


1
W przypadku autoukładu nie ma okna automatycznego zmieniania rozmiaru.
Allen

@Allen, musisz wyłączyć automatyczne układanie, jeśli chcesz użyć autoregulacji.
Mayank Jain

9

Możesz użyć

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

Oraz w Swift 3.0

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

1
Drugi przykład kodu działa doskonale w języku swift 4. GREAT 👍🏻!
iGhost

TAK! Dziękuję wreszcie. Nie wiedziałem o tej sprawie z midX / midY. Perfecto.
Dave Y

8

W systemie IOS9 można używać interfejsu API zakotwiczenia układu.

Kod wyglądałby tak:

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

Zaletą tego przejęcia CGPointMakelub CGRectktóre z tych metod ustawiania środek celu stałą, ale z tej techniki ustawiania relacji między dwoma widokami, które posiadają zawsze, nie ważne jak się parentviewzmienia.

Tylko upewnij się, zanim to zrobisz:

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

i ustawić translatesAutoresizingMaskIntoConstraintsdla każdego widoku fałsz.

Zapobiegnie to awariom i zakłóceniom funkcji AutoLayout.


5

Korzystanie z tego samego środka w widoku i podglądzie jest najprostszym sposobem na zrobienie tego. Możesz zrobić coś takiego,

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

Spowoduje to wyśrodkowanie widoku pomocniczego względem super widoku widoku. W powyższym przypadku działa, ponieważ początek znajduje się w (0, 0).
Abdurrahman Mubeen Ali

3

Kolejne rozwiązanie z PureLayout korzystającym z autoCenterInSuperview.

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

[outerview addSubview:innerView];

[innerView autoCenterInSuperview];

Tak to wygląda:

Wyśrodkuj z PureLayout


2

W C # lub Xamarin.ios możemy używać w ten sposób

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


1

Użyłbym:

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

To jest proste, krótkie i słodkie. Jeśli użyjesz odpowiedzi @ Hejazi powyżej i parent.centerustawisz cokolwiek innego niż (0,0)Twój podgląd podrzędny, nie zostanie wyśrodkowany!


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.