เปลี่ยนพฤติกรรมการเลื่อนเริ่มต้นของส่วนหัวของ UITableView


147

ฉันมี UITableView ที่มีสองส่วน มันเป็นมุมมองตารางที่เรียบง่าย ฉันใช้ viewForHeaderInSection เพื่อสร้างมุมมองที่กำหนดเองสำหรับส่วนหัวเหล่านี้ จนถึงตอนนี้ดีมาก

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

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

ฉันขาดอะไรที่ชัดเจนหรือไม่

ขอบคุณ


1
นั่นเป็นคำถามที่ดีที่สุดข้อหนึ่งในเว็บไซต์นี้! :) ขอบคุณ
Fattie

1
ตรวจสอบที่นี่สำหรับวิธีการที่เหมาะสมเพื่อให้บรรลุผลนี้stackoverflow.com/a/13735238/1880899
สุ Anantwar

คำตอบ:


175

วิธีที่ฉันแก้ไขปัญหานี้คือการปรับค่าcontentOffsetตามcontentInsetในUITableViewControllerDelegate(ขยายUIScrollViewDelegate) ดังนี้:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
       CGFloat sectionHeaderHeight = 40;
   if (scrollView.contentOffset.y<=sectionHeaderHeight&&scrollView.contentOffset.y>=0) {
       scrollView.contentInset = UIEdgeInsetsMake(-scrollView.contentOffset.y, 0, 0, 0);
   } else if (scrollView.contentOffset.y>=sectionHeaderHeight) {
       scrollView.contentInset = UIEdgeInsetsMake(-sectionHeaderHeight, 0, 0, 0);
   }
}

ปัญหาเดียวที่นี่คือมันเด้งเล็กน้อยเมื่อเลื่อนกลับไปด้านบน


{NOTE: ส่วน "40" ควรมีความสูงที่แน่นอนของหัวข้อ 0 ของคุณ หากคุณใช้ตัวเลขที่สูงกว่าความสูงส่วนหัว 0 ของคุณคุณจะเห็นว่าการใช้นิ้วสัมผัสนั้นได้รับผลกระทบ (ลองเช่น "1,000" และคุณจะเห็นว่าพฤติกรรมการตีกลับนั้นแปลกประหลาดที่ด้านบนสุด) ถ้าตัวเลขตรงกับส่วนหัวของคุณสูง 0 ส่วนความรู้สึกนิ้วน่าจะสมบูรณ์หรือใกล้สมบูรณ์}


1
โซลูชั่นที่สมบูรณ์แบบกว่าข้างต้น
prathumca

4
ขอบคุณ! นี่เป็นโซลูชั่นที่สมบูรณ์แบบ คุณมีทางออกสำหรับส่วนท้ายหรือไม่?
Tuan Nguyen

12
วิธีนี้ไม่สามารถจัดการกับ tap-on-menubar ได้อย่างถูกต้องซึ่งควรจะเลื่อนไปที่ด้านบนของรายการ
Reid Ellis

หากคุณต้องการพฤติกรรมเดียวกันสำหรับมุมมองส่วนท้ายเพียงแค่เปลี่ยนบรรทัดสุดท้ายเช่นนี้ scrollView.contentInset = UIEdgeInsetsMake (0, 0, หัวข้อส่วนสูง, 0)
alex

สิ่งนี้น่าจะเพียงพอ: scrollView.contentInset = UIEdgeInsetsMake (scrollView.contentOffset.y> = 0? -scrollView.contentOffset.y: 0, 0, 0, 0);
MacMark

85

คุณยังสามารถเพิ่มส่วนที่มีศูนย์แถวที่ด้านบนและใช้ส่วนท้ายของส่วนก่อนหน้าเป็นส่วนหัวสำหรับส่วนต่อไป


13
ในกรณีของฉันที่ฉันมีมากกว่า 2 ส่วนท้ายจะเบรกที่ด้านล่าง ..
โจเซฟหลิน

3
นี่เป็นความคิดสร้างสรรค์ แต่คุณต้องปรับ indexPath หากคุณใช้ NSFetchedResultsController เพื่อโหลดตาราง
XJones

+1 โดยไกลทางออกที่ดีที่สุด - พาฉันเหมือน 3 บรรทัดเพื่อใช้!
Jon

