มี reloadData สำหรับ UITableView เคลื่อนไหวเมื่อมีการเปลี่ยนแปลง


183

ฉันมี UITableView ที่มีสองโหมด เมื่อเราสลับระหว่างโหมดฉันมีจำนวนส่วนและเซลล์ที่แตกต่างกันต่อส่วน เป็นการดีที่มันจะทำแอนิเมชั่นเจ๋ง ๆ เมื่อโต๊ะโตหรือหดตัว

นี่คือรหัสที่ฉันลองใช้ แต่ไม่ได้ทำอะไรเลย:

CGContextRef context = UIGraphicsGetCurrentContext(); 
[UIView beginAnimations:nil context:context]; 
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; 
[UIView setAnimationDuration:0.5]; 

[self.tableView reloadData];
[UIView commitAnimations];

มีความคิดเกี่ยวกับวิธีที่ฉันจะทำเช่นนี้?

คำตอบ:


400

จริงๆแล้วมันง่ายมาก:

[_tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];

จากเอกสาร :

การเรียกใช้เมธอดนี้ทำให้มุมมองตารางถามแหล่งข้อมูลของเซลล์ใหม่สำหรับส่วนที่ระบุ มุมมองตารางจะสร้างการแทรกของเซลล์ใหม่ในขณะที่มันทำให้เซลล์เก่าออก


13
และเป็นคำตอบที่ดีที่สุดในหน้านี้!
Matthias D

41
สิ่งนี้ไม่ถูกต้องทั้งหมดเนื่องจากจะโหลดเฉพาะส่วนแรกเท่านั้น หากตารางของคุณมีหลายส่วนสิ่งนี้จะไม่ทำงาน
Nosrettap

4
เป็นไปได้ว่าคุณจะได้รับข้อยกเว้นหากไม่มีการเปลี่ยนแปลงข้อมูล .. ดูคำตอบ
Matej

8
@Nosrettap: หากคุณต้องการให้โหลดส่วนต่างๆของ tableView ของคุณเพิ่มขึ้นสิ่งที่คุณต้องทำก็คือขยาย NSIndexSet ของคุณด้วยดัชนีส่วนทั้งหมดที่ต้องรีเฟรชเช่นกัน
JonEasy

รุ่น Swift: _tableView.reloadSections(NSIndexSet(index: 0), withRowAnimation: .Fade)มีการอัปเดตส่วนที่ 0 ซึ่งเป็นค่าเริ่มต้นส่วนแรกเท่านั้น
kbpontius

264

คุณอาจต้องการใช้:

Objective-C

[UIView transitionWithView: self.tableView
                  duration: 0.35f
                   options: UIViewAnimationOptionTransitionCrossDissolve
                animations: ^(void)
 {
      [self.tableView reloadData];
 }
                completion: nil];

รวดเร็ว

UIView.transitionWithView(tableView,
                          duration: 0.35,
                          options: .TransitionCrossDissolve,
                          animations:
{ () -> Void in
    self.tableView.reloadData()
},
                          completion: nil);

สวิฟท์ 3, 4 และ 5

UIView.transition(with: tableView,
                  duration: 0.35,
                  options: .transitionCrossDissolve,
                  animations: { self.tableView.reloadData() }) // left out the unnecessary syntax in the completion block and the optional completion parameter

ไม่ยุ่งยาก : D

คุณสามารถใช้เอUIViewAnimationOptionTransitionsฟเฟกต์ที่เย็นกว่านี้ได้:

  • transitionNone
  • transitionFlipFromLeft
  • transitionFlipFromRight
  • transitionCurlUp
  • transitionCurlDown
  • transitionCrossDissolve
  • transitionFlipFromTop
  • transitionFlipFromBottom

2
สิ่งนี้มีประโยชน์หากสถานะเริ่มต้น / สิ้นสุดของมุมมองตารางของคุณจะแตกต่างกันมาก (และมันจะซับซ้อนในการคำนวณส่วนและแถวเพื่อเพิ่ม / ลบ) แต่คุณมีบางสิ่งที่น้อยกว่า
Ben Packard

