So zentrieren Sie eine Unteransicht von UIView

128

Ich habe ein UIViewInneres in einem UIViewm und ich möchte, dass das Innere UIViewimmer in dem Äußeren zentriert ist, ohne dass es die Breite und Höhe ändern muss.

Ich habe die Streben und Federn so eingestellt, dass sie oben / links / rechts / unten sind, ohne die Größe zu ändern. Aber es zentriert sich immer noch nicht. Irgendeine Idee?

xonegirlz
quelle
2
Die akzeptierte Antwort ist falsch und stürzt ab. Hejazis Antwort funktioniert großartig.
Fattie

Antworten:

209

Ziel c

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

Schnell

yourSubView.center = CGPoint(x: yourView.frame.size.width  / 2,
                             y: yourView.frame.size.height / 2)
glückliches Schwein
quelle
51
Sie sollten das boundsund nicht das verwenden frame, da das frameundefiniert ist, wenn die Ansicht eine hat transform.
Omz
1
In diesem Fall wird es tatsächlich keinen Unterschied machen, da nur sizeverwendet wird.
Peter DeWeese
1
Das spielt keine Rolle, die gesamte frameEigenschaft ist undefiniert, wenn die Ansicht eine hat transform, die nicht die Identitätstransformation ist. Lesen Sie die Dokumentation zur Frame-Eigenschaft von UIView .
Omz
6
Leider ist diese Antwort tatsächlich falsch . Verwenden Sie einfach Hejas richtige Antwort.
Fattie
@Fattie was genau ist hier falsch? Ich habe es zum Zentrieren einer ImageView in einer Ansicht verwendet und es funktioniert.
jreft56
284

Sie können dies tun und es wird immer funktionieren:

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

Und für Swift:

child.center = parent.convert(parent.center, from:parent.superview)
Hejazi
quelle
1
und vergiss danach nicht, child.frame = CGRectIntegral (child.frame);
Fattie
8
Erstens: Dies funktioniert nur, wenn Sie die Mitte / Position Ihrer übergeordneten Ansicht nicht geändert haben. Zweitens: Wenn Sie diese Methode dort verwenden ist keine Notwendigkeit , den Punkt zu konvertieren (es ist bereits im richtigen Format) nur verwenden child.center = parent.center. Ich würde "child.center = CGPointMake (parent.bounds.height / 2, parent.bounds.width / 2)" verwenden. Dadurch wird Ihre Unteransicht immer zentriert, unabhängig davon, auf was Ihr übergeordnetes Ansichtszentrum eingestellt ist.
Alter Name
1
Es ist auch nicht nützlich, wenn die Ansicht noch nicht zur Ansichtshierarchie hinzugefügt wurde (z. B. beim Einfügen des Objekts)
Victor Jalencas
1
@ Hejazi Es wäre schön, auch eine schnelle Antwort hinzuzufügen;)
Milad Faridnia
1
@Soumen Nein, da gibt es einen Unterschied. UIView.boundsist relativ zur Ansicht selbst (und daher bounds.originanfänglich Null), während UIView.centersie im Koordinatensystem der Übersicht angegeben ist .
Hejazi
41

Bevor wir beginnen, möchten wir Sie nur daran erinnern, dass der Ursprungspunkt die obere linke Ecke CGPointeiner Ansicht ist. Eine wichtige Sache, um über Ansichten und Eltern zu verstehen.

Schauen wir uns diesen einfachen Code an, einen Ansichts-Controller, der seiner Ansicht ein schwarzes Quadrat hinzufügt:

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

}

Dadurch wird diese Ansicht erstellt: Der Ursprung und die Mitte des schwarzen Rechtecks ​​passen zu denselben Koordinaten wie das übergeordnete Element

Geben Sie hier die Bildbeschreibung ein

Versuchen wir nun, subView eine weitere SubSubView hinzuzufügen und subSubview denselben Ursprung wie subView zuzuweisen, machen subSubView jedoch zu einer untergeordneten Ansicht von subView

Wir werden diesen Code hinzufügen:

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

Und das ist das Ergebnis:

Geben Sie hier die Bildbeschreibung ein

Wegen dieser Zeile:

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

Sie erwarten, dass der Ursprung des lila Rechtecks ​​mit dem des übergeordneten Rechtecks ​​(dem schwarzen Rechteck) identisch ist, aber er geht darunter, und warum ist das so? Wenn Sie einer anderen Ansicht eine Ansicht hinzufügen, ist der SubView-Frame "world" jetzt das übergeordnete BOUND RECTANGLE. Wenn Sie die Ansicht haben, dass der Ursprung auf dem Hauptbildschirm für alle Unteransichten in Koordinaten (15,15) liegt, ist der obere linke Ecke ist (0,0)

Aus diesem Grund müssen Sie immer auf ein übergeordnetes Element verweisen, indem es ein gebundenes Rechteck bildet, das die "Welt" seiner Unteransichten darstellt. Lassen Sie uns diese Zeile auf Folgendes korrigieren:

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

Und sehen Sie die Magie, die Unteransicht befindet sich jetzt genau in ihrem übergeordneten Ursprung:

Geben Sie hier die Bildbeschreibung ein

Du magst also "ok, ich wollte meine Sicht nur auf die Sicht meiner Eltern zentrieren, was ist die große Sache?" Nun, es ist keine große Sache, Sie müssen nur den übergeordneten Mittelpunkt "übersetzen", der von seinem Rahmen zum übergeordneten Grenzzentrum genommen wird, indem Sie Folgendes tun:

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

Sie sagen ihm tatsächlich: "Nehmen Sie das Eltern-Ansichtszentrum und konvertieren Sie es in die subSubView-Welt."

