13章 UIGestureRecognizer and UIMenuController 创建自定义手势 按钮: 例如长按文本出现的按钮,自定义 UILongPressGestureRecognizer UIPanGestureRecognizer and Simultaneous Recognizers UIMenuController and UIResponderStajdardEditAction ----------------------------------------------------------------------------------------------------------------------------------------- Chapter 13 UIGestureRecognizer and UIMenuController. 1. gesture like pinch or swipe 2.you don't instantiate UIGestureRecognizer, system has some subclass that u can use for the particular gesture. the action message like: - (void) action:(UIGestureRecognizer *)gestureRecognizer; ** when recognizing a gesture,the gesture recognizer intercepts the touch destined for the view.so the like touchBegan: may not receive. the flow: UIApplication --touch event--> UIWindow --touch event--> UIGestureRecognizer -- recognized gesture(yes/no)--> if yes: send action: to view; if not,send touchesBegan:withEvent: to the view. ********************* UITapGestureRecognizer: double tap screen and clear the lines: -(instancetype)initWithFrame:(CGRect)r { //...... UITapGestureRecognizer *doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTap:)]; doubleTapRecognizer.numberOfTapsRequired = 2; [self addGestureRecognizer:doubleTapRecognizer]; return self; } -(void)doubleTap:(UIGestureRecognizer *)gr { // for a double tap, u don't need information from gr [self.linesInProgress removeAllObjects]; [self.finishedLines removeAllObjects]; [self setNeedsDisplay]; } the flow: 1.send touchesBegan:; 2.recognized the double tap, send doubleTap: 3.send touchedCancelled:. *** so if u don't want the 1 happens,set like: doubleTapRecognizer.delaysTouchesBegan = YES; ----------------multiple gesture recognizers---------- like: if u add a tap and double tap to a view,when u double the view,it will send to tap first and then send to doubleTap. So, the truth is : if u double tap the screen,the tap may not what u want to trigger,so set like: [tapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer]; means during the double tap happen, the one tap will force to fail. ***** one tap to choose a line******* when select a line,a menu appear right at the tap point. UIMenuController, UIMenuItem (the list that controller has) each item has a title and action. the action message is send to the first responder of the window,so there is not the gesture,view 's business/// ***There is only one UIMenuController per Application, u can fill it with menu items to it, and give it a rectangle to present form,and set it to be visible.****** do like: -(void) tap:(UIGestureRecognizer *)gr { // get the tap location CGPoint point = [gr locationInView:self]; self.selectedLine = [self lineAtPoint:point]; if(self.selectedLine){ //!!! make ourselves the target of menu item // action messages [self becomeFirstResponder]; // grab the msnu controller UIMenuController *menu = [UIMenuController sharedMenuController]; // create delete item UIMenuItem *deleteItem = [[UIMenuItem alloc] initWithTitle:@"Delete" action:@selector(deleteLine:)]; menu.menuItems = @[deleteItem]; // show it [menu setTargetRect:CGRectMake(point.x,point.y,2,2) inView:self]; [menu setMenuVisible:YES animated:YES]; }else{ // hide menu controller [[UIMenuController sharedMenuController] setMenuVisible:NO animated:YES]; } [self setNeedsDisplay]; } *****if u have a custom class needs to become the first responder,u must override canBecomeFirstResponder: -(BOOL)canBecomeFirstResponder { return YES; } *** what u do below, when u tap a line, the menu is not shown at all. the reason: 1.becomeFirstResponder [done] 2.implemented each item's selector [not yet] so: -(void) deleteLine:(BNRLine *) line { [self.finishedLines removeObject:self.selectedLine]; [self setNeedsDisplay]; } ====================================== UILongPressGestureRecognizer ***when u hold down on a line (a long press),u selected the line and then drag it around by dragging you finger (pan) as add other gesture add the long press gesture. notice that need more than 0.5s,u can change it by set minimumPressDuration. %%the below gesture is the simple gesture: by the time it is recognized,the gesture is over, and the message has been delivered . %% long press is occurs over time and is defined by three separate events. UIGestureRecognizerStatePossible, [press a while] UIGestureRecgonizerStateBegan, [like at lease 0.5] UIGestureRecognizerStateEnded. [remove finger] the state property ************* -(void)longPress:(UIGestureRecognizer *)rg { if(rg.state == UIGestureRecognizerStateBegan){ CGPoint *point = [rg locationInView:self]; self.selectedLine = [self lineAtPoint:point]; if(self.selectedLine){ self.linesInProgress removeAllObjects]; } }else if(rg.state == UIGestureRecognizerStateEnded){ self.selectedLine = nil; } [self setNeedsDisplay]; } ------------UIPanGestureRecognizer Simultaneous Recognizer--------------- pan: move the line with finger around the screen ** normally ,a gesture recognizer does not share the touches.just like eat the touch,and no other recognizer get a chance to handle it. But this is bad ,u need the long press and panning. do like: @interface BNRDrawView () <UIGestureRecognizerDelegate> @property (nonatomic,strong) UIPanGestureRecognizer *moveRecognizer; // other code .... @end // code in implementation self.moveRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(moveLine:) ]; self.moveRecognizer.delegate = self; self.moveRecognizer.cancelsTouchesInView = NO; [self addGestureRecognizer:self.moveRecognizer]; *****u just need to implementation one method about UIGestureRecognizerDelegate protocol,: gestureRecognizer:shouldRecognizerSimultaneouslyWithGestureRecognizer: &&when a recognizer hold the gesture,at the same time ,another recognizer recognized the gesture,so, it will send the message. -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizerShouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)other { if(gestureRecognizer == self.moveRecognizer){ return YES; } return NO; } -(void)moveLine:(UIPanGestureRecognizer *)gr { if(!self.selectedLine){ return; } if(gr.state == UIGestureRecognizerStateChanged){ CGPoint translation = [gr translationInView:self] CGPoint begin = self.selectedLine.begin; CGPoint end = self.selectedLine.end; begin.x += translation.x; begin.y += translation.y; end.x += translation.x; end.y += translation.y; self.selectedLine.begin = begin; self.selectedLine.end = end; [self setNeedsDisplay]; //************] [gr setTranslation:CGPointZero inView:self]; } }
浙公网安备 33010602011771号