1
ภาพเคลื่อนไหวนี้ไม่ดีเท่าการโหลดมุมมองใหม่โดยใช้วิธีการที่สร้างขึ้น แต่ไม่เหมือนกับวิธีการจัดอันดับที่สูงกว่าที่กล่าวถึงที่นี่สิ่งนี้ใช้ได้เมื่อคุณมีหลายส่วน
Mark Bridges

1
ว้าวหลังจากลองใช้เวลาที่เหลือทั้งหมดนี้มันช่างสมบูรณ์แบบสำหรับฉัน
Lucas Goossen

1
@MarkBridges คำตอบที่ได้รับคะแนนสูงกว่านั้นใช้ได้กับหลายส่วน :) -[_tableView reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, sectionCount)] withRowAnimation:UITableViewRowAnimationFade];
lobianco

2
@Athony มันไม่ทำงานหากสถานะสิ้นสุดมีส่วนมาก / น้อยกว่าสถานะเริ่มต้น จากนั้นคุณจะต้องติดตามด้วยตนเองว่าส่วนใดที่เพิ่ม / ลบซึ่งค่อนข้างยุ่งยาก
nikolovski

78

มีอิสระมากขึ้นในCATransitionชั้นเรียน

มันไม่ได้ จำกัด แค่การซีดจาง แต่สามารถเคลื่อนไหวได้เช่นกัน ..


ตัวอย่างเช่น:

(อย่าลืมนำเข้าQuartzCore)

CATransition *transition = [CATransition animation];
transition.type = kCATransitionPush;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.fillMode = kCAFillModeForwards;
transition.duration = 0.5;
transition.subtype = kCATransitionFromBottom;

[[self.tableView layer] addAnimation:transition forKey:@"UITableViewReloadDataAnimationKey"];

เปลี่ยนtypeเพื่อให้ตรงกับความต้องการของคุณเช่นkCATransitionFadeอื่น ๆ

การใช้งานใน Swift:

let transition = CATransition()
transition.type = kCATransitionPush
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.fillMode = kCAFillModeForwards
transition.duration = 0.5
transition.subtype = kCATransitionFromTop
self.tableView.layer.addAnimation(transition, forKey: "UITableViewReloadDataAnimationKey")
// Update your data source here
self.tableView.reloadData()

การอ้างอิงสำหรับCATransition

สวิฟท์ 5:

let transition = CATransition()
transition.type = CATransitionType.push
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
transition.fillMode = CAMediaTimingFillMode.forwards
transition.duration = 0.5
transition.subtype = CATransitionSubtype.fromTop
self.tableView.layer.add(transition, forKey: "UITableViewReloadDataAnimationKey")
// Update your data source here
self.tableView.reloadData()

สิ่งนี้จะเคลื่อนไหวตารางโดยรวมแทนที่จะเป็นแถว / ส่วนเดียว
Agos

@Agos มันยังคงตอบคำถาม คำถามที่ "วิธีการโหลดเพียงหนึ่งแถว" มีค่อนข้างคำตอบที่แตกต่างกันเช่นการใช้ภาพเคลื่อนไหวไปยังสถานที่ให้บริการของlayer UITableViewCell
Matej

@matejkramny ฉันคาดว่าตารางจะเคลื่อนไหวเพียงแถวที่แตกต่างกัน (ตามที่อ้างอิงในคำถาม) แต่วิธีนี้จะผลักตารางทั้งหมดในครั้งเดียว บางทีฉันอาจจะหายไปบางสิ่งบางอย่าง?
Agos

@Agos hmm ไม่ควรทำเช่นนั้น ไม่สามารถทำได้เพียงครึ่งตารางเท่านั้นเนื่องจาก QuartzCore ปรับเปลี่ยนมุมมองโดยตรง คุณสามารถลองรับเซลล์จากมุมมองที่โต๊ะแล้วใช้ภาพเคลื่อนไหวนี้ในแต่ละแม้ว่า ( แต่ไม่แน่ใจว่ามันจะทำงาน)
มาเตจ์

2
ทำงานเหมือนจับใจกับ kCATransitionFade ขอบคุณ! :)
quarezz

60

