編集可能な webView にテキストが表示されています。下にスクロールしてレンダリングされたテキストを編集するためにどこかに触れるとすぐに、一番上までスクロールしてキーボードが表示されるため、編集のためにもう一度下にスクロールする必要があります。webViewがそれを行うのを防ぐ方法はありますか?
4 に答える
同じ問題が発生し、この奇妙な動作の通常の解決策を探しています。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 の可視領域にない場合、テキストの編集で問題が発生します。また、カーソルを表示するために自動的にスクロールしません。私たちはその問題を解決しましたが、これをどのように行ったかについての詳細で読みやすいチュートリアルを作成中です。すでにこの問題を解決している場合は、解決策を見ていただければ幸いです:)
PS: http://www.cocoanetics.com/2011/01/uiwebview-must-die/
ありがとう、セルゲイN.
かなりうまく機能する方法は、キーボードが表示されている間、を一時的に無効setContentOffset:
にすることです。UIScrollView
ただし、これは少しハックであるため、状況によっては、代わりに他の問題が発生する可能性があります。
@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 ビューが最初にスクロールされなくなり、悪いアニメーションが表示されなくなりますが、状況によっては問題が発生する可能性があります (たとえば、Web ビューを保持しているビューに入力コントロールが増えるなど)。これは iOS 5.0 以降で正常にテストされました。iOS 6.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];
}
実際には、keyboardWasShown は、特にユーザーが BT キーボードを接続していて、仮想キーボードを Eject キーで非表示/表示できる場合に、常に呼び出されるとは限りません。次のような独自のクラスを実装しました。
@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 キーボードが使用されていない場合)。キーボード通知または向きの変更をリッスンするハンドラーでは、デフォルトからこのキー値を確認する必要があります。
もう 1 つの追加メソッドは [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
これが、画面上のキーボードの存在を処理することを懸念しているすべての人に役立つことを願っています.