Làm cách nào để tập trung vào một khung nhìn của UIView


128

Tôi có một UIViewbên trong UIViewm và tôi muốn bên trongUIView luôn luôn được tập trung bên trong bên ngoài, mà không cần phải thay đổi kích thước chiều rộng và chiều cao.

Tôi đã đặt thanh chống và lò xo sao cho nó ở trên / trái / phải / dưới mà không đặt thay đổi kích thước. Nhưng nó vẫn không phải là trung tâm. Bất kỳ ý tưởng?


2
Câu trả lời được chấp nhận là sai và sẽ sụp đổ. Câu trả lời của Hejaz hoạt động tuyệt vời.
Fattie

Câu trả lời:


209

Mục tiêu-C

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

Nhanh

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

51
Bạn nên sử dụng boundsvà không phải frame, vì framekhông xác định nếu chế độ xem có a transform.
omz

1
Nó thực sự sẽ không tạo ra sự khác biệt trong trường hợp này, vì chỉ sizeđược sử dụng.
Peter De Weese

1
Điều đó không quan trọng, toàn bộ frametài sản không được xác định nếu chế độ xem có transformbiến đổi không phải là danh tính; đọc tài liệu về thuộc tính khung của UIView .
omz

6
Thật không may câu trả lời này thực sự sai . Đơn giản chỉ cần sử dụng câu trả lời đúng của Heja.
Fattie

@Fattie chính xác thì sao? Tôi đã sử dụng nó để định tâm ImageView trong Chế độ xem và nó đang hoạt động.
jreft56

284

Bạn có thể làm điều này và nó sẽ luôn hoạt động:

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

Và đối với Swift:

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

1
và đừng quên sau đó, child.frame = CGRectIntegral (child.frame);
Fattie

