UICollectionView의 (하위 클래스)에 길게 누르기 제스처 인식기를 추가하는 방법을 궁금합니다. 문서에서 기본적으로 추가된다는 것을 읽었지만 방법을 알 수 없습니다.
내가하고 싶은 것은 셀을 길게 누르고 ( github에서 캘린더가 있습니다 ) 어떤 셀을 탭했는지 확인한 다음 작업을 수행합니다. 어떤 세포가 오래 눌 렸는지 알아야합니다. 이 광범위한 질문에 대해 죄송하지만 Google 또는 SO에서 더 나은 것을 찾을 수 없습니다.
UICollectionView의 (하위 클래스)에 길게 누르기 제스처 인식기를 추가하는 방법을 궁금합니다. 문서에서 기본적으로 추가된다는 것을 읽었지만 방법을 알 수 없습니다.
내가하고 싶은 것은 셀을 길게 누르고 ( github에서 캘린더가 있습니다 ) 어떤 셀을 탭했는지 확인한 다음 작업을 수행합니다. 어떤 세포가 오래 눌 렸는지 알아야합니다. 이 광범위한 질문에 대해 죄송하지만 Google 또는 SO에서 더 나은 것을 찾을 수 없습니다.
답변:
당신에 myCollectionViewController.h파일 추가 UIGestureRecognizerDelegate프로토콜을
@interface myCollectionViewController : UICollectionViewController<UIGestureRecognizerDelegate>
당신의 myCollectionViewController.m파일 :
- (void)viewDidLoad
{
// attach long press gesture to collectionView
UILongPressGestureRecognizer *lpgr
= [[UILongPressGestureRecognizer alloc]
initWithTarget:self action:@selector(handleLongPress:)];
lpgr.delegate = self;
lpgr.delaysTouchesBegan = YES;
[self.collectionView addGestureRecognizer:lpgr];
}
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer.state != UIGestureRecognizerStateEnded) {
return;
}
CGPoint p = [gestureRecognizer locationInView:self.collectionView];
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:p];
if (indexPath == nil){
NSLog(@"couldn't find index path");
} else {
// get the cell at indexPath (the one you long pressed)
UICollectionViewCell* cell =
[self.collectionView cellForItemAtIndexPath:indexPath];
// do stuff with the cell
}
}
class Some {
@objc func handleLongPress(gesture : UILongPressGestureRecognizer!) {
if gesture.state != .Ended {
return
}
let p = gesture.locationInView(self.collectionView)
if let indexPath = self.collectionView.indexPathForItemAtPoint(p) {
// get the cell at indexPath (the one you long pressed)
let cell = self.collectionView.cellForItemAtIndexPath(indexPath)
// do stuff with the cell
} else {
print("couldn't find index path")
}
}
}
let some = Some()
let lpgr = UILongPressGestureRecognizer(target: some, action: #selector(Some.handleLongPress))
class Some {
@objc func handleLongPress(gesture : UILongPressGestureRecognizer!) {
if gesture.state != .ended {
return
}
let p = gesture.location(in: self.collectionView)
if let indexPath = self.collectionView.indexPathForItem(at: p) {
// get the cell at indexPath (the one you long pressed)
let cell = self.collectionView.cellForItem(at: indexPath)
// do stuff with the cell
} else {
print("couldn't find index path")
}
}
}
let some = Some()
let lpgr = UILongPressGestureRecognizer(target: some, action: #selector(Some.handleLongPress))
lpgr.delaysTouchesBegan = YES;되지 않도록 추가 해야합니다 didHighlightItemAtIndexPath.
lpgr.delegate = self;입니까? 당신이 제공하지 않은 대리인 없이도 잘 작동합니다.
UIGestureRecognizerStateBegan것이므로 제스처는 사용자가 손가락을 뗄 때가 아니라 인식 될 때 사용됩니다.
Swift에 대한 동일한 코드 @abbood의 코드 :
viewDidLoad에서 :
let lpgr : UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: "handleLongPress:")
lpgr.minimumPressDuration = 0.5
lpgr.delegate = self
lpgr.delaysTouchesBegan = true
self.collectionView?.addGestureRecognizer(lpgr)
그리고 기능 :
func handleLongPress(gestureRecognizer : UILongPressGestureRecognizer){
if (gestureRecognizer.state != UIGestureRecognizerState.Ended){
return
}
let p = gestureRecognizer.locationInView(self.collectionView)
if let indexPath : NSIndexPath = (self.collectionView?.indexPathForItemAtPoint(p))!{
//do whatever you need to do
}
}
대표자를 잊지 마세요 UIGestureRecognizerDelegate
UIGestureRecognizerState.Ended로 변경 UIGestureRecognizerState.Began하십시오.
UICollectionView의 대리자를 사용하여 길게 누르기 이벤트 수신
아래 3 가지 방법을 단순화해야합니다.
//UICollectionView menu delegate
- (BOOL)collectionView:(UICollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath{
//Do something
return YES;
}
- (BOOL)collectionView:(UICollectionView *)collectionView canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender{
//do nothing
return NO;
}
- (void)collectionView:(UICollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender{
//do nothing
}
여기 답변은 올바른 인식 사용자 정의 길게 누르 제스처 추가 그러나 문서에 따라 여기를 :의 부모 클래스 UICollectionView클래스가 설치 default long-press gesture recognizer당신이 당신의 콜렉션 뷰와 관련된 기본 인식에 사용자 정의 탭 제스처 인식기를 연결해야합니다 있도록 스크롤 상호 작용을 처리합니다.
다음 코드는 사용자 정의 제스처 인식기가 기본 인식기를 방해하지 않도록합니다.
UILongPressGestureRecognizer* longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPressGesture:)];
longPressGesture.minimumPressDuration = .5; //seconds
longPressGesture.delegate = self;
// Make the default gesture recognizer wait until the custom one fails.
for (UIGestureRecognizer* aRecognizer in [self.collectionView gestureRecognizers]) {
if ([aRecognizer isKindOfClass:[UILongPressGestureRecognizer class]])
[aRecognizer requireGestureRecognizerToFail:longPressGesture];
}
The parent class of UICollectionView class installs a default tap gesture recognizer and a default long-press gesture recognizer to handle scrolling interactions. You should never try to reconfigure these default gesture recognizers or replace them with your own versions.그래서 기본 길게 누름 인식기는 스크롤링을 위해 만들어졌습니다. 이것은 수직 이동을 동반해야 함을 의미합니다 .. OP는 묻지 않습니다. 그런 종류의 행동에 대해 그는 그것을 대체하려고하지 않습니다
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
[cell addGestureRecognizer:longPress];
다음과 같은 방법을 추가하십시오.
- (void)longPress:(UILongPressGestureRecognizer*)gesture
{
if ( gesture.state == UIGestureRecognizerStateEnded ) {
UICollectionViewCell *cellLongPressed = (UICollectionViewCell *) gesture.view;
}
}
외부 제스처 인식기를 갖고 UICollectionView에서 내부 제스처 인식기와 충돌하지 않으려면 다음을 수행해야합니다.
제스처 인식기를 추가하고 설정하고 어딘가에 대한 참조를 캡처합니다 (UICollectionView를 서브 클래 싱 한 경우 가장 좋은 옵션은 서브 클래스에 있습니다).
@interface UICollectionViewSubclass : UICollectionView <UIGestureRecognizerDelegate>
@property (strong, nonatomic, readonly) UILongPressGestureRecognizer *longPressGestureRecognizer;
@end
기본 초기화 방법을 재정의 initWithFrame:collectionViewLayout:하고 initWithCoder:길게 누르기 제스처 인식기에 대한 설정 방법 추가
@implementation UICollectionViewSubclass
-(instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout
{
if (self = [super initWithFrame:frame collectionViewLayout:layout]) {
[self setupLongPressGestureRecognizer];
}
return self;
}
-(instancetype)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
[self setupLongPressGestureRecognizer];
}
return self;
}
@end
길게 누르기 제스처 인식기를 인스턴스화하고, 대리자를 설정하고, UICollectionView 제스처 인식기를 사용하여 종속성을 설정하도록 설정 메서드를 작성하고 (따라서 기본 제스처가되고 다른 모든 제스처는 해당 제스처가 인식되기 전에 실패 할 때까지 기다림)보기에 제스처를 추가합니다.
-(void)setupLongPressGestureRecognizer
{
_longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self
action:@selector(handleLongPressGesture:)];
_longPressGestureRecognizer.delegate = self;
for (UIGestureRecognizer *gestureRecognizer in self.collectionView.gestureRecognizers) {
if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) {
[gestureRecognizer requireGestureRecognizerToFail:_longPressGestureRecognizer];
}
}
[self.collectionView addGestureRecognizer:_longPressGestureRecognizer];
}
또한 해당 제스처에 실패하고 동시 인식을 허용하는 UIGestureRecognizerDelegate 메서드를 구현하는 것을 잊지 마십시오 (구현할 필요가있을 수도 있고 필요하지 않을 수도 있으며, 보유한 다른 제스처 인식기 또는 내부 제스처 인식기와의 종속성에 따라 다름).
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if ([self.longPressGestureRecognizer isEqual:gestureRecognizer]) {
return NO;
}
return NO;
}
이에 대한 자격 증명은 LXReorderableCollectionViewFlowLayout의 내부 구현으로 이동합니다.
private func setupLongGestureRecognizerOnCollection() {
let longPressedGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(gestureRecognizer:)))
longPressedGesture.minimumPressDuration = 0.5
longPressedGesture.delegate = self
longPressedGesture.delaysTouchesBegan = true
collectionView?.addGestureRecognizer(longPressedGesture)
}
@objc func handleLongPress(gestureRecognizer: UILongPressGestureRecognizer) {
if (gestureRecognizer.state != .began) {
return
}
let p = gestureRecognizer.location(in: collectionView)
if let indexPath = collectionView?.indexPathForItem(at: p) {
print("Long press at item: \(indexPath.row)")
}
}
또한 UIGestureRecognizerDelegate를 구현하고 viewDidLoad 또는 호출이 필요한 곳에서 setupLongGestureRecognizerOnCollection을 호출하는 것을 잊지 마십시오.
아마도 UILongPressGestureRecognizer를 사용 하는 것이 가장 널리 퍼진 솔루션 일 것입니다. 그러나 나는 두 가지 성가신 문제에 직면합니다.
약간의 무차별 대입을 제안하지만 제안이 필요한대로 작동합니다.
셀에 대한 긴 클릭에 대한 콜백 설명 선언 :
typealias OnLongClickListener = (view: OurCellView) -> Void
변수로 UICollectionViewCell 확장 (예 : OurCellView 이름을 지정할 수 있음) :
/// To catch long click events.
private var longClickListener: OnLongClickListener?
/// To check if we are holding button pressed long enough.
var longClickTimer: NSTimer?
/// Time duration to trigger long click listener.
private let longClickTriggerDuration = 0.5
셀 클래스에 두 가지 메서드 추가 :
/**
Sets optional callback to notify about long click.
- Parameter listener: A callback itself.
*/
func setOnLongClickListener(listener: OnLongClickListener) {
self.longClickListener = listener
}
/**
Getting here when long click timer finishs normally.
*/
@objc func longClickPerformed() {
self.longClickListener?(view: self)
}
여기에서 터치 이벤트를 재정의합니다.
/// Intercepts touch began action.
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
longClickTimer = NSTimer.scheduledTimerWithTimeInterval(self.longClickTriggerDuration, target: self, selector: #selector(longClickPerformed), userInfo: nil, repeats: false)
super.touchesBegan(touches, withEvent: event)
}
/// Intercepts touch ended action.
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
longClickTimer?.invalidate()
super.touchesEnded(touches, withEvent: event)
}
/// Intercepts touch moved action.
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
longClickTimer?.invalidate()
super.touchesMoved(touches, withEvent: event)
}
/// Intercepts touch cancelled action.
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
longClickTimer?.invalidate()
super.touchesCancelled(touches, withEvent: event)
}
그런 다음 콜백 리스너를 선언하는 컬렉션 뷰의 컨트롤러 어딘가에 :
let longClickListener: OnLongClickListener = {view in
print("Long click was performed!")
}
마지막으로 셀에 대한 cellForItemAtIndexPath 설정 콜백에서 :
/// Data population.
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath)
let castedCell = cell as? OurCellView
castedCell?.setOnLongClickListener(longClickListener)
return cell
}
이제 셀에서 긴 클릭 동작을 가로 챌 수 있습니다.
UICollectionViewCell* cell = [self.collectionView cellForItemAtIndexPath:indexPath];참조가 여기에 이 모든 장점에게 정답 상을 바랍니다 : D