iOS 封装一个带复制功能的UILabel

https://www.jianshu.com/p/c47ea8835c9d

https://www.cnblogs.com/gongyuhonglou/p/10823727.html

 

一、在iOS中下面三个控件,自身就有复制-粘贴的功能:
1、UITextView
2、UITextField
3、UIWebView
在iOS8 之后, 我们发现UILabel不在为我们提供长按弹出复制等操作了, 我们来继承UILabel自己写一个带复制功能的UILabel

二、废话少说,直接撸代码

//
//  CopyLabel.m
//  Block学习二次学习01
//
//  Created by XianCheng Wang on 2018/8/4.
//  Copyright © 2018年 XianCheng Wang. All rights reserved.
//

#import "CopyLabel.h"
@implementation CopyLabel
- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        [self pressAction];
    }
    return self;
}
// 初始化设置
- (void)pressAction {
    self.userInteractionEnabled = YES;
    UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressAction:)];
    longPress.minimumPressDuration = 0.25;
    [self addGestureRecognizer:longPress];
}

// 使label能够成为响应事件
- (BOOL)canBecomeFirstResponder {
    
    return YES;
}

// 自定义方法时才显示对就选项菜单,即屏蔽系统选项菜单
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    if (action == @selector(customCopy:)){
        
        return YES;
    }
    return NO;
}

// 父类视图
-(void)addSuperView{
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(removeCopyLabel)];
    tap.numberOfTapsRequired = 1;
    [self.superview addGestureRecognizer:tap];
    self.alpha = kAlpha;
}
-(void)removeCopyLabel{
    self.alpha = 1.0;
}

- (void)customCopy:(id)sender {
    [self removeCopyLabel];
    UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
    pasteboard.string = self.text;
}
- (void)longPressAction:(UIGestureRecognizer *)recognizer {
    // 父类视图
    [self addSuperView];
    if (recognizer.state == UIGestureRecognizerStateBegan) {
        [self becomeFirstResponder];
        UIMenuItem *copyItem = [[UIMenuItem alloc] initWithTitle:@"拷贝" action:@selector(customCopy:)];
        UIMenuController *menuController = [UIMenuController sharedMenuController];
        menuController.menuItems = [NSArray arrayWithObjects:copyItem, nil];
        [menuController setTargetRect:self.frame inView:self.superview];
        [menuController setMenuVisible:YES animated:YES];
    }
}
@end

三、废话少说,直接看效果

- (void)viewDidLoad {
   [super viewDidLoad];
   self.navigationItem.title = @"CopyLabel";
   CopyLabel *copy = [[CopyLabel alloc] initWithFrame:CGRectMake(50,44, [UIScreen mainScreen].bounds.size.width - 100,35)];
   copy.text = @"清明时节雨纷纷,路上行人欲断魂。";
   copy.textColor = [UIColor yellowColor];
   copy.backgroundColor = [UIColor darkGrayColor];
   copy.textAlignment = NSTextAlignmentCenter;
   copy.font = [UIFont boldSystemFontOfSize:14];
   [self.view addSubview:copy];
}
 
copyLabel.gif

四、github地址:https://github.com/gitwangxiancheng/CopyLabel.git

五、是不是很心动,赶快试试吧❤️



作者:小猪也浪漫
链接:https://www.jianshu.com/p/c47ea8835c9d
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
 
 
 

UIPasteboard使用

复制代码
基本使用:

- (void)copyClick {    
    UIPasteboard *pab = [UIPasteboard generalPasteboard];
    pab.string = yqmLabel.text;
    if (pab == nil) {
        [MBProgressHUD showError:@"复制失败"];
    } else {
        [MBProgressHUD showSuccess:@"已复制"];
    }
}
复制代码

 

复制代码
可以赋值的属性:

@property(nullable,nonatomic,copy) NSString *string __TVOS_PROHIBITED __WATCHOS_PROHIBITED;
@property(nullable,nonatomic,copy) NSArray<NSString *> *strings __TVOS_PROHIBITED __WATCHOS_PROHIBITED;

@property(nullable,nonatomic,copy) NSURL *URL __TVOS_PROHIBITED __WATCHOS_PROHIBITED;
@property(nullable,nonatomic,copy) NSArray<NSURL *> *URLs __TVOS_PROHIBITED __WATCHOS_PROHIBITED;

@property(nullable,nonatomic,copy) UIImage *image __TVOS_PROHIBITED __WATCHOS_PROHIBITED;
@property(nullable,nonatomic,copy) NSArray<UIImage *> *images __TVOS_PROHIBITED __WATCHOS_PROHIBITED;

@property(nullable,nonatomic,copy) UIColor *color __TVOS_PROHIBITED __WATCHOS_PROHIBITED;
@property(nullable,nonatomic,copy) NSArray<UIColor *> *colors __TVOS_PROHIBITED __WATCHOS_PROHIBITED;
复制代码

 

 

复制代码
扩展:

在iOS中下面三个控件,自身就有复制-粘贴的功能:
1、UITextView
2、UITextField
3、UIWebView
UIKit framework提供了几个类和协议方便我们在自己的应用程序中实现剪贴板的功能。
1、UIPasteboard:我们可以向其中写入数据,也可以读取数据
2、UIMenuController:显示一个快捷菜单,用来展示复制、剪贴、粘贴等选择的项。
3、UIResponder中的 canPerformAction:withSender:用于控制哪些命令显示在快捷菜单中。
4、当快捷菜单上的命令点击的时候,UIResponderStandardEditActions将会被调用。
下面这些项能被放置到剪贴板中
1、UIPasteboardTypeListString — 字符串数组, 包含kUTTypeUTF8PlainText
2、UIPasteboardTypeListURL — URL数组,包含kUTTypeURL
3、UIPasteboardTypeListImage — 图形数组, 包含kUTTypePNG 和kUTTypeJPEG
4、UIPasteboardTypeListColor — 颜色数组
剪贴板的类型分为两种:
系统级:使用UIPasteboardNameGeneral和UIPasteboardNameFind,系统级应用程序关闭,或者卸载的数据不会丢失。
应用程序级:通过设置,可以让数据在应用程序关闭之后仍然保存在剪贴板中,但是应用程序卸载之后数据就会失去。我们可用通过pasteboardWithName:create:来创建。
例子如下:
有时候我们可能需要复制UILabel上的文本,或者UIImageView的图片,而UILabel和UIImageView默认是不响应Touch事件的,也无法复制,那么我们就需要自己实现一个可复制的UILabel。新添加一个类继承自UILabel:
@interface UICopyLabel : UILabel
@end
#import "UICopyLabel.h"
@implementation UICopyLabel
@end
为了能接收到事件(能成为第一响应者),我们需要覆盖一个方法:
-(BOOL)canBecomeFirstResponder
{
    return YES;
}
还需要针对复制的操作覆盖两个方法:
// 可以响应的方法
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
    return (action == @selector(copy:));
}
//针对于响应方法的实现
-(void)copy:(id)sender
{
    UIPasteboard *pboard = [UIPasteboard generalPasteboard];
    pboard.string = self.text;
}
有了以上三个方法,我们就能处理copy了,当然,在能接收到事件的情况下:
//UILabel默认是不接收事件的,我们需要自己添加touch事件
-(void)attachTapHandler
{
    self.userInteractionEnabled = YES; //用户交互的总开关
    UITapGestureRecognizer *touch = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
    touch.numberOfTapsRequired = 2;
    [self addGestureRecognizer:touch];
    [touch release];
}
//绑定事件
- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        [self attachTapHandler];
    }
    return self;
}
//同上
-(void)awakeFromNib
{
    [super awakeFromNib];
    [self attachTapHandler];
}
我们已经可以接收到事件了!由于我在上方将tap数设为2,所以需要双击才能捕获,接下来,我们需要处理这个tap,以便让菜单栏弹出来:
-(void)handleTap:(UIGestureRecognizer*) recognizer
{
    [self becomeFirstResponder];
    UIMenuItem *copyLink = [[[UIMenuItemalloc] initWithTitle:@"复制"
                                                      action:@selector(copy:)]autorelease];
    [[UIMenuControllersharedMenuController] setMenuItems:[NSArrayarrayWithObjects:copyLink, nil]];
    [[UIMenuControllersharedMenuController] setTargetRect:self.frameinView:self.superview];
    [[UIMenuControllersharedMenuController] setMenuVisible:YESanimated: YES];
}
这样一来,一个可复制的UILabel就诞生了!它能处理接收点击、弹出菜单栏、处理copy,这是一个很普通的可复制控件。
接下来我们做一个可复制的UIImageView,创建一个新的viewController,放两个imageView,默认显示不同的图:
然后把上面的代码直接拷过来,改三个地方:
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
    return (action == @selector(copy:) || action == @selector(paste:));
}
-(void)copy:(id)sender
{
    UIPasteboard *pboard = [UIPasteboard generalPasteboard];
    pboard.image = self.image;
}
-(void)paste:(id)sender
{
    UIPasteboard *pboard = [UIPasteboard generalPasteboard];
    self.image = pboard.image;
}
UIPasteboard有系统级别和应用级别两种类型,所以不仅可以在应用程序内通信,还能在应用程序间通信,比如我复制一个url,然后打开safari,粘贴到地址栏去,而我们可以在应用程序间通信、共享数据。
在PasteBoardWrite里面点“写入”后把textField中的文本写入粘贴板,然后切换到PasteBoardRead的时候显示出来。如果我们的粘贴板只想给“自己人”用的话,就不能用系统的通用粘贴板,需要我们自己创建一个:
//需要提供一个唯一的名字,一般使用倒写的域名:com.mycompany.myapp.pboard
//后面的参数表示,如果不存在,是否创建一个
UIPasteboard *pb = [UIPasteboard pasteboardWithName:@"testBoard" create:YES];
使用这个粘贴板,我们可以把文本存进去,然后在另一个app里面读出来,一些常用的类型已经被设置为属性了:
除此之外,如果是能够转换成plist的数据类型(NSString, NSArray, NSDictionary, NSDate, NSNumber 和 NSURL),我们可以调用setValue:forPasteboardType:方法去存储数据,其他类型只能调用setData:forPasteboardType:方法(plist数据类型也可使用),类似于这样:
//存储数据
NSDictionary *dict = [NSDictionary dictionaryWithObject:textField.text forKey:@"content"];
NSData *dictData = [NSKeyedArchiver archivedDataWithRootObject:dict];
[pb setData:dictData forPasteboardType:@"myType"];
//获取就类似于这样:
UIPasteboard *pb = [UIPasteboard pasteboardWithName:@"testBoard" create:YES];
NSDictionary *dict = [NSKeyedUnarchiver unarchiveObjectWithData:[pb dataForPasteboardType:@"myType"]];
caption.text = [dict objectForKey:@"content"];
上面提到了一个PasteboardType,这是一个统一类型标识符(Uniform Type Identifier UTI),能帮助app获取自己能处理的数据。比如你只能处理文本的粘贴,那给你一个UIImage显然是无用的。你可以使用公用的UTI,也可以使用任意字符,苹果建议使用倒写的域名加上类型名:com.myCompany.myApp.myType

 

posted @ 2021-06-01 14:20  itlover2013  阅读(208)  评论(0编辑  收藏  举报