キーボードが表示されたときにテキストフィールドを上にスクロールする独自の関数を作成しました。テキストフィールドからタップしてキーボードを閉じるために、タップしたときにテキストフィールドで最初のレスポンダーを辞任するUITapGestureRecognizer
を作成しました。
また、テキストフィールドのすぐ下にUITableView
を作成し、ユーザーがテキストを入力するときにアイテムを入力するテキストフィールドのオートコンプリートを作成しました。
ただし、自動完了テーブルのエントリの1つを選択すると、didSelectRowAtIndexPath
は呼び出されません。代わりに、タップジェスチャレコグナイザーが呼び出され、最初のレスポンダーを辞任するようです。
タップジェスチャーレコグナイザーにUITableView
にタップメッセージを渡し続けるように指示する方法があると思いますが、それが何なのかわかりません。どんな助けでも大歓迎です。
OK、ジェスチャレコグナイザードキュメントを検索した結果、ようやく見つかりました。
解決策は、UIGestureRecognizerDelegate
を実装し、以下を追加することでした:
////////////////////////////////////////////////////////////
// UIGestureRecognizerDelegate methods
#pragma mark UIGestureRecognizerDelegate methods
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if ([touch.view isDescendantOfView:autocompleteTableView]) {
// Don't let selections of auto-complete entries fire the
// gesture recognizer
return NO;
}
return YES;
}
それはそれの世話をしました。これが他の人にも役立つことを願っています。
この問題を解決する最も簡単な方法は次のとおりです。
UITapGestureRecognizer *tapRec = [[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(tap:)];
[tapRec setCancelsTouchesInView:NO];
これにより、UIGestureRecognizer
がタップを認識し、次のレスポンダーにタッチを渡すことができます。このメソッドの意図しない結果は、別のView Controllerをプッシュする画面上にUITableViewCell
がある場合です。ユーザーがキーボードを閉じるために行をタップすると、キーボードとプッシュの両方が認識されます。私はこれがあなたの意図することだとは思いませんが、この方法は多くの状況に適しています。
また、ロバートの答えを拡張すると、問題のテーブルビューへのポインタがある場合、文字列に変換する代わりにクラスを直接比較でき、Appleが命名法を変更しないことを期待できます。
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch
{
if([touch.view class] == tableview.class){
return //YES/NO
}
return //YES/NO
}
また、UIGestureRecognizer
を宣言して、このコードを含むデリゲートを含める必要があります。
認識エンジンのcancelsTouchesInView
をfalseに設定します。それ以外の場合は、タッチを「消費」し、テーブルビューに渡しません。そのため、選択イベントは発生しません。
たとえば、Swift
let tapOnScreen: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "CheckTheTime")
tapOnScreen.cancelsTouchesInView = false
view.addGestureRecognizer(tapOnScreen)
Swiftの場合(@Jasonからの回答に基づく):
class MyAwesomeClass: UIViewController, UIGestureRecognizerDelegate
private var tap: UITapGestureRecognizer!
override func viewDidLoad() {
super.viewDidLoad()
self.tap = UITapGestureRecognizer(target: self, action: "viewTapped:")
self.tap.delegate = self
self.view.addGestureRecognizer(self.tap)
}
// UIGestureRecognizerDelegate method
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if touch.view?.isDescendantOfView(self.tableView) == true {
return false
}
return true
}
テーブルビューにタップジェスチャを追加すると同時に、セルの選択を許可するより良いソリューションがある場合があります。
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if gestureRecognizer is UITapGestureRecognizer {
let location = touch.locationInView(tableView)
return (tableView.indexPathForRowAtPoint(location) == nil)
}
return true
}
ユーザーがタップしている画面のポイントでセルを探すだけです。インデックスパスが見つからない場合は、ジェスチャがタッチを受け取るようにします。そうでない場合はキャンセルします。私にとっては素晴らしい作品です。
ジェスチャーオブジェクトに対してcancelsTouchesInView
をfalse
に設定するだけでコードのブロックを記述する必要はないと思います。デフォルトではtrue
であり、単にfalse
に設定するだけです。コードでUITapGesture
オブジェクトを使用し、UIScrollView
(tableview、collectionview)も使用している場合、このプロパティを設定しますfalse
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.dismissKeyboard))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
同様の解決策は、ビューのクラスを使用してgestureRecognizer:shouldReceiveTouch:
を実装し、実行するアクションを決定することです。このアプローチには、テーブルを直接囲む領域のタップをマスクしないという利点があります(これらの領域のビューはUITableViewインスタンスから派生しますが、セルを表しません)。
これには、単一のビューで複数のテーブルを使用して(余分なコードを追加することなく)動作するというボーナスもあります。
注意:Appleはクラス名を変更しないという仮定があります。
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
return ![NSStringFromClass([touch.view class]) isEqualToString:@"UITableViewCellContentView"];
}
ユーザーがテーブルビューのoutsideをタップしたときに、タッチジェスチャ機能をonlyで呼び出す別の状況がありました。ユーザーがテーブルビュー内でタップした場合、タッチジェスチャ関数を呼び出さないでください。さらに、タッチジェスチャ関数が呼び出された場合、タッチイベントを消費するのではなく、タップされたビューに渡す必要があります。
結果のコードは、Abdulrahman Masoudの答えとNikolaj Nielsenの答えの組み合わせです。
extension MyViewController: UIGestureRecognizerDelegate {
func addGestureRecognizer() {
let tapOnScreen = UITapGestureRecognizer(target: self,
action: #selector(functionToCallWhenUserTapsOutsideOfTableView))
// stop the gesture recognizer from "consuming" the touch event,
// so that the touch event can reach other buttons on view.
tapOnScreen.cancelsTouchesInView = false
tapOnScreen.delegate = self
self.view.addGestureRecognizer(tapOnScreen)
}
// if your tap event is on the menu, don't run the touch event.
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if touch.view?.isDescendant(of: self.tableView) == true {
return false
}
return true
}
@objc func functionToCallWhenUserTapsOutsideOfTableView() {
print("user tapped outside table view")
}
}
そして、MyViewController
クラス、UITableView
を持つクラス、onViewDidLoad()
で、addGestureRecognizer()
を呼び出すようにしました:
class MyViewController: UIViewController {
...
override func viewDidLoad() {
super.viewDidLoad()
...
self.addGestureRecognizer()
...
}
...
}
シンプルなソリューションは、UITableViewCellのUIControlインスタンスを使用してタッチを取得することです。 UIControlにuserInteractionEnables == NOのビューを追加して、タップを取得できます。
Swift 4.2の場合、解決策はUIGestureRecognizerDelegate
を実装し、以下を追加することでした:
extension ViewController : UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if touch.view!.isDescendant(of: tblView) {
return false
}
return true
}
}
テーブルビューをクリックすると、このデリゲートメソッドはfalseを返し、テーブルビューのdidSelectRowAtIndexPath
メソッドが正しく機能します。
遅くなり、多くの人が上記の提案がうまくいくことを発見しましたが、私はジェイソンまたはTMilliganの方法を機能させることができませんでした。
数値キーボードのみを使用して数値入力を受け取るtextFieldsを含む複数のセルを持つStatic tableViewがあります。これは私にとって理想的でした:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if(![touch.view isKindOfClass:[UITableViewCell class]]){
[self.firstTF resignFirstResponder];
[self.secondTF resignFirstResponder];
[self.thirdTF resignFirstResponder];
[self.fourthTF resignFirstResponder];
NSLog(@"Touches Work ");
return NO;
}
return YES;
}
この<UIGestureRecognizerDelegate>
が.hファイルに実装されていることを確認してください。
この行![touch.view isKindOfClass:[UITableViewCell class]]
は、tableViewCellがタップされたかどうかを確認し、アクティブなキーボードを閉じます。
ここに私の解決策があります。これは、レコグナイザーのshouldReceiveTouchをキーボードが表示されているかどうかに直接結び付けます。
タップジェスチャレコグナイザーデリゲートで:
#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if ([PFXKeyboardStateListener sharedInstance].visible) {
return YES;
}
return NO;
}
そしてPFXKeyboardStateListener.h
:
@interface PFXKeyboardStateListener : NSObject
{
BOOL _isVisible;
}
+ (PFXKeyboardStateListener *)sharedInstance;
@property (nonatomic, readonly, getter=isVisible) BOOL visible;
@end
そしてPFXKeyboardStateListener.m
:
static PFXKeyboardStateListener *sharedInstance;
@implementation PFXKeyboardStateListener
+ (PFXKeyboardStateListener *)sharedInstance
{
return sharedInstance;
}
+ (void)load
{
@autoreleasepool {
sharedInstance = [[self alloc] init];
}
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (BOOL)isVisible
{
return _isVisible;
}
- (void)didShow
{
_isVisible = YES;
}
- (void)didHide
{
_isVisible = NO;
}
- (id)init
{
if ((self = [super init])) {
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(didShow) name:UIKeyboardDidShowNotification object:nil];
[center addObserver:self selector:@selector(didHide) name:UIKeyboardWillHideNotification object:nil];
}
return self;
}
@end
キーボードリスナーのシングルトンパターンを更新したい場合がありますが、私はまだそれにしていません。これが他のすべての人にも役立つことを願っています。 ^^
UIGestureRecognizerのデリゲートにこのメソッドを実装します。
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch
{
UIView *superview = touch.view;
do {
superview = superview.superview;
if ([superview isKindOfClass:[UITableViewCell class]])
return NO;
} while (superview && ![superview isKindOfClass:[UITableView class]]);
return superview != nil;
}
Swiftでは、これを内部で使用できます
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if CheckTheTime() == true {
// do something
}else{
}
}
func CheckTheTime() -> Bool{
return true
}
Uisearchbarとself.viewのuitableviewを含む私の場合は異なりました。ビューをタッチして、uisearchbarキーボードを閉じたいと思いました。
var tapGestureRecognizer:UITapGestureRecognizer?
override func viewWillAppear(animated: Bool) {
tapGestureRecognizer = UITapGestureRecognizer(target: self, action:Selector("handleTap:"))
}
UISearchBarデリゲートメソッド:
func searchBarShouldBeginEditing(searchBar: UISearchBar) -> Bool {
view.addGestureRecognizer(tapGestureRecognizer!)
return true
}
func searchBarShouldEndEditing(searchBar: UISearchBar) -> Bool {
view.removeGestureRecognizer(tapGestureRecognizer!)
return true
}
ユーザーがself.viewをタッチすると:
func handleTap(recognizer: UITapGestureRecognizer) {
sampleSearchBar.endEditing(true)
sampleSearchBar.resignFirstResponder()
}