ฉันเชื่อว่าคุณสามารถอัปเดตโครงสร้างข้อมูลของคุณจากนั้น:

[tableView beginUpdates];
[tableView deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES];
[tableView insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES];
[tableView endUpdates];

นอกจากนี้ "withRowAnimation" ไม่ได้เป็นบูลีน แต่เป็นสไตล์แอนิเมชั่น:

UITableViewRowAnimationFade,
UITableViewRowAnimationRight,
UITableViewRowAnimationLeft,
UITableViewRowAnimationTop,
UITableViewRowAnimationBottom,
UITableViewRowAnimationNone,
UITableViewRowAnimationMiddle

สิ่งที่เรียบง่าย แต่ง่ายต่อการไปยัง StackOverflow และรับตัวอย่างข้อมูลที่คุณต้องการมากกว่า trawl docs . ขอบคุณ!
Jasper Blues

24

คำตอบทั้งหมดเหล่านี้สมมติว่าคุณกำลังใช้ UITableView ที่มีเพียง 1 ส่วน

เมื่อต้องการจัดการสถานการณ์ที่คุณใช้มากกว่า 1 ส่วนอย่างถูกต้อง:

NSRange range = NSMakeRange(0, myTableView.numberOfSections);
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:range];
[myTableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic];

(หมายเหตุ: คุณควรตรวจสอบให้แน่ใจว่าคุณมีมากกว่า 0 หัวข้อ!)

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

int sectionNumber = 0; //Note that your section may be different

int nextIndex = [currentItems count]; //starting index of newly added items

[myTableView beginUpdates];

for (NSObject *item in itemsToAdd) {
    //Add the item to the data source
    [currentItems addObject:item];

    //Add the item to the table view
    NSIndexPath *path = [NSIndexPath indexPathForRow:nextIndex++ inSection:sectionNumber];
    [myTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationAutomatic];
}

[myTableView endUpdates];

3
จุดดีเกี่ยวกับการคำนวณส่วน แต่ฉันมีเพียงส่วนเดียวและรหัสของคุณมีข้อผิดพลาดแบบออฟไลน์ ฉันต้องเปลี่ยนบรรทัดแรกของรหัสของคุณเป็น NSRange range = NSMakeRange (0, myTableView.numberOfSections);
Danyal Aytekin

18

วิธีเข้าหานี้คือบอก tableView เพื่อลบและเพิ่มแถวและส่วนด้วย

insertRowsAtIndexPaths:withRowAnimation:,
deleteRowsAtIndexPaths:withRowAnimation:,
insertSections:withRowAnimation:และ
deleteSections:withRowAnimation:

วิธีการของ UITableView

เมื่อคุณเรียกใช้เมธอดเหล่านี้ตารางจะเคลื่อนไหวเข้า / ออกรายการที่คุณร้องขอจากนั้นเรียกใช้ reloadData ด้วยตนเองเพื่อให้คุณสามารถอัปเดตสถานะหลังจากภาพเคลื่อนไหวนี้ ส่วนนี้มีความสำคัญ - ถ้าคุณเคลื่อนไหวทุกอย่าง แต่ไม่เปลี่ยนข้อมูลที่ส่งคืนโดยแหล่งข้อมูลของตารางแถวจะปรากฏขึ้นอีกครั้งหลังจากที่ภาพเคลื่อนไหวเสร็จสมบูรณ์

ดังนั้นขั้นตอนการสมัครของคุณจะเป็น:

[self setTableIsInSecondState:YES];

[myTable deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES]];

ตราบใดที่วิธีการ dataSource ของตารางของคุณคืนค่าชุดของส่วนและแถวใหม่ที่ถูกต้องโดยการตรวจสอบ[self tableIsInSecondState](หรืออะไรก็ตาม) สิ่งนี้จะได้ผลที่คุณต้องการ


16

ฉันไม่สามารถแสดงความคิดเห็นกับคำตอบด้านบน แต่การดำเนินการอย่างรวดเร็วจะเป็น:

self.tableView.reloadSections([0], with: UITableViewRowAnimation.fade)

คุณสามารถรวมส่วนได้มากเท่าที่คุณต้องการอัปเดตในอาร์กิวเมนต์แรกสำหรับ reloadSections

