วิธีซ่อนส่วนหัวส่วนแรกใน UITableView (สไตล์ที่จัดกลุ่ม)


108

เนื่องจากการออกแบบมุมมองตารางโดยใช้รูปแบบการจัดกลุ่มเปลี่ยนไปอย่างมากใน iOS 7 ฉันจึงต้องการซ่อน (หรือลบ) ส่วนหัวส่วนแรก จนถึงตอนนี้ฉันยังไม่ประสบความสำเร็จ

ค่อนข้างง่ายรหัสของฉันมีลักษณะดังนี้:

- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    if (section == 0)
        return 0.0f;
    return 32.0f;
}

- (UIView*) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    if (section == 0) {
        UIView* view = [[UIView alloc] initWithFrame: CGRectMake(0.0f, 0.0f, 640.0f, 0.0f)];
        return view;
    }
    return nil;
}

- (NSString*) tableView:(UITableView *) tableView titleForHeaderInSection:(NSInteger)section
{
    if (section == 0) {
        return nil;
    } else {
        // return some string here ...
    }
}

ถ้าฉันคืนค่าความสูงเป็น 0 อีกสองวิธีจะไม่ถูกเรียกด้วยดัชนีส่วน 0 แต่ส่วนหัวที่ว่างเปล่ายังคงวาดด้วยความสูงเริ่มต้น (ใน iOS 6 จะเรียกสองวิธีนี้อย่างไรก็ตามผลลัพธ์ที่มองเห็นได้จะเหมือนกัน)

ถ้าฉันส่งคืนค่าที่แตกต่างกันส่วนหัวของส่วนจะได้รับความสูงที่ระบุ

ถ้าฉันคืน 0.01 มันเกือบถูกต้อง อย่างไรก็ตามเมื่อฉันเปิด "ภาพไม่ตรงแนวสี" ในเครื่องจำลองจะทำเครื่องหมายเซลล์มุมมองตารางทั้งหมด (ซึ่งดูเหมือนว่าจะเป็นผลที่ตามมา)

คำตอบสำหรับคำถามUITableView: ซ่อนส่วนหัวจากส่วนว่างเปล่าดูเหมือนจะบ่งบอกว่ามีบางคนประสบความสำเร็จในการซ่อนส่วนหัวของส่วน แต่อาจใช้กับสไตล์ธรรมดา (แทนที่จะเป็นสไตล์ที่จัดกลุ่ม)

การประนีประนอมที่ดีที่สุดคือการคืนค่าความสูง 0.5 ส่งผลให้เส้นที่ค่อนข้างหนากว่าใต้แถบนำทาง อย่างไรก็ตามฉันจะขอบคุณถ้ามีใครรู้ว่าส่วนหัวส่วนแรกสามารถซ่อนไว้อย่างสมบูรณ์ได้อย่างไร

อัปเดต

จากการวิเคราะห์ของcaglar ( https://stackoverflow.com/a/19056823/413337 ) ปัญหาจะเกิดขึ้นก็ต่อเมื่อมีมุมมองตารางอยู่ในตัวควบคุมการนำทาง


ฉันไม่ได้รับส่วนนั้น => if (section == 0) return view; กลับศูนย์; เช่นส่งคืนมุมมองเมื่อเป็นส่วนแรกและไม่มีเป็นอย่างอื่น
เซน

แนวคิดคือการส่งคืนมุมมองที่มีความสูงเป็น 0 สำหรับส่วนแรกและคืนค่าศูนย์สำหรับส่วนอื่น ๆ ทั้งหมดเพื่อให้มุมมองตารางใช้มุมมองส่วนหัวเริ่มต้นสำหรับส่วนนั้น ศูนย์ส่วนหนึ่งไว้เป็นอย่างดีทำงาน; มุมมองตารางแสดงส่วนหัวสำหรับส่วนเหล่านี้ แต่ส่วนหนึ่งส่วน 0 section == 0ไม่เกี่ยวข้องเพราะวิธีการที่จะไม่เรียกว่ามี
Codo

1
คำตอบนี้ดูเหมือนจะสั้นและไพเราะ stackoverflow.com/a/23955420/3965
Mr Rogers

คำตอบ:


154

ฉันมีวิธีแก้ปัญหาที่ดูเหมือนจะสะอาดพอสมควรสำหรับฉัน ดังนั้นฉันจึงตอบคำถามของตัวเอง

เนื่องจาก 0 เนื่องจากความสูงของส่วนหัวแรกไม่ทำงานฉันจึงส่งคืน 1 จากนั้นฉันใช้contentInsetเพื่อซ่อนความสูงนั้นไว้ใต้แถบนำทาง

วัตถุประสงค์ -C:

- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    if (section == 0)
            return 1.0f;
    return 32.0f;
}

