手写输入—随手写
最近做的是关于教育的app,分老师版和学生版;学生版有做题功能,领导最近看到别的app里面有手写输入功能,保留原笔迹,也就是说写成什么样就是什么样,然后保存,上传。
思路1:
①上面排版的是collectionView
② 输入区域,根据UIView的touch事件,生成UIBezilPath。然后得到了path。layer.path = bezierPath.cgpath 。然后layer.stokeColor = xxxx
③ 最后layer加到item的某个view属性的layer上,调整下transform即可实现.aspectFit的效果
④ 当touch事件结束一段时间后(这个时间根据需求定),生成path走后面的渲染方法。
⑤但放到collectionView的item里,必须保证用一个transform让它们统一大小,并和item边缘相切。
思路2:
①上面排版的是textView
②输入区域,根据UIView的touch事件,生成UIBezilPath。然后得到了path。layer.path = bezierPath.cgpath 。然后layer.stokeColor = xxxx生成path走后面的渲染方法
③当touch事件结束一段时间后,对渲染部分截图(具体截多大的图,从什么位置截,demo里细讲),保存。
④利用textview的TextAttachment属性显示图片,bounds是设定图片大小,index是设定图片的位置
总结:
根绝需求分析,第一个思路不是太满足项目需求,因为领导要求是可以编辑,用collectionView就很麻烦,还要写光标,果断选择思路2
具体实现过程
先实现画板部分

