设备旋转后,UITableView纠正滚动位置

我正在为一本书build立一个像读者的东西。 当用户旋转手机,我想增加字体大小。 我正在使用UITableView来显示文本块。

问题是,增加字体大小会增加我的表格视图中行的高度,如果我在纵向模式下阅读段落320,则在横向模式下获得280或类似的东西。

我已经build立了一个使用这个代码的循环通知监听器:

  UIDevice *device = [UIDevice currentDevice]; [device beginGeneratingDeviceOrientationNotifications]; NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; [nc addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:device]; 

并试图保存旋转之前的最后一段索引,然后向下滚动到旋转后,但我似乎无法达到预期的效果。

处理这种情况的最好办法是什么?我在哪里实际执行“之前”和“之后”的轮换状态?

我希望它可以在iOS 4 +上运行。

Swift 3版的Said willRotateToInterfaceOrientation Samed的回答( willRotateToInterfaceOrientationdidRotateFromInterfaceOrientation被弃用):

 override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) { coordinator.animate(alongsideTransition: { context in // Save the visible row position self.visibleRows = self.tableView.indexPathsForVisibleRows! context.viewController(forKey: UITransitionContextViewControllerKey.from) }, completion: { context in // Scroll to the saved position prior to screen rotate self.tableView.scrollToRow(at: self.visibleRows[0], at: .top, animated: false) }) } 

使用委托方法willRotateToInterfaceOrientation:将可见单元格存储在数组中,然后使用UITableView的另一个委托方法didRotateFromInterfaceOrientation:滚动到之前存储在数组中的可见索引path。 这是build议的,你不必依靠在不同的线程中不一致的0.2秒等待来处理后期旋转事件。

 - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { // Save the visible row position visibleRows = [tableview indexPathsForVisibleRows]; } -(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { // Scroll to the saved position prior to screen rotate [tableView scrollToRowAtIndexPath:[visibleRows objectAtIndex:0] atScrollPosition:UITableViewScrollPositionTop animated:NO]; } 

一个简单的方法是存储顶部可见单元格的索引path,更改字体大小然后恢复顶部单元格:

 NSIndexPath* topCellIndexPath = [[_tableView indexPathsForVisibleRows] objectAtIndex:0]; //Insert code to change font size here [_tableView scrollToRowAtIndexPath:topCellIndexPath atScrollPosition:UITableViewScrollPositionTop animated:NO]; 

这个代码可以放在方向改变时运行的任何方法中,比如放在问题中的orientationChanged:方法。

这不会考虑到在单元格中间滚动,所以如果单元格的高度很大,将无法正常工作,需要使用内容偏移量的更复杂的方法。 让我知道如果是这样的话。

由于我无法得到一个好的答案,我会回答自己。 我看到处处都找不到方法来做我想要的,所以我只是使用shouldAutorotateToInterfaceOrientation方法来增加字体的大小,然后开始一个睡眠0.2秒的小线程,然后滚动到所需的行。 谢谢你的帮助。

编辑:使用委托方法willRotateToInterfaceOrientation:将可见单元格存储在数组中,然后使用委托方法didRotateFromInterfaceOrientation:滚动到您在数组中logging的可见索引path。

 - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { // Save the visible row position visibleRows = [tableview indexPathsForVisibleRows]; } -(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { // Scroll to the saved position prior to screen rotate [tableView scrollToRowAtIndexPath:[visibleRows objectAtIndex:0] atScrollPosition:UITableViewScrollPositionTop animated:NO]; } 
  - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation) fromInterfaceOrientation { NSLog(@"didRotateFromInterfaceOrientation:%d",fromInterfaceOrientation); [tableView reloadRowsAtIndexPaths:[tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationNone]; } 

然后,我build议添加interfaceOrientation数字或简单的表格宽度到出列单元格的名称,这样tableView知道一个旋转中的单元格与另一个单元格中的单元格不同。 像这样:

 - (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath withType:(NSString *)s_type { UITableViewCell *cell = nil; // add width of table to the name so that rotations will change the cell dequeue names s_cell = [s_cell stringByAppendingString: [NSString stringWithFormat:@"%@%d",@"Width",(int)tv.bounds.size.width] ]; NSLog(@"%@",s_cell); cell = [tv dequeueReusableCellWithIdentifier:s_cell]; if( cell == nil ) { cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:s_cell] autorelease]; } } 

首先,重新加载所有的表格单元格,使用[self.tableView reloadData]

其次,在( UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath方法中添加负责缩小的代码行。

例:

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { //Some identifier and recycling stuff if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) { //Make labels smaller } else { //Make them bigger } } 

或者你可以在创build时调用updateCellForRotate:forRow:方法。 但我不确定这个function是如何工作的,所以我不能太具体。