Thay đổi hành vi cuộn mặc định của tiêu đề phần UITableView


147

Tôi có một UITableView với hai phần. Đây là một bảng xem đơn giản. Tôi đang sử dụng viewForHeaderInSection để tạo các chế độ xem tùy chỉnh cho các tiêu đề này. Càng xa càng tốt.

Hành vi cuộn mặc định là khi gặp một phần, tiêu đề của phần vẫn được neo bên dưới thanh Nav, cho đến khi phần tiếp theo cuộn vào xem.

Câu hỏi của tôi là: tôi có thể thay đổi hành vi mặc định để các tiêu đề phần KHÔNG được neo ở đầu, mà thay vào đó, cuộn dưới thanh điều hướng với các hàng còn lại của phần?

Tôi có thiếu một cái gì đó rõ ràng?

Cảm ơn.


1
Đó phải là một trong những câu hỏi tốt nhất bằng văn bản trên trang web này! :) Cảm ơn.
Fattie

1
Kiểm tra ở đây để biết cách đúng để đạt được hiệu ứng này stackoverflow.com/a/13735238/1880899
Sumit Anantwar

Câu trả lời:


175

Con đường tôi giải quyết vấn đề này là để điều chỉnh contentOffsettheo contentInsettrong UITableViewControllerDelegate(mở rộng UIScrollViewDelegate) như thế này:

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

Vấn đề duy nhất ở đây là nó mất một chút độ nảy khi cuộn trở lại đầu trang.


{LƯU Ý: "40" phải là chiều cao chính xác của tiêu đề 0 của BẠN. Nếu bạn sử dụng một số lớn hơn chiều cao tiêu đề của phần 0, bạn sẽ thấy cảm giác ngón tay bị ảnh hưởng (thử như "1000" và bạn sẽ thấy hành vi nảy là kỳ lạ ở trên cùng). nếu số khớp với chiều cao tiêu đề của phần 0 của bạn, cảm giác ngón tay dường như là hoàn hảo hoặc gần hoàn hảo.}


1
Giải pháp hoàn hảo hơn những điều trên.
prathumca

4
Cảm ơn bạn! Đây là một giải pháp hoàn hảo. Bạn có giải pháp cho phần chân trang?
Tuấn Nguyễn

12
Giải pháp này không xử lý tap-on-menubar một cách chính xác, được cho là cuộn lên đầu danh sách.
Reid Ellis

Nếu bạn cần hành vi tương tự cho chế độ xem chân trang, chỉ cần thay đổi dòng cuối cùng như thế này: scrollView.contentInset = UIEdgeInsetsMake (0, 0, partHeaderHeight, 0)
alex

Điều này dường như là đủ: scrollView.contentInset = UIEdgeInsetsMake (scrollView.content Offerset.y> = 0? -CrollView.content Offerset.y: 0, 0, 0, 0);
MacMark

85

Bạn cũng có thể thêm một phần có hàng 0 ở trên cùng và chỉ cần sử dụng chân trang của phần trước làm tiêu đề cho phần tiếp theo.


13
Trong trường hợp của tôi khi tôi có nhiều hơn 2 phần, phần chân trang sẽ neo ở phía dưới ..
Joseph Lin

3
Đây là sáng tạo nhưng bạn cần điều chỉnh indexPath nếu bạn đang sử dụng NSFetchedResultsControll để tải bảng.
XJones

+1 cho đến nay là giải pháp TỐT NHẤT - đưa tôi như 3 dòng để thực hiện!
Jon

Brilliant Brilliant Brilliant Brilliant :-)
iphonic

Làm thế nào điều này sẽ làm việc cho chân trang mà neo? Sẽ đánh giá cao một số trợ giúp! Cảm ơn
darwindeed

36

Nếu tôi làm điều này, tôi sẽ tận dụng thực tế là UITableViews theo kiểu Plain có các tiêu đề dính và các tiêu đề theo kiểu Grouped thì không. Ít nhất tôi có thể thử sử dụng một ô bảng tùy chỉnh để mô phỏng sự xuất hiện của các ô Đơn giản trong một bảng được nhóm.

