Ipad 可编辑webView自动滚动到顶部

Ipad 可编辑webView自动滚动到顶部,ipad,ios5,uiwebview,contenteditable,Ipad,Ios5,Uiwebview,Contenteditable,我在可编辑的网络视图中显示了一些文本。当我向下滚动并触摸某处编辑渲染文本时,它会滚动到顶部,键盘会出现,因此我必须再次向下滚动进行编辑。有没有办法阻止webView这样做 遇到了同样的问题,仍然在寻找这种奇怪行为的正常解决方案。 我们仍然无法阻止UIWebView这样做,如果你看看iPad上的Evernote应用程序,你会发现同样的问题,不幸的是:( 我们唯一能做的就是在显示键盘时保存UIWebView的contentOffset,并在打开键盘后恢复 这将看起来像: //register you

我在可编辑的网络视图中显示了一些文本。当我向下滚动并触摸某处编辑渲染文本时,它会滚动到顶部,键盘会出现,因此我必须再次向下滚动进行编辑。有没有办法阻止webView这样做

遇到了同样的问题,仍然在寻找这种奇怪行为的正常解决方案。 我们仍然无法阻止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];
    ...
}
之后,您需要在显示键盘时处理事件:

- (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的可见区域时,您将面临编辑文本的问题,并且它不会自动滚动以使光标可见。我们已经解决了这个问题,但我正在创建详细易读的教程来说明我们是如何做到这一点的。如果您已经解决了这个问题,我将非常感谢您好的,看看你的解决方案:)

附言:

谢谢,, Sergey N.

用于“当光标不在可见区域时编辑文本”问题的函数


实际上,KeyboardwasShow并不总是被调用,特别是当用户连接了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];
这样,您就可以将键盘的状态保存到NSUserDefaultSettings中(如果它显示为停靠状态,并且确实显示在屏幕上,并且未使用BT键盘)。在侦听键盘通知或方向更改的处理程序中,应该从默认值中检查此键值

另一种方法是[UIApplication currentBounds]; 它通过扩展类别(如:(.h文件)显示在应用程序中


希望这能帮助那些关心如何处理屏幕上是否有键盘的人。

一种效果相当好的方法是在显示键盘时,暂时禁用
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{

}
这首先会阻止webview滚动到顶部,因此不会显示不良动画,但是,在某些情况下,它可能会导致一些问题(例如,视图中包含更多的输入控件来保存webview)。在iOS 5.0+中成功测试了这一点。
在iOS 6.0中,滚动到顶部似乎是固定的,因此无需解决任何问题。

非常感谢您提供如此全面的答案。我很感激。这个解决方案在一定程度上解决了这个问题。关于“当光标不在可见区域时编辑文本”的问题,我使用以下两个函数在textView中解决了它。虽然我也必须在webView中尝试它们。Sergey,你写了那个教程了吗?:)我已经为这些
UIWebView
s挣扎了很长一段时间。嗨,Leo,我们还不能解决这个滚动问题,只是试图在用户进入编辑模式和键盘出现之前保存光标,然后在键盘打开和视图滚动到顶部后恢复该位置。我正在准备的教程是如何处理打开的键盘以及当用户手动滚动web视图并尝试开始编辑它时的情况-光标不在可见区域。此外,当键盘打开/松开/使用BT键盘+不同的屏幕方向时,我们正在处理更改视图插入的问题,以允许用户始终看到从何处开始键入文本谢谢!很有魅力!^^并在4.3模拟器上运行。更喜欢这个解决方案,因为它消除了屏幕碰撞。对于想要完全控制页面的phonegap开发人员非常有用
#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
- (void)keyboardWillShow:(NSNotification *)aNotification {
    [self disableMethod:@selector(setContentOffset:) onClass:[UIScrollView class]];
}
- (void)keyboardWasShown:(NSNotification *)aNotification {
    [self enableMethod:@selector(setContentOffset:) onClass:[UIScrollView class]];
}
-(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{

}