web-dev-qa-db-ja.com

UIButtonがiPhone画面の下部領域でタッチを正しく登録できない

私は、正方形/長方形のような電卓に配置された多くの異なるボタンを備えたアプリを持っています。実際には、デフォルトのiOS計算機に非常に似ています。約6行で、各ボタンは4列です。

問題

私が抱えている問題は、一番下の行にあるボタンに関係しています(iPhone 4の画面の下の約10分の1)。押したときに「ボタンを押した」ことを登録するには、押したままにする(約1秒未満)必要があるという意味で、押しても正常に動作しません。これは、標準のショートタップとは対照的です。

この一番下の行以外に、このような動作をするボタンはありません。

さらに、これらのボタンの上端をタップすると、通常の動作をし、タッチするとすぐに反応します。これにより、ボタン自体は問題ではないが、ビューのレイアウトに問題があると思います。

この問題は物理デバイスでのみ発生することにも注意してください。シミュレーターでは、ボタンは正常に動作します。

コンテキスト

これらのボタンを含むビューは、アプリのルートビューコントローラーではありません。代わりに次のように移行されます(ここでは空想はありません)。

[self presentViewController:navController animated:YES completion:nil];

自分がルートビューコントローラである場合

私が問題を抱えているビューコントローラーはナビゲーションコントローラー内に含まれており、上記のルートビューコントローラーによってモーダルに表示されます。

これまでに試したこと

  • 自動レイアウトのオンとオフを切り替える:同じ問題

  • ビューの階層の再配置:問題のあるボタンを他のすべてのビューの上と後ろに移動しましたが、結果は同じです:同じ問題

  • 複数のデバイス(iPhone 4、4s、5):同じ問題(ボタンは3.5インチと4インチの両方のシミュレータで正常に応答しますが)

  • 他のアプリのテスト(この領域のボタンが他のアプリで押された場合、それらは正常に動作します)

追加情報

  • 問題のあるビューコントローラのすべてがInterface Builderでレイアウトされます
  • ボタンはすべて標準設定のシステムボタンであり、テキスト以外はすべてまったく同じです。
  • 画面のすべての要素(ボタン、ラベルなど)は「ビュー」のサブビューです
  • ボタンは互いに同一平面上にあり、1ピクセルまたは2ピクセルを超えてオーバーラップしないでください。
  • 問題のあるボタンの寸法は、幅80 x高さ44です。
  • 問題のあるボタンが画面の下部に揃っている
  • ボタンに加えて、1つのUIImageといくつかのラベルがありますが、これらは画面の上部にあり、どのボタンとも重複していません。
29
Iowa15

これは、ボタンとUIScreenEdgePanGestureRecognizer(またはそれが何であれ)の間の相互作用のように聞こえます。UIScreenEdgePanGestureRecognizerは、ユーザーがシステムのコントロールセンターを起動したいことを検出する責任があります。

ここには実際には2つの潜在的な問題があります。

  • アプリに向けられたジェスチャの可能性とシステムに向けられたジェスチャの間に相互作用(つまり、競合)が存在する可能性があります。ジェスチャー認識機能がある場合は、デリゲートメソッドを使用して、それらとシステムのジェスチャー認識機能を仲介する必要があります。

  • 画面のエッジ近く(つまり、画面のエッジジェスチャレコグナイザの「ゾーン」)でタップすると機能する確立されたバグがありますが、ボタンが正常に動作しませんphysically、つまり、ログに記録されていることが示されていても、タップされたかのようにlookしません(ここで私の回答を参照してください: https://stackoverflow.com/a/22000692/341994 )。

17
matt

この問題の原因は、Appleが画面の下部にGestureRecognizerを配置し、他のビューでのタッチを遅らせるように思われることです。アプリのウィンドウでジェスチャー認識機能をいじった後、 UIButtonのサブクラスを組み込んだソリューション:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    BOOL inside = [super pointInside: point withEvent: event];

    if (inside && !self.isHighlighted && event.type == UIEventTypeTouches)
    {
        self.highlighted = YES;
    }

    return inside;
}

TouchesBegan:は遅延して呼び出されますが、指定されたメソッドが呼び出されています。ビューが画面の下部にあるかどうかの確認は、この修正で発生する可能性のある副作用を防ぐのに適している場合があります。

31
Lukas

SwiftでのLukasの回答とハイライトされた選択を解除

extension UIButton {

  public override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {

    var inside = super.pointInside(point, withEvent: event)

    if inside != highlighted && event?.type == .Touches {
        highlighted = inside
    }

    return inside

  }

}
9
ar_dsw

Swift 3ソリューション

extension UIControl {

    open override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        let inside = super.point(inside: point, with: event)
        if inside != isHighlighted && event?.type == .touches {
            isHighlighted = inside
        }
        return inside
    }
}
5
Randy

私はSwiftに基づいて Luka's の回答に完全な解決策を書きました。競合するボタンをこのクラスに準拠させるだけで、問題はなくなります:

_class BorderBugFixButton : UIButton {

    override func awakeFromNib() {
        super.awakeFromNib()
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "unHighlight", name: UIApplicationWillResignActiveNotification, object: nil)
    }

    deinit {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }

    override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
        let inside = super.pointInside(point, withEvent: event)
        if inside != highlighted && event?.type == .Touches {
            highlighted = inside
        }
        return inside
    }

    internal func unHighlight() {
        highlighted = false
    }

}
_

追伸:Storyboards/Xib'sが苦手な方は、awakeFromNib()の実装をinit()に移行してください。

4
Danny Bravo

古いStoryboardsをiOS 7以降に更新する際に何度もこの問題に遭遇しました。通常、問題のViewControllerがUIScrollViewの形式である場合です。ストーリーボードのViewControllerオブジェクト(ビューではなく、黄色の円が付いているビュー)のこれら2つの設定を再確認します。上部と下部のバーの下にある[エッジの延長]をオフにすると、scrollViewのフレームが64ポイント下に調整されました(ナビゲーションバーとステータスバーの高さ)。

UIButton not working on bottom of screen NavBar.bottomとscrollView.topの間のスペースを0に戻した後、ボタンが機能し始めました。これは、scrollView.frame.bottomがウィンドウの下部から64ピクセル上にあったためである可能性があります。そのため、その領域でのタッチは、技術的にscrollViewのフレームからはずれていたものの、何らかの理由で視覚的に表示されていたため無視されました。

0
self.name

delaysTouchesBeganviewWillAppearを無効にすることで、この問題を解決できました

self.navigationController?.interactivePopGestureRecognizer?.delaysTouchesBegan = false
0
SamB

iOS 9.3、Xcode 7.3

Lukas 'answer を実装するUIButtonクラスにカテゴリを作成することをお勧めします。カテゴリの作成方法については、この投稿を参照してください: Xcode 6以降でカテゴリを作成するにはどうすればよいですか?

従来の「+」記号を使用して適切な名前を付けます。つまり、「BottomOfScreen」という名前を付けると、結果のファイル名は「UIButton + BottomOfScreen」になります。

Objective-Cを使用している場合は、新しいカテゴリの* .hおよび* .mファイルを取得します。

*。h

#import <UIKit/UIKit.h>

@interface UIButton (BottomOfScreen)

@end

*。m

#import "UIButton+BottomOfScreen.h"

@implementation UIButton (BottomOfScreen)

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    BOOL inside = [super pointInside:point withEvent:event];

    if (inside && !self.isHighlighted && (event.type == UIEventTypeTouches))
    {
        self.highlighted = true;
    }
    else
    {
        nil;
    }

    return inside;
}

@end
0
serge-k