Tôi đã không thực sự thử điều này để nó có thể không hoạt động, nhưng đó là những gì tôi khuyên bạn nên làm.


Có lẽ sẽ làm việc, nhưng nó đã được thử? Và có vẻ như rất nhiều công việc khi câu trả lời của @ voidStern hoạt động hoàn hảo !!
bentford

Câu trả lời của voidStern không hoạt động với tôi khi tôi có nhiều hơn hai phần. Câu trả lời của Colin đơn giản / thanh lịch hơn, không cần phải tự thay đổi số phần và thêm số phần.
Joseph Lin

Mẹo: sử dụng tableView.separatorColor = [UIColor clearColor];để bắt chước chế độ xem bảng đơn giản.
Joseph Lin

3
Tôi đã thử làm điều này, nhưng khi tôi không thể làm cho các ô bảng được nhóm trông giống như các ô đơn giản, tức là loại bỏ lề trái và lề phải ở hai bên của các ô. Làm thế nào bạn làm điều này?
Adam Carter

1
Cảm ơn rất nhiều vì đã làm cho mọi thứ rõ ràng về UITableViewStyle tức là được nhóm và đơn giản, điều này quyết định xem tiêu đề / chân trang của phần xem bảng có bị dính hay không. Cảm ơn nhiều @Colin Barrett
Dhaval H. Nena

28

Tôi biết nó đến muộn, nhưng tôi đã tìm ra giải pháp dứt khoát!

Những gì bạn muốn làm là nếu bạn có 10 phần, hãy để dataSource trả về 20. Sử dụng số chẵn cho các tiêu đề của phần và số lẻ cho nội dung của phần. một cái gì đó như thế này

- (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;
    }
}

Voilá! : D


ý tưởng tuyệt vời. Nhưng nếu bạn có tiêu đề chỉ mục, tôi nghi ngờ điều này sẽ làm chúng rối tung lên.
roocell

tại sao? bạn có thể làm tương tự với phần tiêu đề. Chỉ cần nhớ nil cho số lẻ và một tiêu đề cho số chẵn.
LocoMike

1
có - phương pháp này hoạt động tuyệt vời. Đó là rất nhiều sổ sách kế toán (có lẽ phải làm theo cách tôi phải có được tiêu đề phần) Nhưng nó đã làm việc. Thủ thuật là numberOfRowsInSection và cellForRowAtIndexPath sử dụng if (phần% 2! = 0 && phần! = 0) trong khi tiêu đềForHeaderInSection và các chức năng chỉ mục phần khác sử dụng if (phần% 2 == 0)
roocell

người khởi tạo nên chọn đây là câu trả lời. Sẽ thật tuyệt nếu có một cách để phân lớp uitableview để neo tiêu đề phần tự động.
roocell

Điều này làm việc tốt nhất cho tôi. Tôi đã thử giải pháp @ Colin trước tiên, nhưng nó không hoạt động tốt với tùy chỉnh nặng nề UITableViewmà tôi đang sử dụng.
kubi

15

Có một số điều cần thực hiện để giải quyết vấn đề này theo cách không hack:

  1. Đặt kiểu xem bảng thành UITableViewStyleGrouped
  2. Đặt chế độ xem bảng backgroundColorthành[UIColor clearColor]
  3. Đặt ô backgroundViewtrên mỗi ô xem bảng thành dạng xem trống vớibackgroundColor [UIColor clearColor]
  4. Nếu cần, hãy đặt chế độ xem bảng rowHeightmột cách thích hợp hoặc ghi đè tableView:heightForRowAtIndexPath:nếu các hàng riêng lẻ có độ cao khác nhau.

(+1) @Neil, tôi đã thử câu trả lời của bạn nhưng thật không may, vì UITableViewStyleGroupedcác ô của bảng có thêm lề thay đổi căn chỉnh của chúng với tiêu đề. Đây là một vấn đề khi bạn thực sự muốn mô tả một bảng nhiều cột và sử dụng tiêu đề để hiển thị tiêu đề cột (và sau đó có các mục trong bảng riêng lẻ phù hợp với các tiêu đề này).
brainjam

