Как добавить сенсорное событие в UIView?

280

Как добавить сенсорное событие в UIView?
Я пытаюсь:

UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, nextY)] autorelease];
[headerView addTarget:self action:@selector(myEvent:) forControlEvents:UIControlEventTouchDown];
// ERROR MESSAGE: UIView may not respond to '-addTarget:action:forControlEvents:'

Я не хочу создавать подкласс и перезаписать

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
Манни
источник
Для быстрого вы можете получить его здесь: stackoverflow.com/questions/28675209/…
Mr.Javed Multani

Ответы:

578

В iOS 3.2 и выше вы можете использовать распознаватели жестов. Например, вот как вы бы обработали событие касания:

//The setup code (in viewDidLoad in your view controller)
UITapGestureRecognizer *singleFingerTap = 
  [[UITapGestureRecognizer alloc] initWithTarget:self 
                                          action:@selector(handleSingleTap:)];
[self.view addGestureRecognizer:singleFingerTap];

//The event handling method
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer
{
  CGPoint location = [recognizer locationInView:[recognizer.view superview]];

  //Do stuff here...
}

Есть также множество встроенных жестов. Проверьте документы для обработки событий iOS и UIGestureRecognizer. У меня также есть куча примеров кода на github, которые могут помочь.

Натан Эрор
источник
Но это перезаписывает сенсорный defautlt действие представления. ¿Можно ли вызвать сенсорное действие по умолчанию для вида? Что-то вроде [супер
трогает Беган
2
Что делает линия CGPoint?
zakdances
2
@yourfriendzak the CGPointпредставляет местоположение касания в суперпредставлении повернутого вида. Вы можете использовать эту точку, чтобы переместить повернутый вид (или родственный вид) в повернутое местоположение. Это более полезно в обработчике UIPanGestureRecognizerдля перетаскивания вида по экрану.
Натан Эрор
5
отличный краткий ответ, спасибо. но боже, разве не было бы неплохо, если бы это было немного проще ?! :)
natbro
Это не так уж плохо, но я бы хотел, чтобы существовал блочный API, например github.com/neror/ftutils/blob/master/Headers/FTUtils/… . Xcode 4 также поддерживает добавление / настройку распознавателей жестов в Interface Builder.
Натан Эрор
126

Распознаватели жестов

Существует ряд часто используемых сенсорных событий (или жестов), о которых вы можете получать уведомления, когда добавляете в свое представление Gesture Recognizer . Следующие типы жестов поддерживаются по умолчанию:

  • UITapGestureRecognizer Нажмите (короткое касание экрана один или несколько раз)
  • UILongPressGestureRecognizer Долгое касание (касание экрана долгое время)
  • UIPanGestureRecognizer Пан (перемещая палец по экрану)
  • UISwipeGestureRecognizer Проведите (быстро двигая пальцем)
  • UIPinchGestureRecognizer Щепотка (перемещение двух пальцев вместе или врозь - обычно для увеличения)
  • UIRotationGestureRecognizer Поворот (перемещение двух пальцев по кругу)

В дополнение к этому вы также можете сделать свой собственный распознаватель жестов.

Добавление жеста в Интерфейсном Разработчике

Перетащите распознаватель жестов из библиотеки объектов на ваше представление.

введите описание изображения здесь

Управляйте перетаскиванием из жеста в Схеме документа в свой код View Controller, чтобы создать Outlet и Action.

введите описание изображения здесь

Это должно быть установлено по умолчанию, но также убедитесь, что User Action Enabled имеет значение true для вашего представления.

введите описание изображения здесь

Добавление жеста программно

Чтобы добавить жест программно, вы (1) создаете распознаватель жестов, (2) добавляете его в представление и (3) создаете метод, который вызывается при распознавании жеста.

import UIKit
class ViewController: UIViewController {