Brilliant Brilliant Brilliant :-)
iphonic

มันจะทำงานอย่างไรสำหรับส่วนท้ายของเบรกนั้น จะขอบคุณความช่วยเหลือ! ขอบคุณ
darwindeeds

36

หากฉันทำสิ่งนี้ฉันจะใช้ประโยชน์จากความจริงที่ว่า UITableViews ในรูปแบบ Plain มีส่วนหัวที่เหนียวและแบบ Grouped ไม่มี อย่างน้อยฉันก็อาจลองใช้เซลล์ตารางแบบกำหนดเองเพื่อเลียนแบบลักษณะของเซลล์ธรรมดาในตารางแบบกลุ่ม

ฉันไม่ได้ลองสิ่งนี้จริง ๆ ดังนั้นมันอาจไม่ทำงาน แต่นั่นคือสิ่งที่ฉันแนะนำให้ทำ


อาจใช้งานได้ แต่เคยลองมาแล้วหรือไม่ และดูเหมือนว่าจะทำงานมากมายเมื่อคำตอบของ @ voidStern ทำงานได้อย่างสมบูรณ์แบบ !!
bentford

คำตอบของ voidStern ไม่ได้ผลสำหรับฉันเมื่อฉันมีมากกว่าสองส่วน คำตอบของโคลินนั้นง่ายกว่าและสวยงามกว่าโดยไม่จำเป็นต้องเปลี่ยนหมายเลขหมวดด้วยตนเองและเพิ่มจำนวนหมวด
Joseph Lin

เคล็ดลับ: ใช้tableView.separatorColor = [UIColor clearColor];เพื่อเลียนแบบมุมมองตารางธรรมดา
Joseph Lin

3
ฉันพยายามทำสิ่งนี้ แต่เมื่อฉันไม่สามารถทำให้เซลล์ตารางที่จัดกลุ่มมีลักษณะเหมือนเซลล์ธรรมดาเช่นลบขอบซ้ายและขวาทั้งสองด้านของเซลล์ คุณทำสิ่งนี้ได้อย่างไร
Adam Carter

1
ขอบคุณมากที่ทำให้สิ่งที่ชัดเจนเกี่ยวกับ UITableViewStyle เช่นการจัดกลุ่มและธรรมดาซึ่งตัดสินใจว่าส่วนหัว / ส่วนท้ายของ tableview จะเหนียวหรือไม่ ขอขอบคุณ @Colin Barrett
Dhaval H. Nena

28

ฉันรู้ว่ามันมาสาย แต่ฉันได้พบทางออกที่ชัดเจนแล้ว!

สิ่งที่คุณต้องการทำคือถ้าคุณมี 10 ส่วนให้ dataSource คืนค่า 20 ใช้เลขคู่สำหรับส่วนหัวและเลขคี่สำหรับเนื้อหาส่วน อะไรแบบนี้

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (section%2 == 0) {
        return 0;
    }else {
        return 5;
    }
}

-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    if (section%2 == 0) {
        return [NSString stringWithFormat:@"%i", section+1];
    }else {
        return nil;
    }
}

Voila! : D


ความคิดที่ดี. แต่ถ้าคุณมีชื่อส่วนดัชนีฉันสงสัยว่าสิ่งนี้จะทำให้พวกเขาสับสน
roocell

ทำไม? คุณสามารถทำเช่นเดียวกันกับชื่อหัวข้อ เพียงจำศูนย์สำหรับเลขคี่และชื่อสำหรับเลขคู่
LocoMike

1
ใช่ - วิธีนี้ใช้งานได้ดี มันเป็นการทำบัญชีจำนวนมาก (อาจเกี่ยวข้องกับวิธีที่ฉันต้องได้รับชื่อหมวด) แต่มันก็ใช้ได้ เคล็ดลับคือ numberOfRowsInSection และ cellForRowAtIndexPath ใช้ถ้า (ส่วน% 2! = 0 && ส่วน! = 0) ในขณะที่ฟังก์ชั่น titleForHeaderInSection และส่วนดัชนีอื่น ๆ ใช้ถ้า (ส่วน% 2 == 0)
roocell

ผู้สร้างควรเลือกสิ่งนี้เป็นคำตอบ มันจะดีถ้ามีวิธี subclass uitableview ในการยึดชื่อหัวข้อโดยอัตโนมัติ
roocell

