Hành vi xem thường kỳ lạ trong iOS11. Các ô cuộn lên với hoạt ảnh đẩy điều hướng


116

Gần đây, tôi đã di chuyển một số mã sang SDK iOS 11 beta 5 mới.

Bây giờ tôi nhận được một hành vi rất khó hiểu từ UITableView. Bảng xem bản thân nó không phải là ưa thích. Tôi có các ô tùy chỉnh nhưng phần lớn nó chỉ dành cho chiều cao của chúng.

Khi tôi đẩy bộ điều khiển chế độ xem của mình với chế độ xem bảng, tôi nhận được một hoạt ảnh bổ sung trong đó các ô "cuộn lên" (hoặc có thể toàn bộ khung chế độ xem bảng được thay đổi) và xuống dọc theo hoạt ảnh điều hướng đẩy / bật lên. Vui lòng xem gif:

bàn lượn sóng

Tôi tạo thủ công tableviewtrong loadViewphương thức và thiết lập các ràng buộc bố cục tự động để bằng với chế độ xem đầu, cuối, trên, dưới của chế độ xem bảng. Superview là chế độ xem gốc của bộ điều khiển chế độ xem.

Mã đẩy của bộ điều khiển xem rất chuẩn: self.navigationController?.pushViewController(notifVC, animated: true)

Mã tương tự cung cấp hành vi bình thường trên iOS 10.

Bạn có thể vui lòng chỉ cho tôi hướng dẫn về những gì là sai?

CHỈNH SỬA: Tôi đã tạo một bộ điều khiển tableview rất đơn giản và tôi có thể tạo lại hành vi tương tự ở đó. Mã:

class VerySimpleTableViewController : UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
    }


    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 4
    }


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)

        cell.textLabel?.text = String(indexPath.row)
        cell.accessoryType = .disclosureIndicator

        return cell
    }


    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)

        let vc = VerySimpleTableViewController.init(style: .grouped)

        self.navigationController?.pushViewController(vc, animated: true)
    }
}

CHỈNH SỬA 2: Tôi đã có thể thu hẹp vấn đề xuống tùy chỉnh của mình về UINavigationBar. Tôi có một tùy chỉnh như thế này:

rootNavController.navigationBar.setBackgroundImage(createFilledImage(withColor: .white, size: 1), for: .default)

nơi createFilledImagetạo ra hình ảnh vuông với kích thước và màu sắc đã cho.

Nếu tôi bình luận ra dòng này, tôi sẽ trở lại hành vi bình thường.

Tôi sẽ đánh giá cao bất kỳ suy nghĩ nào về vấn đề này.


Có thể không phải là vấn đề với việc tùy chỉnh thanh điều hướng. Tôi đang gặp vấn đề tương tự (câu trả lời được chấp nhận đã giải quyết được vấn đề này) mà không có bất kỳ tùy chỉnh nào. Tôi nghĩ rằng đó có thể là vấn đề với cách iOS xử lý tableview khi nó được tạo theo cách thủ công dưới dạng subview, thay vì sử dụng UITableViewController.
Mark Leonard

2
Tôi chỉ thấy hành vi này khi tôi đặt navigationBar.isTranslucentthành false, nếu không nó hoạt động tốt.
b_ray

5
Đây có vẻ là một lỗi trong iOS11 GM, xin vui lòng đánh lừa rằng báo cáo lỗi để vấn đề này được một số sự chú ý từ Apple: openradar.appspot.com/34465226
b_ray

1
Vấn đề này dường như đã được khắc phục trong iOS 11.2 beta. Tôi sẽ không đặt contentInsetAdjustmentBehavior thành không bao giờ vì nó làm hỏng các chế độ xem cuộn của iPhone X do không đưa ra phần đệm ở cuối màn hình. Dưới cùng của chế độ xem nội dung của bạn vẫn nằm dưới "nút" trang chủ của iPhone X.
batu

Câu trả lời:


150

Điều này là do UIScrollView's (UITableView là một lớp con của UIScrollview) thuộc tính mới contentInsetAdjustmentBehavior, được đặt thành .automatictheo mặc định.