    @IBOutlet weak var myView: UIView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 1. create a gesture recognizer (tap gesture)
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(sender:)))
        
        // 2. add the gesture recognizer to a view
        myView.addGestureRecognizer(tapGesture)
    }
    
    // 3. this method is called when a tap is recognized
    @objc func handleTap(sender: UITapGestureRecognizer) {
        print("tap")
    }
}

Ноты

  • senderПараметр является необязательным. Если вам не нужна ссылка на этот жест, вы можете не указывать его. Однако, если вы это сделаете, удалите (sender:)имя метода после действия.
  • Наименование handleTapметода было произвольным. Назовите это как хотите .action: #selector(someMethodName(sender:))

Больше примеров

Вы можете изучить средства распознавания жестов, которые я добавил к этим представлениям, чтобы увидеть, как они работают.

введите описание изображения здесь

Вот код для этого проекта:

import UIKit
class ViewController: UIViewController {
    
    @IBOutlet weak var tapView: UIView!
    @IBOutlet weak var doubleTapView: UIView!
    @IBOutlet weak var longPressView: UIView!
    @IBOutlet weak var panView: UIView!
    @IBOutlet weak var swipeView: UIView!
    @IBOutlet weak var pinchView: UIView!
    @IBOutlet weak var rotateView: UIView!
    @IBOutlet weak var label: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Tap
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap))
        tapView.addGestureRecognizer(tapGesture)
        
        // Double Tap
        let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap))
        doubleTapGesture.numberOfTapsRequired = 2
        doubleTapView.addGestureRecognizer(doubleTapGesture)
        
        // Long Press
        let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(gesture:)))
        longPressView.addGestureRecognizer(longPressGesture)
        
        // Pan
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(gesture:)))
        panView.addGestureRecognizer(panGesture)
        
        // Swipe (right and left)
        let swipeRightGesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe(gesture:)))
        let swipeLeftGesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe(gesture:)))
        swipeRightGesture.direction = UISwipeGestureRecognizerDirection.right
        swipeLeftGesture.direction = UISwipeGestureRecognizerDirection.left
        swipeView.addGestureRecognizer(swipeRightGesture)
        swipeView.addGestureRecognizer(swipeLeftGesture)
        
        // Pinch
        let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(handlePinch(gesture:)))
        pinchView.addGestureRecognizer(pinchGesture)
        
        // Rotate
        let rotateGesture = UIRotationGestureRecognizer(target: self, action: #selector(handleRotate(gesture:)))
        rotateView.addGestureRecognizer(rotateGesture)
        
    }
    
    // Tap action
    @objc func handleTap() {
        label.text = "Tap recognized"
        
        // example task: change background color
        if tapView.backgroundColor == UIColor.blue {
            tapView.backgroundColor = UIColor.red
        } else {
            tapView.backgroundColor = UIColor.blue
        }
        
    }
    
    // Double tap action
    @objc func handleDoubleTap() {
        label.text = "Double tap recognized"
        
        // example task: change background color
        if doubleTapView.backgroundColor == UIColor.yellow {
            doubleTapView.backgroundColor = UIColor.green
        } else {
            doubleTapView.backgroundColor = UIColor.yellow
        }
    }
    
    // Long press action
    @objc func handleLongPress(gesture: UILongPressGestureRecognizer) {
        label.text = "Long press recognized"
        
        // example task: show an alert
        if gesture.state == UIGestureRecognizerState.began {
            let alert = UIAlertController(title: "Long Press", message: "Can I help you?", preferredStyle: UIAlertControllerStyle.alert)
            alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
            self.present(alert, animated: true, completion: nil)
        }
    }
    
    // Pan action
    @objc func handlePan(gesture: UIPanGestureRecognizer) {
        label.text = "Pan recognized"
        
        // example task: drag view
        let location = gesture.location(in: view) // root view
        panView.center = location
    }
    
    // Swipe action
    @objc func handleSwipe(gesture: UISwipeGestureRecognizer) {
        label.text = "Swipe recognized"
        
        // example task: animate view off screen
        let originalLocation = swipeView.center
        if gesture.direction == UISwipeGestureRecognizerDirection.right {
            UIView.animate(withDuration: 0.5, animations: {
                self.swipeView.center.x += self.view.bounds.width
            }, completion: { (value: Bool) in
                self.swipeView.center = originalLocation
            })
        } else if gesture.direction == UISwipeGestureRecognizerDirection.left {
            UIView.animate(withDuration: 0.5, animations: {
                self.swipeView.center.x -= self.view.bounds.width
            }, completion: { (value: Bool) in
                self.swipeView.center = originalLocation
            })
        }
    }
    
    // Pinch action
    @objc func handlePinch(gesture: UIPinchGestureRecognizer) {
        label.text = "Pinch recognized"
        
        if gesture.state == UIGestureRecognizerState.changed {
            let transform = CGAffineTransform(scaleX: gesture.scale, y: gesture.scale)
            pinchView.transform = transform
        }
    }
    
    // Rotate action
    @objc func handleRotate(gesture: UIRotationGestureRecognizer) {
        label.text = "Rotate recognized"
        
        if gesture.state == UIGestureRecognizerState.changed {
            let transform = CGAffineTransform(rotationAngle: gesture.rotation)
            rotateView.transform = transform
        }
    }
}