- (NSString*) tableView:(UITableView *) tableView titleForHeaderInSection:(NSInteger)section
{
    if (section == 0) {
        return nil;
    } else {
        // return some string here ...
    }
}

- (void) viewDidLoad
{
    [super viewDidLoad];

     self.tableView.contentInset = UIEdgeInsetsMake(-1.0f, 0.0f, 0.0f, 0.0);
}

รวดเร็ว:

override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return section == 0 ? 1.0 : 32
}

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.contentInset = UIEdgeInsets(top: -1, left: 0, bottom: 0, right: 0)
}

6
การใช้ความสูงส่วนหัว 0.1f จะดีกว่าในการซ่อน
Chuck Krutsinger

4
ฉันได้ลองใช้ 0.1f แต่ผลที่ได้คือภาพวาดไม่ได้จัดแนวพิกเซลอีกต่อไปทำให้ภาพเบลอและประสิทธิภาพลดลง ลองใช้ในเครื่องจำลอง: มีตัวเลือกในการเน้นการจัดตำแหน่งที่มีปัญหา
Codo

31
อันที่จริงการนำไปใช้งานที่ดีกว่า (มีโอกาสน้อยที่จะพังในอนาคต) คือการใช้CGFLOAT_MINแทนค่าแบบฮาร์ดโค้ด กล่าวอีกนัยหนึ่งไม่ควรทำreturn 1.0fหรือ0.1fแทนreturn CGFLOAT_MINหาก Apple เคยเปลี่ยนค่าต่ำสุดที่ยอมรับได้คุณจะมีรหัสให้เปลี่ยนหากคุณฮาร์ดโค้ดค่าส่งคืน นอกจากนี้คุณยังไม่รู้ว่าคุณใช้ค่าที่น้อยที่สุดเท่าที่จะเป็นไปได้หรือไม่ เมื่อใช้ค่าคงที่ที่กำหนดคุณจะรับประกันได้ว่าจะใช้ค่าที่น้อยที่สุดเท่าที่จะเป็นไปได้และโค้ดของคุณจะรอดจากการเปลี่ยนแปลงของระบบปฏิบัติการ
Chris Ostmo

11
@ คริส: ฉันกลัวว่าคุณจะไม่เข้าใจ ฉันไม่ส่งคืนค่าที่น้อยมาก แต่มีขนาดหลายเท่าของพิกเซลเพื่อให้ภาพวาดยังคงเรียงพิกเซล (เพื่อประสิทธิภาพที่ดีและความคมชัด) จากนั้นฉันก็ชดเชยโดยใช้สิ่งที่ใส่เข้าไปในเนื้อหา สิ่งนี้ไม่น่าจะเปลี่ยนแปลงในอนาคตเนื่องจากเป็นระยะที่มองเห็นได้ชัดเจนและไม่ใช่สิ่งที่ระบบปฏิบัติการจะเพิกเฉย
Codo

8
+1 สำหรับการไม่ใช้ค่าพิกเซลเศษเป็นออฟเซ็ต UI
Ricardo Sanchez-Saez

52

นี่คือวิธีซ่อนส่วนหัวส่วนแรกใน UITableView (สไตล์ที่จัดกลุ่ม)

โซลูชัน Swift 3.0 & Xcode 8.0

  1. ผู้รับมอบสิทธิ์ของ TableView ควรใช้เมธอด heightForHeaderInSection

  2. ภายในเมธอด heightForHeaderInSection ให้ส่งกลับจำนวนบวกน้อยที่สุด (ไม่ใช่ศูนย์!)

    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    
        let headerHeight: CGFloat
    
        switch section {
        case 0:
            // hide the header
            headerHeight = CGFloat.leastNonzeroMagnitude
        default:
            headerHeight = 21
        }
    
        return headerHeight
    }

6
การส่งคืน CGFloat.leastNonzeroMagnitude แทน 0 ช่วยฉัน ขอบคุณ!
anoo_radha

คำตอบที่สมบูรณ์แบบขอบคุณ
ปิแอร์

อย่างไรก็ตามCGFLOAT_MINสำหรับobjcนั้นเหมือนกับCGFloat.leastNonzeroMagnitudeในSwift
DawnSong

