พฤติกรรม uitableview แปลก ๆ ใน iOS11 เซลล์เลื่อนขึ้นพร้อมกับแอนิเมชั่นแบบพุชการนำทาง


116

ฉันเพิ่งย้ายรหัสบางส่วนไปยัง iOS 11 beta 5 SDK ใหม่

ตอนนี้ฉันได้รับพฤติกรรมที่สับสนมากจาก UITableView Tableview เองก็ไม่ได้แฟนซีขนาดนั้น ฉันมีเซลล์ที่กำหนดเอง แต่ส่วนใหญ่เป็นเพียงความสูง

เมื่อฉันดันตัวควบคุมมุมมองด้วย tableview ฉันจะได้รับภาพเคลื่อนไหวเพิ่มเติมโดยที่เซลล์ "เลื่อนขึ้น" (หรืออาจจะเปลี่ยนกรอบมุมมองตารางทั้งหมด) และลงพร้อมกับภาพเคลื่อนไหวการนำทางแบบพุช / ป๊อป โปรดดู gif:

มุมมองหยัก

ฉันสร้างด้วยตนเองtableviewในloadViewวิธีการและรูปแบบการตั้งค่าอัตโนมัติ จำกัด จะเท่ากับชั้นนำต่อท้ายด้านบนด้านล่างของ SuperView tableview ของ ซูเปอร์วิวคือมุมมองรูทของตัวควบคุมมุมมอง

ดูรหัสการผลักดันคอนโทรลเลอร์เป็นมาตรฐานมาก: self.navigationController?.pushViewController(notifVC, animated: true)

รหัสเดียวกันให้การทำงานปกติบน iOS 10

คุณช่วยชี้ทิศทางของสิ่งที่ผิดได้ไหม

แก้ไข: ฉันได้สร้างตัวควบคุม tableview ที่เรียบง่ายมากและฉันสามารถสร้างพฤติกรรมเดียวกันได้ที่นั่น รหัส:

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

แก้ไข 2: ฉันสามารถ จำกัด ปัญหาให้แคบลงไปที่การปรับแต่ง UINavigationBar ของฉัน ฉันมีการปรับแต่งดังนี้:

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

ที่createFilledImageสร้างภาพสี่เหลี่ยมจัตุรัสที่มีขนาดและสีที่กำหนด

ถ้าฉันแสดงความคิดเห็นในบรรทัดนี้ฉันจะกลับมาทำตัวปกติ

ฉันขอขอบคุณที่คิดเกี่ยวกับเรื่องนี้


อาจไม่มีปัญหากับการปรับแต่งแถบนำทาง ฉันประสบปัญหาเดียวกัน (คำตอบที่ยอมรับแก้ไขได้) โดยไม่ต้องปรับแต่งใด ๆ ฉันคิดว่าอาจเป็นปัญหากับวิธีที่ iOS จัดการกับ tableview เมื่อสร้างขึ้นด้วยตนเองเป็นมุมมองย่อยแทนที่จะใช้ UITableViewController
Mark Leonard

2
ฉันจะเห็นพฤติกรรมนี้เมื่อตั้งค่าnavigationBar.isTranslucentเป็นfalseเท่านั้นมิฉะนั้นจะใช้ได้ดี
b_ray

5
สิ่งนี้ดูเหมือนจะเป็นข้อบกพร่องใน iOS11 GM โปรดหลอกรายงานข้อผิดพลาดเพื่อให้ปัญหานี้ได้รับความสนใจจาก Apple: openradar.appspot.com/34465226
b_ray

1
ปัญหานี้ดูเหมือนจะได้รับการแก้ไขแล้วใน iOS 11.2 เบต้า ฉันจะไม่ตั้งค่า contentInsetAdjustmentBehavior เป็นไม่เคยเพราะมันทำให้การเลื่อน iPhone X แตกโดยไม่ให้ช่องว่างที่ด้านล่างของหน้าจอ ด้านล่างของมุมมองเนื้อหาจะอยู่ใต้ "ปุ่ม" หน้าแรกของ iPhone X
Batu

คำตอบ:


150

เนื่องจากUIScrollView's (UITableView เป็นคลาสย่อยของcontentInsetAdjustmentBehaviorคุณสมบัติใหม่ของ UIScrollview)ซึ่งตั้งค่าเป็นค่า.automaticเริ่มต้น