Ноты

  • Вы можете добавить несколько распознавателей жестов к одному представлению. Для простоты, однако, я этого не делал (за исключением жеста смахивания). Если вам нужно для вашего проекта, вы должны прочитать документацию распознавателя жестов . Это довольно понятно и полезно.
  • Известные проблемы с моими примерами выше: (1) Панорамирование сбрасывает свой кадр при следующем событии жеста. (2) При первом перелистывании вид смахивания происходит с неправильного направления. (Эти ошибки в моих примерах не должны влиять на ваше понимание того, как работают распознаватели жестов.)
Suragch
источник
2
Ваш ответ действительно хорош и полезен с подробным описанием. И вот почему я голосую, ты тоже отвечаешь. Но вы просто пропустили одну инструкцию, которую, я думаю, вы должны включить в свой ответ, поскольку вы объяснили ее в деталях. Эта инструкция о настройке "<yourView> .EnableUserInteraction = TRUE". Я надеюсь, что вы согласны со мной.
Э-э Вихар
3
Для того, чтобы сделать эту работу на UIViewвас необходимо также добавить:self.isUserInteractionEnabled = true;
Neiker
52

Я думаю, что вы можете просто использовать

UIControl *headerView = ...
[headerView addTarget:self action:@selector(myEvent:) forControlEvents:UIControlEventTouchDown];

я имею в виду headerView распространяется от UIControl.

Личенг
источник
7
Это лучший ответ. UITapGestureRecognizerэто не замена UIControlEventTouchDown. А Tapобычно состоит из UIControlEventTouchDownи UIControlEventTouchUpInside.
Ох,
62
А UIViewне является UIControlи, следовательно, не имеет доступа к addTarget:action:forControlEvents:.
Роберт Джозеф
9
Также обратите внимание, что UIControl наследуется от UIView. Для моих целей все, что мне нужно было сделать, это простой переключатель типа подкласса.
pretzels1337
1
вы можете установить его класс в UIControl @RobertJoseph. Перейдите в xib-файл и установите для пользовательского класса View значение UIControl. теперь вы можете обрабатывать события в нем ..
Zar E Ahmer
2
Так почему же это лучшее решение снова, так как я меняю наследование только для обработки отводов?
Энтони Глядченко
21

Свифт 3 и Свифт 4

import UIKit

extension UIView {
  func addTapGesture(tapNumber: Int, target: Any, action: Selector) {
    let tap = UITapGestureRecognizer(target: target, action: action)
    tap.numberOfTapsRequired = tapNumber
    addGestureRecognizer(tap)
    isUserInteractionEnabled = true
  }
}

использование

yourView.addTapGesture(tapNumber: 1, target: self, action: #selector(yourMethod))
Индраджит Синх Райхада
источник
Спасибо. Прекрасно работает!
Микрася
1
Люблю это! Добавление ко всем проектам;)
budidino
17

