2012-07-17 71 views
3

我在可编辑的webView中显示了一些文本。只要我向下滚动并触摸某处来编辑呈现的文本,它就会自动滚动到顶部并出现键盘,因此我必须再次将其向下滚动以进行编辑。有没有办法阻止webView做到这一点?可编辑的webView自动滚动到顶部

回答

6

得到了同样的问题,仍然在寻找的这种怪异的行为,正常的解决方案。 我们仍然不能阻止一个UIWebView从这样做,如果你看一下iPad上的Evernote的应用程序,你会看到同样的问题在那里,不幸的是:( 我们可以在此做的唯一一件事就是保存的UIWebView的contentOffset当键盘所示,如果键盘打开后恢复

这看起来像:

//register your controller for keyboard notifications 
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; 
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) UIKeyboardDidShowNotification object:nil]; 

然后,你将需要处理像键盘通知:

- (void)keyboardWillShow:(NSNotification *)aNotification { 

// scroll view will scroll to beginning, but we save current offset 
[_yourViewWithWebView saveOffset]; 
    ... 
} 

你的Wi之后会需要处理事件表现出键盘的时候:

- (void)keyboardWasShown:(NSNotification*)aNotification{ 
... 
// scroll view scrolled to beginning, but we restore previous offset 
[_yourViewWithWebView restoreOffset]; 
} 

因此在您的视图包含一个UIWebView您需要实现:

static CGPoint editableWebViewOffsetPoint; 

- (void) saveOffset{ 
    editableWebViewOffsetPoint = yourWebView.scrollView.contentOffset; 
} 

- (void) restoreOffset{ 
    //just use animation block to have scroll animated after jumping to top and back to old position 
    [UIView animateWithDuration:.2 
      delay:0 
      options:UIViewAnimationOptionCurveEaseIn 
      animations:^{ 
       yourWebView.scrollView.contentOffset = editableWebViewOffsetPoint; 
      } 
      completion:nil]; 

} 

希望一般来说这将帮助你解决你的问题至少部分。

如果有人可以帮助我们防止UIWebView的滚动每个显示键盘时到顶部,我深深的体会到这一点。

UIWebView.scrollView.scrollsToTop = NO;没有帮助。

显示键盘,并使其显示后的键盘也没有工作之前禁用滚动。

此外,在未来,你会当光标不在UIWebView的可视区域面临编辑文本的问题 - 它不会自动滚动本身,使光标可见。我们已经解决了这个问题,但是我正在编写关于我们如何完成这个任务的详细和可读教程。如果你已经解决了这个问题,我会很感激看看你的解决方案:)

PS:http://www.cocoanetics.com/2011/01/uiwebview-must-die/

谢谢 谢尔盖N.

+0

非常感谢这么全面的回答。我很感激。该解决方案确实在一定程度上解决了问题。关于“光标不在可见区域时编辑文本”问题,我使用以下两个函数在textView中解决了这个问题。尽管我也必须在webView中尝试它们。 – gamersoul 2012-07-19 05:02:49

+0

谢尔盖,你是对的。肯定会死的。 – velkopopovizky 2012-07-19 10:12:45

+0

谢尔盖,你写过那个教程了吗? :)我一直在努力与这些'UIWebView's很长一段时间。 – 2012-09-25 23:03:06

0

的“编辑文本功能,当光标不在可见区域“问题。

- (void)keyboardWasShown:(NSNotification *)aNotification { 

//if(self.navigationController.viewControllers objectAtIndex:([self.navigationController.viewControllers count]-1)==self.) 
NSLog(@"keyboardshown"); 
if (keyboardshown) 
    return; 
keyboardshown=YES; 
NSDictionary* userInfo = [aNotification userInfo]; 

CGRect keyboardEndFrame; 
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame]; 

CGRect newFrame = self.textView.frame; 
CGRect keyboardFrame = [self.textView convertRect:keyboardEndFrame toView:nil]; 