คุณสามารถลบล้างพฤติกรรมนี้ด้วยข้อมูลโค้ดต่อไปนี้ใน viewDidLoad ของตัวควบคุมที่ได้รับผลกระทบ:

    tableView.contentInsetAdjustmentBehavior = .never

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


2
ความคิดเห็นนี้เกี่ยวกับคำจำกัดความของ UIScrollViewContentInsetAdjustmentBehavior.automatic กล่าวว่า: "... สำหรับความเข้ากันได้ย้อนหลังจะปรับเนื้อหาด้านบนและด้านล่างด้วยเมื่อมุมมองเลื่อนเป็นของตัวควบคุมมุมมองด้วย automaticAdjustsScrollViewInsets = ใช่ภายในตัวควบคุมการนำทางไม่ว่าจะเลื่อนหรือไม่ ดูเลื่อนได้ " ทฤษฎีของฉันคือ contentInset ของแถบนำทางได้รับผลกระทบจากการตั้งค่าภาพพื้นหลังซึ่งจะปรับแบบไดนามิก
Maggy Hillen

8
คุณสามารถทำได้ด้วยสตอรีบอร์ด ตัวตรวจสอบขนาด -> การแทรกเนื้อหา -> ตั้งค่า 'ไม่เคย'
Woongbi Kim

4
หากเนื้อหาของคุณขยายออกไปด้านหลังแถบแท็บการปิดใช้งานtableView.contentInsetAdjustmentBehaviorจะทำให้สิ่งที่ใส่เข้าไปเสียหาย
kean

4
นอกจากนี้เพียงแค่ปิดใช้งานสิ่งนี้จะทำให้ตัวบ่งชี้การเลื่อนอยู่ด้านหลัง (gizmo ด้านบน) บน iPhone X ในแนวนอน จุดรวมของพฤติกรรมนี้คือการปรับพื้นที่เนื้อหาของ scrollview เพื่อให้สามารถมองเห็นได้บนหน้าจอที่ไม่ใช่รูปสี่เหลี่ยมผืนผ้า ฉันคิดว่าตอนนี้เราสามารถเห็นสิ่งนี้บน iPhone X Sim เท่านั้น
PhoneyDeveloper

8
ปัญหานี้เกิดจากข้อบกพร่องใน iOS 11 ที่ตั้งค่า safeAreaInsets ของมุมมองของตัวควบคุมมุมมองไม่ถูกต้องระหว่างการเปลี่ยนการนำทางซึ่งควรได้รับการแก้ไขใน iOS 11.2 การตั้งค่าcontentInsetAdjustmentBehaviorที่จะ.neverไม่ได้เป็นวิธีแก้ปัญหาที่ดีเพราะมันอาจจะมีผลข้างเคียงที่ไม่พึงประสงค์อื่น ๆ หากคุณใช้วิธีแก้ปัญหาคุณควรลบออกสำหรับ iOS เวอร์ชัน> = 11.2
smileyborg

23

นอกจากคำตอบของ maggy แล้ว

Objective-C

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

ปัญหานี้เกิดจากข้อบกพร่องใน iOS 11 ที่safeAreaInsetsมุมมองของตัวควบคุมมุมมองถูกตั้งค่าไม่ถูกต้องระหว่างการเปลี่ยนการนำทางซึ่งควรได้รับการแก้ไขใน iOS 11.2 การตั้งค่า contentInsetAdjustmentBehaviorที่จะ.neverไม่ได้เป็นวิธีแก้ปัญหาที่ดีเพราะมันอาจจะมีผลข้างเคียงที่ไม่พึงประสงค์อื่น ๆ หากคุณใช้วิธีแก้ปัญหาคุณควรลบออกสำหรับ iOS เวอร์ชัน> = 11.2

- กล่าวถึงโดย smileyborg (Software Engineer ที่ Apple)


6

คุณสามารถแก้ไขพฤติกรรมนี้พร้อมกันได้ตลอดทั้งแอปพลิเคชันโดยใช้ NSProxy ในตัวอย่างเช่น didFinishLaunchingWithOptions:

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

1
สิ่งนี้จะทำลายคอนโทรลเลอร์ของระบบเช่น UIImagePickerController
galway