Bạn có thể ghi đè hành vi này bằng đoạn mã sau trong viewDidLoad của bất kỳ bộ điều khiển nào bị ảnh hưởng:

    tableView.contentInsetAdjustmentBehavior = .never

https://developer.apple.com/documentation/uikit/uiscrollview/2902261-contentinsetadjustmentbehavior


2
nhận xét này về định nghĩa của UIScrollViewContentInsetAdjustmentBehavior.automatic cho biết: "... để tương thích ngược cũng sẽ điều chỉnh nội dung trên cùng và dưới cùng Đặt khi chế độ xem cuộn thuộc sở hữu của bộ điều khiển chế độ xem với tự độngAdjustsScrollViewInsets = CÓ bên trong bộ điều khiển điều hướng, bất kể cuộn xem có thể cuộn được ". Lý thuyết của tôi là contentInset của thanh điều hướng bị ảnh hưởng bởi việc thiết lập hình nền, sau đó sẽ tự động điều chỉnh.
Maggy Hillen

8
Bạn cũng có thể làm điều đó với bảng phân cảnh. Trình kiểm tra kích thước -> Nội dung -> Đặt 'Không bao giờ'.
Woongbi Kim

4
Nếu nội dung của bạn mở rộng phía sau thanh tab, việc vô hiệu hóa tableView.contentInsetAdjustmentBehaviorsẽ phá vỡ các nội dung .
kean

4
Ngoài ra, chỉ cần tắt tính năng này sẽ đặt chỉ báo cuộn phía sau (gizmo trên cùng) trên iPhone X theo chiều ngang. Toàn bộ điểm của hành vi này là điều chỉnh vùng nội dung của các chế độ xem cuộn để chúng hiển thị trên các màn hình không phải là hình chữ nhật. Tôi nghĩ rằng chúng ta chỉ có thể thấy điều này hiện tại trên iPhone X Sim.
PhoneyDeveloper

8
Sự cố này do một lỗi trong iOS 11, nơi safeAreaInsets của chế độ xem của bộ điều khiển chế độ xem được đặt không chính xác trong quá trình chuyển đổi điều hướng, lỗi này sẽ được khắc phục trong iOS 11.2. Thiết lập contentInsetAdjustmentBehaviorđể .neverkhông phải là một cách giải quyết tuyệt vời vì nó có thể sẽ có tác dụng phụ không mong muốn khác. Nếu bạn sử dụng một giải pháp thay thế, bạn nên đảm bảo xóa nó cho các phiên bản iOS> = 11.2.
smileyborg

23

Ngoài câu trả lời của maggy

MỤC TIÊU-C

if (@available(iOS 11.0, *)) {
    scrollViewForView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}

Sự cố này là do lỗi trong iOS 11 trong đó safeAreaInsetschế độ xem của bộ điều khiển chế độ xem được đặt không chính xác trong quá trình chuyển đổi điều hướng, lỗi này sẽ được khắc phục trong iOS 11.2. Thiết lập contentInsetAdjustmentBehaviorđể .neverkhông phải là một cách giải quyết tuyệt vời vì nó có thể sẽ có tác dụng phụ không mong muốn khác. Nếu bạn sử dụng một giải pháp thay thế, bạn nên đảm bảo xóa nó cho các phiên bản iOS> = 11.2

-được đề cập bởi smileyborg (Kỹ sư phần mềm tại Apple)


6

Bạn có thể chỉnh sửa hành vi này cùng một lúc trong toàn bộ ứng dụng bằng cách sử dụng NSProxy trong didFinishLaunchingWithOptions:

if (@available(iOS 11.0, *)) {
      [UIScrollView appearance].contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
} 

1
Điều này sẽ phá vỡ bộ điều khiển của hệ thống, như UIImagePickerController
galway

6