สิ่งนี้ทำงานได้ดีที่สุดสำหรับฉัน ฉันลองใช้วิธีแก้ปัญหาของ @ Colin ก่อน แต่มันก็ไม่ได้ผลกับการปรับแต่งUITableViewที่ฉันใช้
kubi

15

มีหลายสิ่งที่ต้องทำเพื่อแก้ไขปัญหานี้ในลักษณะที่ไม่แฮ็ค:

  1. ตั้งค่าลักษณะมุมมองตารางเป็น UITableViewStyleGrouped
  2. ตั้งค่ามุมมองตารางbackgroundColorเป็น[UIColor clearColor]
  3. ตั้งค่าbackgroundViewเซลล์ในมุมมองตารางแต่ละตารางให้เป็นมุมมองว่างเปล่าด้วยbackgroundColor [UIColor clearColor]
  4. หากจำเป็นให้กำหนดมุมมองตารางrowHeightอย่างเหมาะสมหรือแทนที่tableView:heightForRowAtIndexPath:หากแต่ละแถวมีความสูงต่างกัน

(+1) @Neil ฉันลองตอบ แต่น่าเสียดายสำหรับUITableViewStyleGroupedเซลล์ตารางมีระยะขอบพิเศษที่เปลี่ยนการจัดแนวด้วยส่วนหัว ปัญหานี้เป็นปัญหาเมื่อคุณต้องการแสดงตารางหลายคอลัมน์และใช้ส่วนหัวเพื่อแสดงชื่อคอลัมน์ (จากนั้นให้รายการตารางแต่ละรายการสอดคล้องกับชื่อเรื่องเหล่านี้)
brainjam

15

โพสต์ครั้งแรกที่นี่วิธีแก้ปัญหาอย่างรวดเร็วโดยใช้ IB เดียวกันสามารถทำได้โดยทางโปรแกรม แต่ค่อนข้างง่าย

วิธีที่ง่ายกว่าในการบรรลุเป้าหมายนี้ (โดยใช้ IB):

ลาก UIView ลงบน TableView ของคุณเพื่อทำให้เป็นมุมมองส่วนหัว

  1. ตั้งค่าความสูงของมุมมองส่วนหัวนั้นเป็น 100px
  2. ตั้งค่า tableview contentInset (top) เป็น -100
  3. ส่วนหัวของส่วนนี้จะเลื่อนเหมือนเซลล์ทั่วไป

บางคนแสดงความคิดเห็นที่บอกว่าวิธีนี้ซ่อนส่วนหัวแรก แต่ฉันไม่ได้สังเกตเห็นปัญหาดังกล่าว มันทำงานได้อย่างสมบูรณ์แบบสำหรับฉันและเป็นวิธีที่ง่ายที่สุดที่ฉันเคยเห็น


โปรดทราบว่าคุณควรตั้งค่ามุมมองให้ใช้สีพื้นหลังของสีที่ชัดเจนมิฉะนั้นถ้าคุณเลื่อนผ่านด้านบนที่คุณเห็นสีขาวในการตีกลับ
Doc

3
มันซ่อนส่วนหัวแรกของฉัน
Leena

Leena คุณใช้ iOS เวอร์ชันใด มุมมองเป็น UITableViewController หรือ UIView ที่มี UITableView อยู่หรือไม่ ฉันไม่แน่ใจว่าทำไมสำหรับบางคนโซลูชันนี้ซ่อนส่วนหัวแรกดังนั้นฉันจึงพยายามค้นหาความแตกต่าง
Doc

โซลูชั่นนี้สมบูรณ์แบบ ฉันกำลังมองหาพื้นหลังของเซลล์ด้านบนและล่างที่ไม่มีที่สิ้นสุด - สิ่งนี้ทำให้มันสำเร็จ ดี!
Taylor Halliday

วิธีนี้ดีมาก ง่ายกว่าสำเร็จมากกว่าคำตอบอื่น ๆ ในหัวข้อนี้ ในความคิดของฉันนี้ควรเป็นคำตอบที่ยอมรับ
John Rogers

15

