這應該是這個系列最後一篇了。我寫了很多都不是很好,不過如果不寫,那就永遠寫不好。歡迎大家交流糾錯。 UIMenuController,它不像Alert那麼不友好,也不像ActionSheet,一定要點擊一下;你可以無視它的出現,也可以通過它調用一些設定好的方法。它就長這樣: 這個控制項是不是很熟悉,微 ...
這應該是這個系列最後一篇了。我寫了很多都不是很好,不過如果不寫,那就永遠寫不好。歡迎大家交流糾錯。
UIMenuController,它不像Alert那麼不友好,也不像ActionSheet,一定要點擊一下;你可以無視它的出現,也可以通過它調用一些設定好的方法。它就長這樣:
這個控制項是不是很熟悉,微信裡面你長按就回出現的一個view。做IM的話,標桿就是wechat了,所以你們的產品怎麼會放過它(你)呢。
先設計一個我們常用的場景:你在聊天界面,長按textView,然後彈出這個菜單,接著你點擊了某一個Item。
聊天頁面:tableView + inputBar(就是有輸入框的一個view啦)。
這裡面你會用到,tableView的的代理,要實現幾個delegate。
1 #pragma mark - UITableViewDataSource & UITableViewDelegate 2 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 3 // 有多少條數據 4 return [dataArray count]; 5 } 6 7 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 8 static NSString * CellIdentifier = @"MessageCell"; 9 MessageCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 10 if (cell == nil) { 11 cell = [MessageCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; 12 cell.selectionStyle = UITableViewCellSelectionStyleDefault; 13 } 14 MessageModel * model = [dataArray objectAtIndex:indexPath.row]; 15 [cell setMyContent:model]; 16 return cell; 17 } 18 19 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 20 // 這裡就用之前寫到的的高度計算 21 return #cellHeightFromModelData#; 22 }
那我們再來看一下cell,cell要做幾件事:1、自己的frame要算出來;2、要放好textView或imageView,我這裡只說一下textView咯;
.h 我們要聲明一個public的方法,用model來設置cell,減少VC的代碼量。 還有一個block,給VC回傳textView交互事件。
1 typedef NS_ENUM(NSInteger,CellOperations) { 2 TextCopy, 3 TextDelete, 4 TextTransfor, 5 TextCollection, 6 7 ImageCopy, 8 ImageDelete, 9 ImageTransfor, 10 ImageCollection, 11 }; 12 13 @property(nonatomic,copy)void (^CellOperation)(MessageModel* message, CellOperations cop); 14 15 - (void)setMyContent:(MessageModel *)message;
.m 我們要算自己的高度,textView的高度。還有傳遞textView的一些事件到VC上。
1 - (void)setMyContent:(MessageModel *)message { 2 // 傳遞參數 3 // 算高度 4 // 設置textView的大小 以及背景框的大小 5 } 6 7 - (void)textViewCallBack:(CellOperations cop){ 8 // 把textView的操作 截獲 9 // 調用自己的 callBackVC 將操作傳遞出去 10 } 11 12 - (void)callBackVC:(CellOperations cop){ 13 // 往VC傳遞操作事件 14 }
實現上面的3個方法,我們就可以繪製出Cell,並且可以傳遞textView的操作了。
接下來,textView。
.h 這裡我們要聲明一個Block 給Cell傳值
@property(nonatomic,copy)void (^TVOperation)(CellOperations cop);
.m 這是就要實現UIMenuController
1 // 2 // DisplayTextView.m 3 // 4 // 5 // Created by akforsure on 15/12/1. 6 // Copyright © 2015年 akforsure. All rights reserved. 7 // 8 9 #import "DisplayTextView.h" 10 11 @implementation DisplayTextView { 12 UIMenuController * menu; 13 } 14 - (instancetype)initWithFrame:(CGRect)frame { 15 self = [super initWithFrame:frame]; 16 if(self) { 17 // 展示用的textView 要不能編輯 最好也不能選取,不然很二的 18 self.editable = NO; 19 self.selectable = NO; 20 } 21 return self; 22 } 23 - (void)showMenu{ 24 // 如果已經出現了 我們就return 25 if([menu isMenuVisible]) return; 26 // textView 一定要是第一響應 也要設置為可以是第一響應 27 [self becomeFirstResponder]; 28 // 設置UIMenuItems 並且添加到頁面上 29 UIMenuItem *menuItem0 = [[UIMenuItem alloc]initWithTitle:@"複製" action:@selector(kCopy:)]; 30 UIMenuItem *menuItem1 = [[UIMenuItem alloc]initWithTitle:@"刪除" action:@selector(kDelete:)]; 31 UIMenuItem *menuItem2 = [[UIMenuItem alloc]initWithTitle:@"轉發" action:@selector(transfor:)]; 32 UIMenuItem *menuItem3 = [[UIMenuItem alloc]initWithTitle:@"收藏" action:@selector(collection:)]; 33 menu = [UIMenuController sharedMenuController]; 34 [menu setMenuItems:[NSArray arrayWithObjects:menuItem0,menuItem1,menuItem2,menuItem3,nil]]; 35 [menu setTargetRect:self.bounds inView:self]; 36 [menu setMenuVisible: YES animated: YES]; 37 } 38 // 這個方法一定要實現的 不然你無法響應你的操作 39 - (BOOL)canBecomeFirstResponder { 40 return YES; 41 } 42 // 這個方法是對點擊的響應 返回YES 就是可以被識別 43 - (BOOL)canPerformAction:(SEL)action withSender:(id)sender { 44 45 if(action == @selector(kCopy:)) { 46 return YES; 47 }else if (action == @selector(kDelete:)) { 48 return YES; 49 }else if (action == @selector(transfor:)) { 50 return YES; 51 } 52 else if (action == @selector(collection:)) { 53 return YES; 54 } 55 [super canPerformAction:action withSender:sender]; 56 return NO; 57 } 58 #pragram mark - private methods 每一個事件的實現 59 - (void)kCopy:(id)sender { 60 if(self.TVOperation){ 61 self.TVOperation(TextCopy); 62 } 63 NSLog(@"textkCopy"); 64 } 65 - (void)kDelete:(id)sender { 66 if(self.TVOperation){ 67 self.TVOperation(TextDelete); 68 } 69 NSLog(@"textkDelete"); 70 } 71 - (void)transfor:(id)sender { 72 if(self.TVOperation){ 73 self.TVOperation(TextTransfor); 74 } 75 NSLog(@"texttransfor"); 76 } 77 - (void)collection:(id)sender { 78 if(self.TVOperation){ 79 self.TVOperation(TextCollection); 80 } 81 NSLog(@"textcollection"); 82 } 83 84 85 // Only override drawRect: if you perform custom drawing. 86 // An empty implementation adversely affects performance during animation. 87 // 在draw的時候加入long press 手勢 88 - (void)drawRect:(CGRect)rect { 89 // Drawing code 90 // 去除 長按手勢 91 for ( UIGestureRecognizer *recognizer in self.gestureRecognizers) { 92 if ( [recognizer isKindOfClass:[UILongPressGestureRecognizer class]]) { 93 recognizer.enabled = NO; 94 //這裡可能有問題,我不是很確定 不過用了一段時間也沒啥 95 } 96 } 97 // 重新加入長按手勢 98 UILongPressGestureRecognizer *kGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(showMenu)]; 99 [self addGestureRecognizer:kGesture]; 100 } 101 102 @end
到這裡為止,我們就完成了你看到的那個效果了,我沒有給全所有代碼,因為我希望大家都自己動手寫一下。