Подтвердить что ты не робот

UIButton не смог правильно зарегистрировать сенсорный экран в нижней части экрана iPhone

У меня есть приложение со множеством различных кнопок, расположенных в калькуляторе вроде квадратного/прямоугольного формата. На самом деле это очень похоже на калькулятор iOS по умолчанию. Есть приблизительно 6 строк с 4 столбцами каждая из кнопок.

Проблема

Проблема, с которой я сталкиваюсь, включает в себя кнопки в нижнем ряду (приблизительно нижний 10-й экран на iPhone 4). Они не ведут себя нормально при нажатии в том смысле, что при нажатии они должны быть нажаты и удерживаться (примерно на секунду) для регистрации нажатия кнопки. Это противоречит стандартному кратковременному крану.

Никакие другие кнопки, кроме этой нижней строки, не ведут себя таким образом.

Кроме того, если эти кнопки задействованы на их верхнем краю, они ведут себя нормально, реагируя, как только они касаются. Это заставляет меня думать, что сами кнопки не являются проблемами, но есть некоторые проблемы с макетом моих просмотров.

Следует также отметить, что эта проблема присутствует только на физических устройствах. На симуляторе кнопки ведут себя нормально.

Контекст

Вид, содержащий эти кнопки, не является контроллером корневого представления приложения. Вместо этого он переходит к такому (ничего не интересное здесь):

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

Где self является контроллером корневого представления

Контроллер представления, с которым у меня возникают проблемы, содержится в контроллере навигации и представлен с помощью контроллера корневого представления, который вы можете видеть выше.

Что я пробовал до сих пор

  • Включение и выключение автоматического макета: та же проблема

  • Изменение иерархии представлений: я переместил проблематичные кнопки сверху и сзади всех остальных представления с тем же результатом: та же проблема

  • Несколько устройств (iPhone 4, 4s, 5): одна и та же проблема (хотя кнопки обычно реагируют как на 3,5-дюймовые, так и на 4-дюймовые симуляторы)

  • Тестирование других приложений (когда кнопки в этой области нажаты в других приложениях, они ведут себя нормально)

Дополнительная информация

  • Все выложено в Interface Builder для контроллера проблемных представлений.
  • Все кнопки являются системными кнопками со стандартными настройками и все они точно совпадают с их текстом.
  • Все элементы экрана (кнопки, метки и т.д.) являются подзонами "view"
  • Кнопки находятся на одном уровне друг с другом и не должны перекрывать более одного или двух пикселей.
  • Проблемные кнопки имеют размеры: 80 ширина X 44 высота.
  • Проблемные кнопки скрыты от нижней части экрана.
  • В дополнение к кнопкам есть один UIImage и несколько меток, однако они находятся в верхней части экрана и не перекрываются ни с одной из кнопок.
4b9b3361

Ответ 1

Это звучит как взаимодействие между кнопками и UIScreenEdgePanGestureRecognizer (или что-то еще), которое отвечает за обнаружение того, что пользователь хочет вызвать системный центр управления.

Здесь есть два возможных вопроса:

  • Может быть взаимодействие (например, конфликт) между возможностью жестов, направленной на ваше приложение, и жестом, направленным на систему. Если у вас есть распознаватели жестов, вам может потребоваться использовать методы делегата для посредничества между ними и распознавателями жестов системы.

  • Существует хорошо установленная ошибка, когда работает крана возле края экрана (т.е. в зоне распознавания жестов экрана), но это заставляет кнопку плохо себя вести физически, то есть она выглядит не так, как будто он был задействован, хотя журнал показывает, что он имеет (см. мой ответ здесь: fooobar.com/questions/238950/...).

Ответ 2

Причиной этой проблемы является то, что Apple, похоже, помещает GestureRecognizer в нижней части экрана, что задерживает касания в любом другом представлении. После возиться с распознавателями жестов в окнах App я придумал решение, которое включает подкласс 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;
}

Данный метод вызывается, хотя touchhesBegan: называется задержкой. Проверка того, что представление находится в нижней части экрана, может быть подходящим для предотвращения возможных побочных эффектов с этим исправлением.

Ответ 3

Ответ Лукаса на быстрый и снятый снимок

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

  }

}

Ответ 4

Я написал полное решение в быстром, основанном на ответе Luka. Просто сделайте любые конфликтующие кнопки соответствующими этому классу, и проблема исчезнет:

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
    }

}

P.S.: Для тех из вас, кто не любит Storiesboards/Xib, просто перенесите реализацию awakeFromNib() в init()

Ответ 5

Решение 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
    }
}

Ответ 6

Я столкнулся с этим много раз при работе с обновлением Storyboards до iOS 7+, обычно, когда рассматриваемый ViewController имеет форму UIScrollView. Дважды проверьте эти 2 настройки в своей раскадровке на объекте ViewController (не на представлении, а на желтом круге). Когда я снял флажок "Расширять края" в верхнем и нижнем столбцах, кадр scrollView был отрегулирован на 64 точки (высота строк Nav и Status).

UIButton not working on bottom of screen После установки промежутка между NavBar.bottom и scrollView.top до 0, кнопка начала работать. Это может быть связано с тем, что scrollView.frame.bottom был на 64 пикселя выше нижней части окна, поэтому касания в этой области были проигнорированы, поскольку они были технически из кадра scrollView, но по какой-то причине визуально отображались.

Ответ 7

iOS 9.3, Xcode 7.3

Я бы предположил, что вы должны сделать категорию для класса UIButton, который реализует ответ Lukas. Инструкции по созданию категории см. В этом сообщении: Как создать категорию в Xcode 6 или выше?

Дайте ему соответствующее имя с традиционным знаком "+", т.е. если вы назовете его "BottomOfScreen", то получившееся имя файла будет "UIButton + BottomOfScreen".

Если вы используете objective-c, то вы получите файлы *.h и *.m с новой категорией.

*. Ч

#import <UIKit/UIKit.h>

@interface UIButton (BottomOfScreen)

@end

* м.

#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