ฉันไม่พอใจกับวิธีแก้ไขที่อธิบายไว้ที่นี่ดังนั้นฉันจึงพยายามรวมมันเข้าด้วยกัน ผลลัพธ์คือโค้ดต่อไปนี้ซึ่งได้รับแรงบันดาลใจจาก @awulf และ @cescofry มันใช้งานได้สำหรับฉันเพราะฉันไม่มีส่วนหัวของมุมมองตารางจริง หากคุณมีส่วนหัวมุมมองตารางอยู่แล้วคุณอาจต้องปรับความสูง

// Set the edge inset
self.tableView.contentInset = UIEdgeInsetsMake(-23.0f, 0, 0, 0);

// Add a transparent UIView with the height of the section header (ARC enabled)
[self.tableView setTableHeaderView:[[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 23.0f)]];

นี่เป็นวิธีที่ง่ายที่สุดที่ฉันพบ
Zorayr

สิ่งนี้ใช้ได้กับฉันใน iOS9.2 ดังนั้นถึงแม้ว่าจะเป็นคำตอบที่เก่ากว่า แต่ก็ยังใช้ได้ และมันไม่ได้ซ่อนส่วนหัวของส่วนแรก ทำงานและทำงานได้อย่างสมบูรณ์แบบ
idStar

สมบูรณ์ หาก tableview ของคุณมีส่วนหัวอยู่แล้วเพียงเพิ่มความสูงด้วยออฟเซ็ตจากนั้นเพิ่มค่าคงที่ข้อ จำกัด สูงสุดของเนื้อหาส่วนหัวเพื่อย้ายเนื้อหาลงไปที่ตำแหน่งเดิม
เจสัน

14

เพียงเปลี่ยนสไตล์ TableView:

self.tableview = [[UITableView alloc] initwithFrame:frame style:UITableViewStyleGrouped];

เอกสารประกอบ UITableViewStyle :

UITableViewStylePlain- มุมมองตารางธรรมดา ส่วนหัวหรือท้ายกระดาษของส่วนใด ๆ จะแสดงเป็นตัวคั่นอินไลน์และลอยเมื่อมุมมองตารางถูกเลื่อน

UITableViewStyleGrouped- มุมมองตารางที่มีส่วนนำเสนอกลุ่มของแถวที่แตกต่างกัน ส่วนหัวและท้ายกระดาษไม่ลอย


คำตอบที่ดีทำงานให้ฉัน ไม่จำเป็นต้องมีการทำงานใด ๆ
Shams Ahmed

9

เลือกสไตล์ TableView ที่จัดกลุ่ม

เลือกสไตล์มุมมองตารางที่จัดกลุ่มจากตัวตรวจสอบแอตทริบิวต์ TableView ของคุณในกระดานเรื่องราว


5

ตั้งค่า headerView ของตารางด้วยมุมมองโปร่งใสที่มีความสูงเท่ากันของส่วนหัวในมุมมองส่วน เริ่มต้น tableview ด้วย ay frame ที่ -height

self.tableview = [[UITableView alloc] initWithFrame:CGRectMake(0, - height, 300, 400)];

UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, width, height)] autorelease];
[self.tableView setTableHeaderView:headerView];

4

ฉันพบโซลูชันทางเลือกใช้เซลล์แรกของแต่ละส่วนแทนส่วนหัวจริงโซลูชันนี้ไม่ปรากฏว่าสะอาด แต่ทำงานได้ดีคุณสามารถใช้เซลล์ต้นแบบที่กำหนดไว้สำหรับส่วนหัวของคุณและในวิธีcellForRowAtIndexPathขอ indexPath.row == 0 ถ้าเป็นจริงให้ใช้เซลล์ต้นแบบส่วนหัวมิฉะนั้นใช้เซลล์ต้นแบบเริ่มต้นของคุณ


หากคุณยังคงต้องการทำงานกับindexPath.row& indexPath.sectionโปรดตรวจสอบให้แน่ใจว่าคุณได้รับส่วนสูง0.0fเพื่อ- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)sectionให้ส่วนหัวของคุณมองไม่เห็น
ซุป

4

เปลี่ยนสไตล์ TableView ของคุณ:

self.tableview = [[UITableView alloc] initwithFrame:frame style:UITableViewStyleGrouped];

ตามเอกสารของ apple สำหรับ UITableView:

UITableViewStylePlain- มุมมองตารางธรรมดา ส่วนหัวหรือท้ายกระดาษของส่วนใด ๆ จะแสดงเป็นตัวคั่นอินไลน์และลอยเมื่อมุมมองตารางถูกเลื่อน