newFrame.size.height -= keyboardFrame.size.height;  
[UIView beginAnimations:@"ResizeForKeyboard" context:nil]; 
[UIView setAnimationBeginsFromCurrentState:YES]; 

[UIView setAnimationDuration:0.3]; 
[self.textView setFrame:newFrame]; 
[UIView commitAnimations]; 



} 

- (void)keyboardWasHidden:(NSNotification *)aNotification { 

if (!keyboardshown) 
    return; 
keyboardshown=NO; 

NSDictionary* userInfo = [aNotification userInfo]; 

CGRect keyboardEndFrame; 
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame]; 

CGRect newFrame = self.textView.frame; 
CGRect keyboardFrame = [self.textView convertRect:keyboardEndFrame toView:nil]; 

newFrame.size.height += keyboardFrame.size.height; 
[UIView beginAnimations:@"ResizeForKeyboard" context:nil]; 
[UIView setAnimationDuration:0.3]; 
self.textView.frame = newFrame; 
[UIView commitAnimations]; 




} 
0

实际上keyboardWasShown不会总是特别是当用户已经BT键盘连接和虚拟一个可以隐藏/通过弹出键所示调用。我们已经实现了自己的类,如:

@implementation KeyboardUtils 

+ (CGRect) convertRect:(CGRect)rect toView:(UIView *)view { 
    UIWindow *window = [view isKindOfClass:[UIWindow class]] ? (UIWindow *) view : [view window]; 
    return [view convertRect:[window convertRect:rect fromWindow:nil] fromView:nil]; 
} 

/** 
* This is working but deprecated solution 
* Based on UIKeyboardCenterBeginUserInfoKey and UIKeyboardCenterEndUserInfoKey which are deprecated since iOS 3.2 
*/ 
+ (BOOL)checkKeyboardOnDisplayCenterBegin:(CGRect)centerBegin centerEnd:(CGRect)centerEnd{ 

    CGRect mainScreen = [UIApplication currentBounds]; 

    BOOL isKeyboardOnDisplay = CGRectContainsPoint(mainScreen, centerEnd.origin); 

    [[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:isKeyboardOnDisplay] forKey:@"isKeyboardOnDisplay"]; 
    [[NSUserDefaults standardUserDefaults] synchronize]; 

    return isKeyboardOnDisplay; 
} 

/** 
* This method allows to verify if software keyboard is currently present on screen for the application 
* Allows to handle undocked, split states of keyboard, as well as connected Bluetooth keyboard. 
* Needed to adjust UI - scrolling and insets for editable parts of the app, as well as avoid application be beneath open keyboard 
*/ 
+ (BOOL)checkKeyboardOnDisplayBeginFrame:(CGRect)frameBegin endFrame:(CGRect)frameEnd{ 
    CGRect mainScreen = [UIApplication currentBounds]; 
    UIView *firstView = [[(AppDelegate *)[[UIApplication sharedApplication] delegate] window].subviews objectAtIndex:0]; 

    CGRect convertedEndFrame = [KeyboardUtils convertRect:frameEnd toView:firstView]; 

    BOOL isKeyboardOnDisplay = CGRectContainsRect(mainScreen, convertedEndFrame); 

    [[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:isKeyboardOnDisplay] forKey:@"isKeyboardOnDisplay"]; 
    [[NSUserDefaults standardUserDefaults] synchronize]; 

    return isKeyboardOnDisplay; 
} 



