UITableView
ตั้งค่าเป็นเซลล์แบบคงที่
เป็นไปได้ไหมที่จะซ่อนเซลล์บางเซลล์โดยทางโปรแกรม?
UITableView
ตั้งค่าเป็นเซลล์แบบคงที่
เป็นไปได้ไหมที่จะซ่อนเซลล์บางเซลล์โดยทางโปรแกรม?
คำตอบ:
คุณกำลังมองหาโซลูชันนี้:
StaticDataTableViewController 2.0
https://github.com/xelvenone/StaticDataTableViewController
ซึ่งสามารถแสดง / ซ่อน / โหลดเซลล์แบบคงที่โดยมีหรือไม่มีภาพเคลื่อนไหวก็ได้!
[self cell:self.outletToMyStaticCell1 setHidden:hide];
[self cell:self.outletToMyStaticCell2 setHidden:hide];
[self reloadDataAnimated:YES];
หมายเหตุให้ใช้เท่านั้น (reloadDataAnimate: YES / NO) (อย่าเรียก [self.tableView reloadData] โดยตรง)
วิธีนี้ไม่ใช้วิธีแก้ปัญหาแฮ็กกี้ด้วยการตั้งค่าความสูงเป็น 0 และช่วยให้คุณเคลื่อนไหวการเปลี่ยนแปลงและซ่อนส่วนทั้งหมดได้
IBOutletCollection
แต่ฉันไม่เห็นว่ามันจะสร้างความแตกต่างได้อย่างไร ฉันเพิ่งดาวน์โหลดโค้ดเมื่อวานนี้ดังนั้นฉันจึงไม่คิดว่าเป็นเวอร์ชันเก่า
ในการซ่อนเซลล์แบบคงที่ใน UITable:
ในคลาสผู้ร่วมประชุมคอนโทรลเลอร์ UITableView ของคุณ:
วัตถุประสงค์ -C:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell* cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
if(cell == self.cellYouWantToHide)
return 0; //set the hidden cell's height to 0
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
รวดเร็ว:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
var cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath)
if cell == self.cellYouWantToHide {
return 0
}
return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}
วิธีนี้จะเรียกสำหรับแต่ละเซลล์ใน UITable เมื่อเรียกมันสำหรับเซลล์ที่คุณต้องการซ่อนเราจะตั้งค่าความสูงเป็น 0 เราระบุเซลล์เป้าหมายโดยการสร้างเต้าเสียบสำหรับมัน:
ClipToBounds
ปัญหานี้คุณสามารถตั้งค่าเซลล์เป็นซ่อนได้ สิ่งนี้ดูเหมือนจะสะอาดกว่าสำหรับฉัน ;-)
วิธีที่ดีที่สุดคือตามที่อธิบายไว้ในบล็อกต่อไปนี้ http://ali-reynolds.com/2013/06/29/hide-cells-in-static-table-view/
ออกแบบมุมมองตารางแบบคงที่ของคุณตามปกติในตัวสร้างอินเทอร์เฟซ - พร้อมด้วยเซลล์ที่ซ่อนอยู่ แต่มีสิ่งหนึ่งที่คุณต้องทำสำหรับทุกเซลล์ที่มีศักยภาพที่คุณต้องการซ่อน - ตรวจสอบคุณสมบัติ "คลิปมุมมองย่อย" ของเซลล์มิฉะนั้นเนื้อหาของเซลล์จะไม่หายไปเมื่อคุณพยายามซ่อนมัน (โดยการลดขนาดความสูง - เพิ่มเติมในภายหลัง)
ดังนั้น - คุณมีสวิตช์ในเซลล์และสวิตช์ควรจะซ่อนและแสดงเซลล์คงที่ เชื่อมต่อกับ IBAction และทำสิ่งนี้:
[self.tableView beginUpdates]; [self.tableView endUpdates];
ช่วยให้คุณมีภาพเคลื่อนไหวที่ดีสำหรับเซลล์ที่ปรากฏและหายไป ตอนนี้ใช้วิธีการมอบหมายมุมมองตารางต่อไปนี้:
- (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.section == 1 && indexPath.row == 1) { // This is the cell to hide - change as you need // Show or hide cell if (self.mySwitch.on) { return 44; // Show the cell - adjust the height as you need } else { return 0; // Hide the cell } } return 44; }
และนั่นแหล่ะ พลิกสวิตช์แล้วเซลล์จะซ่อนและปรากฏขึ้นอีกครั้งด้วยภาพเคลื่อนไหวที่ราบรื่นและสวยงาม
วิธีแก้ปัญหาของฉันไปในทิศทางเดียวกันกับ Gareth แม้ว่าฉันจะทำบางอย่างที่แตกต่าง
ที่นี่:
1. ซ่อนเซลล์
ไม่มีทางที่จะซ่อนเซลล์โดยตรง UITableViewController
เป็นแหล่งข้อมูลที่ให้เซลล์คงที่และปัจจุบันไม่มีวิธีใดที่จะบอกได้ว่า "ไม่ต้องระบุเซลล์ x" ดังนั้นเราจึงต้องจัดหาแหล่งข้อมูลของเราเองซึ่งมอบหมายให้UITableViewController
เพื่อรับเซลล์คงที่
ง่ายที่สุดคือการ subclass UITableViewController
และแทนที่วิธีการทั้งหมดที่จำเป็นต้องมีการทำงานแตกต่างกันเมื่อเซลล์หลบซ่อนตัวอยู่
ในกรณีที่ง่ายที่สุด (ตารางส่วนเดียวเซลล์ทั้งหมดมีความสูงเท่ากัน) สิ่งนี้จะเป็นดังนี้:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [super tableView:tableView numberOfRowsInSection:section] - numberOfCellsHidden;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Recalculate indexPath based on hidden cells
indexPath = [self offsetIndexPath:indexPath];
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}
- (NSIndexPath*)offsetIndexPath:(NSIndexPath*)indexPath
{
int offsetSection = indexPath.section; // Also offset section if you intend to hide whole sections
int numberOfCellsHiddenAbove = ... // Calculate how many cells are hidden above the given indexPath.row
int offsetRow = indexPath.row + numberOfCellsHiddenAbove;
return [NSIndexPath indexPathForRow:offsetRow inSection:offsetSection];
}
หากตารางของคุณมีหลายส่วนหรือเซลล์มีความสูงต่างกันคุณจะต้องลบล้างวิธีการเพิ่มเติม หลักการเดียวกันนี้ใช้ที่นี่: คุณต้องชดเชย indexPath ส่วนและแถวก่อนที่จะมอบหมายให้ super
นอกจากนี้โปรดทราบว่าพารามิเตอร์ indexPath สำหรับวิธีการเช่นdidSelectRowAtIndexPath:
จะแตกต่างกันสำหรับเซลล์เดียวกันขึ้นอยู่กับสถานะ (เช่นจำนวนเซลล์ที่ซ่อนอยู่) ดังนั้นจึงเป็นความคิดที่ดีที่จะหักล้างพารามิเตอร์ indexPath และทำงานกับค่าเหล่านี้เสมอ
2. ทำให้เกิดการเปลี่ยนแปลง
ตามที่ Gareth ได้กล่าวไว้แล้วคุณจะได้รับความผิดพลาดที่สำคัญหากคุณเคลื่อนไหวการเปลี่ยนแปลงโดยใช้reloadSections:withRowAnimation:
วิธีการ
ฉันพบว่าถ้าคุณโทรหาreloadData:
ทันทีหลังจากนั้นภาพเคลื่อนไหวจะดีขึ้นมาก (เหลือเพียงจุดบกพร่องเล็กน้อย) ตารางจะแสดงอย่างถูกต้องหลังภาพเคลื่อนไหว
สิ่งที่ฉันกำลังทำคือ:
- (void)changeState
{
// Change state so cells are hidden/unhidden
...
// Reload all sections
NSIndexSet* reloadSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [self numberOfSectionsInTableView:tableView])];
[tableView reloadSections:reloadSet withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView reloadData];
}
numberOfRowsInSection:
จะถูกเรียกเมื่อตารางโหลดครั้งแรกเท่านั้น เมื่อฉันเรียก [self.tableView reloadData] numberOfRowsInSection:
จะไม่ถูกเรียกอีกเลย เฉพาะcellForRowAtIndexPath:
ที่เรียกว่า ฉันขาดอะไรไป?
cellOneOutlet.hidden = true
ตอนนี้แทนที่วิธีการด้านล่างตรวจสอบว่าสถานะเซลล์ใดถูกซ่อนไว้และส่งคืนความสูง 0 สำหรับเซลล์เหล่านั้น นี่เป็นหนึ่งในหลายวิธีที่คุณสามารถซ่อนเซลล์ใด ๆ ใน tableView แบบคงที่ได้อย่างรวดเร็ว
override func tableView(tableView: UITableView, heightForRowAtIndexPathindexPath: NSIndexPath) -> CGFloat
{
let tableViewCell = super.tableView(tableView,cellForRowAtIndexPath: indexPath)
if tableViewCell.hidden == true
{
return 0
}
else{
return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}
}
let tableViewCell = super.tableView(tableView,cellForRowAtIndexPath: indexPath)
ไม่ให้ฉันใช้ let tableViewCell = tableView.cellForRow(at: indexPath as IndexPath)
ฉันคิดว่ามันจะถูกแทนที่ด้วย
UITableViewController
ฉันจึงไม่มีUITableView
วิธีการมอบสิทธิ์ใด ๆ เพื่อให้โทรheightForRow
ได้ต้องมีวิธีอื่นด้วยหรือไม่?
ฉันคิดทางเลือกอื่นที่ซ่อนส่วนต่างๆและไม่ลบออก ฉันลองใช้แนวทางของ @ henning77 แต่ฉันยังคงพบปัญหาเมื่อฉันเปลี่ยนจำนวนส่วนของ UITableView แบบคงที่ วิธีนี้ได้ผลดีสำหรับฉัน แต่โดยหลักแล้วฉันพยายามซ่อนส่วนต่างๆแทนที่จะเป็นแถว ฉันลบบางแถวได้ทันที แต่มันยุ่งกว่านี้มากฉันจึงพยายามจัดกลุ่มสิ่งต่างๆเป็นส่วนที่ฉันต้องการแสดงหรือซ่อน นี่คือตัวอย่างวิธีที่ฉันซ่อนส่วนต่างๆ:
ก่อนอื่นฉันประกาศคุณสมบัติ NSMutableArray
@property (nonatomic, strong) NSMutableArray *hiddenSections;
ใน viewDidLoad (หรือหลังจากที่คุณสอบถามข้อมูลของคุณแล้ว) คุณสามารถเพิ่มส่วนที่คุณต้องการซ่อนลงในอาร์เรย์ได้
- (void)viewDidLoad
{
hiddenSections = [NSMutableArray new];
if(some piece of data is empty){
// Add index of section that should be hidden
[self.hiddenSections addObject:[NSNumber numberWithInt:1]];
}
... add as many sections to the array as needed
[self.tableView reloadData];
}
จากนั้นใช้วิธีการมอบหมาย TableView ต่อไปนี้
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
return nil;
}
return [super tableView:tableView titleForHeaderInSection:section];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if([self.hiddenSections containsObject:[NSNumber numberWithInt:indexPath.section]]){
return 0;
}
return [super tableView:tableView heightForRowAtIndexPath:[self offsetIndexPath:indexPath]];
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if([self.hiddenSections containsObject:[NSNumber numberWithInt:indexPath.section]]){
[cell setHidden:YES];
}
}
จากนั้นตั้งค่าความสูงของส่วนหัวและส่วนท้ายเป็น 1 สำหรับส่วนที่ซ่อนอยู่เนื่องจากคุณไม่สามารถตั้งค่าความสูงเป็น 0 ได้ทำให้มีพื้นที่เพิ่ม 2 พิกเซล แต่เราสามารถชดเชยได้โดยปรับความสูงของส่วนหัวที่มองเห็นถัดไป
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
CGFloat height = [super tableView:tableView heightForHeaderInSection:section];
if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
height = 1; // Can't be zero
}
else if([self tableView:tableView titleForHeaderInSection:section] == nil){ // Only adjust if title is nil
// Adjust height for previous hidden sections
CGFloat adjust = 0;
for(int i = (section - 1); i >= 0; i--){
if([self.hiddenSections containsObject:[NSNumber numberWithInt:i]]){
adjust = adjust + 2;
}
else {
break;
}
}
if(adjust > 0)
{
if(height == -1){
height = self.tableView.sectionHeaderHeight;
}
height = height - adjust;
if(height < 1){
height = 1;
}
}
}
return height;
}
-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
return 1;
}
return [super tableView:tableView heightForFooterInSection:section];
}
จากนั้นหากคุณมีแถวที่ต้องการซ่อนคุณสามารถปรับ numberOfRowsInSection และแถวใดที่จะส่งคืนใน cellForRowAtIndexPath ในตัวอย่างนี้ที่นี่ฉันมีส่วนที่มีสามแถวซึ่งสามแถวใด ๆ อาจว่างเปล่าและจำเป็นต้องลบออก
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger rows = [super tableView:tableView numberOfRowsInSection:section];
if(self.organization != nil){
if(section == 5){ // Contact
if([self.organization objectForKey:@"Phone"] == [NSNull null]){
rows--;
}
if([self.organization objectForKey:@"Email"] == [NSNull null]){
rows--;
}
if([self.organization objectForKey:@"City"] == [NSNull null]){
rows--;
}
}
}
return rows;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [super tableView:tableView cellForRowAtIndexPath:[self offsetIndexPath:indexPath]];
}
ใช้ offsetIndexPath นี้เพื่อคำนวณ indexPath สำหรับแถวที่คุณกำลังลบแถวตามเงื่อนไข ไม่จำเป็นหากคุณซ่อนเฉพาะส่วน
- (NSIndexPath *)offsetIndexPath:(NSIndexPath*)indexPath
{
int row = indexPath.row;
if(self.organization != nil){
if(indexPath.section == 5){
// Adjust row to return based on which rows before are hidden
if(indexPath.row == 0 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Email"] != [NSNull null]){
row++;
}
else if(indexPath.row == 0 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Address"] != [NSNull null]){
row = row + 2;
}
else if(indexPath.row == 1 && [self.organization objectForKey:@"Phone"] != [NSNull null] && [self.organization objectForKey:@"Email"] == [NSNull null]){
row++;
}
else if(indexPath.row == 1 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Email"] != [NSNull null]){
row++;
}
}
}
NSIndexPath *offsetPath = [NSIndexPath indexPathForRow:row inSection:indexPath.section];
return offsetPath;
}
มีหลายวิธีในการลบล้าง แต่สิ่งที่ฉันชอบเกี่ยวกับวิธีนี้คือสามารถใช้ซ้ำได้ ตั้งค่าอาร์เรย์ hiddenSections เพิ่มเข้าไปและจะซ่อนส่วนที่ถูกต้อง การซ่อนแถวให้ยุ่งยากกว่าเล็กน้อย แต่เป็นไปได้ เราไม่สามารถกำหนดความสูงของแถวที่เราต้องการซ่อนเป็น 0 ได้หากเราใช้ UITableView แบบจัดกลุ่มเนื่องจากเส้นขอบจะวาดไม่ถูกต้อง
NSMutableSet
สำหรับhiddenSections
แทน เร็วกว่ามากเนื่องจากคุณทดสอบการเป็นสมาชิกเป็นส่วนใหญ่
NSMutableSet
สำหรับhiddenSections
แม้ว่าฉันจะเข้าใจว่าประเด็นของคำตอบของคุณเป็นแนวคิดมากกว่าที่จู้จี้จุกจิกว่าคุณควรใช้โครงสร้างข้อมูลประเภทใด
ปรากฎว่าคุณสามารถซ่อนและแสดงเซลล์ใน UITableView แบบคงที่และด้วยภาพเคลื่อนไหว และไม่ใช่เรื่องยากที่จะทำสำเร็จ
สาระสำคัญ:
Use tableView:heightForRowAtIndexPath:
เพื่อระบุความสูงของเซลล์แบบไดนามิกตามสถานะบางอย่างtableView.beginUpdates();tableView.endUpdates()
tableView.cellForRowAtIndexPath:
tableView:heightForRowAtIndexPath:
ใช้ cached indexPaths เพื่อแยกความแตกต่างของเซลล์ใช่เป็นไปได้แน่นอนแม้ว่าฉันกำลังดิ้นรนกับปัญหาเดียวกันในขณะนี้ ฉันจัดการเพื่อซ่อนเซลล์แล้วและทุกอย่างก็ใช้ได้ แต่ตอนนี้ฉันไม่สามารถทำให้สิ่งนั้นเคลื่อนไหวได้อย่างเรียบร้อย นี่คือสิ่งที่ฉันพบ:
ฉันซ่อนแถวตามสถานะของสวิตช์เปิด / ปิดในแถวแรกของส่วนแรก หากสวิตช์เปิดอยู่จะมี 1 แถวด้านล่างในส่วนเดียวกันมิฉะนั้นจะมี 2 แถวที่ต่างกัน
ฉันมีตัวเลือกที่เรียกว่าเมื่อสวิตช์ถูกสลับและฉันตั้งค่าตัวแปรเพื่อระบุว่าฉันอยู่ในสถานะใดจากนั้นฉันเรียก:
[[self tableView] reloadData];
ฉันแทนที่tableView: willDisplayCell: forRowAtIndexPath: function และถ้าเซลล์ควรจะถูกซ่อนฉันจะทำสิ่งนี้:
[cell setHidden:YES];
ซึ่งจะซ่อนเซลล์และเนื้อหา แต่ไม่ได้ลบเนื้อที่ที่มีอยู่ออกไป
หากต้องการลบช่องว่างให้แทนที่ฟังก์ชันtableView: heightForRowAtIndexPath:และส่งคืน 0 สำหรับแถวที่ควรซ่อน
นอกจากนี้คุณยังต้องแทนที่tableView: numberOfRowsInSection:และส่งคืนจำนวนแถวในส่วนนั้น คุณต้องทำอะไรแปลก ๆ ที่นี่เพื่อที่ว่าถ้าตารางของคุณเป็นสไตล์ที่จัดกลุ่มมุมโค้งมนจะเกิดขึ้นในเซลล์ที่ถูกต้อง ในตารางคงที่ของฉันมีชุดเซลล์เต็มสำหรับส่วนดังนั้นจึงมีเซลล์แรกที่มีตัวเลือกจากนั้น 1 เซลล์สำหรับตัวเลือกสถานะเปิดและอีก 2 เซลล์สำหรับตัวเลือกสถานะปิดรวมเป็น 4 เซลล์ เมื่อตัวเลือกเปิดอยู่ฉันต้องส่งคืน 4 ซึ่งรวมถึงตัวเลือกที่ซ่อนอยู่เพื่อให้ตัวเลือกสุดท้ายที่แสดงมีกล่องกลม เมื่อปิดตัวเลือกสองตัวเลือกสุดท้ายจะไม่ปรากฏขึ้นดังนั้นฉันจึงกลับ 2 ทั้งหมดนี้รู้สึกอึดอัด ขออภัยหากสิ่งนี้ไม่ชัดเจนมากนักอธิบายยาก เพื่อแสดงการตั้งค่านี่คือโครงสร้างของส่วนตารางใน IB:
ดังนั้นเมื่อตัวเลือกอยู่บนตารางรายงานสองแถวซึ่ง ได้แก่ :
เมื่อตัวเลือกปิดอยู่ตารางจะรายงานสี่แถว ได้แก่ :
วิธีนี้ไม่ถูกต้องด้วยเหตุผลหลายประการซึ่งเท่าที่ฉันได้รับจากการทดลองของฉันจนถึงตอนนี้โปรดแจ้งให้เราทราบหากคุณพบวิธีที่ดีกว่า ปัญหาที่ฉันสังเกตเห็นคือ:
รู้สึกผิดที่ต้องบอกตารางว่าจำนวนแถวแตกต่างจากที่สันนิษฐานไว้ในข้อมูลพื้นฐาน
ฉันไม่สามารถทำให้การเปลี่ยนแปลงเคลื่อนไหวได้ ฉันได้ลองใช้tableView: reloadSections: withRowAnimation:แทนที่จะเป็น reloadData และผลลัพธ์ดูเหมือนจะไม่สมเหตุสมผลฉันยังคงพยายามทำให้มันใช้งานได้ ขณะนี้สิ่งที่ดูเหมือนจะเกิดขึ้นคือ tableView ไม่อัปเดตแถวที่ถูกต้องดังนั้นจึงยังคงซ่อนอยู่ซึ่งควรจะแสดงและช่องว่างจะถูกทิ้งไว้ใต้แถวแรก ฉันคิดว่านี่อาจเกี่ยวข้องกับประเด็นแรกเกี่ยวกับข้อมูลพื้นฐาน
หวังว่าจะมีคนแนะนำวิธีอื่นหรืออาจจะขยายด้วยภาพเคลื่อนไหวได้บ้าง แต่อาจจะช่วยให้คุณเริ่มต้นได้ ฉันขอโทษที่ไม่มีการเชื่อมโยงหลายมิติในฟังก์ชันฉันใส่ไว้ แต่พวกเขาถูกปฏิเสธโดยตัวกรองสแปมเนื่องจากฉันเป็นผู้ใช้ที่ค่อนข้างใหม่
[[self tableView] reloadData];
อีกครั้งหลังจากซ่อนเซลล์
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
ในUITableViewController
คลาสย่อยสำหรับการสร้างเซลล์แบบคงที่ เส้นทางดัชนีมีการจัดทำดัชนีแบบคงที่ไม่ใช่แบบไดนามิก ...
ตามคำตอบของ Justas แต่สำหรับ Swift 4:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let cell = super.tableView(tableView, cellForRowAt: indexPath)
if cell == self.cellYouWantToHide {
return 0
}
return super.tableView(tableView, heightForRowAt: indexPath)
}
tableView.reloadRows(at:, with:)
อัปเดตเซลล์หากคุณเปลี่ยนความสูงในขณะที่แถวนั้นมองเห็นได้แล้ว
เอาล่ะหลังจากพยายามฉันมีคำตอบที่ไม่ธรรมดา ฉันกำลังใช้ตัวแปร "isHidden" หรือ "hidden" เพื่อตรวจสอบว่าควรซ่อนเซลล์นี้หรือไม่
สร้าง IBOutlet ไปยังตัวควบคุมมุมมองของคุณ
@IBOutlet weak var myCell: UITableViewCell!
อัปเดตmyCell
ในฟังก์ชันที่กำหนดเองของคุณตัวอย่างเช่นคุณสามารถเพิ่มใน viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
self.myCell.isHidden = true
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let cell = super.tableView(tableView, cellForRowAt: indexPath)
guard !cell.isHidden else {
return 0
}
return super.tableView(tableView, heightForRowAt: indexPath)
}
วิธีนี้จะลดตรรกะของคุณในวิธีการมอบหมายงานและคุณจะต้องมุ่งเน้นไปที่ความต้องการทางธุรกิจของคุณเท่านั้น
คำตอบข้างต้นที่ซ่อน / แสดงเซลล์เปลี่ยน rowHeight หรือยุ่งกับข้อ จำกัด การจัดวางอัตโนมัติไม่ได้ผลสำหรับฉันเนื่องจากปัญหาการจัดวางอัตโนมัติ รหัสนั้นไม่สามารถทนได้
สำหรับตารางคงที่ธรรมดาสิ่งที่ได้ผลดีที่สุดสำหรับฉันคือ:
นี่คือตัวอย่างจากตัวควบคุมมุมมองตารางของฉัน:
@IBOutlet weak var titleCell: UITableViewCell!
@IBOutlet weak var nagCell: UITableViewCell!
@IBOutlet weak var categoryCell: UITableViewCell!
var cellsToShow: [UITableViewCell] = []
override func viewDidLoad() {
super.viewDidLoad()
determinCellsToShow()
}
func determinCellsToShow() {
if detail!.duration.type != nil {
cellsToShow = [titleCell, nagCell, categoryCell]
}
else {
cellsToShow = [titleCell, categoryCell]
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return cellsToShow[indexPath.row]
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellsToShow.count
}
สำหรับ iOS 11 ฉันพบว่าคำตอบของMohamed Salehเวอร์ชันแก้ไขทำงานได้ดีที่สุดโดยมีการปรับปรุงบางอย่างตามเอกสารของ Apple มันเคลื่อนไหวอย่างหลีกเลี่ยง hacks น่าเกลียดหรือค่า hardcoded และใช้ความสูงของแถวตั้งอยู่แล้วใน Interface Builder
แนวคิดพื้นฐานคือการตั้งค่าความสูงของแถวเป็น 0 สำหรับแถวที่ซ่อนอยู่ จากนั้นใช้tableView.performBatchUpdates
เพื่อทริกเกอร์ภาพเคลื่อนไหวที่ทำงานอย่างสม่ำเสมอ
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath == indexPathOfHiddenCell {
if cellIsHidden {
return 0
}
}
// Calling super will use the height set in your storyboard, avoiding hardcoded values
return super.tableView(tableView, heightForRowAt: indexPath)
}
คุณจะต้องตรวจสอบให้แน่ใจcellIsHidden
และindexPathOfHiddenCell
ตั้งค่าให้เหมาะสมกับกรณีการใช้งานของคุณ สำหรับรหัสของฉันเป็นคุณสมบัติบนตัวควบคุมมุมมองตารางของฉัน
ไม่ว่าด้วยวิธีใดก็ตามที่ควบคุมการมองเห็น (อาจเป็นการทำงานของปุ่มหรือdidSelectRow
) ให้สลับเซลล์ IsHidden state ภายในperformBatchUpdates
บล็อก:
tableView.performBatchUpdates({
// Use self to capture for block
self.cellIsHidden = !self.cellIsHidden
}, completion: nil)
Apple แนะนำให้ทำperformBatchUpdates
ซ้ำbeginUpdates
/endUpdates
ทุกครั้งที่ทำได้
ฉันพบวิธีแก้ปัญหาสำหรับการซ่อนเซลล์แบบเคลื่อนไหวในตารางแบบคงที่
// Class for wrapping Objective-C block
typedef BOOL (^HidableCellVisibilityFunctor)();
@interface BlockExecutor : NSObject
@property (strong,nonatomic) HidableCellVisibilityFunctor block;
+ (BlockExecutor*)executorWithBlock:(HidableCellVisibilityFunctor)block;
@end
@implementation BlockExecutor
@synthesize block = _block;
+ (BlockExecutor*)executorWithBlock:(HidableCellVisibilityFunctor)block
{
BlockExecutor * executor = [[BlockExecutor alloc] init];
executor.block = block;
return executor;
}
@end
จำเป็นต้องมีพจนานุกรมเพิ่มเติมเพียงชุดเดียว:
@interface MyTableViewController ()
@property (nonatomic) NSMutableDictionary * hidableCellsDict;
@property (weak, nonatomic) IBOutlet UISwitch * birthdaySwitch;
@end
และดูการใช้งาน MyTableViewController เราต้องการสองวิธีในการแปลง indexPath ระหว่างดัชนีที่มองเห็นและมองไม่เห็น ...
- (NSIndexPath*)recoverIndexPath:(NSIndexPath *)indexPath
{
int rowDelta = 0;
for (NSIndexPath * ip in [[self.hidableCellsDict allKeys] sortedArrayUsingSelector:@selector(compare:)])
{
BlockExecutor * executor = [self.hidableCellsDict objectForKey:ip];
if (ip.section == indexPath.section
&& ip.row <= indexPath.row + rowDelta
&& !executor.block())
{
rowDelta++;
}
}
return [NSIndexPath indexPathForRow:indexPath.row+rowDelta inSection:indexPath.section];
}
- (NSIndexPath*)mapToNewIndexPath:(NSIndexPath *)indexPath
{
int rowDelta = 0;
for (NSIndexPath * ip in [[self.hidableCellsDict allKeys] sortedArrayUsingSelector:@selector(compare:)])
{
BlockExecutor * executor = [self.hidableCellsDict objectForKey:ip];
if (ip.section == indexPath.section
&& ip.row < indexPath.row - rowDelta
&& !executor.block())
{
rowDelta++;
}
}
return [NSIndexPath indexPathForRow:indexPath.row-rowDelta inSection:indexPath.section];
}
IBAction หนึ่งรายการในค่า UISwitch เปลี่ยน:
- (IBAction)birthdaySwitchChanged:(id)sender
{
NSIndexPath * indexPath = [self mapToNewIndexPath:[NSIndexPath indexPathForRow:1 inSection:1]];
if (self.birthdaySwitch.on)
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
else
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
บางวิธี UITableViewDataSource และ UITableViewDelegate:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int numberOfRows = [super tableView:tableView numberOfRowsInSection:section];
for (NSIndexPath * indexPath in [self.hidableCellsDict allKeys])
if (indexPath.section == section)
{
BlockExecutor * executor = [self.hidableCellsDict objectForKey:indexPath];
numberOfRows -= (executor.block()?0:1);
}
return numberOfRows;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
indexPath = [self recoverIndexPath:indexPath];
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
indexPath = [self recoverIndexPath:indexPath];
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// initializing dictionary
self.hidableCellsDict = [NSMutableDictionary dictionary];
[self.hidableCellsDict setObject:[BlockExecutor executorWithBlock:^(){return self.birthdaySwitch.on;}] forKey:[NSIndexPath indexPathForRow:1 inSection:1]];
}
- (void)viewDidUnload
{
[self setBirthdaySwitch:nil];
[super viewDidUnload];
}
@end
ตอบอย่างรวดเร็ว :
เพิ่มวิธีการต่อไปนี้ใน TableViewController ของคุณ:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return indexPathOfCellYouWantToHide == indexPath ? 0 : super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}
หาก tableView พยายามวาดเซลล์ที่คุณต้องการซ่อนก็จะไม่แสดงผลเนื่องจากความสูงจะถูกตั้งค่าเป็น 0pt ด้วยวิธีการด้านบนทุกอย่างจะไม่เปลี่ยนแปลง
โปรดทราบว่า indexPathOfCellYouWantToHide
สามารถเปลี่ยนแปลงได้ตลอดเวลา :)
ใน> Swift 2.2 ฉันได้รวมคำตอบไว้สองสามคำไว้ที่นี่
สร้างทางออกจากสตอรีบอร์ดเพื่อเชื่อมโยงไปยัง staticCell ของคุณ
@IBOutlet weak var updateStaticCell: UITableViewCell!
override func viewDidLoad() {
...
updateStaticCell.hidden = true
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.row == 0 {
return 0
} else {
return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}
}
ฉันต้องการซ่อนเซลล์แรกของฉันดังนั้นฉันจึงตั้งค่าความสูงเป็น 0 ตามที่อธิบายไว้ข้างต้น
Swift 4:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var height = super.tableView(tableView, heightForRowAt: indexPath)
if (indexPath.row == HIDDENROW) {
height = 0.0
}
return height
}
สำหรับสถานการณ์ที่ง่ายที่สุดเมื่อคุณซ่อนเซลล์ที่ด้านล่างสุดของมุมมองตารางคุณสามารถปรับ contentInset ของ tableView หลังจากที่คุณซ่อนเซลล์:
- (void)adjustBottomInsetForHiddenSections:(NSInteger)numberOfHiddenSections
{
CGFloat bottomInset = numberOfHiddenSections * 44.0; // or any other 'magic number
self.tableView.contentInset = UIEdgeInsetsMake(self.tableView.contentInset.top, self.tableView.contentInset.left, -bottomInset, self.tableView.contentInset.right);
}
นี่เป็นวิธีใหม่ในการทำสิ่งนี้โดยใช้ https://github.com/k06a/ABStaticTableViewController
NSIndexPath *ip = [NSIndexPath indexPathForRow:1 section:1];
[self deleteRowsAtIndexPaths:@[ip] withRowAnimation:UITableViewRowAnimationFade]
โซลูชันจาก k06a ( https://github.com/k06a/ABStaticTableViewController ) ดีกว่าเพราะซ่อนทั้งส่วนรวมถึงส่วนหัวและส่วนท้ายของเซลล์โดยที่โซลูชันนี้ ( https://github.com/peterpaulis/StaticDataTableViewController ) จะซ่อนทุกอย่างยกเว้นส่วนท้าย
แก้ไข
StaticDataTableViewController
ฉันเพิ่งพบวิธีการแก้ปัญหาถ้าคุณต้องการที่จะซ่อนอยู่ในส่วนท้าย นี่คือสิ่งที่คุณต้องคัดลอกในไฟล์ StaticTableViewController.m:
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
if ([tableView.dataSource tableView:tableView numberOfRowsInSection:section] == 0) {
return nil;
} else {
return [super tableView:tableView titleForFooterInSection:section];
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
CGFloat height = [super tableView:tableView heightForFooterInSection:section];
if (self.originalTable == nil) {
return height;
}
if (!self.hideSectionsWithHiddenRows) {
return height;
}
OriginalSection * os = self.originalTable.sections[section];
if ([os numberOfVissibleRows] == 0) {
//return 0;
return CGFLOAT_MIN;
} else {
return height;
}
//return 0;
return CGFLOAT_MIN;
}
คุณทำได้แน่นอน ขั้นแรกให้กลับไปที่ tableView ของคุณจำนวนเซลล์ที่คุณต้องการแสดงจากนั้นเรียกใช้super
เพื่อให้ได้เซลล์ที่ต้องการจากกระดานเรื่องราวของคุณและส่งคืนสำหรับ tableView:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.mode.numberOfCells()
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = super.tableView(tableView, cellForRowAtIndexPath: self.mode.indexPathForIndexPath(indexPath))
return cell
}
หากเซลล์ของคุณมีความแตกต่างกันให้ส่งคืนด้วย:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return super.tableView(tableView, heightForRowAtIndexPath: self.mode.indexPathForIndexPath(indexPath))
}
นอกจากโซลูชัน @Saleh Masum แล้ว:
หากคุณได้รับข้อผิดพลาดในการจัดวางอัตโนมัติคุณสามารถลบข้อ จำกัด ออกจากไฟล์tableViewCell.contentView
Swift 3:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let tableViewCell = super.tableView(tableView, cellForRowAt: indexPath)
if tableViewCell.isHidden == true
{
tableViewCell.contentView.removeConstraints(tableViewCell.contentView.constraints)
return 0
}
else{
return super.tableView(tableView, heightForRowAt: indexPath)
}
}
นี้การแก้ปัญหาขึ้นอยู่กับการไหลของแอปของคุณ หากคุณต้องการแสดง / ซ่อนเซลล์ในอินสแตนซ์ตัวควบคุมมุมมองเดียวกันนี่อาจไม่ใช่ทางเลือกที่ดีที่สุดเนื่องจากจะลบข้อ จำกัดออกไป
ฉันมีวิธีที่ดีกว่าในการซ่อนเซลล์แบบคงที่และแม้แต่ส่วนต่างๆแบบไดนามิกโดยไม่ต้องแฮ็ก
การตั้งค่าความสูงของแถวเป็น 0 สามารถซ่อนแถวได้ แต่จะไม่ได้ผลหากคุณต้องการซ่อนทั้งส่วนซึ่งจะมีช่องว่างบางส่วนแม้ว่าคุณจะซ่อนแถวทั้งหมดก็ตาม
แนวทางของฉันคือการสร้างอาร์เรย์ส่วนของเซลล์แบบคงที่ จากนั้นเนื้อหาของมุมมองตารางจะถูกขับเคลื่อนโดยอาร์เรย์ส่วน
นี่คือโค้ดตัวอย่างบางส่วน:
var tableSections = [[UITableViewCell]]()
private func configTableSections() {
// seciton A
tableSections.append([self.cell1InSectionA, self.cell2InSectionA])
// section B
if shouldShowSectionB {
tableSections.append([self.cell1InSectionB, self.cell2InSectionB])
}
// section C
if shouldShowCell1InSectionC {
tableSections.append([self.cell1InSectionC, self.cell2InSectionC, self.cell3InSectionC])
} else {
tableSections.append([self.cell2InSectionC, self.cell3InSectionC])
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return tableSections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableSections[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return tableSections[indexPath.section][indexPath.row]
}
ด้วยวิธีนี้คุณสามารถรวมรหัสการกำหนดค่าทั้งหมดของคุณเข้าด้วยกันโดยไม่ต้องเขียนรหัสที่น่ารังเกียจเพื่อคำนวณจำนวนแถวและส่วน และแน่นอนว่าไม่0
ความสูงอีกต่อไป
รหัสนี้ยังดูแลรักษาง่ายมาก ตัวอย่างเช่นหากคุณต้องการเพิ่ม / ลบเซลล์หรือส่วนเพิ่มเติม
ในทำนองเดียวกันคุณสามารถสร้างอาร์เรย์หัวเรื่องส่วนหัวและอาร์เรย์หัวเรื่องส่วนท้ายเพื่อกำหนดค่าชื่อส่วนของคุณแบบไดนามิก