ภาพเคลื่อนไหวอื่น ๆ ที่มีอยู่ในเอกสาร: https://developer.apple.com/reference/uikit/uitableviewrowanimation

จาง แถวหรือแถวที่แทรกหรือลบจะจางหายไปหรือออกจากมุมมองตาราง

ขวา แทรกแถวหรือแถวเลื่อนในจากขวา; แถวที่ถูกลบหรือแถวเลื่อนออกไปทางขวา

ซ้าย แถวแทรกหรือแถวเลื่อนเข้าจากทางซ้าย แถวที่ถูกลบหรือแถวเลื่อนออกไปทางซ้าย

ด้านบน แถวแทรกหรือแถวเลื่อนในจากด้านบน; แถวหรือแถวที่ถูกลบจะเลื่อนออกไปทางด้านบน

ด้านล่าง แทรกแถวหรือแถวเลื่อนในจากด้านล่าง; แถวหรือแถวที่ถูกลบจะเลื่อนออกไปทางด้านล่าง

กรณีไม่มี แถวที่แทรกหรือลบใช้ภาพเคลื่อนไหวเริ่มต้น

ตรงกลาง มุมมองตารางความพยายามที่จะให้เซลล์เก่าและใหม่ศูนย์กลางในพื้นที่ที่พวกเขาทำหรือจะครอบครอง พร้อมใช้งานใน iPhone 3.2

อัตโนมัติ มุมมองตารางจะเลือกสไตล์ของภาพเคลื่อนไหวที่เหมาะสมสำหรับคุณ (เปิดตัวใน iOS 5.0)


1
สำหรับ Swift 4.2: self.tableView.reloadSections ([0], ด้วย: UITableView.RowAnimation.fade)
Reefwing




1

ในกรณีของฉันฉันต้องการเพิ่มอีก 10 แถวใน tableview (สำหรับประเภทการทำงาน "แสดงผลลัพธ์เพิ่มเติม") และฉันทำสิ่งต่อไปนี้:

  NSInteger tempNumber = self.numberOfRows;
  self.numberOfRows += 10;
  NSMutableArray *arrayOfIndexPaths = [[NSMutableArray alloc] init];
  for (NSInteger i = tempNumber; i < self.numberOfRows; i++) {
    [arrayOfIndexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
  }
  [self.tableView beginUpdates];
  [self.tableView insertRowsAtIndexPaths:arrayOfIndexPaths withRowAnimation:UITableViewRowAnimationTop];
  [self.tableView endUpdates];

ในกรณีส่วนใหญ่แทนที่จะเป็น "self.numberOfRows" คุณมักจะใช้จำนวนอาร์เรย์ของวัตถุสำหรับ tableview ดังนั้นเพื่อให้แน่ใจว่าโซลูชันนี้ทำงานได้ดีสำหรับคุณ "arrayOfIndexPaths" ต้องเป็นอาร์เรย์ที่ถูกต้องของพา ธ ดัชนีของแถวที่ถูกแทรก หากแถวนั้นมีอยู่สำหรับพา ธ ดัชนีใด ๆ รหัสอาจผิดพลาดดังนั้นคุณควรใช้วิธี "reloadRowsAtIndexPaths: withRowAnimation:" สำหรับพา ธ ดัชนีเหล่านั้นเพื่อหลีกเลี่ยงการหยุดทำงาน


1

หากคุณต้องการเพิ่มภาพเคลื่อนไหวที่คุณกำหนดเองไปยังเซลล์ UITableView ให้ใช้

[theTableView reloadData];
[theTableView layoutSubviews];
NSArray* visibleViews = [theTableView visibleCells];

เพื่อรับอาร์เรย์ของเซลล์ที่มองเห็นได้ จากนั้นเพิ่มภาพเคลื่อนไหวที่กำหนดเองใด ๆ ลงในแต่ละเซลล์

ลองดูกระทู้นี้ที่ฉันโพสต์เพื่อสร้างแอนิเมชันของเซลล์ https://gist.github.com/floprr/1b7a58e4a18449d962bd


1

การสร้างภาพเคลื่อนไหวโดยไม่มี reloadData () ในSwiftสามารถทำได้เช่นนี้ (ตั้งแต่เวอร์ชั่น 2.2):

tableview.beginUpdates()
var indexPathsToDeleteForAnimation: [NSIndexPath] = []
var numOfCellsToRemove = ArrayOfItemsToRemove ?? 0

// Do your work here
while numOfCellsToRemove > 0 {
    // ...or here, if you need to add/remove the same amount of objects to/from somewhere
    indexPathsToDeleteForAnimation.append(NSIndexPath(forRow: selectedCellIndex+numOfCellsToRemove, inSection: 0))
    numOfCellsToRemove -= 1
}
tableview.deleteRowsAtIndexPaths(indexPathsToDeleteForAnimation, withRowAnimation: UITableViewRowAnimation.Right)
tableview.endUpdates()

ในกรณีที่คุณต้องเรียก reloadData () หลังจากที่ภาพเคลื่อนไหวสิ้นสุดลงคุณสามารถยอมรับการเปลี่ยนแปลงใน CATransaction ดังนี้:

CATransaction.begin()
CATransaction.setCompletionBlock({() in self.tableview.reloadData() })
tableview.beginUpdates()
var indexPathsToDeleteForAnimation: [NSIndexPath] = []
var numOfCellsToRemove = ArrayOfItemsToRemove.count ?? 0

// Do your work here
while numOfCellsToRemove > 0 {
     // ...or here, if you need to add/remove the same amount of objects to/from somewhere
     indexPathsToDeleteForAnimation.append(NSIndexPath(forRow: selectedCellIndex+numOfCellsToRemove, inSection: 0))
     numOfCellsToRemove -= 1
}
tableview.deleteRowsAtIndexPaths(indexPathsToDeleteForAnimation, withRowAnimation: UITableViewRowAnimation.Right)
tableview.endUpdates()
CATransaction.commit()

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


1
CATransition *animation = [CATransition animation];
animation.duration = .3;
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromLeft];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[animation setDuration:.3];

