iPhone の UITextView でタッチを処理しようとしています。たとえば、UIImageViewsのサブクラスを作成し、touchesBeganメソッドを実装することで、タップやその他のタッチイベントを正常に処理できました...ただし、明らかにUITextViewでは機能しません:(
UITextView には、ユーザー インタラクションとマルチ タッチが有効になっています。誰でもこれを処理できましたか?
iPhone の UITextView でタッチを処理しようとしています。たとえば、UIImageViewsのサブクラスを作成し、touchesBeganメソッドを実装することで、タップやその他のタッチイベントを正常に処理できました...ただし、明らかにUITextViewでは機能しません:(
UITextView には、ユーザー インタラクションとマルチ タッチが有効になっています。誰でもこれを処理できましたか?
UITextView でシングル/ダブル/トリプル タップを処理する場合は、UIGestureReconnizer を委譲し、textview にジェスチャ レコグナイザーを追加できます。
Heres の同じコード (viewDidLoad 内):
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap)];
//modify this number to recognizer number of tap
[singleTap setNumberOfTapsRequired:1];
[self.textView addGestureRecognizer:singleTap];
[singleTap release];
と
-(void)handleSingleTap{
//handle tap in here
NSLog(@"Single tap on view");
}
この助けを願っています:D
より良い解決策 (何かをスウィズルしたり、プライベートAPIを使用したりせずに:D)
以下で説明するようUITapGestureRecognizers
に、textview に new を追加しても期待どおりの結果が得られず、ハンドラー メソッドが呼び出されることはありません。これは、UITextView
すでにいくつかのタップ ジェスチャ認識機能がセットアップされており、デリゲートによってジェスチャ認識機能が適切に機能せず、デリゲートを変更するとさらに悪い結果になる可能性があるためです。
幸いなことUITextView
に、必要なジェスチャ認識機能が既にセットアップされていますが、問題はビューの状態に応じて変化することです (つまり、日本語を入力する場合と英語を入力する場合、および編集モードでない場合とでジェスチャ認識機能のセットが異なります)。UITextView のサブクラスでこれらをオーバーライドすることでこれを解決しました。
- (void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
{
[super addGestureRecognizer:gestureRecognizer];
// Check the new gesture recognizer is the same kind as the one we want to implement
// Note:
// This works because `UITextTapRecognizer` is a subclass of `UITapGestureRecognizer`
// and the text view has some `UITextTapRecognizer` added :)
if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
UITapGestureRecognizer *tgr = (UITapGestureRecognizer *)gestureRecognizer;
if ([tgr numberOfTapsRequired] == 1 &&
[tgr numberOfTouchesRequired] == 1) {
// If found then add self to its targets/actions
[tgr addTarget:self action:@selector(_handleOneFingerTap:)];
}
}
}
- (void)removeGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
{
// Check the new gesture recognizer is the same kind as the one we want to implement
// Read above note
if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
UITapGestureRecognizer *tgr = (UITapGestureRecognizer *)gestureRecognizer;
if ([tgr numberOfTapsRequired] == 1 &&
[tgr numberOfTouchesRequired] == 1) {
// If found then remove self from its targets/actions
[tgr removeTarget:self action:@selector(_handleOneFingerTap:)];
}
}
[super removeGestureRecognizer:gestureRecognizer];
}
- (void)_handleOneFingerTap:(UITapGestureRecognizer *)tgr
{
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:tgr forKey:@"UITapGestureRecognizer"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"TextViewOneFingerTapNotification" object:self userInfo:userInfo];
// Or I could have handled the action here directly ...
}
このようにすることで、テキストビューがいつジェスチャー認識エンジンを変更しても、必要なタップジェスチャー認識エンジンを常にキャッチします→したがって、ハンドラーメソッドはそれに応じて呼び出されます:)
結論:
にジェスチャ レコグナイザーを追加する場合UITextView
は、テキスト ビューにジェスチャ レコグナイザーがまだ含まれていないことを確認する必要があります。
古い回答
以前の回答には短所があり、期待どおりに機能しないため、プライベートメソッドをスウィズルしてこの回答を思いつきました。ここでは、 のタッピング動作を変更するのではなくUITextView
、呼び出されたメソッドをインターセプトして、元のメソッドを呼び出すだけです。
詳細説明
UITextView
UIGestureRecognizers
これらにはそれぞれ atarget
と aaction
がありますが、それらtarget
はそれ自体ではなく、 forwardUITextView
クラスのオブジェクトですUITextInteractionAssistant
。(このアシスタントはの@package
ivar ですUITextView
が、前方定義はパブリック ヘッダー: UITextField.h にあります)。
UITextTapRecognizer
のタップと通話oneFingerTap:
を認識するUITextInteractionAssistant
ので、その通話を傍受したい :)
#import <objc/runtime.h>
// Prototype and declaration of method that is going be swizzled
// When called: self and sender are supposed to be UITextInteractionAssistant and UITextTapRecognizer objects respectively
void proxy_oneFingerTap(id self, SEL _cmd, id sender);
void proxy_oneFingerTap(id self, SEL _cmd, id sender){
[[NSNotificationCenter defaultCenter] postNotificationName:@"TextViewOneFinderTap" object:self userInfo:nil];
if ([self respondsToSelector:@selector(proxy_oneFingerTap:)]) {
[self performSelector:@selector(proxy_oneFingerTap:) withObject:sender];
}
}
...
// subclass of UITextView
// Add above method and swizzle it with.
- (void)doTrickForCatchingTaps
{
Class class = [UITextInteractionAssistant class]; // or below line to avoid ugly warnings
//Class class = NSClassFromString(@"UITextInteractionAssistant");
SEL new_selector = @selector(proxy_oneFingerTap:);
SEL orig_selector = @selector(oneFingerTap:);
// Add method dynamically because UITextInteractionAssistant is a private class
BOOL success = class_addMethod(class, new_selector, (IMP)proxy_oneFingerTap, "v@:@");
if (success) {
Method originalMethod = class_getInstanceMethod(class, orig_selector);
Method newMethod = class_getInstanceMethod(class, new_selector);
if ((originalMethod != nil) && (newMethod != nil)){
method_exchangeImplementations(originalMethod, newMethod); // Method swizzle
}
}
}
//... And in the UIViewController, let's say
[textView doTrickForCatchingTaps];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textViewWasTapped:) name:@"TextViewOneFinderTap" object:nil];
- (void)textViewWasTapped:(NSNotification *)noti{
NSLog(@"%@", NSStringFromSelector:@selector(_cmd));
}
UITextView instance.delegate = self を割り当てる必要があります (同じコントローラーでイベントを処理する場合)
インターフェイスに UITextViewDelegate プロトコルを必ず実装してください...例:
@interface myController : UIViewController <UITextViewDelegate>{
}
次に、次のいずれかを実装できます
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView;
- (BOOL)textViewShouldEndEditing:(UITextView *)textView;
- (void)textViewDidBeginEditing:(UITextView *)textView;
- (void)textViewDidEndEditing:(UITextView *)textView;
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
- (void)textViewDidChange:(UITextView *)textView;
- (void)textViewDidChangeSelection:(UITextView *)textView;
大きなビューのサブビューとしてテキストビューを使用しています。ユーザーがテキストビューをスクロールできるようにする必要がありますが、編集することはできません。テキストビュー自体を含め、テキストビューのスーパービューのシングルタップを検出したいと思います。
もちろん、私はテキストビューがそれから始まるタッチを飲み込むという問題に遭遇しました。ユーザーインタラクションを無効にするとこれは修正されますが、ユーザーはテキストビューをスクロールできなくなります。
私の解決策は、テキストビューを編集可能にし、テキストビューのshouldBeginEditingデリゲートメソッドを使用してテキストビューのタップを検出することでした。NOを返すだけで編集できなくなりますが、テキストビュー(したがってスーパービュー)がタップされていることがわかります。このメソッドとsuperviewのtouchesEndedメソッドの間に必要なものがあります。
これは実際のタッチにアクセスしたい人には機能しないことを私は知っていますが、タップを検出するだけであれば、このアプローチは機能します!
Touch Down
イベントを送信することもできます。Interface Builder を介してこのイベントを関連付けます。
次に、イベント ハンドラーにコードを追加します。
- (IBAction)onAppIDTap:(id)sender {
//Your code
}
UIScrollView を作成して、[scrollView addSubview: textview]
テキストビューをスクロールできるようにするのはどうですか?