UICollectionViewCell에서 길게 누르기 제스처
UICollectionView의 (하위 클래스)에 길게 누르기 제스처 인식기를 추가하는 방법을 궁금합니다. 문서에서 기본적으로 추가된다는 것을 읽었지만 방법을 알 수 없습니다.
내가하고 싶은 것은 셀을 길게 누르고 ( github에서 캘린더가 있습니다 ) 어떤 셀을 탭했는지 확인한 다음 작업을 수행합니다. 어떤 세포가 오래 눌 렸는지 알아야합니다. 이 광범위한 질문에 대해 죄송하지만 Google 또는 SO에서 더 나은 것을 찾을 수 없습니다.
목표 -C
당신에 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))
스위프트 4
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))
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
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
}
Answers here to add a custom longpress gesture recognizer are correct however according to the documentation here: the parent class of UICollectionView
class installs a default long-press gesture recognizer
to handle scrolling interactions so you must link your custom tap gesture recognizer to the default recognizer associated with your collection view.
The following code will avoid your custom gesture recognizer to interfere with the default one:
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];
}
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
[cell addGestureRecognizer:longPress];
and add the method like this.
- (void)longPress:(UILongPressGestureRecognizer*)gesture
{
if ( gesture.state == UIGestureRecognizerStateEnded ) {
UICollectionViewCell *cellLongPressed = (UICollectionViewCell *) gesture.view;
}
}
To have an external gesture recognizer and do not conflict with internal gesture recognizers on the UICollectionView you need to:
Add your gesture recognizer, set up it and capture a reference for it somewhere (the best option is on your subclass if you subclassed UICollectionView)
@interface UICollectionViewSubclass : UICollectionView <UIGestureRecognizerDelegate>
@property (strong, nonatomic, readonly) UILongPressGestureRecognizer *longPressGestureRecognizer;
@end
Override default initialization methods initWithFrame:collectionViewLayout:
and initWithCoder:
and add set up method for you long press gesture recognizer
@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
Write your setup method so it instantiates long press gesture recognizer, set it's delegate, setup dependencies with UICollectionView gesture recognizer (so it be the main gesture and all other gestures will wait till that gesture fails before being recognized) and add gesture to the view
-(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];
}
Also don't forget to implement UIGestureRecognizerDelegate methods that fails that gesture and allow simultaneous recognition (you may or may don't need to implement it, it depends on other gesture recognizers you have or dependencies with internal gesture recognizers)
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if ([self.longPressGestureRecognizer isEqual:gestureRecognizer]) {
return NO;
}
return NO;
}
credentials for that goes to internal implementation of LXReorderableCollectionViewFlowLayout
Perhaps, using UILongPressGestureRecognizer is the most widespread solution. But I encounter with it two annoying troubles:
- sometimes this recognizer works in incorrect way when we're moving our touch;
- recognizer intercepts other touch actions so we can't use highlight callbacks of our UICollectionView in a proper way.
Let me suggest one a little bit bruteforce, but working as it's required suggestion:
Declaring a callback description for long click on our cell:
typealias OnLongClickListener = (view: OurCellView) -> Void
Extending UICollectionViewCell with variables (we can name it OurCellView, for example):
/// 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
Adding two methods in our cell class:
/**
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)
}
And overriding touch events here:
/// 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)
}
Then somewhere in controller of our collection view declaring callback listener:
let longClickListener: OnLongClickListener = {view in
print("Long click was performed!")
}
And finally in cellForItemAtIndexPath setting callback for our cells:
/// 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
}
Now we can intercept long click actions on our cells.
참고URL : https://stackoverflow.com/questions/18848725/long-press-gesture-on-uicollectionviewcell
'Programming' 카테고리의 다른 글
jquery를 사용하지 않고 문서 높이와 너비를 얻는 방법 (0) | 2020.08.15 |
---|---|
div 너비보다 작은 테두리 길이? (0) | 2020.08.15 |
Django의 urls.py에서 템플릿으로 바로 이동하려면 어떻게해야합니까? (0) | 2020.08.15 |
선택한 실행 대상은이 작업에 유효하지 않습니다. (0) | 2020.08.15 |
중복 AssemblyVersion 특성 (0) | 2020.08.15 |