36

คำตอบนั้นตลกมากสำหรับฉันและทีมของฉันและทำงานได้อย่างมีเสน่ห์

  • ในตัวสร้างอินเทอร์เฟซเพียงแค่ย้ายมุมมองตารางภายใต้มุมมองอื่นในลำดับชั้นของมุมมอง

เหตุผล:

เราตั้งข้อสังเกตว่านี้เกิดขึ้นเฉพาะสำหรับดูเป็นครั้งแรกในลำดับชั้นดูถ้านี้มุมมองแรกเป็น UITableView ดังนั้น UITableView ที่คล้ายกันอื่น ๆ ทั้งหมดจึงไม่มีส่วนที่น่ารำคาญนี้ยกเว้นส่วนแรก เราพยายามย้าย UITableView ออกจากตำแหน่งแรกในลำดับชั้นมุมมองและทุกอย่างก็ทำงานตามที่คาดไว้


1
คุณยังคงมีเอฟเฟกต์กระจกฝ้าของแถบนำทางเมื่อคุณเลื่อนมุมมองตารางหรือไม่?
Codo

คุณจะมีเอฟเฟกต์เบลอนี้เมื่อคุณตั้งค่า tableView ของคุณตามนั้น คุณต้องตั้งค่าเป็นcontentInsetตัวอย่าง{0, 64, 0, 0}เพื่อให้มีออฟเซ็ต 64px จากด้านบน (แถบสถานะบวกแถบนำทาง) ต้องแนบ tableView ที่ด้านบนของหน้าจอไม่ใช่ topLayoutGuide (เพื่อให้มันไปถึงใต้แถบนำทาง)
Julian F. Weinert

หากคุณไม่ได้ใช้การดึงเพื่อรีเฟรชสิ่งนี้จะดูดี
Michael

2
ว้าว. สิ่งนี้ใช้ได้ผลกับฉันใน iOS 9 และทำให้ฉันรู้สึกแย่
จัดสรร

นี่ควรเป็นคำตอบที่ได้รับการยอมรับ ช่างเป็นข้อผิดพลาดแปลก ๆ !
Oded Harth

25

ใช้เคล็ดลับนี้สำหรับ tableView ประเภทจัดกลุ่ม

คัดลอกวางโค้ดด้านล่างสำหรับมุมมองตารางของคุณในเมธอดviewDidLoad :

tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, tableView.bounds.size.width, 0.01f)];

ฉันยังไม่ได้ลอง แต่ฉันสงสัยว่าโซลูชันนี้มีข้อเสียเช่นเดียวกับโซลูชันที่เสนออื่น ๆ : ภาพวาดไม่ได้จัดแนวพิกเซลอีกต่อไปทำให้ภาพเบลอและประสิทธิภาพลดลง เครื่องจำลองสามารถเปิดเผยได้: มีตัวเลือกในการเน้นการจัดตำแหน่งที่มีปัญหา อย่างไรก็ตามหากปัดเศษเป็น 0 แสดงว่าเป็นทางออกที่ดีอย่างแน่นอน
Codo

ใช่ฉันเดาว่ามันจะปัดเศษเป็น 0 เพราะฉันใช้มันหลายครั้ง แต่ไม่พบความเบลอในภาพวาด
Nitesh Borad

TableHeaderView และ Section Header view? อะไรคือความแตกต่าง
AsifHabib

หรือสั้นกว่าเล็กน้อย: _tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 1)].
mojuba

@AsifHabib: tableHeaderView ถูกวางไว้ที่ด้านบนสุดขององค์ประกอบตารางทั้งหมด เป็นมุมมองส่วนหัวของตารางเอง และมุมมองส่วนหัวเป็นมุมมองที่จะวางในแต่ละส่วน สามารถมีมุมมองส่วนหัวหลายส่วนตามจำนวนส่วนที่ระบุในตาราง แต่จะมีเพียงมุมมองส่วนหัวตารางเดียว
Nitesh Borad

21

วิธีนี้ใช้ได้

override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    if section == 0 {
        return CGFloat.min
    }
    return 25
}

override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    if section == 0 {
        return nil
    }else {
        ...
    }
}

2
นี่เป็นรูปแบบที่ดีของโซลูชันของฉันยกเว้นว่าจะใช้ค่าเศษส่วน ด้วยวิธีนี้ข้อความและรูปภาพจะไม่จัดแนวพิกเซลอีกต่อไปการวาดภาพจะช้าลงและผลลัพธ์อาจเบลอได้ เครื่องจำลองมีตัวเลือก "สีไม่ตรงแนวภาพ" เพื่อเปิดเผยปัญหานี้
Codo