UITableViewStyleGrouped- มุมมองตารางที่มีส่วนนำเสนอกลุ่มของแถวที่แตกต่างกัน ส่วนหัวและท้ายกระดาษไม่ลอย หวังว่าการเปลี่ยนแปลงเล็ก ๆ นี้จะช่วยคุณได้ ..


2

ตอนนี้สไตล์ที่จัดกลุ่มดูเหมือนจะเป็นสไตล์ธรรมดาใน iOS 7 (ในแง่ของความเรียบและพื้นหลัง) สำหรับเราการแก้ไขที่ดีที่สุดและง่ายที่สุด (เช่นแฮ็กน้อยที่สุด) คือการเปลี่ยนสไตล์ของมุมมองตารางเป็นการจัดกลุ่ม การต่อกับ contentInsets เป็นปัญหาเสมอเมื่อเรารวมแถบนำทางแบบเลื่อนออกไปที่ด้านบน ด้วยลักษณะมุมมองตารางที่จัดกลุ่มจะมีลักษณะเหมือนกัน (กับเซลล์ของเรา) และส่วนหัวของส่วนจะคงที่ ไม่มีความแปลกในการเลื่อน


นี่เป็นทางออกที่ดีที่สุดโดยเฉพาะอย่างยิ่งถ้าเซลล์มีการกำหนดเองดูเหมือนว่าจะหยุด "ถือ" ของส่วนหัวของส่วนเมื่อเลื่อนไปด้านบน
เหล็กรีไซเคิล

1

กำหนดสิ่งที่ใส่เข้าไปใน tableView ของคุณ หากคุณมีส่วนหัวสูง 22px และคุณไม่ต้องการให้เหนียวเมื่อคุณโหลดใหม่เพิ่มข้อมูล:

self.tableView.contentInset = UIEdgeInsetsMake(-22, 0, 0, 0); 
self.tableView.contentSize = CGSizeMake(self.tableView.contentSize.width, self.tableView.contentSize.height+22); 

ทำงานเหมือนจับใจสำหรับฉัน ใช้งานได้กับส่วนท้ายด้วยเช่นกันเพียงกำหนดส่วนแทรกด้านลบที่ด้านล่างแทน


นี่เพิ่งตัดส่วนหัวแรกหรือไม่
cannyboy

ทำงานให้ฉันอย่างสมบูรณ์แบบ !! ขอบคุณ
Daniel



0

@ คำตอบของ LocoMike ติดตั้ง tableView ของฉันได้ดีที่สุด แต่ก็ใช้ไม่ได้เมื่อใช้ท้ายกระดาษด้วย ดังนั้นนี่คือวิธีแก้ไขเมื่อใช้หัวกระดาษและท้ายกระดาษ:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return (self.sections.count + 1) * 3;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (section % 3 != 1) {
        return 0;
    }
    section = section / 3;
    ...
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    if (section % 3 != 0) {
        return nil;
    }
    section = section / 3;
    ...
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    if (section % 3 != 0) {
        return 0;
    }
    section = section / 3;
    ...
}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
    if (section % 3 != 2) {
        return 0;
    }
    section = section / 3;
    ...
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    if (section % 3 != 0) {
        return nil;
    }
    section = section / 3;
    ...
}

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
    if (section % 3 != 2) {
        return nil;
    }
    section = section / 3;
    ...
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    int section = indexPath.section;
    section = section / 3;
    ...
}

0

คำตอบ @awulf เวอร์ชันสวิฟท์ซึ่งใช้งานได้ดี!

func scrollViewDidScroll(scrollView: UIScrollView) {
    let sectionHeight: CGFloat = 80
    if scrollView.contentOffset.y <= sectionHeight {
        scrollView.contentInset = UIEdgeInsetsMake( -scrollView.contentOffset.y, 0, 0, 0)
    }else if scrollView.contentOffset.y >= sectionHeight {
        scrollView.contentInset = UIEdgeInsetsMake(-sectionHeight, 0, 0, 0)
    }
}

-2

ฉันได้เรียนรู้ว่าเพียงแค่ตั้งค่าคุณสมบัติ tableHeaderView ให้ทำเช่น:

 tableView.tableHeaderView = customView;

และนั่นคือมัน

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