На основании принятого ответа вы можете определить макрос:

#define handle_tap(view, delegate, selector) do {\
    view.userInteractionEnabled = YES;\
    [view addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget:delegate action:selector]];\
} while(0)

Этот макрос использует ARC, поэтому нет releaseвызова.

Пример использования макроса:

handle_tap(userpic, self, @selector(onTapUserpic:));
rudyryk
источник
4
Если вы создаете представление в раскадровке, не забудьте включить опцию «взаимодействие с пользователем включено».
Дэвид
где мы должны определить макросы в .h или .m и каковы должны быть имена параметров. я имею в виду #define handle_tap (вид UIView, делегат делегата, селектор SEL) делаю ..
Zar E Ahmer
8

Вы можете достичь этого, добавив Gesture Recogniser в ваш код.

Шаг 1: ViewController.m:

// Declare the Gesture.
UITapGestureRecognizer *gesRecognizer = [[UITapGestureRecognizer alloc] 
                                          initWithTarget:self 
                                          action:@selector(handleTap:)];
gesRecognizer.delegate = self;

// Add Gesture to your view.
[yourView addGestureRecognizer:gesRecognizer]; 

Шаг 2: ViewController.m:

// Declare the Gesture Recogniser handler method.
- (void)handleTap:(UITapGestureRecognizer *)gestureRecognizer{
   NSLog(@"Tapped");
}

ПРИМЕЧАНИЕ: здесь yourView в моем случае был @property (strong, nonatomic) IBOutlet UIView *localView;

РЕДАКТИРОВАТЬ: * localView - это белая рамка в Main.storyboard снизу

введите описание изображения здесь

введите описание изображения здесь

