设备旋转后,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的回答( willRotateToInterfaceOrientation
和didRotateFromInterfaceOrientation
被弃用):
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是如何工作的,所以我不能太具体。