6

นี่คือวิธีที่ฉันจัดการเพื่อแก้ไขปัญหานี้ได้ในขณะที่ยังช่วยให้ iOS 11 ชุดขุ่นโดยอัตโนมัติ ฉันใช้UITableViewController.

  • เลือก "ขยายขอบใต้แถบด้านบน" และ "ขยายขอบภายใต้แถบทึบแสง" ในตัวควบคุมมุมมองของคุณในสตอรีบอร์ด (หรือแบบเป็นโปรแกรม ) การแทรกพื้นที่ปลอดภัยจะป้องกันไม่ให้มุมมองของคุณอยู่ใต้แถบด้านบน
  • ตรวจสอบปุ่ม "Insets to Safe Area" บนมุมมองตารางของคุณในสตอรีบอร์ด (หรือtableView.insetsContentViewsToSafeArea = true) - สิ่งนี้อาจไม่จำเป็น แต่เป็นสิ่งที่ฉันทำ
  • ตั้งค่าพฤติกรรมการปรับแทรกเนื้อหาเป็น "แกนเลื่อน" (หรือtableView.contentInsetAdjustmentBehavior = .scrollableAxes) - .alwaysอาจใช้ได้เช่นกัน แต่ฉันไม่ได้ทดสอบ

อีกสิ่งหนึ่งที่ควรลองหากทุกอย่างล้มเหลว:

แทนที่viewSafeAreaInsetsDidChange UIViewControllerเมธอดเพื่อรับมุมมองตารางเพื่อบังคับให้ตั้งค่ามุมมองการเลื่อนแทรกไปยังส่วนแทรกพื้นที่ปลอดภัย ใช้ร่วมกับการตั้งค่า "ไม่เคย" ในคำตอบของ Maggy

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

หมายเหตุ: self.tableViewและself.viewควรเป็นสิ่งเดียวกันสำหรับUITableViewController


พยายามเกือบทุกอย่างในหัวข้อนี้และสิ่งนี้ได้ผลสำหรับฉัน TableViewVC ที่ฝังอยู่ใน TabBarVC ขอบคุณ!
Josh Wolff

3

สิ่งนี้ดูเหมือนข้อบกพร่องมากกว่าพฤติกรรมที่ตั้งใจไว้ เกิดขึ้นเมื่อแถบนำทางไม่โปร่งแสงหรือเมื่อตั้งค่าภาพพื้นหลัง

หากคุณเพิ่งตั้งค่า contentInsetAdjustmentBehavior เป็น. ไม่ว่าจะตั้งค่าการแทรกเนื้อหาบน iPhone X ไม่ถูกต้องเช่นเนื้อหาจะไปอยู่ที่ด้านล่างใต้แถบเลื่อน

จำเป็นต้องทำสองสิ่ง:
1. ป้องกันไม่ให้ scrollView เคลื่อนไหวขึ้นเมื่อกด / ป๊อป
2. รักษาพฤติกรรมอัตโนมัติเนื่องจากจำเป็นสำหรับ iPhone X หากไม่มีสิ่งนี้เช่นในแนวตั้งเนื้อหาจะอยู่ด้านล่างแถบเลื่อนด้านล่าง

วิธีแก้ปัญหาง่ายๆใหม่:ใน XIB: เพียงเพิ่ม UIView ใหม่ที่ด้านบนของมุมมองหลักของคุณโดยตั้งค่าด้านบนนำหน้าและต่อท้ายไปยัง superview และความสูงที่ตั้งค่าเป็น 0 คุณไม่จำเป็นต้องเชื่อมต่อกับมุมมองย่อยอื่น ๆ หรืออะไรเลย

โซลูชันเก่า:

หมายเหตุ: หากคุณใช้ UIScrollView ในโหมดแนวนอนมันยังไม่ได้ตั้งค่าการแทรกในแนวนอนอย่างถูกต้อง (ข้อผิดพลาดอื่น?) ดังนั้นคุณต้องปักหมุดนำหน้า / ต่อท้ายของ scrollView ไปที่ safeAreaInsets ใน IB

หมายเหตุ 2: วิธีแก้ปัญหาด้านล่างยังมีปัญหาว่าถ้า tableView เลื่อนไปด้านล่างและคุณดันตัวควบคุมและป๊อปกลับมันจะไม่อยู่ที่ด้านล่างอีกต่อไป

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 คืออะไร?
PhoneyDeveloper