Und Sie erhalten dieses Ergebnis:

Geben Sie hier die Bildbeschreibung ein

Daniel Krom
quelle
Wo soll die Zeile 'subSubView.center = subView.convertPoint (subView.center, fromView: subSubView)' platziert werden?
Thamarai T
26

Ich würde ... benutzen:

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

Ich benutze gerne die CGRectOptionen ...

SWIFT 3:

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

1. Wenn Sie das automatische Layout aktiviert haben:

  • Tipp: Um eine Ansicht mit Autolayout auf eine andere Ansicht zu zentrieren, können Sie denselben Code für zwei beliebige Ansichten verwenden, die mindestens eine übergeordnete Ansicht gemeinsam nutzen.

Deaktivieren Sie zunächst die automatische Größenänderung von untergeordneten Ansichten

UIView *view1, *view2;
[childview setTranslatesAutoresizingMaskIntoConstraints:NO];
  1. Wenn Sie UIView + Autolayout oder Purelayout sind :

    [view1 autoAlignAxis:ALAxisHorizontal toSameAxisOfView:view2];
    [view1 autoAlignAxis:ALAxisVertical toSameAxisOfView:view2];
  2. Wenn Sie nur Autolayout-Methoden auf UIKit-Ebene verwenden:

    [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. Ohne Autolayout:

Ich bevorzuge:

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);
})];
Cemal Eker
quelle
6
Es ist zu beachten, dass diese Lösung im Gegensatz zur akzeptierten Antwort sauber an Pixelgrenzen ausgerichtet wird und bei bestimmten Breiten eine Unschärfe der Ansicht verhindert.
Brad Larson
1
Wenn ich mich nicht irre, child.frame = CGRectIntegral (child.frame); ist eine elegante Lösung für das von BL beschriebene Problem.
Fattie
1
@ JoeBlow: Danke für das Heads Up. Früher liebte ich das Runden, aber mit Blockstil ist es eleganter zu verwendenCGRectIntegral
Cemal Eker
Könnten Sie die Syntax erklären, mit der Sie den Frame festlegen? Ich habe sie noch nie gesehen. Ist es immer die letzte Anweisung in der "Schließung", die der Eigenschaft zugewiesen wird? Und wo finde ich es in den Apple-Dokumenten?
Johannes
"Wenn Sie nur Autolayout-Methoden auf UIKit-Ebene verwenden:" führt zu Fehlern.
Jonny
13

Der einfachste Weg:

child.center = parent.center
Juancazalla
quelle
Was ich meine ist, dass Sie mehr Erklärungen / Beschreibungen hinzufügen sollten, wie dies funktioniert.
Tushar
Ich habe viele Antworten dieser Art gesucht, diese einfache hat den Trick für mich getan. Vielen Dank.
Gbossa
9

Geben Sie hier die Bildbeschreibung ein

Stellen Sie diese automatische Größenmaske auf Ihre innere Ansicht ein.

Mayank Jain
quelle
1
Mit Autolayout gibt es kein Fenster zur automatischen Größenänderung.
Allen
@Allen Sie müssen das Autolayout deaktivieren, wenn Sie die automatische Größenänderung verwenden möchten.
Mayank Jain
8

Mit IOS9 können Sie die Layout-Anker-API verwenden.

Der Code würde folgendermaßen aussehen:

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

Dies hat den Vorteil gegenüber CGPointMakeoder CGRectbesteht darin, dass Sie mit diesen Methoden den Mittelpunkt der Ansicht auf eine Konstante setzen, mit dieser Technik jedoch eine Beziehung zwischen den beiden Ansichten festlegen, die für immer gültig ist, unabhängig davon, wie sich die parentviewÄnderungen ändern.

Stellen Sie einfach sicher, bevor Sie dies tun:

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

und das translatesAutoresizingMaskIntoConstraintsfür jede Ansicht auf false zu setzen.

Dies verhindert Abstürze und AutoLayout-Interferenzen.

Roymunson
quelle
8

Sie können verwenden

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

Und in Swift 3.0

yourView.center = CGPoint(x: superview.bounds.midX, y: superview.bounds.midY)
Sayali Shinde
quelle
1
Das zweite Codebeispiel funktioniert perfekt in Swift 4. GREAT 👍🏻!
iGhost
JA! Danke endlich. Ich wusste nichts über diese MidX / MidY-Sache. Perfecto.
Dave Y
5

Die Verwendung derselben Mitte in der Ansicht und Unteransicht ist der einfachste Weg, dies zu tun. Sie können so etwas tun,

UIView *innerView = ....;
innerView.view.center = self.view.center;
[self.view addSubView:innerView];
codeFood
quelle
Dadurch wird die Unteransicht in Bezug auf die Superansicht der Ansicht zentriert. Im obigen Fall funktioniert es, weil der Ursprung bei (0, 0) liegt.
Abdurrahman Mubeen Ali
3

Eine andere Lösung mit PureLayout mit autoCenterInSuperview.

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

[outerview addSubview:innerView];

[innerView autoCenterInSuperview];

So sieht es aus:

Mit PureLayout zentrieren

H6.
quelle
2

In c # oder Xamarin.ios können wir dies verwenden

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

Anisetti Nagendra
quelle
1

Ich würde ... benutzen:

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

Das ist einfach, kurz und süß. Wenn Sie die Antwort von @ Hejazi oben verwenden und parent.centerauf etwas anderes als (0,0)Ihre Unteransicht eingestellt sind, wird sie nicht zentriert!

Alte Bezeichnung
quelle
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
Sidd Redkar
quelle