我在我正在创建的笔记记录应用程序中有一个视图,它由一个UITableView和一个UITextView作为自定义UITableViewCell(以及其他东西)组成。我知道在另一个UIScrollView中有一个UIScrollView通常不推荐,但我没有看到更好的方法来实现我的目的。
无论如何,我现在遇到的问题是UITextView尽管已禁用滚动,但仍然影响UITableView本身的滚动。换句话说,当我在UITextView中输入文本或选择它时,UITextView会自动滚动UITableView。有时它可以按照需要工作,适当地滚动到所选文本,但通常不滚动,通常滚动到UITextView单元格的底部(这根本不是我想要的)。所以我一直在尝试手动处理滚动或找到一种让它自动运行的方法,但到目前为止我没有运气。
我一直在这里和Google上搜索解决方案好几天,但我还没有想出任何有效的方法。我试过简单地滚动到textViewDidBeginEditing
方法中的所需区域或拦截UIKeyboardWillShowNotification
通知,但都没有产生所需的效果 - 前者在UITextView已经自动滚动后滚动,后者在之前滚动(因此自动滚动仍然以任何一种方式发生。)
我还尝试了对单元格中使用的UITextView进行子类化并覆盖所有滚动方法(即scrollRectToVisible
),但这似乎也不会阻止自动滚动。我在UITextView正在使用时尝试调整UITableView的框架,这只会让事情变得更糟。
所以我得出的结论是,我必须以某种方式禁用UITextView中的所有自动滚动,或者阻止两者以某种方式进行通信。我一直试图找到一种方法来做到这一点,到目前为止我还没有运气。有谁知道如何做到这一点或有一个替代解决方案我的问题?我真的很感激这里有任何帮助。
以下是我认为与此问题相关的代码。如果有帮助,我很乐意再提供。此外,这是我的第一个iOS应用程序,所以请原谅我,如果我的代码中有一些不好的技术,或者有一些我忽略的东西。
的UITableViewController:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
switch (indexPath.row) {
case 0:
cell = [self cellForTitleCell:indexPath withTableView:tableView];
break;
case 1:
cell = [self cellForBodyCell:indexPath withTableView:tableView];
break;
default:
cell = [self cellForListCell:indexPath withTableView:tableView];
break;
}
return cell;
}
- (UITableViewCell *)cellForBodyCell:(NSIndexPath *)indexPath withTableView: (UITableView *) tableView
{
static NSString *CellIdentifier = @"NoteViewBodyCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
NSString *bodyText = note.Body;
float frameHeight = [self tableView:tableView heightForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
frameHeight += self.navigationController.navigationBar.frame.size.height;
frameHeight += self.navigationController.toolbar.frame.size.height;
if (bodyTextView == nil)
{
bodyTextView = [[BodyTextView alloc] initWithFrame:CGRectMake(0, 0, 320, 460 - frameHeight)];
bodyTextView.font = [UIFont systemFontOfSize:17.0];
bodyTextView.text = bodyText;
bodyTextView.textColor = [UIColor blackColor];
bodyTextView.editable = YES;
bodyTextView.delegate = self;
bodyTextView.tag = 6;
CGSize bodySize = [bodyTextView.text sizeWithFont:bodyTextView.font
constrainedToSize:CGSizeMake(self.tableView.bounds.size.width-20, 9999)
lineBreakMode:UILineBreakModeWordWrap];
CGRect bodyFrame = bodyTextView.frame;
if (bodySize.height < 460 - frameHeight)
bodySize.height = 460 - frameHeight;
bodyFrame.size.height = bodySize.height;
bodyTextView.frame = bodyFrame;
bodyTextView.scrollEnabled = NO;
}
[cell.contentView addSubview:bodyTextView];
cell.frame = bodyTextView.frame;
bodyTextView.inputAccessoryView = keyboardToolbar;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat rowHeight;
CGSize bodyTextSize;
switch (indexPath.row) {
case 0:
rowHeight = 40;
break;
case 1:
if ([self isStringEmpty:bodyTextView.text])
bodyTextSize = [note.Body sizeWithFont:[UIFont systemFontOfSize:17.0] constrainedToSize:CGSizeMake(self.tableView.bounds.size.width-20, 9999) lineBreakMode:UILineBreakModeWordWrap];
else
bodyTextSize = bodyTextView.contentSize;
if (bodyTextSize.height < 460 - 128)
rowHeight = 460 - 128;
else
rowHeight = bodyTextSize.height;
break;
default:
rowHeight = 40;
break;
}
return rowHeight;
}
- (void)textViewDidChange:(UITextView *)textView
{
[self.tableView beginUpdates];
[self.tableView endUpdates];
CGRect bodyFrame = bodyTextView.frame;
bodyFrame.size.height = bodyTextView.contentSize.height;
if (bodyFrame.size.height < 460 - 128)
bodyFrame.size.height = 460 - 128;
bodyTextView.frame = bodyFrame;
}
UITextView(子类):
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
self.scrollEnabled = NO;
}
return self;
}
- (void) scrollRectToVisible:(CGRect)rect animated:(BOOL)animated
{
// do nothing
}
- (UIEdgeInsets) contentInset
{
return UIEdgeInsetsZero;
}
- (void)scrollRangeToVisible:(NSRange)range
{
// do nothing
}
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated
{
// do nothing
}
- (BOOL) isScrollEnabled
{
return NO;
}
我尝试过的一些方法(在StackOverflow上找到):
// tried calling this method in both textViewDidBeginEditing and keyboardWillShow
- (BOOL)scrollToCursor
{
// if there is a selection cursor…
if(bodyTextView.selectedRange.location != NSNotFound)
{
NSLog(@"selectedRange: %d %d", bodyTextView.selectedRange.location, bodyTextView.selectedRange.length);
// work out how big the text view would be if the text only went up to the cursor
NSRange range;
range.location = bodyTextView.selectedRange.location;
range.length = bodyTextView.text.length - range.location;
NSString *string = [bodyTextView.text stringByReplacingCharactersInRange:range withString:@""];
CGSize size = [string sizeWithFont:bodyTextView.font constrainedToSize:bodyTextView.bounds.size lineBreakMode:UILineBreakModeWordWrap];
// work out where that position would be relative to the textView's frame
CGRect viewRect = bodyTextView.frame;
int scrollHeight = viewRect.origin.y + size.height;
CGRect finalRect = CGRectMake(1, scrollHeight, 1, 1);
// scroll to it
[self.tableView scrollRectToVisible:finalRect animated:YES];
return YES;
}
else
{
NSLog(@"NO CURSOR");
return NO;
}
}
- (void) keyboardWillShow:(NSNotification *)notification
{
if ([bodyTextView isFirstResponder])
{
NSLog(@"starting to change scroll view");
// Get the keyboard size
CGRect keyboardBounds;
[[notification.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] getValue: &keyboardBounds];
// Detect orientation
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
CGRect frame = self.tableView.frame;
// Start animation
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.3f];
// Reduce size of the Table view
if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown)
frame.size.height -= keyboardBounds.size.height;
else
frame.size.height -= keyboardBounds.size.width;
frame.size.height += keyboardToolbar.frame.size.height;
// Apply new size of table view
self.tableView.frame = frame;
// Scroll the table view to see the TextField just above the keyboard
if (self.bodyTextView)
{
CGRect textViewRect = [self.tableView convertRect:bodyTextView.bounds fromView:bodyTextView];
[self.tableView scrollRectToVisible:textViewRect animated:NO];
}
[UIView commitAnimations];
}
isKeyboardVisible = YES;
}
- (void) keyboardWillHide:(NSNotification *)notification
{
if ([bodyTextView isFirstResponder])
{
// Get the keyboard size
CGRect keyboardBounds;
[[notification.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] getValue: &keyboardBounds];
// Detect orientation
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
CGRect frame = self.tableView.frame;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.3f];
// Reduce size of the Table view
if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown)
frame.size.height += keyboardBounds.size.height;
else
frame.size.height += keyboardBounds.size.width;
// Apply new size of table view
self.tableView.frame = frame;
[UIView commitAnimations];
}
isKeyboardVisible = NO;
}
答案 0 :(得分:2)
我相信大多数UITableView
的自动滚动代码都位于UITableViewController
。例如,如果其中一个表行中有UITextField
朝向屏幕底部,则当用户点击UITextField
时,表格会自动向上滚动以便为键盘腾出空间。由于您希望最小化自动滚动,我建议不要使用UITableViewController
。相反,只是子类UIViewController
&amp;让它实施UITableViewDelegate
&amp; UITableViewDataSource
。话虽这么说,你也会错过UITableViewController
提供的一些好事。
HTH,
阿克沙伊
答案 1 :(得分:0)
bodyTextView是您尝试滚动/不滚动的文本视图吗?如果是这样,您是否在代码中的其他位置设置了委托?意思是,你在某处有bodyTextView.delegate = self;
之类的东西吗?如果您尚未设置其委托,那可能是因为它没有响应您的某些代码。为了能够这样做,请通过将<UITextViewDelegate>
添加到头文件中来订阅文本视图委托,并按照我的解释设置其委托。