15

Ban đầu được đăng ở đây , một giải pháp nhanh chóng sử dụng IB. Điều tương tự có thể được thực hiện theo chương trình mặc dù khá đơn giản.

Một cách có lẽ dễ dàng hơn để đạt được điều này (sử dụng IB):

Kéo một UIView vào TableView của bạn để làm cho nó xem tiêu đề của nó.

  1. Đặt chiều cao của chế độ xem tiêu đề thành 100px
  2. Đặt nội dung xem bảngInset (trên cùng) thành -100
  3. Phần tiêu đề bây giờ sẽ cuộn giống như bất kỳ ô thông thường.

Một số người nhận xét rằng giải pháp này ẩn tiêu đề đầu tiên, tuy nhiên tôi không nhận thấy bất kỳ vấn đề nào như vậy. Nó hoạt động hoàn hảo với tôi và cho đến nay là giải pháp đơn giản nhất mà tôi từng thấy cho đến nay.


Lưu ý rằng có lẽ bạn nên đặt chế độ xem để sử dụng màu nền của màu rõ ràng, nếu không, nếu bạn cuộn qua phần trên, bạn sẽ thấy màu trắng trong phần nảy.
Dốc

3
Nó che giấu tiêu đề đầu tiên của tôi
Leena

Leena, phiên bản iOS nào bạn đang chạy? Chế độ xem là UITableViewControll hay UIView có UITableView trong đó? Tôi không chắc tại sao đối với một số người, giải pháp này lại ẩn tiêu đề đầu tiên nên tôi đang cố gắng tìm bất kỳ sự khác biệt nào.
Dốc

Giải pháp này là hoàn hảo. Tôi đang tìm kiếm một sự xuất hiện nền tế bào trên và dưới vô hạn - điều này hoàn toàn hoàn thành nó. Đẹp!
Taylor Halliday

Giải pháp này là tuyệt vời. Dễ dàng thực hiện hơn các câu trả lời khác trong chủ đề này. Theo tôi, đây nên là câu trả lời được chấp nhận.
John Rogers

15

Tôi không hài lòng với các giải pháp được mô tả ở đây cho đến nay, vì vậy tôi đã cố gắng kết hợp chúng. Kết quả là đoạn mã sau, lấy cảm hứng từ @awulf và @cescofry. Nó hoạt động với tôi vì tôi không có tiêu đề xem bảng thực sự. Nếu bạn đã có một tiêu đề xem bảng, bạn có thể phải điều chỉnh chiều cao.

// 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)]];

Đây là một giải pháp đơn giản nhất mà tôi tìm thấy.
Zorayr

Điều này làm việc cho tôi trên iOS9.2, vì vậy mặc dù câu trả lời cũ hơn, nó vẫn hợp lệ. Và nó đã không ẩn tiêu đề phần đầu tiên. Hoạt động, và hoạt động hoàn hảo.
idstar

Hoàn hảo. Nếu chế độ xem bảng của bạn đã có tiêu đề, chỉ cần tăng chiều cao của nó bằng phần bù sau đó tăng hằng số ràng buộc hàng đầu của nội dung tiêu đề để chuyển nội dung xuống vị trí ban đầu
Jason

14

Chỉ cần thay đổi Kiểu xem bảng:

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

Tài liệu UITableViewStyle :

UITableViewStylePlain- Chế độ xem bảng đơn giản. Bất kỳ tiêu đề hoặc chân trang phần nào được hiển thị dưới dạng dấu tách dòng và nổi khi chế độ xem bảng được cuộn.

UITableViewStylegrouped- Một khung nhìn bảng có các phần thể hiện các nhóm hàng khác nhau. Các phần đầu trang và chân trang không nổi.


câu trả lời tuyệt vời, làm việc cho tôi không cần bất kỳ công việc nào xung quanh
Shams Ahmed

8

Chọn kiểu TableView được nhóm