8
Một: Điều này chỉ hoạt động nếu bạn không thay đổi trung tâm / vị trí của chế độ xem cha mẹ. Thứ hai: Nếu bạn đang sử dụng phương pháp này, không cần phải chuyển đổi điểm (nó đã ở định dạng chính xác) chỉ cần sử dụng child.center = parent.center. Tôi sẽ sử dụng `child.center = CGPointMake (Parent.bound.height / 2, Parent.bound. Thong / 2) '. Điều này sẽ luôn có trung tâm xem của bạn bất kể trung tâm xem cha mẹ của bạn được đặt thành gì.
Tên cũ

1
Nó cũng không hữu ích nếu chế độ xem chưa được thêm vào cấu trúc phân cấp chế độ xem (chẳng hạn như khi nhập đối tượng)
Victor Jalencas 24/2/2015

1
@Hejazi Thật tốt khi thêm câu trả lời nhanh chóng;)
Milad Faridnia

1
@Soumen Không, có một sự khác biệt. UIView.boundslà tương đối so với quan điểm riêng của mình (và do đó bounds.originlà ban đầu bằng không), trong khi UIView.centerđược quy định trong hệ tọa độ của SuperView .
Hejazi

41

Trước khi bắt đầu, chúng ta hãy nhắc rằng điểm gốc là góc trên bên trái CGPointcủa chế độ xem. Một điều quan trọng để hiểu về quan điểm và cha mẹ.

Hãy xem mã đơn giản này, một bộ điều khiển chế độ xem thêm vào nó xem hình vuông màu đen:

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

}

Điều này sẽ tạo ra khung nhìn này: gốc và tâm hình chữ nhật màu đen không khớp với tọa độ giống như cha mẹ của nó

nhập mô tả hình ảnh ở đây

Bây giờ, hãy thử thêm subView khác SubSubView và cung cấp subSubview cùng nguồn gốc với subView, nhưng làm cho subSubView thành một khung nhìn con của subView

Chúng tôi sẽ thêm mã này:

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

Và đây là kết quả:

nhập mô tả hình ảnh ở đây

Vì dòng này:

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

Bạn mong đợi nguồn gốc của hình chữ nhật màu tím giống như cha mẹ của nó (hình chữ nhật màu đen) nhưng nó nằm dưới nó, và tại sao vậy? Bởi vì khi bạn thêm chế độ xem vào chế độ xem khác, "thế giới" của khung nhìn phụ giờ đây là chế độ cha mẹ BOUND RECTANGLE, nếu bạn có chế độ xem trên màn hình chính ở chế độ coords (15,15) cho tất cả các chế độ xem phụ, thì góc trên bên trái sẽ là (0,0)

Đây là lý do tại sao bạn cần luôn luôn đề cập đến cha mẹ bởi hình chữ nhật bị ràng buộc, đó là "thế giới" của các khung nhìn phụ, cho phép sửa dòng này thành:

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

Và hãy xem điều kỳ diệu, subSubview hiện được đặt chính xác trong nguồn gốc của nó:

nhập mô tả hình ảnh ở đây

Vì vậy, bạn thích "ok tôi chỉ muốn tập trung vào quan điểm của mình theo quan điểm của bố mẹ tôi, chuyện lớn là gì?" tốt, nó không phải là vấn đề lớn, bạn chỉ cần "dịch" điểm Trung tâm mẹ được lấy từ khung của nó sang trung tâm giới hạn của cha mẹ bằng cách thực hiện điều này:

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

Bạn đang thực sự nói với anh ấy "đưa cha mẹ xem trung tâm và chuyển đổi nó thành thế giới subSubView".

Và bạn sẽ nhận được kết quả này:

nhập mô tả hình ảnh ở đây


Đến nơi đặt dòng 'subSubView.center = subView.convertPoint (subView.center, fromView: subSubView)'?
Thamarai T

26

Tôi sẽ dùng:

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

Tôi thích sử dụng các CGRecttùy chọn ...

Chuyển 3:

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

19

1. Nếu bạn đã bật tự động thanh toán:

  • Gợi ý: Để tập trung chế độ xem trên một chế độ xem khác với tự động thanh toán, bạn có thể sử dụng cùng một mã cho bất kỳ hai chế độ xem nào chia sẻ ít nhất một chế độ xem chính.

Trước hết, vô hiệu hóa chế độ xem tự động

UIView *view1, *view2;
[childview setTranslatesAutoresizingMaskIntoConstraints:NO];
  1. Nếu bạn là UIView + Autolayout hoặc Purelayout :

    [view1 autoAlignAxis:ALAxisHorizontal toSameAxisOfView:view2];
    [view1 autoAlignAxis:ALAxisVertical toSameAxisOfView:view2];
  2. Nếu bạn chỉ sử dụng các phương thức tự động thanh toán cấp độ 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. Không có tự động thanh toán:

Tôi thích:

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
Cần lưu ý rằng, không giống như câu trả lời được chấp nhận, giải pháp này sẽ căn chỉnh sạch sẽ trên các ranh giới pixel và ngăn chặn độ mờ của chế độ xem cho các độ rộng nhất định.
Brad Larson

1
Nếu tôi không nhầm, child.frame = CGRectIntegral (child.frame); là một loại giải pháp bắt tất cả / sử dụng bất cứ nơi nào cho vấn đề BL mô tả.
Fattie

1
@JoeBlow: Cảm ơn vì đã ngẩng cao đầu. Tôi đã từng thích làm tròn nhưng với kiểu khối, nó sẽ thanh lịch hơn khi sử dụngCGRectIntegral
Cemal Eker

Bạn có thể giải thích cú pháp bạn sử dụng để đặt khung không, tôi chưa từng thấy nó trước đây. Có phải nó luôn luôn là tuyên bố cuối cùng trong "đóng cửa" được gán cho tài sản? Và tôi có thể tìm thấy nó ở đâu trong tài liệu của Apple?
Johannes

"Nếu bạn chỉ sử dụng các phương thức tự động thanh toán mức UIKit:" sẽ xảy ra lỗi.
Jonny

13

Cách dễ nhất:

child.center = parent.center

Ý tôi là bạn nên thêm giải thích / mô tả về cách thức hoạt động của nó.
Tushar

Tìm kiếm rất nhiều câu trả lời thuộc loại này, câu trả lời đơn giản này đã giúp tôi rất nhiều. Cảm ơn.
gbossa

9

nhập mô tả hình ảnh ở đây

Đặt mặt nạ tự động này vào chế độ xem bên trong của bạn.


1
Với tính năng tự động thanh toán, không có cửa sổ tự động hóa.
Allen

@ ALLen bạn phải tắt autolayout nếu bạn muốn sử dụng autoresizing.
Mayank Jain

8

Với IOS9, bạn có thể sử dụng API neo bố cục.

Mã sẽ trông như thế này:

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

Ưu điểm của điều này là CGPointMakehoặc CGRectvới các phương thức đó, bạn đang đặt trung tâm của chế độ xem thành một hằng số nhưng với kỹ thuật này, bạn đang đặt mối quan hệ giữa hai chế độ xem sẽ giữ mãi mãi, bất kể parentviewthay đổi như thế nào .

Chỉ cần chắc chắn trước khi bạn làm điều này để làm:

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

và để đặt translatesAutoresizingMaskIntoConstraintscho mỗi chế độ xem thành sai.

Điều này sẽ ngăn chặn sự cố và AutoLayout can thiệp.


8

Bạn có thể dùng

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

Và trong Swift 3.0

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

1
Ví dụ mã thứ hai hoạt động hoàn hảo trong swift 4. TUYỆT VỜI!
iGhost

ĐÚNG! Cảm ơn bạn, cuối cùng. Không biết về điều midX / midY đó. Hoàn hảo.
Dave Y

5

Sử dụng cùng một trung tâm trong chế độ xem và xem phụ là cách đơn giản nhất để thực hiện. Bạn có thể làm một cái gì đó như thế này,

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

Điều này sẽ tập trung vào chế độ xem phụ đối với chế độ xem siêu. Trong trường hợp trên, nó hoạt động vì gốc tọa độ là (0, 0).
Abdurrahman Mubeen Ali

3

Một giải pháp khác với PureLayout sử dụng autoCenterInSuperview.

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

[outerview addSubview:innerView];

[innerView autoCenterInSuperview];

Đây là nó trông như thế nào:

Trung tâm với PureLayout


2

Trong c # hoặc Xamarin.ios, chúng ta có thể sử dụng như thế này

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


1

Tôi sẽ dùng:

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

Điều này là đơn giản, ngắn và ngọt ngào. Nếu bạn sử dụng câu trả lời của @ Hejazi ở trên và parent.centerđược đặt thành bất cứ điều gì khác ngoài cuộc (0,0)phỏng vấn của bạn sẽ không được tập trung!


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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.