Есть ли простой способ разрешить взаимодействие с кнопкой в UIView, который находится под другим UIView - где нет реальных объектов из верхнего UIView поверх кнопки?
Например, на данный момент у меня есть UIView (A) с объектом вверху и объектом внизу экрана и ничего в середине. Он находится поверх другого UIView с кнопками посередине (B). Однако я не могу взаимодействовать с кнопками в середине B.
Я вижу кнопки в B - я установил фон A на clearColor - но кнопки в B, похоже, не получают касаний, несмотря на то, что на самом деле поверх этих кнопок нет объектов из A.
РЕДАКТИРОВАТЬ - я все еще хочу иметь возможность взаимодействовать с объектами в верхнем UIView
Конечно, есть простой способ сделать это?
objective-c
ios
cocoa-touch
Делани
источник
источник
UIButton
который находится под полупрозрачным, вUIView
то время как непрозрачная частьUIView
все еще будет реагировать на события касания.Ответы:
Вы должны создать подкласс UIView для вашего вида сверху и переопределить следующий метод:
Вы также можете посмотреть метод hitTest: event:.
источник
return
утверждение, ноreturn CGRectContainsPoint(eachSubview.frame, point)
у меня работает. Чрезвычайно полезный ответ в противном случаеMIDDLE_Y1<=y<=MIDDLE_Y2
области.Хотя многие ответы здесь будут работать, я немного удивлен, увидев, что наиболее удобный, общий и надежный ответ здесь не был дан. @Ash подошел ближе всего, за исключением того, что с возвратом супервизора происходит что-то странное ... не делайте этого.
Этот ответ взят из ответа, который я дал на аналогичный вопрос здесь .
[super hitTest:point withEvent:event]
вернет самое глубокое представление в иерархии этого представления, которое было затронуто. ЕслиhitView == self
(то есть, если под точкой касания нет подпредставления), вернитесьnil
, указав, что это представление не должно получать касание. То, как работает цепочка респондентов, означает, что иерархия представлений выше этой точки будет продолжаться до тех пор, пока не будет найдено представление, которое будет реагировать на касание. Не возвращайте супервизор, так как это не зависит от того, должен ли супервизор принимать прикосновения или нет!Это решение:
pointInside:withEvent:
чтобы вернуть конкретную осязаемую область).Я использую это достаточно часто, чтобы абстрагировать его в подкласс, чтобы сохранить бессмысленные подклассы представления для одного переопределения. В качестве бонуса добавьте свойство, чтобы сделать его настраиваемым:
Затем сделайте шаг вперед и используйте этот вид везде, где вы можете использовать равнину
UIView
. Настройка его так просто , как установкаonlyRespondToTouchesInSubviews
вYES
.источник
Есть несколько способов справиться с этим. Я предпочитаю переопределить hitTest: withEvent: в представлении, которое является общим супервизором (возможно, косвенно) для конфликтующих представлений (похоже, вы называете их A и B). Например, что-то вроде этого (здесь A и B - указатели UIView, где B - «скрытый», обычно игнорируемый):
Вы также можете изменить
pointInside:withEvent:
метод в соответствии с предложением gyim. Это позволяет вам достичь практически того же результата, эффективно «протыкая дыру» в A, по крайней мере, для касаний.Другой подход - пересылка событий, что означает переопределение
touchesBegan:withEvent:
и аналогичные методы (например, иtouchesMoved:withEvent:
т. Д.) Для отправки некоторых штрихов к другому объекту, а не к тому месту, где они были сначала. Например, в A можно написать что-то вроде этого:Однако это не всегда будет работать так, как вы ожидаете! Главное, чтобы встроенные элементы управления, такие как UIButton, всегда игнорировали перенаправленные касания. Из-за этого первый подход более надежен.
Есть хороший пост в блоге, объясняющий все это более подробно, а также небольшой рабочий проект xcode для демонстрации идей, доступный здесь:
http://bynomial.com/blog/?p=74
источник
Ставить надо
upperView.userInteractionEnabled = NO;
, иначе прикосновения перехватит вид сверху.Версия для Interface Builder - это флажок в нижней части панели «Атрибуты просмотра», который называется «Взаимодействие с пользователем включено». Снимите флажок, и все будет хорошо.
источник
Пользовательская реализация pointInside: withEvent: действительно казалась подходящей, но работа с жестко заданными координатами казалась мне странной. В итоге я проверил, находится ли CGPoint внутри кнопки CGRect с помощью функции CGRectContainsPoint ():
источник
Недавно я написал класс, который мне в этом поможет. Использование его в качестве настраиваемого класса для
UIButton
илиUIView
будет передавать события касания, которые были выполнены на прозрачном пикселе.Это решение несколько лучше, чем принятый ответ, потому что вы все равно можете щелкнуть значок,
UIButton
который находится под полупрозрачным, вUIView
то время как непрозрачная часть по-UIView
прежнему будет реагировать на события касания.Как вы можете видеть на GIF-изображении, кнопка Giraffe представляет собой простой прямоугольник, но события касания на прозрачных областях передаются желтому
UIButton
цвету под ней.Ссылка на класс
источник
Думаю, я немного опоздал на эту вечеринку, но я добавлю следующее возможное решение:
Если вы используете этот код для переопределения стандартной функции hitTest пользовательского UIView, он будет игнорировать ТОЛЬКО само представление. Любые подпредставления этого представления будут возвращать свои обращения в обычном режиме, и любые обращения, которые были бы отправлены в само представление, передаются его суперпредставлению.
-Ash
источник
[self superview]
. в документации по этому методу состояние «Возвращает самого дальнего потомка получателя в иерархии представлений (включая самого себя), который содержит указанную точку» и «Возвращает ноль, если точка находится полностью вне иерархии представлений получателя». Я думаю, тебе следует вернутьсяnil
. когда вы вернете nil, управление передается супервизору, чтобы он проверил, есть ли у него какие-либо совпадения или нет. поэтому в основном он будет делать то же самое, за исключением того, что возвращение супервизора может что-то сломать в будущем.Просто перебираю принятый ответ и помещаю его здесь для справки. Принятый ответ работает отлично. Вы можете расширить его следующим образом, чтобы позволить подпредставлениям вашего представления получать прикосновение ИЛИ передать его любым представлениям позади нас:
Примечание. Вам даже не нужно выполнять рекурсию в дереве вложенного представления, потому что каждый
pointInside:withEvent:
метод сделает это за вас.источник
Может помочь установка отключенного свойства userInteraction. Например:
(Примечание: в приведенном выше коде "self" относится к представлению)
Таким образом, вы можете отображать только в topView, но не получите вводимые пользователем данные. Все эти прикосновения пользователя будут проходить через это представление, и нижнее представление будет отвечать за них. Я бы использовал этот topView для отображения прозрачных изображений или их анимации.
источник
Этот подход довольно чистый и позволяет прозрачным подпредставлениям также не реагировать на прикосновения. Просто создайте подкласс
UIView
и добавьте к его реализации следующий метод:источник
Мое решение здесь:
Надеюсь это поможет
источник
Есть кое-что, что вы можете сделать, чтобы перехватить касание в обоих представлениях.
Вид сверху:
Но это идея.
источник
Вот версия Swift:
источник
Swift 3
источник
Я никогда не создавал полный пользовательский интерфейс с использованием набора инструментов пользовательского интерфейса, поэтому у меня нет большого опыта работы с ним. Вот что, я думаю, должно работать.
Каждый UIView, а это UIWindow, имеет свойство
subviews
, которое представляет собой массив NSArray, содержащий все подвиды.Первое вложенное представление, которое вы добавляете к представлению, получит индекс 0, следующее - 1 и так далее. Вы также можете заменить
addSubview:
наinsertSubview: atIndex:
илиinsertSubview:aboveSubview:
и такие методы, которые могут определять положение вашего подпредставления в иерархии.Поэтому проверьте свой код, чтобы увидеть, какое представление вы добавляете первым в свой UIWindow. Это будет 0, другое - 1.
Теперь из одного из ваших вложенных представлений, чтобы перейти к другому, вы должны сделать следующее:
Сообщите мне, работает ли это в вашем случае!
(под этим маркером мой предыдущий ответ):
Если представлениям необходимо взаимодействовать друг с другом, они должны делать это через контроллер (то есть с использованием популярной модели MVC ).
Когда вы создаете новое представление, вы можете убедиться, что оно регистрируется в контроллере.
Таким образом, методика состоит в том, чтобы убедиться, что ваши представления регистрируются с помощью контроллера (который может хранить их по имени или как угодно в словаре или массиве). Либо вы можете заставить контроллер отправлять вам сообщение, либо вы можете получить ссылку на представление и напрямую общаться с ним.
Если в вашем представлении нет ссылки на контроллер (что может иметь место), вы можете использовать синглтоны и / или методы класса, чтобы получить ссылку на ваш контроллер.
источник
Я думаю, что правильный способ - использовать цепочку представлений, встроенную в иерархию представлений. Для ваших вложенных представлений, которые помещаются в основное представление, не используйте общий UIView, а вместо этого подкласс UIView (или один из его вариантов, например UIImageView), чтобы сделать MYView: UIView (или любой другой супертип, который вы хотите, например UIImageView). В реализации YourView реализуйте метод touchesBegan. Затем этот метод будет вызван при касании этого представления. Все, что вам нужно в этой реализации, - это метод экземпляра:
this touchesBegan - это api респондента, поэтому вам не нужно объявлять его в публичном или частном интерфейсе; это одно из тех волшебных API, о которых вам просто нужно знать. Этот self.superview в конечном итоге передаст запрос к viewController. Затем в viewController реализуйте touchBegan для обработки прикосновения.
Обратите внимание, что место касания (CGPoint) автоматически настраивается относительно окружающего представления для вас, поскольку оно перемещается вверх по цепочке иерархии представлений.
источник
Просто хочу опубликовать это, потому что у меня была несколько похожая проблема, я потратил значительное количество времени, пытаясь реализовать здесь ответы, но безуспешно. Что я в итоге сделал:
и реализуя
UIGestureRecognizerDelegate
:Вид снизу представлял собой навигационный контроллер с несколькими сегментами, и у меня была своего рода дверь наверху, которая могла закрываться с помощью жеста панорамирования. Все это было встроено в еще одну ВК. Работал как шарм. Надеюсь это поможет.
источник
Внедрение Swift 4 для решения на основе HitTest
источник
Полученный из превосходного и в основном надежного ответа Стюарта и полезной реализации Сегева, вот пакет Swift 4, который вы можете добавить в любой проект:
А затем с помощью hitTest:
источник