Đây là cách tôi quản lý để khắc phục sự cố này trong khi vẫn cho phép iOS 11 tự động đặt nội dung . Tôi đang sử dụng UITableViewController.

  • Chọn "Mở rộng các cạnh dưới các thanh trên cùng" và "Mở rộng các cạnh dưới các thanh mờ" trong bộ điều khiển chế độ xem của bạn trong bảng phân cảnh (hoặc theo chương trình ). Các thiết lập khu vực an toàn sẽ ngăn tầm nhìn của bạn đi xuống dưới thanh trên cùng.
  • Kiểm tra nút "Insets to Safe Area" trên chế độ xem bảng trong bảng phân cảnh của bạn. (hoặc tableView.insetsContentViewsToSafeArea = true) - Điều này có thể không cần thiết nhưng đó là những gì tôi đã làm.
  • Đặt hành vi điều chỉnh cài đặt nội dung thành "Trục có thể cuộn" (hoặc tableView.contentInsetAdjustmentBehavior = .scrollableAxes) - .alwayscũng có thể hoạt động nhưng tôi đã không kiểm tra.

Một điều khác để thử nếu vẫn thất bại:

Ghi đè viewSafeAreaInsetsDidChange UIViewControllerphương thức để có được chế độ xem bảng để buộc thiết lập các nội dung của chế độ xem cuộn thành các cài đặt vùng an toàn. Điều này kết hợp với cài đặt 'Không bao giờ' trong câu trả lời của Maggy.

- (void)viewSafeAreaInsetsDidChange {
    [super viewSafeAreaInsetsDidChange];
    self.tableView.contentInset = self.view.safeAreaInsets;
}

Lưu ý: self.tableViewself.viewphải giống như vậy đối vớiUITableViewController


Đã thử hầu hết mọi thứ trên chủ đề này, và điều này đã hiệu quả với tôi. TableViewVC được nhúng trong TabBarVC. Cảm ơn bạn!
Josh Wolff

3

Điều này có vẻ giống như một lỗi hơn là hành vi dự kiến. Nó xảy ra khi thanh điều hướng không trong mờ hoặc khi hình nền được đặt.

Nếu bạn chỉ đặt contentInsetAdjustmentBehavior thành. Bất cứ khi nào, phần chèn nội dung sẽ không được đặt chính xác trên iPhone X, chẳng hạn như nội dung sẽ đi vào khu vực dưới cùng, dưới thanh cuộn.

Cần phải làm hai việc:
1. ngăn chuyển động scrollView lên trên push / pop
2. giữ lại hành vi .automatic vì nó cần thiết cho iPhone X. Nếu không có điều này, ví dụ như ở chế độ dọc, nội dung sẽ nằm dưới thanh cuộn dưới cùng.

Giải pháp đơn giản mới: trong XIB: Chỉ cần thêm UIView mới trên đầu chế độ xem chính của bạn với đầu, đầu và cuối đến superview và chiều cao được đặt thành 0. Bạn không phải kết nối nó với các subview khác hoặc bất kỳ thứ gì.

Giải pháp cũ:

Lưu ý: Nếu bạn đang sử dụng UIScrollView ở chế độ ngang, nó vẫn không đặt các đường nối nằm ngang một cách chính xác (một lỗi khác?), Vì vậy bạn phải ghim đầu / cuối của scrollView vào safeAreaInsets trong IB.

Lưu ý 2: Giải pháp bên dưới cũng có vấn đề là nếu tableView được cuộn xuống dưới cùng và bạn đẩy bộ điều khiển và bật lại, nó sẽ không ở dưới cùng nữa.

override func viewDidLoad()
{
    super.viewDidLoad()

    // This parts gets rid of animation when pushing
    if #available(iOS 11, *)
    {
        self.tableView.contentInsetAdjustmentBehavior = .never
    }
}

override func viewDidDisappear(_ animated: Bool)
{
    super.viewDidDisappear(animated)
    // This parts gets rid of animation when popping
    if #available(iOS 11, *)
    {
        self.tableView.contentInsetAdjustmentBehavior = .never
    }
}

override func viewDidAppear(_ animated: Bool)
{
    super.viewDidAppear(animated)
    // This parts sets correct behaviour(insets are correct on iPhone X)
    if #available(iOS 11, *)
    {
        self.tableView.contentInsetAdjustmentBehavior = .automatic
    }
}

ParentView là gì?
PhoneyDeveloper

Chế độ xem chính của bộ điều khiển chế độ xem của bạn, tôi đã cập nhật câu trả lời. Cám ơn.
El Horrible

