• iOS开发之功能模块--用runtime给UIView类别拓展PressMenu工具


    这是个很有用的列别工具类,在聊天对话框添加和QQ一样的"复制、粘贴、取消"等选项,而且使用起来很方便,只要找到聊天泡泡内部的某个View,比如Label或者背景冒泡的UIImageView,直接add...即可实现下面的效果:

    直接上源码:

    UIView+PressMenu.h

     1 #import <UIKit/UIKit.h>
     2 
     3 @interface UIView (PressMenu)
     4 @property (strong, nonatomic) NSArray *menuTitles;
     5 @property (strong, nonatomic) UILongPressGestureRecognizer *pressGR;
     6 @property (copy, nonatomic) void(^menuClickedBlock)(NSInteger index, NSString *title);
     7 @property (strong, nonatomic) UIMenuController *menuVC;
     8 
     9 - (void)addPressMenuTitles:(NSArray *)menuTitles menuClickedBlock:(void(^)(NSInteger index, NSString *title))block;
    10 - (void)showMenuTitles:(NSArray *)menuTitles menuClickedBlock:(void(^)(NSInteger index, NSString *title))block;
    11 
    12 - (BOOL)isMenuVCVisible;
    13 - (void)removePressMenu;
    14 @end

    UIView+PressMenu.m

      1 #import "UIView+PressMenu.h"
      2 #import <objc/runtime.h>
      3 
      4 @implementation UIView (PressMenu)
      5 
      6 static const NSString *kPressMenuSelectorPrefix = @"easePressMenuClicked_";
      7 static char PressMenuTitlesKey, PressMenuBlockKey, PressMenuGestureKey, MenuVCKey;
      8 
      9 #pragma mark M
     10 - (void)addPressMenuTitles:(NSArray *)menuTitles menuClickedBlock:(void(^)(NSInteger index, NSString *title))block{
     11     self.userInteractionEnabled = YES;
     12     self.menuClickedBlock = block;
     13     self.menuTitles = menuTitles;
     14     if (self.pressGR == nil) {
     15         self.pressGR = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlePress:)];
     16     }
     17     [self addGestureRecognizer:self.pressGR];
     18 }
     19 
     20 - (void)showMenuTitles:(NSArray *)menuTitles menuClickedBlock:(void(^)(NSInteger index, NSString *title))block{
     21     self.menuClickedBlock = block;
     22     self.menuTitles = menuTitles;
     23     [self p_showMenu];
     24 }
     25 
     26 - (BOOL)isMenuVCVisible{
     27     if (self.menuVC) {
     28         return [self.menuVC isMenuVisible];
     29     }
     30     return NO;
     31 }
     32 
     33 - (void)removePressMenu{
     34     if (self.menuVC) {
     35         [self.menuVC setMenuVisible:NO animated:YES];
     36         self.menuVC = nil;
     37     }
     38     if ([self.pressGR isKindOfClass:[UILongPressGestureRecognizer class]]) {
     39         [self removeGestureRecognizer:self.pressGR];
     40         self.pressGR = nil;
     41     }
     42     if (self.menuClickedBlock) {
     43         self.menuClickedBlock = nil;
     44     }
     45     if (self.menuTitles) {
     46         self.menuTitles = nil;
     47     }
     48 }
     49 
     50 #pragma mark SET_GET
     51 - (void)setMenuTitles:(NSArray *)menuTitles{
     52     objc_setAssociatedObject(self, &PressMenuTitlesKey, menuTitles, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
     53 }
     54 - (NSArray *)menuTitles{
     55     return objc_getAssociatedObject(self, &PressMenuTitlesKey);
     56 }
     57 
     58 - (void)setMenuClickedBlock:(void (^)(NSInteger, NSString *))menuClickedBlock{
     59     objc_setAssociatedObject(self, &PressMenuBlockKey, menuClickedBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
     60 }
     61 - (void (^)(NSInteger, NSString *))menuClickedBlock{
     62     return objc_getAssociatedObject(self, &PressMenuBlockKey);
     63 }
     64 
     65 - (void)setPressGR:(UILongPressGestureRecognizer *)pressGR{
     66     objc_setAssociatedObject(self, &PressMenuGestureKey, pressGR, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
     67 }
     68 - (UILongPressGestureRecognizer *)pressGR{
     69     return objc_getAssociatedObject(self, &PressMenuGestureKey);
     70 }
     71 
     72 - (void)setMenuVC:(UIMenuController *)menuVC{
     73     objc_setAssociatedObject(self, &MenuVCKey, menuVC, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
     74 }
     75 - (UIMenuController *)menuVC{
     76     return objc_getAssociatedObject(self, &MenuVCKey);
     77 }
     78 
     79 #pragma mark canPerformAction
     80 - (BOOL)canBecomeFirstResponder{
     81     if (self.menuClickedBlock) {
     82         return YES;
     83     }else{
     84         return [super canBecomeFirstResponder];
     85     }
     86 }
     87 
     88 -(BOOL)canPerformAction:(SEL)action withSender:(id)sender{
     89     if (self.menuClickedBlock) {
     90         for (int i=0; i<self.menuTitles.count; i++) {
     91             if (action == NSSelectorFromString([NSString stringWithFormat:@"%@%d:", kPressMenuSelectorPrefix, i])) {
     92                 return YES;
     93             }
     94         }
     95         return NO;
     96     }else{
     97         return [super canPerformAction:action withSender:sender];
     98     }
     99 }
    100 
    101 -(void)handlePress:(UIGestureRecognizer*)recognizer{
    102     if (recognizer.state == UIGestureRecognizerStateBegan) {
    103         [self p_showMenu];
    104     }
    105 }
    106 
    107 - (void)p_showMenu{
    108     [self becomeFirstResponder];
    109     NSMutableArray *menuItems = [[NSMutableArray alloc] initWithCapacity:self.menuTitles.count];
    110     Class cls = [self class];
    111     SEL imp = @selector(pressMenuClicked:);
    112     for (int i=0; i<self.menuTitles.count; i++) {
    113         NSString *title = [self.menuTitles objectAtIndex:i];
    114         //注册名添加方法sel,sel的具体实现在imp(pressMenuClicked:)
    115         SEL sel = sel_registerName([[NSString stringWithFormat:@"%@%d:", kPressMenuSelectorPrefix, i] UTF8String]);
    116         class_addMethod(cls, sel, [cls instanceMethodForSelector:imp], "v@");
    117         UIMenuItem *menuItem = [[UIMenuItem alloc] initWithTitle:title action:sel];
    118         [menuItems addObject:menuItem];
    119     }
    120     UIMenuController *menu = [UIMenuController sharedMenuController];
    121     [menu setMenuItems:menuItems];
    122     [menu setTargetRect:self.frame inView:self.superview];
    123     [menu setMenuVisible:YES animated:YES];
    124     self.menuVC = menu;
    125 }
    126 
    127 - (void)pressMenuClicked:(id)sender {
    128     NSString *selStr = NSStringFromSelector(_cmd);
    129     NSString *indexStr = [selStr substringFromIndex:kPressMenuSelectorPrefix.length];
    130     NSInteger index = indexStr.integerValue;
    131     if (index >=0 && index<self.menuTitles.count) {
    132         NSString *title = [self.menuTitles objectAtIndex:index];
    133         if (self.menuClickedBlock) {
    134             self.menuClickedBlock(index, title);
    135         }
    136     }
    137 }
    138 
    139 @end
  • 相关阅读:
    Jetpack MVVM 高频提问和解答
    Android-Jetpack架构组件-—-Navigation#
    Jetpack明星组件 —ViewModel #
    Android开发把 LiveData 用于事件传递那些坑#
    Android官方架构组件Lifecycle#
    Android架构组件JetPack之Lifecycle#
    Android架构组件JetPack之LiveData的工作原理#
    DataBinding从入门到通透#
    SpringBoot 分包方式多数据源
    SpringBoot与数据访问
  • 原文地址:https://www.cnblogs.com/goodboy-heyang/p/5742773.html
Copyright © 2020-2023  润新知