//触摸点开始记录,一移动再记录,这样就记录无数多个点便成了线
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{if (self.beginEditingBlock) {self.beginEditingBlock();}[self.timer invalidate];self.timer = nil;self.seconds = 1;flag=NO;NSArray *array = [touches allObjects];for(UITouch *touch in array){Squiggle *squiggle = [[Squiggle alloc] init];[squiggle setLineWidth:lineWidth];[squiggle setStrokeColor:color];//self  指当前这次触摸事件[squiggle addPoint:[touch locationInView:self]];//因为每次触摸事件的 内存地址唯一,所以将其作为 squiggle的关键字key//将内存地址转换为对象NSValue *touchValue = [NSValue valueWithPointer:(__bridge const void * _Nullable)(touch)];NSString *key = [NSString stringWithFormat:@"%@",touchValue];[squigglesDic setValue:squiggle forKey:key];}
}-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{if (self.beginPaintBlock) {self.beginPaintBlock();}[self.timer invalidate];self.timer = nil;self.seconds = 1;self.timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(timeAnim) userInfo:nil repeats:YES];flag=YES;NSArray *array = [touches allObjects];for(UITouch *touch in array){//这里因为在前面 touchBegan中已经存好了相应的key,每一次触摸都有一关键字对应,这里只是在触摸的基础上移动画点NSValue *touchValue = [NSValue valueWithPointer:(__bridge const void * _Nullable)(touch)];Squiggle *squiggle = [squigglesDicvalueForKey:[NSString stringWithFormat:@"%@",touchValue]];CGPoint current = [touch locationInView:self];CGPoint previous = [touch previousLocationInView:self];//一直将当前点加进pointsArray中[squiggle addPoint:current];//更新后,得声明重新执行下 drawRect方法,系统不会自动执行CGPoint lower,higher;lower.x = (previous.x > current.x ? current.x : previous.x);lower.y = (previous.y > current.y ? current.y : previous.y);higher.x = (previous.x < current.x ? current.x : previous.x);higher.y = (previous.y < current.y ? current.y : previous.y);// redraw the screen in the required region[self setNeedsDisplayInRect:CGRectMake(lower.x-lineWidth,lower.y-lineWidth, higher.x - lower.x + lineWidth*2,higher.y - lower.y + lineWidth * 2)];}
}
保存图片
-(void)endFinish
{NSMutableArray *arr = _painterView.finishSquiggles;CGFloat minX = 0.0;CGFloat minY = 0.0;CGFloat maxX = 0.0;CGFloat maxY = 0.0;NSInteger index = 0;for(Squiggle *squiggle in arr){for (int i = 0; i<squiggle.pointsXArray.count; i++) {CGFloat x = [squiggle.pointsXArray[i] floatValue];CGFloat y = [squiggle.pointsYArray[i] floatValue];index++;if (index==1) {minX = x;maxX = x;minY = y;maxY = y;}else{if (x<minX) {minX = x;}if (x>maxX) {maxX = x;}if (y<minY) {minY = y;}if (y>maxY) {maxY = y;}}}}[pintArray addObject:[_painterView screenshot]];UIImage *image = [_painterView screenshotWithRect:CGRectMake(minX-2, minY-2, maxX-minX+4, maxY-minY+4)];CGFloat scale = image.size.width/image.size.height;UIImage *resultImage;NSInteger mMaxW = 42;NSInteger mMaxH = 40;if (image.size.height>mMaxH||image.size.width>mMaxW) {CGFloat imageW = 0;CGFloat imageH = 0;if (image.size.width>mMaxW) {if (image.size.height>mMaxH) {imageH = mMaxH;imageW = imageH*scale;CGSize size = CGSizeMake(imageW, imageH);//                    UIGraphicsBeginImageContext(size);UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);[image drawInRect:CGRectMake(0, 0, size.width, size.height)];resultImage= UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();}else{imageW = mMaxW;imageH = mMaxW/scale;CGSize size = CGSizeMake(imageW, imageH);//                    UIGraphicsBeginImageContext(size);UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);[image drawInRect:CGRectMake(0, 0, size.width, size.height)];resultImage= UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();}}else{if (image.size.height>mMaxH) {imageH = mMaxH;imageW = imageH*scale;CGSize size = CGSizeMake(imageW, imageH);//                    UIGraphicsBeginImageContext(size);UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);[image drawInRect:CGRectMake(0, 0, size.width, size.height)];resultImage= UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();}else{resultImage = image;}}}else{resultImage = image;}[pintArray addObject:resultImage];[_painterView resetView];NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithAttributedString:contentTextView.attributedText];NSTextAttachment *textAttachment = [[NSTextAttachment alloc] initWithData:nil ofType:nil] ;textAttachment.image = resultImage; //要添加的图片NSAttributedString *textAttachmentString = [NSAttributedString attributedStringWithAttachment:textAttachment] ;CGFloat location = contentTextView.selectedRange.location;[string insertAttributedString:textAttachmentString atIndex:(NSUInteger)location];//index为用户指定要插入图片的位置contentTextView.attributedText = string;contentTextView.selectedRange = NSMakeRange(location+1, 0);
}

编辑
-(void)clickMenuButton:(UIButton *)sender
{
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithAttributedString:contentTextView.attributedText];
CGFloat location = contentTextView.selectedRange.location;

if (sender.tag==0) {//空格[string insertAttributedString:[[NSAttributedString alloc]initWithString:@" "] atIndex:(NSInteger)location];contentTextView.attributedText = string;contentTextView.selectedRange = NSMakeRange(location+1, 0);
}else if (sender.tag==1){//换行[string insertAttributedString:[[NSAttributedString alloc]initWithString:@"\n"] atIndex:(NSInteger)location];contentTextView.attributedText = string;contentTextView.selectedRange = NSMakeRange(location+@"\n".length, 0);
}else{//删除if (location<1) {return;}NSAttributedString *mu1 = [string attributedSubstringFromRange:NSMakeRange(0, location-1)];NSAttributedString *mu2 = [string attributedSubstringFromRange:NSMakeRange(location, string.length-location)];if (mu2.length==0) {mu2 = [[NSAttributedString alloc]initWithString:@""];}NSMutableAttributedString *muAtt = [[NSMutableAttributedString alloc]initWithAttributedString:mu1];[muAtt appendAttributedString:mu2];contentTextView.attributedText = [[NSAttributedString alloc]initWithAttributedString:muAtt];if (location>0) {contentTextView.selectedRange = NSMakeRange(location-1, 0);}else{contentTextView.selectedRange = NSMakeRange(0, 0);}
}
[self beginPaint];

}

demo放在GitHub上了记得Star 、 Fork

手写输入---随手写相关推荐

  1. 开源纯C日志函数库iLOG3快速入门(五、与随手写的简单写日志函数的比较)

    2019独角兽企业重金招聘Python工程师标准>>> 前几天看到一个网友的评论:"这种一般自己实现个用用就行了 没必要整第三方库". 的确,很多个人或公司都自己 ...

  2. 一场游戏一场梦------------------大学随手写(11年05月-------11年06月04)

    一场游戏一场梦------------------大学随手写(11年05月-------11年06月04)2011-05-19 13:45 (分类:乱七八糟) 片段一:生活就如同QQ够级 2011年0 ...

  3. python出题器_随手写的python出题小玩意

    我给我小孩写了个100内加减法的,应同事要求,顺手整了个99乘法的 功能很简单,生成一个练习99乘法的excel文件,直接打出来给小孩做就行 效果如图: 源码附上 [Python] 纯文本查看 复制代 ...

  4. 一些自身工作经历和感悟,随手写的,很乱

    最近在反思自己的状态是不是适合编程 感觉毕业好几年了都没有什么成就 底层底层不算精通,上层上层也不会 毕业这几年就是混日子过来了 码农这个行业是吃硬本事的行业,如果没有金刚钻,就 早点转行,可是其他行 ...

  5. PTA 7-4(随手写的,不适合网站提交)

    做法:将两个数组合并为一个数组,每当要输出不为重复的值时与之前的数组元素比较,查重,有相同便跳过,没有就输出. 下面展示一些 内联代码片. 代码: #include <stdio.h> i ...

  6. 【随手写】偷懒新技能:Applescript

    爬虫来爬我:Mac 按键精灵 AppleScript 需求:N台服务器,每台服务器上有M个日志要看... 通过跳板机到达服务器,于是有个我的机器->跳板机->服务器的连接,我的机器到跳板机 ...

  7. PB编程通俗快速入手(自己2002年教别人PB时随手写的,很多年了,放上来送给新手们)

    PB编程通俗快速入手 逍遥的心 第一章   一般使用   1.  程序的开始,application的open事件. 退出程序例程:halt为退出函数 int SureQuit SureQuit = ...

  8. 第三方电容笔支持随手写吗?ipad2023手写笔推荐

    Ipad设备已经被广泛地应用到日常生活中,一些人甚至用平板电脑取代了纸质的笔记本.所以,苹果的原装电容笔引发了不少热度,所以很多人都有同样的疑问,一支近千块钱的电容笔,有什么特别之处呢?我觉得如果是专 ...

  9. 随手写系列——写一个凯撒密码转换页面

    文章目录 先展示效果 H5编写 C3编写 JS编写--方法一:过程版 JS编写--方法二:对象版 代码获取 先展示效果 (因为主要是实现功能,所以CSS写的很粗糙) H5编写 基础结构如下: 先构成最 ...

  10. 利用Swift语言特性,随手写个伪随机数生成器

    // // main.swift // Ultimate // // Created by Mewlan Musajan on 2/13/22. // // Apple Inc. "The ...

最新文章

  1. vector can通信源码_CAN总线IMU在自动驾驶安全控制中的应用
  2. 鳗鱼劈断后下半身还能运动,机器人:拿来吧你丨Science子刊封面
  3. php丢包率测试,linux 网络延时、丢包与传输带宽关系测试
  4. Visual Studio 打开程序提示仅我的代码怎么办
  5. matlab 去掉矩阵中某些元素,怎么修改矩阵中的某些元素 或者简单点说保留矩阵中的元素...
  6. php解析markdown前端渲染,Vuejs使用 vue-markdown 来渲染评论方法
  7. 数据结构实验4-栈与字符串
  8. eclipse 每次打开 提示 subversive svn connectors
  9. prd文档 范例_PRD文档范例,产品经理值得收藏的写作手册
  10. 快解析:管家婆辉煌II TOP+异地访问解决方案
  11. 计算机桌面黑屏有鼠标,win7系统启动黑屏只有显示鼠标指针怎么办(图文)
  12. AcWing 327 玉米田 题解 (动态规划—DP—状态压缩DP)
  13. 力扣707设计链表(单链表,JavaScript)
  14. Java操作桌面应用 --- Desktop 类
  15. 定期清理gitlab的备份监控gitlab备份
  16. 【项目实战】正确辨析蓝绿部署、金丝雀发布(灰度发布)、滚动发布、A/B测试
  17. Pyghon学习记录
  18. 手机搜狐概念版 html,概念版来了 手机搜狐带你全新体验移动式阅读
  19. Python安装库的几种方法(使用Pycharm几种方法)
  20. 【Grub2】常见命令

热门文章

  1. 深入理解java虚拟机(4)---类加载机制
  2. java生成eml_用Java创建一个.eml(email)文件
  3. WinEdit如何修改字体大小
  4. 从小白到Python大神只需要100天
  5. The seventh Word-Day
  6. 极狐GitLab CI/CD 测试题
  7. 狐妖小红娘手游服务器维护,狐妖小红娘手游:游戏界面详细解析,狐妖小粉丝不要错过哦...
  8. 年轻时放纵享乐,不要指望年老时一念向善
  9. ESP8266/ESP-01固件下载方法
  10. 用原始代码制作简易的百度页面