+ (BOOL)checkKeyboardOnDisplayFromNotification:(NSNotification *)aNotification{ 
    BOOL isKeyboardOnDisplay = [KeyboardUtils checkKeyboardOnDisplayBeginFrame:[[aNotification.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue] 
                     endFrame:[[aNotification.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]];  
    return isKeyboardOnDisplay; 
} 

然后你可以使用它像:

- (void)keyboardWillChangeFrame:(NSNotification*)aNotification{ 
    [KeyboardUtils checkKeyboardOnDisplayFromNotification:aNotification]; 
} 

哪里keyboardWillChangeFrame是选择-观察员:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil]; 

以这样的方式你保存你的键盘状态(如果它显示为停靠状态并且确实存在于显示器上,并且不使用BT键盘)进入NSUserDefaultSettings。在听取键盘通知或方向更改的处理程序中,您应该从默认值中检查此键值。

另外一个方法是[UIApplication currentBounds]; 它存在于应用程序通过像类扩展它:(h文件)

#import <UIKit/UIKit.h> 

@interface UIApplication (AppDimensions) 
+(CGSize) currentSize; 
+(CGRect) currentBounds; 
+(CGSize) sizeInOrientation:(UIInterfaceOrientation)orientation; 
@end 

.m文件:

#import "UIApplication+AppDimensions.h" 

@implementation UIApplication (AppDimensions) 

+(CGSize) currentSize 
{ 
    return [UIApplication sizeInOrientation:[UIApplication sharedApplication].statusBarOrientation]; 
} 

+(CGRect) currentBounds{ 
    CGRect bounds = [UIScreen mainScreen].bounds; 
    bounds.size = [UIApplication currentSize]; 
    return bounds; 
} 

+(CGSize) sizeInOrientation:(UIInterfaceOrientation)orientation 
{ 
    CGSize size = [UIScreen mainScreen].bounds.size; 
    UIApplication *application = [UIApplication sharedApplication]; 
    if (UIInterfaceOrientationIsLandscape(orientation)) 
    { 
     size = CGSizeMake(size.height, size.width); 
    } 
    if (application.statusBarHidden == NO) 
    { 
     size.height -= MIN(application.statusBarFrame.size.width, application.statusBarFrame.size.height); 
    } 
    return size; 
} 

@end 

希望这将帮助任何人谁是关心处理键盘的存在屏幕上。

4

工作得很好的方法是在键盘显示时临时禁用UIScrollView上的setContentOffset:。尽管这有点不妥,但在某些情况下,它可能会导致其他问题。

正如@Sergey N.的响应,注册键盘的通知,但不是保存/恢复contentOffset,使用这些:在类其他

- (void)keyboardWillShow:(NSNotification *)aNotification { 
    [self disableMethod:@selector(setContentOffset:) onClass:[UIScrollView class]]; 
} 
- (void)keyboardWasShown:(NSNotification *)aNotification { 
    [self enableMethod:@selector(setContentOffset:) onClass:[UIScrollView class]]; 
} 

某处(或其他类,只要你替换上面的调用self),将这些:

-(void)swizzleMethod:(SEL)origSel from:(Class)origClass toMethod:(SEL)toSel from:(Class)toClass{ 
    Method origMethod = class_getInstanceMethod(origClass, origSel); 
    Method newMethod = class_getInstanceMethod(toClass, toSel); 
    method_exchangeImplementations(origMethod, newMethod); 
} 
-(void)disableMethod:(SEL)sel onClass:(Class)cl{ 
    [self swizzleMethod:sel from:cl toMethod:@selector(doNothing) from:[self class]]; 
} 
-(void)enableMethod:(SEL)method onClass:(Class)cl{ 
    [self swizzleMethod:@selector(doNothing) from:[self class] toMethod:method from:cl]; 
} 
-(void)doNothing{ 

} 

这样可以防止web视图从摆在首位滚动到顶部,这样就不会显示不错的动画,但是,在一些situatio ns可能会导致一些问题(例如,在拥有webview的视图中有更多的输入控件)。在iOS 5.0+中成功测试了这一点。 在iOS 6.0中,滚动到顶部似乎是固定的,因此没有必要解决方法。

+0

谢谢你!奇迹般有效! ^^它可以在4.3模拟器上运行。像这个解决方案更好,因为它消除了屏幕碰撞。对于想要完全控制其页面的phonegap开发人员非常有用 – Arthur 2013-03-07 12:37:12