[[_elementTableView layer] addAnimation:animation forKey:@"UITableViewReloadDataAnimationKey"];

[tableView reloadData];

2
เหตุใดจึงตั้งระยะเวลา.3สองครั้ง
Pang

1

หากต้องการโหลดทุกส่วนไม่ได้เป็นเพียงหนึ่งเดียวกับระยะเวลาที่กำหนดเอง

durationพารามิเตอร์ผู้ใช้ของUIView.animateเพื่อตั้งค่าช่วงเวลาที่กำหนดเอง

UIView.animate(withDuration: 0.4, animations: { [weak self] in
    guard let `self` = self else { return }
    let indexSet = IndexSet(integersIn: 0..<self.tableView.numberOfSections)
    self.tableView.reloadSections(indexSet, with: UITableView.RowAnimation.fade)
})

0

UITableViewภาพเคลื่อนไหวพื้นเมืองใน Swift

แทรกและลบแถวทั้งหมดtableView.performBatchUpdatesพร้อมกันเพื่อให้เกิดขึ้นพร้อมกัน การสร้างคำตอบจาก @iKenndac ใช้วิธีการต่าง ๆ เช่น:

  • tableView.insertSections
  • tableView.insertRows
  • tableView.deleteSections
  • tableView.deleteRows

Ex:

 tableView.performBatchUpdates({
   tableView.insertSections([0], with: .top)
 })

ส่วนนี้จะแทรกส่วนที่ตำแหน่งศูนย์ด้วยภาพเคลื่อนไหวที่โหลดจากด้านบน นี่จะเรียกใช้cellForRowAtเมธอดอีกครั้งและตรวจสอบเซลล์ใหม่ที่ตำแหน่งนั้น คุณสามารถโหลดมุมมองตารางทั้งหมดอีกครั้งด้วยภาพเคลื่อนไหวที่เฉพาะเจาะจง

Re: คำถาม OP ต้องมีการตั้งค่าสถานะตามเงื่อนไขเพื่อแสดงเซลล์สำหรับสถานะมุมมองตารางอื่น

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