Annu
источник
У меня есть несколько просмотров, так что я могу узнать идентификатор отправителя?
Мойн Ширази
Вы должны перейти к внутреннему подпредставлению, затем вы можете сделать паас отправителем .--------- for (UIView * view в self.topicScrollView.subviews) {// Перейти внутрь суперпредставления if ([view isKindOfClass: [UIButton class]]) {// Перейти к этому конкретному виду // Здесь вы достигли этой точки. }}
Annu
8

В Swift 4.2 и Xcode 10

Используйте UITapGestureRecognizer для добавления сенсорного события

//Add tap gesture to your view
let tap = UITapGestureRecognizer(target: self, action: #selector(handleGesture))
yourView.addGestureRecognizer(tap)

// GestureRecognizer
@objc func handleGesture(gesture: UITapGestureRecognizer) -> Void {
//Write your code here
}

Если вы хотите использовать SharedClass

//This is my shared class
import UIKit

class SharedClass: NSObject {

    static let sharedInstance = SharedClass()

    //Tap gesture function
    func addTapGesture(view: UIView, target: Any, action: Selector) {
        let tap = UITapGestureRecognizer(target: target, action: action)
        view.addGestureRecognizer(tap)
    }
} 

У меня есть 3 представления в моем ViewController, называемые view1, view2 и view3.

override func viewDidLoad() {
    super.viewDidLoad()
    //Add gestures to your views
    SharedClass.sharedInstance.addTapGesture(view: view1, target: self, action: #selector(handleGesture))
    SharedClass.sharedInstance.addTapGesture(view: view2, target: self, action: #selector(handleGesture))
    SharedClass.sharedInstance.addTapGesture(view: view3, target: self, action: #selector(handleGesture2))

}

// GestureRecognizer
@objc func handleGesture(gesture: UITapGestureRecognizer) -> Void {
    print("printed 1&2...")
}
// GestureRecognizer
@objc func handleGesture2(gesture: UITapGestureRecognizer) -> Void {
    print("printed3...")
}
IOS
источник
6

Вот версия Swift:

// MARK: Gesture Extensions
extension UIView {

    func addTapGesture(#tapNumber: Int, target: AnyObject, action: Selector) {
        let tap = UITapGestureRecognizer (target: target, action: action)
        tap.numberOfTapsRequired = tapNumber
        addGestureRecognizer(tap)
        userInteractionEnabled = true
    }

    func addTapGesture(#tapNumber: Int, action: ((UITapGestureRecognizer)->())?) {
        let tap = BlockTap (tapCount: tapNumber, fingerCount: 1, action: action)
        addGestureRecognizer(tap)
        userInteractionEnabled = true
    }
}
Esqarrouth
источник
что такое BlockTap?
Он Ифэй 何 一 非
1
О человек, забыл эту часть. Это пользовательская функция. Здесь: github.com/goktugyil/EZSwiftExtensions/blob/master/Sources/…
Esqarrouth
5

Свифт 3:

let tapGestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTapGestureRecognizer(_:)))
view.addGestureRecognizer(tapGestureRecognizer)

func handleTapGestureRecognizer(_ gestureRecognizer: UITapGestureRecognizer) {

}
Жанг
источник
1

Кажется довольно простым в эти дни. Это версия Swift.

let tap = UITapGestureRecognizer(target: self, action: #selector(viewTapped))
    view.addGestureRecognizer(tap)

@objc func viewTapped(recognizer: UIGestureRecognizer)
{
    //Do what you need to do!
}
дай ми спокой
источник
0

Вот это IOS Tapgesture; Сначала вам нужно создать действие для GestureRecognizer после написания кода ниже под действием, как показано ниже

- (IBAction)tapgesture:(id)sender

{


[_password resignFirstResponder];


[_username resignFirstResponder];

NSLog(@" TapGestureRecognizer  tapped");

}
Sathish
источник
0

Другой способ - добавить прозрачную кнопку в представление.

UIButton *b = [UIButton buttonWithType:UIButtonTypeCustom];
b.frame = CGRectMake(0, 0, headerView.width, headerView.height);
[headerView addSubview:b];
[b addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchDown];

А затем обработайте щелчок:

- (void)buttonClicked:(id)sender
{}
thanhbinh84
источник
0

Создайте распознаватель жестов (подкласс), который будет реализовывать сенсорные события, например touchesBegan. Вы можете добавить его в представление после этого.

Таким образом, вы будете использовать состав вместо подклассов (который был запросом).

Джери Борбас
источник
0

Почему бы вам не попробовать SSEventListener ?

Вам не нужно создавать какой-либо распознаватель жестов и отделять свою логику от другого метода. SSEventListenerподдерживает настройку блоков слушателя в представлении для прослушивания жеста одним касанием, жеста двойного касания и жеста N-касания, а также жеста длительного нажатия. Установка прослушивателя с одним касанием становится следующим образом:

[view ss_addTapViewEventListener:^(UITapGestureRecognizer *recognizer) { ... } numberOfTapsRequired:1];

Shengsheng
источник
0

Objective-C:

UIControl *headerView = [[UIControl alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, nextY)];
[headerView addTarget:self action:@selector(myEvent:) forControlEvents:UIControlEventTouchDown];

Swift:

let headerView = UIControl(frame: CGRect(x: 0, y: 0, width: tableView.bounds.size.width, height: nextY))
headerView.addTarget(self, action: #selector(myEvent(_:)), for: .touchDown)

Вопрос задает:

Как добавить сенсорное событие в UIView?

Это не просит события касания .

Конкретно ОП хочет реализовать UIControlEventTouchDown

Переключение UIViewна UIControlправильный ответ здесь , потому что Gesture Recognisersничего не знает о .touchDown, .touchUpInside, и .touchUpOutsideт.д.

Кроме того, UIControl наследуется от UIView, поэтому вы не теряете никакой функциональности.

Если все, что вам нужно, это касание, то вы можете использовать Gesture Recogniser. Но если вам нужен более точный контроль, как требует этот вопрос, вам понадобится UIControl.

https://developer.apple.com/documentation/uikit/uicontrol?language=objc https://developer.apple.com/documentation/uikit/uigesturerecognizer?language=objc

janakmshah
источник