ใช้งานได้ดีสำหรับคนอย่างฉันที่ใช้เซลล์แบบคงที่ด้วย containerView
thibaut noah

3
Swift 3> 'CGFloat.min' ถูกเปลี่ยนชื่อเป็น 'CGFloat.leastNormalMagnitude'
rjobidon

6

ฉันเพิ่งคัดลอกรหัสของคุณและลองแล้ว มันทำงานได้ตามปกติ (พยายามในโปรแกรมจำลอง) ฉันแนบมุมมองผลลัพธ์ คุณต้องการมุมมองแบบนั้นใช่ไหม? หรือฉันเข้าใจปัญหาของคุณผิด?

ใส่คำอธิบายภาพที่นี่


1
ใช่นั่นคือสิ่งที่ฉันต้องการโดยทั่วไปยกเว้นมุมมองตารางของฉันอยู่ในตัวควบคุมการนำทาง สิ่งนี้สามารถสร้างความแตกต่างได้หรือไม่?
Codo

2
ฉันเพิ่ม tableView ไปยังตัวควบคุมการนำทางและสถานการณ์ของคุณจะปรากฏขึ้น :) ฉันคิดว่าใน iOS 7 การแก้ไขความสูงส่วนหัวนี้เป็นค่าเริ่มต้นในมุมมองตารางสไตล์แบบกลุ่ม โดยการเปลี่ยนเฟรมของ tableView มุมมองส่วนหัวแรกอาจถูกซ่อนไว้ (เช่น set x = 0 y = -40) อย่างไรก็ตามฉันรู้ว่าการแก้ปัญหานี้ไม่ใช่ทางออกที่ดี
caglar

1
ขอบคุณมากสำหรับผลงานของคุณ ดังนั้นดูเหมือนว่าปัญหาจะเกิดขึ้นก็ต่อเมื่อมุมมองตารางใช้สไตล์ที่จัดกลุ่มและอยู่ในตัวควบคุมการนำทาง
Codo

พยายามเปลี่ยนจาก viewcontroller เป็น tableviewcontroller ฉันไม่สามารถแก้ไขปัญหากับส่วนหัวได้ บางทีฉันอาจพลาดบางอย่างที่พยายามจะแปลงมัน (iOS 7.0.3 ซิม)
Evgeni Petrov

1
ปัญหานี้ปรากฏในภาพรวมนี้เช่นกัน! เซลล์ที่ 0 ไม่ได้เริ่มจาก x: 0.0f & y: 0.0f
Burhanuddin Sunelwala

6

Swift3: heightForHeaderInSection ทำงานร่วมกับ 0 คุณเพียงแค่ต้องตรวจสอบให้แน่ใจว่าส่วนหัวถูกตั้งค่าเป็น clipsToBounds

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
       return 0
}

หากคุณไม่ได้ตั้งค่าส่วนหัวที่ซ่อนไว้ของ clipsToBounds จะมองเห็นได้เมื่อเลื่อน

func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
    guard let header = view as? UITableViewHeaderFooterView else { return }

    header.clipsToBounds = true
}

1
clipsToBound = true มีความสำคัญมากหากคุณวางแผนที่จะซ่อนมุมมองส่วนหัวของส่วนทั้งหมด การตั้งค่าความสูงเป็น 0 / CGFLOAT_MIN นั้นไม่เพียงพอ
Altimac

5

อัปเดต [9/19/17]: คำตอบเก่าใช้ไม่ได้กับฉันอีกต่อไปใน iOS 11 ขอบคุณ Apple สิ่งต่อไปนี้ทำ:

self.tableView.sectionHeaderHeight = UITableViewAutomaticDimension;
self.tableView.estimatedSectionHeaderHeight = 20.0f;
self.tableView.contentInset = UIEdgeInsetsMake(-18.0, 0.0f, 0.0f, 0.0);

คำตอบก่อนหน้า:

ตามที่โพสต์ไว้ในความคิดเห็นโดยChris Ostomoสิ่งต่อไปนี้ใช้ได้ผลกับฉัน:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return CGFLOAT_MIN; // to get rid of empty section header
}

