ฉันใช้UITableView
แอพใน iPhone และมีรายชื่อคนที่อยู่ในกลุ่ม ฉันต้องการมันเพื่อที่ว่าเมื่อผู้ใช้คลิกที่บุคคลใดบุคคลหนึ่ง (เช่นการเลือกเซลล์) เซลล์จะเพิ่มความสูงเพื่อแสดงตัวควบคุม UI หลายตัวเพื่อแก้ไขคุณสมบัติของบุคคลนั้น
เป็นไปได้ไหม
ฉันใช้UITableView
แอพใน iPhone และมีรายชื่อคนที่อยู่ในกลุ่ม ฉันต้องการมันเพื่อที่ว่าเมื่อผู้ใช้คลิกที่บุคคลใดบุคคลหนึ่ง (เช่นการเลือกเซลล์) เซลล์จะเพิ่มความสูงเพื่อแสดงตัวควบคุม UI หลายตัวเพื่อแก้ไขคุณสมบัติของบุคคลนั้น
เป็นไปได้ไหม
คำตอบ:
ฉันพบวิธีแก้ปัญหาที่ง่ายมาก ๆ สำหรับเรื่องนี้ซึ่งเป็นผลข้างเคียงจากการUITableView
ทำงานของฉัน .....
จัดเก็บความสูงของเซลล์ในตัวแปรที่รายงานความสูงดั้งเดิมตามปกติผ่านทางtableView: heightForRowAtIndexPath:
จากนั้นเมื่อคุณต้องการทำให้ความสูงเปลี่ยนแปลงนั้นเพียงแค่เปลี่ยนค่าของตัวแปรและเรียกสิ่งนี้ว่า ...
[tableView beginUpdates];
[tableView endUpdates];
คุณจะพบว่ามันไม่ได้ทำการรีโหลดแบบเต็ม แต่ก็เพียงพอที่UITableView
จะรู้ได้ว่ามันต้องวาดเซลล์ใหม่และคว้าค่าความสูงใหม่สำหรับเซลล์ .... และคาดเดาอะไร มันเป็นภาพเคลื่อนไหวการเปลี่ยนแปลงสำหรับคุณ หวาน.
ฉันมีคำอธิบายโดยละเอียดและตัวอย่างโค้ดแบบเต็มในบล็อกของฉัน ... Animate UITableView Cell Height Change
You can also use this method followed by the endUpdates method to animate the change in the row heights without reloading the cell.
developer.apple.com/library/ios/documentation/UIKit/Reference/
ฉันชอบคำตอบของ Simon Lee ฉันไม่ได้ลองวิธีนี้ แต่ดูเหมือนว่ามันจะเปลี่ยนขนาดของเซลล์ทั้งหมดในรายการ ฉันหวังว่าจะมีการเปลี่ยนแปลงเพียงเซลล์ที่แตะอยู่ ฉันชอบ Simon แต่มีความแตกต่างเล็กน้อย สิ่งนี้จะเปลี่ยนรูปลักษณ์ของเซลล์เมื่อมีการเลือก และมันก็ทำให้เคลื่อนไหว เป็นอีกวิธีในการทำ
สร้าง int เพื่อเก็บค่าสำหรับดัชนีเซลล์ที่เลือกในปัจจุบัน:
int currentSelection;
แล้ว:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
int row = [indexPath row];
selectedNumber = row;
[tableView beginUpdates];
[tableView endUpdates];
}
แล้ว:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([indexPath row] == currentSelection) {
return 80;
}
else return 40;
}
ฉันแน่ใจว่าคุณสามารถทำการเปลี่ยนแปลงที่คล้ายกันใน tableView: cellForRowAtIndexPath: เพื่อเปลี่ยนประเภทของเซลล์หรือแม้แต่การโหลดไฟล์ xib สำหรับเซลล์
เช่นนี้การเลือกปัจจุบันจะเริ่มต้นที่ 0 คุณจะต้องทำการปรับหากคุณไม่ต้องการให้เซลล์แรกของรายการ (ที่ดัชนี 0) ดูเป็นค่าเริ่มต้น
เพิ่มคุณสมบัติเพื่อติดตามเซลล์ที่เลือก
@property (nonatomic) int currentSelection;
ตั้งค่าเป็นค่า Sentinel ใน (ตัวอย่าง) viewDidLoad
เพื่อให้แน่ใจว่าการUITableView
เริ่มต้นในตำแหน่ง 'ปกติ'
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
//sentinel
self.currentSelection = -1;
}
ในheightForRowAtIndexPath
คุณสามารถตั้งค่าความสูงที่คุณต้องการสำหรับเซลล์ที่เลือก
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
int rowHeight;
if ([indexPath row] == self.currentSelection) {
rowHeight = self.newCellHeight;
} else rowHeight = 57.0f;
return rowHeight;
}
ในdidSelectRowAtIndexPath
คุณบันทึกการเลือกปัจจุบันและบันทึกความสูงแบบไดนามิกถ้าจำเป็น
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// do things with your cell here
// set selection
self.currentSelection = indexPath.row;
// save height for full text label
self.newCellHeight = cell.titleLbl.frame.size.height + cell.descriptionLbl.frame.size.height + 10;
// animate
[tableView beginUpdates];
[tableView endUpdates];
}
}
ในการdidDeselectRowAtIndexPath
ตั้งค่าดัชนีการเลือกกลับไปที่ค่าแมวมองและเคลื่อนไหวเซลล์กลับสู่รูปแบบปกติ
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
// do things with your cell here
// sentinel
self.currentSelection = -1;
// animate
[tableView beginUpdates];
[tableView endUpdates];
}
}
reloadData ไม่ดีเพราะไม่มีภาพเคลื่อนไหว ...
นี่คือสิ่งที่ฉันกำลังพยายาม:
NSArray* paths = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]];
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView deleteRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
มันใช้งานได้ดี เกือบจะ ฉันกำลังเพิ่มความสูงของเซลล์และบางครั้งก็มี "อาการสะอึก" เล็กน้อยในมุมมองตารางเมื่อเซลล์ถูกแทนที่ราวกับว่าบางตำแหน่งการเลื่อนในมุมมองตารางกำลังถูกเก็บรักษาเซลล์ใหม่ (ซึ่งเป็นเซลล์แรก ในตาราง) จบลงด้วยการชดเชยสูงเกินไปและ scrollview กระดอนเพื่อเปลี่ยนตำแหน่ง
ฉันไม่รู้ว่าทุกอย่างเกี่ยวกับการเรียก startUpdates / endUpdates นี้คืออะไรคุณสามารถใช้งาน-[UITableView reloadRowsAtIndexPaths:withAnimation:]
ได้ นี่เป็นโครงการตัวอย่าง
reloadRowsAtIndexPaths
ฉันแก้ไขด้วย
ฉันบันทึกในdidSelectRowAtIndexPath
indexPath ของเซลล์ที่เลือกและเรียกใช้reloadRowsAtIndexPaths
ที่ส่วนท้าย (คุณสามารถส่ง NSMutableArray สำหรับรายการองค์ประกอบที่คุณต้องการโหลดซ้ำ)
ในheightForRowAtIndexPath
คุณสามารถตรวจสอบว่า indexPath อยู่ในรายการหรือไม่ของเซลล์ expandIndexPath และส่งความสูง
คุณสามารถตรวจสอบตัวอย่างพื้นฐานนี้: https://github.com/ferminhg/iOS-Examples/tree/master/iOS-UITableView-Cell-Height-Change/celdascambiadetam มันเป็นวิธีง่ายๆ
ฉันเพิ่มรหัสประเภทถ้าช่วยคุณ
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 20;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath: (NSIndexPath*)indexPath
{
if ([indexPath isEqual:_expandIndexPath])
return 80;
return 40;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Celda";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
[cell.textLabel setText:@"wopwop"];
return cell;
}
#pragma mark -
#pragma mark Tableview Delegate Methods
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSMutableArray *modifiedRows = [NSMutableArray array];
// Deselect cell
[tableView deselectRowAtIndexPath:indexPath animated:TRUE];
_expandIndexPath = indexPath;
[modifiedRows addObject:indexPath];
// This will animate updating the row sizes
[tableView reloadRowsAtIndexPaths:modifiedRows withRowAnimation:UITableViewRowAnimationAutomatic];
}
แทนที่จะเป็นbeginUpdates()
/ endUpdates()
การโทรที่แนะนำตอนนี้:
tableView.performBatchUpdates(nil, completion: nil)
Apple บอกว่าเกี่ยวกับ startUpdates / endUpdates: "ใช้เมธอด performBatchUpdates (_: เสร็จสมบูรณ์ :) :) แทนที่จะเป็นแบบนี้ทุกครั้งที่ทำได้"
ดู: https://developer.apple.com/documentation/uikit/uitableview/1614908-beginupdates
ลองทำสิ่งนี้เพื่อขยายแถวดัชนี:
@property (nonatomic) NSIndexPath *expandIndexPath;
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath
{
if ([indexPath isEqual:self.expandedIndexPath])
return 100;
return 44;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSMutableArray *modifiedRows = [NSMutableArray array];
if ([indexPath isEqual:self.expandIndexPath]) {
[modifiedRows addObject:self.expandIndexPath];
self.expandIndexPath = nil;
} else {
if (self.expandedIndexPath)
[modifiedRows addObject:self.expandIndexPath];
self.expandIndexPath = indexPath;
[modifiedRows addObject:indexPath];
}
// This will animate updating the row sizes
[tableView reloadRowsAtIndexPaths:modifiedRows withRowAnimation:UITableViewRowAnimationAutomatic];
// Preserve the deselection animation (if desired)
[tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ViewControllerCellReuseIdentifier];
cell.textLabel.text = [NSString stringWithFormat:@"I'm cell %ld:%ld", (long)indexPath.section, (long)indexPath.row];
return cell;
}
BOOL flag;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
flag = !flag;
[tableView beginUpdates];
[tableView reloadRowsAtIndexPaths:@[indexPath]
withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView endUpdates];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES == flag ? 20 : 40;
}
แค่โน้ตสำหรับคนอย่างฉันที่กำลังค้นหาเพิ่ม "รายละเอียดเพิ่มเติม" ในเซลล์ที่กำหนดเอง
[tableView beginUpdates];
[tableView endUpdates];
ทำได้ดีมาก แต่อย่าลืมดูเซลล์ "ครอบตัด" จาก Interface Builder เลือกมือถือของคุณ -> ดูเนื้อหา -> จากการตรวจสอบทรัพย์สินเลือก " คลิป subview "
Simons รุ่นที่สั้นกว่าตอบสำหรับ Swift 3 และอนุญาตให้สลับการเลือกเซลล์
var cellIsSelected: IndexPath?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
cellIsSelected = cellIsSelected == indexPath ? nil : indexPath
tableView.beginUpdates()
tableView.endUpdates()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if cellIsSelected == indexPath {
return 250
}
return 65
}
Swift 4 and above
เพิ่มโค้ดด้านล่างลงในวิธีการมอบสิทธิ์แบบแถวของคุณใน tableview
tableView.beginUpdates()
tableView.setNeedsLayout()
tableView.endUpdates()
คำตอบของ Simon Lee รุ่นที่รวดเร็ว
// MARK: - Variables
var isCcBccSelected = false // To toggle Bcc.
// MARK: UITableViewDelegate
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
// Hide the Bcc Text Field , until CC gets focused in didSelectRowAtIndexPath()
if self.cellTypes[indexPath.row] == CellType.Bcc {
if (isCcBccSelected) {
return 44
} else {
return 0
}
}
return 44.0
}
จากนั้นใน didSelectRowAtIndexPath ()
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
// To Get the Focus of CC, so that we can expand Bcc
if self.cellTypes[indexPath.row] == CellType.Cc {
if let cell = tableView.cellForRowAtIndexPath(indexPath) as? RecipientTableViewCell {
if cell.tag == 1 {
cell.recipientTypeLabel.text = "Cc:"
cell.recipientTextField.userInteractionEnabled = true
cell.recipientTextField.becomeFirstResponder()
isCcBccSelected = true
tableView.beginUpdates()
tableView.endUpdates()
}
}
}
}
ใช่มันเป็นไปได้
UITableView
มีวิธีการมอบหมาย didSelectRowAtIndexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[UIView animateWithDuration:.6
delay:0
usingSpringWithDamping:UIViewAnimationOptionBeginFromCurrentState
initialSpringVelocity:0
options:UIViewAnimationOptionBeginFromCurrentState animations:^{
cellindex = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section];
NSArray* indexArray = [NSArray arrayWithObjects:indexPath, nil];
[violatedTableView beginUpdates];
[violatedTableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationAutomatic];
[violatedTableView endUpdates];
}
completion:^(BOOL finished) {
}];
}
แต่ในกรณีของคุณหากผู้ใช้เลื่อนและเลือกเซลล์อื่นคุณต้องมีเซลล์ที่เลือกล่าสุดเพื่อย่อและขยายการreloadRowsAtIndexPaths:
เรียกเซลล์ที่เลือกในปัจจุบันheightForRowAtIndexPath:
ดังนั้นจัดการให้สอดคล้อง
นี่คือรหัสของUITableView
คลาสย่อยที่กำหนดเองซึ่งขยายUITextView
ที่เซลล์ตารางโดยไม่ต้องโหลดซ้ำ (และโฟกัสของแป้นพิมพ์หายไป):
- (void)textViewDidChange:(UITextView *)textView {
CGFloat textHeight = [textView sizeThatFits:CGSizeMake(self.width, MAXFLOAT)].height;
// Check, if text height changed
if (self.previousTextHeight != textHeight && self.previousTextHeight > 0) {
[self beginUpdates];
// Calculate difference in height
CGFloat difference = textHeight - self.previousTextHeight;
// Update currently editing cell's height
CGRect editingCellFrame = self.editingCell.frame;
editingCellFrame.size.height += difference;
self.editingCell.frame = editingCellFrame;
// Update UITableView contentSize
self.contentSize = CGSizeMake(self.contentSize.width, self.contentSize.height + difference);
// Scroll to bottom if cell is at the end of the table
if (self.editingNoteInEndOfTable) {
self.contentOffset = CGPointMake(self.contentOffset.x, self.contentOffset.y + difference);
} else {
// Update all next to editing cells
NSInteger editingCellIndex = [self.visibleCells indexOfObject:self.editingCell];
for (NSInteger i = editingCellIndex; i < self.visibleCells.count; i++) {
UITableViewCell *cell = self.visibleCells[i];
CGRect cellFrame = cell.frame;
cellFrame.origin.y += difference;
cell.frame = cellFrame;
}
}
[self endUpdates];
}
self.previousTextHeight = textHeight;
}
ฉันใช้คำตอบที่ยอดเยี่ยมของ @ Joy และมันทำงานได้อย่างสมบูรณ์กับ ios 8.4 และ XCode 7.1.1
ในกรณีที่คุณต้องการทำให้เซลล์ของคุณสลับได้ฉันเปลี่ยน -tableViewDidSelect เป็นต่อไปนี้:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
//This is the bit I changed, so that if tapped once on the cell,
//cell is expanded. If tapped again on the same cell,
//cell is collapsed.
if (self.currentSelection==indexPath.row) {
self.currentSelection = -1;
}else{
self.currentSelection = indexPath.row;
}
// animate
[tableView beginUpdates];
[tableView endUpdates];
}
ฉันหวังว่าสิ่งนี้จะช่วยคุณได้
ตรวจสอบวิธีนี้หลังจาก iOS 7 และใหม่กว่า
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath{
return UITableViewAutomaticDimension;
}
มีการปรับปรุงสิ่งนี้ใน iOS 8 เราสามารถตั้งค่าเป็นคุณสมบัติของมุมมองตารางได้
อินพุต -
tableView.beginUpdates () tableView.endUpdates () ฟังก์ชั่นเหล่านี้จะไม่เรียก
func tableView (_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {}
แต่ถ้าคุณทำ tableView.reloadRows (ที่: [selectedIndexPath! as IndexPath], ด้วย: .none)
มันจะเรียก func tableView (_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {} ฟังก์ชันนี้
ฉันเพิ่งแก้ไขปัญหานี้ด้วยการแฮ็คเล็กน้อย:
static int s_CellHeight = 30;
static int s_CellHeightEditing = 60;
- (void)onTimer {
cellHeight++;
[tableView reloadData];
if (cellHeight < s_CellHeightEditing)
heightAnimationTimer = [[NSTimer scheduledTimerWithTimeInterval:0.001 target:self selector:@selector(onTimer) userInfo:nil repeats:NO] retain];
}
- (CGFloat)tableView:(UITableView *)_tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (isInEdit) {
return cellHeight;
}
cellHeight = s_CellHeight;
return s_CellHeight;
}
เมื่อฉันต้องการขยายความสูงของเซลล์ที่ฉันตั้งค่าisInEdit = YES
และเรียกใช้เมธอด[self onTimer]
และมันจะสร้างการเติบโตของเซลล์จนกว่าจะถึงค่า s_CellHeightEditing :-)
รับพา ธ ดัชนีของแถวที่เลือก รีโหลดตาราง ในเมธอด heightForRowAtIndexPath ของ UITableViewDelegate ให้ตั้งค่าความสูงของแถวที่เลือกเป็นความสูงที่แตกต่างกันและสำหรับวิธีอื่นให้ส่งกลับความสูงของแถวปกติ
[table reloadData]
ผลการโทรในการเปลี่ยนแปลงความสูงเกิดขึ้นทันทีแทนที่จะเคลื่อนไหว