2013-09-25 69 views
5

Tôi đang sử dụng iOS 6, UIScrollView phân trang và bố cục tự động thuần túy.Khung hình không phản ánh ràng buộc bố cục tự động sau khi loại bỏ bộ điều khiển chế độ xem

Tóm tắt: Tôi đã tạo bộ điều khiển chế độ xem để cuộn trang nội dung. Một số chế độ xem được tạo và được định cấu hình trong bảng phân cảnh, các chế độ xem khác theo chương trình. Dưới đây là hệ thống phân cấp chế độ xem:

- Main view (storyboard) 
    - UIScrollView (storyboard) 
    - content view (programmatically) 
     - subviews representing pages of content (programmatically) 

Các ràng buộc cho chế độ xem cuộn được định cấu hình trong IB. Đây là cách tôi cấu hình các khó khăn cho quan điểm nội dung trong mã:

- (void)viewDidLoad 
{ 
    // ABPageScrollerContentView is a subclass of UIView; it overrides intrinsicContentSize; the size is calculated without referencing the scroll view's dimensions 
    self.contentView = [[ABPageScrollerContentView alloc] init]; 
    self.contentView.translatesAutoresizingMaskIntoConstraints = NO; 
    [self.pageScrollerView addSubview:self.contentView]; 

    // configure constraints between scroll view and content view... 
    UIView *contentView = self.contentView; 
    NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(contentView); 

    [self.pageScrollerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[contentView]|" options:0 metrics:0 views:viewsDictionary]]; 
    [self.pageScrollerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[contentView]|" options:0 metrics:0 views:viewsDictionary]]; 

    // the content view's subviews are added/removed in the tilePages method (not shown); tilePages is called later in the view controller lifecycle... 
} 

Nếu người dùng chạm một nút chỉnh sửa, một bộ điều khiển xem được trình bày modally sử dụng một segue trong kịch bản này. Sau khi bộ điều khiển xem bị loại bỏ, hệ thống dường như không thể giải thích được khung của khung nhìn nội dung mặc dù các ràng buộc không thay đổi.

Tôi bỏ qua những điều khiển xem thể hiện trong phương pháp đại biểu sau đây:

- (void)didExitEditPageViewVC:(id)controller 
{ 
    // update currently displayed page view from data model... 

    // logged content view frame = (0, 0; 1020, 460) 

    [self dismissViewControllerAnimated:YES completion:^{ 

     // logged content view frame = (-170, 0; 1020, 460) 
    }]; 
} 

Tôi không hiểu làm thế nào các thành phần x xuất xứ của khung thay đổi từ 0 đến -170. Các ràng buộc giống hệt nhau trước và sau khi loại bỏ trình điều khiển khung nhìn.

Dưới đây là khung và các khó khăn ngay trước khi gọi dismissViewControllerAnimated: hoàn thành: Phương pháp:

(lldb) po self.contentView 
$0 = 0x1ede2b40 <AEBPageScrollerContentView: 0x1ede2b40; frame = (0 0; 1020 460); layer = <CALayer: 0x1edd6f00>> 

(lldb) po self.pageScrollerView.constraints 
$1 = 0x1ed076c0 <__NSArrayM 0x1ed076c0>(
<NSLayoutConstraint:0x1ede2980 H:|-(0)-[AEBPageScrollerContentView:0x1ede2b40] (Names: '|':UIScrollView:0x1edd3410)>, 
<NSLayoutConstraint:0x1eded480 H:[AEBPageScrollerContentView:0x1ede2b40]-(0)-| (Names: '|':UIScrollView:0x1edd3410)>, 
<NSLayoutConstraint:0x1edecbc0 V:|-(0)-[AEBPageScrollerContentView:0x1ede2b40] (Names: '|':UIScrollView:0x1edd3410)>, 
<NSLayoutConstraint:0x1ede1040 V:[AEBPageScrollerContentView:0x1ede2b40]-(0)-| (Names: '|':UIScrollView:0x1edd3410)> 
) 

Dưới đây là khung và các khó khăn sau khi xem trình bày điều khiển tái xuất hiện:

contentView = <AEBPageScrollerContentView: 0x1ede2b40; frame = (-170 0; 1020 460); layer = <CALayer: 0x1edd6f00>> 

self.pageScrollerView.constraints = 
(
    "<NSLayoutConstraint:0x1ede2980 H:|-(0)-[AEBPageScrollerContentView:0x1ede2b40] (Names: '|':UIScrollView:0x1edd3410)>", 
    "<NSLayoutConstraint:0x1eded480 H:[AEBPageScrollerContentView:0x1ede2b40]-(0)-| (Names: '|':UIScrollView:0x1edd3410)>", 
    "<NSLayoutConstraint:0x1edecbc0 V:|-(0)-[AEBPageScrollerContentView:0x1ede2b40] (Names: '|':UIScrollView:0x1edd3410)>", 
    "<NSLayoutConstraint:0x1ede1040 V:[AEBPageScrollerContentView:0x1ede2b40]-(0)-| (Names: '|':UIScrollView:0x1edd3410)>" 
) 

Tại sao khung nội dung của khung nhìn thay đổi bất ngờ? Và tại sao nó không phù hợp với những gì được quyết định bởi những ràng buộc?

Cuộc gọi bị trì hoãn tới hasAmbiguousLayout trả về false một cách đáng ngạc nhiên. Không có ngoại lệ nào được ném ra. Chế độ xem cuộn thậm chí còn cuộn, mặc dù chế độ xem nội dung bị tắt một phần.

Không nơi nào tôi đặt rõ ràng kích thước nội dung của chế độ xem cuộn; Tôi để nó cho hệ thống. Chế độ xem nội dung có kích thước nội tại (kích thước của chế độ xem nội dung có vẻ ổn, đó là nguồn gốc của chế độ xem nội dung là vấn đề).

Độ lệch nội dung của chế độ xem cuộn là giống nhau trước và sau khi loại bỏ trình điều khiển chế độ xem. Tuy nhiên, sự dịch chuyển của thành phần x của nguồn gốc của nội dung xem là tỷ lệ thuận với độ lệch nội dung. Độ lệch nội dung càng lớn thì thành phần x của nguồn gốc của nội dung xem càng âm sau khi bộ điều khiển chế độ xem bị loại bỏ. Và, tại một bù đắp nội dung của "zero", thành phần x là số không. Vì vậy, nếu bộ điều khiển xem phương thức được trình bày trong khi xem trang đầu tiên của nội dung (khi bù đắp nội dung là "không"), khung của khung nhìn nội dung là chính xác khi loại bỏ bộ điều khiển xem. Trường hợp nội dung-offset-of-zero là trường hợp duy nhất trong đó khung của khung nhìn nội dung phản ánh chính xác các ràng buộc của khung nhìn nội dung.

Tôi đã thử chèn cuộc gọi vào bố cụcNếu được thực hiện ở những nơi khác nhau không có kết quả.

Mọi đề xuất?

Trả lời

7

Tôi tạo ra một lớp con UIScrollView mà làm việc xung quanh vấn đề này (mà BTW là cố định trong iOS7):

@interface ConstraintsSafeScrollView : UIScrollView 
@end 

@implementation ConstraintsSafeScrollView { 
    CGPoint _savedContentOffset; 
    UIEdgeInsets _savedContentInset; 
} 

- (void)willMoveToWindow:(UIWindow *)newWindow { 
    if (newWindow) { 
    // Reset the scrollview to the top. 
    [super setContentOffset:CGPointMake(-_savedContentInset.left, -_savedContentInset.top)]; 
    } 
    [super willMoveToWindow:newWindow]; 
} 

// Overridden to store the latest value. 
- (void)setContentOffset:(CGPoint)contentOffset { 
    _savedContentOffset = contentOffset; 
    [super setContentOffset:contentOffset]; 
} 

// Overridden to store the latest value. 
- (void)setContentInset:(UIEdgeInsets)contentInset { 
    _savedContentInset = contentInset; 
    [super setContentInset:contentInset]; 
} 

- (void)didMoveToWindow { 
    if (self.window) { 
    // Restore offset and insets to their previous values. 
    self.contentOffset = _savedContentOffset; 
    self.contentInset = _savedContentInset; 

    } 
    [super didMoveToWindow]; 
} 

@end 
+1

Clever giải pháp. Tôi thích ý tưởng phân lớp UIScrollView. Dễ dàng để loại bỏ khi sửa chữa đến. Tôi đã nâng cấp dự án của mình lên iOS 7, nhưng tôi đã chuyển sang một phần khác của dự án của mình. Khi tôi quay lại bộ điều khiển chế độ xem này, tôi có thể xóa phiên bản sửa lỗi của mình. – bilobatum

0

Kể từ trường hợp duy nhất trong đó khung xem nội dung là chính xác sau khi sa thải của bộ điều khiển xem phương thức là khi nội dung xem di chuyển của bù đắp là "zero", tôi giải quyết vấn đề này như sau:

// presenting view controller's implementation 
self.contentOffsetBeforeModalViewControllerDismissal = self.pageScrollerView.contentOffset; 

self.pageScrollerView.contentOffset = CGPointMake(0, 0); 

[self dismissViewControllerAnimated:YES completion:nil]; 

Sau đó, , tôi phục hồi nội dung thực tế bù đắp trong phương pháp viewDidLayoutSubviews quan điểm điều khiển của trình bày:

- (void)viewDidLayoutSubviews 
{ 
    if (!CGPointEqualToPoint(self.contentOffsetBeforeModalViewControllerDismissal, CGPointZero)) { 

     self.pageScrollerView.contentOffset = self.contentOffsetBeforeModalViewControllerDismissal; 

     self.contentOffsetBeforeModalViewControllerDismissal = CGPointZero; 
    } 
} 

Khi nó quay ra, tôi không thể khôi phục lại nội dung bù đắp trong viewWillAppear quan điểm điều khiển của trình bày: phương pháp bởi vì nó quá sớm. Khôi phục nội dung bù đắp trong viewDidAppear: đã quá muộn vì nó tạo ra một bản cập nhật giao diện người dùng. Khi làm việc với bố cục tự động, tôi thấy rằng thường xuyên hơn không phải viewDidLayoutSubviews vừa đúng về mặt thời gian.

Điều này giống như một chút hack; nhưng đó là một hack quen thuộc: tiết kiệm một chút của nhà nước, để cho hệ thống làm điều của nó, khôi phục lại trạng thái đó.

Thật không may, một lỗi khác xuất hiện nhanh chóng. Nếu tôi trình bày và loại bỏ bộ điều khiển xem phương thức, cuộn đến một trang khác, sau đó trình bày lại bộ điều khiển chế độ xem, ứng dụng sẽ bị lỗi khi trình điều khiển chế độ xem bị loại bỏ. Không có thông tin nào được đưa ra trong bảng điều khiển về lý do khiến ứng dụng có thể gặp sự cố. Ngoại lệ đã được ném vào cuộc gọi để bỏ quaViewControllerAnimated: completion :.

Sự cố sau này đã được giải quyết bằng cách tắt phương pháp ốp lát trang tùy chỉnh của tôi (được kích hoạt bất kỳ lúc nào thay đổi bù trừ nội dung của chế độ xem cuộn). Phương pháp ốp lát trang đảm bảo rằng các trang nội dung chính xác được hiển thị và tái chế các bản xem trước. Tôi không cần trang tiling để xảy ra trong nội dung của tôi bù đắp-khiêu vũ, bởi vì các subviews chính xác đã được nạp. Vì vậy, đây là việc sửa chữa cuối cùng cho giải tán bộ điều khiển xem phương thức mà không cần thay khung xem nội dung hoặc đâm ứng dụng:

// presenting view controller's implementation 
self.disablePageTiling = YES // flag causes tilePages to do nothing 

self.contentOffsetBeforeModalViewControllerDismissal = self.pageScrollerView.contentOffset; 

self.pageScrollerView.contentOffset = CGPointMake(0, 0); // triggers tilePages, but nothing will happen because of the flag 

[self dismissViewControllerAnimated:YES completion:^{ 
    self.disablePageTiling = NO; 
}]; 

Việc thực hiện viewDidLayoutSubviews vẫn giữ nguyên như trên.

Tôi không coi những vấn đề này phải được giải quyết hoàn toàn bằng bất kỳ phương tiện nào. Khi sử dụng bố cục tự động với chế độ xem cuộn, tôi luôn kiên trì với cảm giác dai dẳng này mà tôi đang viết mã xấu. Vì vậy, tôi hoan nghênh cái nhìn sâu sắc hơn nữa. Tôi cũng tò mò về việc liệu iOS 7 có ảnh hưởng đến những vấn đề này hay không.