มุมมองหลักของตัวควบคุมมุมมองของคุณฉันได้อัปเดตคำตอบแล้ว ขอบคุณ.
El Horrible

เมื่อฉันใช้ UITableViewController tableView คือมุมมองของตัวควบคุมมุมมอง นอกจากนี้สิ่งที่ใส่เข้าไปควรแตกต่างกันเมื่อหมุนอุปกรณ์ ฉันต้องการการปรับเปลี่ยน ฉันไม่ชอบภาพเคลื่อนไหวเมื่อ tableView ปรากฏขึ้นครั้งแรก
PhoneyDeveloper

ในกรณีของคุณเนื่องจาก UITableView เป็นมุมมองของคอนโทรลเลอร์จึงควรมี safeAreaInsets.bottom = 34 (แนวตั้ง) ดังนั้นคุณสามารถตั้งค่า tableView.contentInset = tableView.safeAreaInsets ได้
El Horrible

นั่นไม่ได้ผลสำหรับฉัน ใน viewDidLoad สิ่งที่ใส่เข้าไปทั้งหมดเป็นศูนย์ หากฉันพยายามใช้รหัสนั้นใน viewWillLayoutSubviews ตัวบ่งชี้การเลื่อนจะได้รับสิ่งที่ใส่เข้าไป แต่ tableView นั้นสามารถเลื่อนในแนวนอนได้ ถ้าฉันแค่ดูสิ่งที่ใส่เข้าไปใน viewWillLayoutSubviews โดยไม่ปิดการใช้งานการปรับค่า bottom adjustmentContentInset จะกลายเป็น 21 และนั่นคือทั้งหมดที่ดูเหมือนจะเปลี่ยนไป
PhoneyDeveloper


2

โปรดตรวจสอบให้แน่ใจว่าพร้อมกับรหัสด้านบนแล้วใส่รหัสเพิ่มเติมดังนี้ มันแก้ปัญหาได้

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

แค่นี้ก็แก้ปัญหาได้แล้ว !! ขอบคุณ. เสียเวลาไปหลายชั่วโมงกับปัญหานี้!
Murat Yasar

2

นอกจากนี้หากคุณใช้แถบแท็บเนื้อหาด้านล่างของมุมมองคอลเลกชันจะเป็นศูนย์ สำหรับสิ่งนี้ให้ใส่โค้ดด้านล่างใน viewDidAppear:

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

2

ในกรณีของฉันมันใช้งานได้ (วางไว้ใน viewDidLoad):

self.navigationController.navigationBar.translucent = YES;

1

การลบพื้นที่เพิ่มเติมที่ด้านบนcollectionViewหรือtableView

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

โค้ดด้านบนcollectionViewหรือtableViewอยู่ใต้แถบนำทาง
ด้านล่างรหัสป้องกันไม่ให้มุมมองคอลเลกชันไปที่การนำทาง

    self.edgesForExtendedLayout = UIRectEdge.bottom

แต่ฉันชอบที่จะใช้ตรรกะและโค้ดด้านล่างสำหรับUICollectionView

ค่าที่ใส่ขอบจะถูกนำไปใช้กับสี่เหลี่ยมผืนผ้าเพื่อย่อหรือขยายพื้นที่ที่แสดงโดยสี่เหลี่ยมผืนผ้านั้น โดยทั่วไปจะใช้การแทรกขอบในระหว่างเค้าโครงมุมมองเพื่อแก้ไขกรอบของมุมมอง ค่าบวกทำให้กรอบแทรก (หรือหด) ตามจำนวนที่ระบุ ค่าลบทำให้เฟรมเริ่มต้น (หรือขยาย) ตามจำนวนที่ระบุ

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

วิธีที่ดีที่สุดสำหรับ UICollectionView

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


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

ฉันใช้ UISearchController กับ resultsControllers แบบกำหนดเองที่มีมุมมองตาราง การผลักตัวควบคุมใหม่บนตัวควบคุมผลลัพธ์ทำให้ tableview อยู่ภายใต้การค้นหา

รหัสข้างต้นแก้ไขปัญหาได้ทั้งหมด

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.