Khi tôi đang sử dụng UITableViewController, tableView là view của view controller. Ngoài ra, các tấm lót phải khác nhau khi thiết bị được xoay. Tôi muốn điều chỉnh. Tôi chỉ không thích hoạt ảnh khi tableView lần đầu tiên xuất hiện.
PhoneyDeveloper

Trong trường hợp của bạn vì UITableView là chế độ xem của bộ điều khiển nên nó phải có safeAreaInsets.bottom = 34 (dọc), vì vậy bạn chỉ có thể đặt tableView.contentInset = tableView.safeAreaInsets.
El Horrible

Điều đó không hiệu quả với tôi. Trong viewDidLoad, tất cả các nội dung đều bằng không. Nếu tôi cố gắng sử dụng mã đó trong viewWillLayoutSubviews thì chỉ báo cuộn được đưa vào nhưng bản thân tableView có thể cuộn theo chiều ngang. Nếu tôi chỉ nhìn vào các nội dung trong viewWillLayoutSubviews mà không tắt điều chỉnh thìContentInset được điều chỉnh dưới cùng sẽ trở thành 21 và đó là tất cả những gì dường như thay đổi.
PhoneyDeveloper


2

vui lòng đảm bảo cùng với mã trên, thêm mã bổ sung như sau. Nó đã giải quyết được vấn đề

override func viewDidLayoutSubviews() { 
     super.viewDidLayoutSubviews() 
     tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) // print(thisUISBTV.adjustedContentInset) 
}

Điều này một mình giải quyết vấn đề của tôi !! Cảm ơn bạn. Lãng phí quá nhiều giờ cho vấn đề này!
Murat Yasar

2

Ngoài ra, nếu bạn sử dụng thanh tab, nội dung dưới cùng của chế độ xem bộ sưu tập sẽ bằng không. Đối với điều này, hãy đặt mã bên dưới vào viewDidAppear:

if #available(iOS 11, *) {
    tableView.contentInset = self.collectionView.safeAreaInsets
}

2

Trong trường hợp của tôi, điều này đã hoạt động (đặt nó vào viewDidLoad):

self.navigationController.navigationBar.translucent = YES;

1

Loại bỏ không gian thừa ở đầu collectionViewhoặctableView

    if #available(iOS 11.0, *) {
        collectionView.contentInsetAdjustmentBehavior  = .never
        //tableView.contentInsetAdjustmentBehavior  = .never
    } else {
        automaticallyAdjustsScrollViewInsets = false
    }

Mã trên collectionViewhoặc tableViewđi dưới thanh điều hướng.
Mã bên dưới ngăn chế độ xem bộ sưu tập đi dưới điều hướng

    self.edgesForExtendedLayout = UIRectEdge.bottom

nhưng tôi thích sử dụng logic và mã bên dưới cho UICollectionView

Giá trị chèn cạnh được áp dụng cho một hình chữ nhật để thu nhỏ hoặc mở rộng khu vực được biểu thị bởi hình chữ nhật đó. Thông thường, các cạnh trong được sử dụng trong khi bố trí chế độ xem để sửa đổi khung của chế độ xem. Giá trị dương làm cho khung bị chèn (hoặc thu nhỏ) theo số lượng đã chỉ định. Giá trị âm làm cho khung được bắt đầu (hoặc mở rộng) theo số lượng đã chỉ định.

collectionView.contentInset = UIEdgeInsets(top: -30, left: 0, bottom: 0, right: 0)
//tableView.contentInset = UIEdgeInsets(top: -30, left: 0, bottom: 0, right: 0)

Cách tốt nhất cho UICollectionView

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets(top: -30, left: 0, bottom: 0, right: 0)
}

0

Xóa mã này làm việc cho tôi

self.edgesForExtendedLayout = UIRectEdgeNone

0
  if #available(iOS 11, *) {
        self.edgesForExtendedLayout = UIRectEdge.bottom
  }

Tôi đã sử dụng UISearchController với kết quả tùy chỉnhControllers có chế độ xem bảng. Việc đẩy bộ điều khiển mới trên bộ điều khiển kết quả khiến chế độ xem bảng ở dưới tìm kiếm.

Đoạn mã được liệt kê ở trên đã hoàn toàn khắc phục được sự cố

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.