Chọn kiểu Chế độ xem bảng được nhóm từ Trình theo dõi thuộc tính của bảng Xem trong bảng phân cảnh.


5

Đặt tiêu đề Xem của bảng với chế độ xem trong suốt có cùng chiều cao của tiêu đề trong chế độ xem phần. Cũng bắt đầu chế độ xem bảng với khung ay ở mức cao.

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

Tôi đã tìm thấy một giải pháp thay thế, sử dụng ô đầu tiên của mỗi phần thay vì phần tiêu đề thực, giải pháp này không có vẻ sạch sẽ, nhưng hoạt động rất tốt, bạn có thể sử dụng một ô nguyên mẫu được xác định cho phần tiêu đề của mình và trong phương thức cellForRowAtIndexPath yêu cầu indexPath.row == 0, nếu đúng, sử dụng ô nguyên mẫu của phần tiêu đề, phần khác sử dụng ô nguyên mẫu mặc định của bạn.


Nếu bạn vẫn muốn làm việc với indexPath.row& indexPath.section, hãy đảm bảo bạn trả lại chiều cao 0.0fcho - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)sectionđể các tiêu đề của bạn không nhìn thấy được.
Súp

4

Thay đổi kiểu xem bảng của bạn:

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

Theo tài liệu táo cho UITableView:

UITableViewStylePlain- Chế độ xem bảng đơn giản. Bất kỳ tiêu đề hoặc chân trang phần nào được hiển thị dưới dạng dấu tách dòng và nổi khi chế độ xem bảng được cuộn.

UITableViewStylegrouped- Một khung nhìn bảng có các phần thể hiện các nhóm hàng khác nhau. Các phần đầu trang và chân trang không nổi. Hy vọng sự thay đổi nhỏ này sẽ giúp bạn ..


2

Giờ đây, kiểu cơ bản được nhóm trông giống như kiểu đơn giản trong iOS 7 (về độ phẳng và nền), đối với chúng tôi, cách khắc phục tốt nhất và dễ nhất (tức là ít hack nhất) là chỉ cần thay đổi kiểu của chế độ xem bảng thành nhóm. Giắc cắm với contentInsets luôn là một vấn đề khi chúng tôi tích hợp một thanh điều hướng di chuyển ở trên cùng. Với kiểu xem bảng được nhóm, nó trông giống hệt nhau (với các ô của chúng tôi) và các tiêu đề phần được cố định. Không có sự kỳ lạ cuộn.


Đây là giải pháp tốt nhất đặc biệt nếu các ô là tùy chỉnh, có vẻ như chỉ cần dừng "giữ" tiêu đề của phần khi cuộn chạm vào đầu.
Thép tái chế

1

Chỉ định một phần tử âm cho bảngView của bạn. Nếu bạn có các tiêu đề phần cao 22px và bạn không muốn chúng bị dính, ngay sau khi bạn tải lại, hãy thêm:

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

Hoạt động như một cơ duyên đối với tôi. Thay vào đó, cũng hoạt động cho phần chân trang, chỉ cần gán phần phụ âm ở phía dưới.


Điều này chỉ cắt ra tiêu đề đầu tiên ??
cannyboy

Làm việc cho tôi hoàn hảo !! Cảm ơn
Daniel

0

Tôi thêm bảng vào Chế độ xem cuộn và có vẻ như hoạt động tốt.


0

Kiểm tra câu trả lời của tôi ở đây . Đây là cách dễ nhất để thực hiện các tiêu đề phần không nổi mà không có bất kỳ hack nào.


0

Câu trả lời của @ LocoMike phù hợp nhất với bảngView của tôi, tuy nhiên nó cũng bị hỏng khi sử dụng chân trang. Vì vậy, đây là giải pháp chính xác khi sử dụng các tiêu đề và chân trang:

- (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

Phiên bản Swift của câu trả lời @awulf, hoạt động rất tốt!

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

Tôi đã học được rằng chỉ cần đặt thuộc tính tableHeaderView sẽ làm điều đó, tức là:

 tableView.tableHeaderView = customView;

và đó là nó.

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.