ฉันสงสัยว่าเนื้อหาของมุมมองตารางของคุณไม่ได้จัดแนวพิกเซลอีกต่อไปทำให้เบลอและประสิทธิภาพลดลง เครื่องจำลองสามารถเปิดเผยได้: มีตัวเลือกในการเน้นการจัดตำแหน่งที่มีปัญหา อย่างไรก็ตามหากปัดเศษเป็น 0 แสดงว่าเป็นทางออกที่ดีอย่างแน่นอน
Codo

ไม่ฉันไม่ได้สังเกตเห็นปัญหาเกี่ยวกับเนื้อหาใด ๆ ข้อ จำกัด ดูเหมือนดี
Manindra Moharana

1
เวล! ไม่ทำงานใน iOS 11 อีกต่อไป! การแก้ไขของฉันใช้เวลาไม่ถึงหนึ่งสัปดาห์ ..
😞

4

นี่คือวิธีการกำจัดส่วนหัวของส่วนบนสุดใน UITableView แบบจัดกลุ่มใน Swift:

tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: CGFloat.leastNormalMagnitude))

3

ใน Swift 4.2 และเวอร์ชันก่อนหน้าจำนวนมากแทนที่จะตั้งค่าความสูงของส่วนหัวแรกเป็น 0 เหมือนในคำตอบอื่น ๆ คุณสามารถตั้งค่าส่วนหัวอื่น ๆ เป็นnilได้ สมมติว่าคุณมีสองส่วนและต้องการให้ส่วนที่สอง (กล่าวคือ1) มีส่วนหัวเท่านั้น ส่วนหัวนั้นจะมีข้อความFoobar :

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return section == 1 ? "Foobar" : nil
}

3

ลองทำเช่นนี้หากคุณต้องการลบส่วนหัวทั้งหมดออกทั้งหมด

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return CGFloat.leastNormalMagnitude
}

func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
    return CGFloat.leastNormalMagnitude
}

นั่นคือสิ่งที่ฉันต้องการ ทางออกที่ง่ายและสะดวก 1+
iGhost

0

ฉันยังไม่สามารถแสดงความคิดเห็นได้ แต่คิดว่าจะเพิ่มว่าถ้าคุณมีUISearchControllerตัวควบคุมUISearchBarของคุณเป็นของคุณtableHeaderViewการตั้งค่าความสูงของส่วนแรกเป็น 0heightForHeaderInSectionจะใช้งานได้จริง

ฉันใช้ self.tableView.contentOffset = CGPointMake(0, self.searchController.searchBar.frame.size.height);เพื่อให้แถบค้นหาถูกซ่อนโดยค่าเริ่มต้น

ผลลัพธ์คือไม่มีส่วนหัวสำหรับส่วนแรกและการเลื่อนลงจะแสดงแถบค้นหาเหนือแถวแรก


0

วิธีที่ง่ายที่สุดคือการย้อนกลับnilหรือ""ในfunc tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?ส่วนที่คุณไม่ต้องการแสดงส่วนหัว


0

เวอร์ชัน Swift: Swift 5.1
ส่วนใหญ่คุณสามารถตั้งค่าความสูงใน tableView delegate ได้ดังนี้:

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
   return UIView(frame: CGRect(x: 0, y: 0, width: view.width, height: CGFloat.leastNormalMagnitude))
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
   return CGFloat.leastNormalMagnitude
}

บางครั้งเมื่อคุณสร้าง UITableView ด้วย Xib หรือ Storyboard คำตอบของอัพจะไม่ได้ผล คุณสามารถลองวิธีที่สอง:

let headerView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: CGFloat.leastNormalMagnitude))
self.tableView.tableHeaderView = headerView

หวังว่าจะเหมาะกับคุณ!


0

สิ่งต่อไปนี้ใช้ได้กับฉันใน iOS 13.6 และ Xcode 11.6 พร้อมกับUITableViewControllerที่ฝังอยู่ในUINavigationController:

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    nil
}

override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    .zero
}

ไม่จำเป็นต้องใช้กลอุบายอื่น ๆ overrideคำหลักไม่จำเป็นเมื่อไม่ได้ใช้UITableViewController(เช่นเมื่อเพียงแค่ดำเนินการUITableViewDelegateวิธีการ) แน่นอนว่าหากเป้าหมายคือการซ่อนเพียงส่วนหัวของส่วนแรกตรรกะนี้อาจรวมอยู่ในเงื่อนไขดังนี้:

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    if section == 0 {
        return nil
    } else {
        // Return some other view...
    }
}

override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    if section == 0 {
        return .zero
    } else {
        // Return some other height...
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.