iOS小伙伴们有时候是不是会遇到开发时需要实现实时连接的画画功能呢? 类似于你画我猜!这个开发功能可以用于直播软件和在线教育软件里面

刚好我公司项目最近有这个功能,今天刚开发完,跟大家分享一下心得和方法,首先这个功能的实现其实就三个步骤

1:公司拥有自己的socket服务器,这是基础,实时链接数据

2:画画功能,画画功能其实就是把自己在屏幕视图上滑过的地方的点记录起来,根据CAShapeLayer和UIBezierPath进行描点画画

3:最后就是数据传输,需要我们在每次滑动的时候就把手指经历过的地方的点发送给对方,这就需要把点加载进数组里面,然后把数组转化为二进制数据发送给对方,具体要求看产品需求

最后直接上代码和效果图,有需要的小伙伴可以互相探讨哦

绘画代码:

//

//  WhiteBoardDrawView.h

//  NIM

//

//  Created by 赵发生 on 15/7/1.

//  Copyright (c) 2015年 Netease. All rights reserved.

//

#import <UIKit/UIKit.h>

@interface NTESWhiteboardDrawView : UIView

- (void)setLineColor:(UIColor *)color;

- (void)setLineWidth:(CGFloat)width;

- (void)addPoints:(NSMutableArray *)points isNewLine:(BOOL)newLine;

- (void)deleteLastLine;

- (void)clear;

@end

#import "NTESWhiteboardDrawView.h"

#import <QuartzCore/QuartzCore.h>

#import "NTESCADisplayLinkHolder.h"

@interface NTESWhiteboardDrawView()<NTESCADisplayLinkHolderDelegate>

@property(nonatomic, strong)NSMutableArray *myLines;

@property(nonatomic, assign)BOOL shouldDraw;

@property(nonatomic, strong)NTESCADisplayLinkHolder *displayLinkHolder;

@end

@implementation NTESWhiteboardDrawView

#pragma mark - public methods

- (id)initWithFrame:(CGRect)frame

{

if (self = [super initWithFrame:frame]) {

_myLines = [[NSMutableArray alloc] init];

CAShapeLayer *shapeLayer = (CAShapeLayer *)self.layer;

shapeLayer.strokeColor = [UIColor blackColor].CGColor;

shapeLayer.fillColor = [UIColor clearColor].CGColor;

shapeLayer.lineJoin = kCALineJoinRound;

shapeLayer.lineCap = kCALineCapRound;

shapeLayer.lineWidth = 2;

shapeLayer.masksToBounds = YES;

_displayLinkHolder = [[NTESCADisplayLinkHolder alloc] init];

[_displayLinkHolder setFrameInterval:3];

[_displayLinkHolder startCADisplayLinkWithDelegate:self];

}

return self;

}

-(void)dealloc

{

[_displayLinkHolder stop];

}

+ (Class)layerClass

{

return [CAShapeLayer class];

}

- (void)setLineColor:(UIColor *)color

{

CAShapeLayer *shapeLayer = (CAShapeLayer *)self.layer;

shapeLayer.strokeColor = color.CGColor;

}

- (void)setLineWidth:(CGFloat)width{

CAShapeLayer *shapeLayer = (CAShapeLayer *)self.layer;

shapeLayer.lineWidth = width;

}

- (void)addPoints:(NSMutableArray *)points isNewLine:(BOOL)newLine

{

__weak typeof(self) wself = self;

dispatch_async(dispatch_get_main_queue(), ^{

[wself addPoints:points toLines:[wself myLines] isNewLine:newLine];

});

}

- (void)deleteLastLine

{

__weak typeof(self) wself = self;

dispatch_async(dispatch_get_main_queue(), ^{

[wself deleteLastLine:[wself myLines]];

});

}

- (void)deleteAllLines

{

__weak typeof(self) wself = self;

dispatch_async(dispatch_get_main_queue(), ^{

[wself deleteAllLines:[wself myLines]];

});

}

- (void)clear

{

[self deleteAllLines];

}

#pragma mark - private methods

- (void)addPoints:(NSMutableArray *)points

toLines:(NSMutableArray *)lines

isNewLine:(BOOL)newLine

{

if (newLine) {

[lines addObject:points];

}

else if (lines.count == 0) {

[lines addObject:points];

}

else {

NSMutableArray *lastLine = [lines lastObject];

[lastLine addObjectsFromArray:points];

}

_shouldDraw = YES;

}

-(void)deleteLastLine:(NSMutableArray *)lines

{

[lines removeLastObject];

_shouldDraw = YES;

}

-(void)deleteAllLines:(NSMutableArray *)lines

{

[lines removeAllObjects];

_shouldDraw = YES;

}

- (void)onDisplayLinkFire:(NTESCADisplayLinkHolder *)holder

duration:(NSTimeInterval)duration

displayLink:(CADisplayLink *)displayLink

{

if (!_shouldDraw) {

return;

}

UIBezierPath *path = [[UIBezierPath alloc] init];

NSUInteger linesCount = _myLines.count;

for (NSUInteger i = 0 ; i < linesCount; i ++) {

NSArray *line = [_myLines objectAtIndex:i];

NSUInteger pointsCount = line.count;

for (NSUInteger j = 0 ; j < pointsCount; j ++) {

NSArray *point = [line objectAtIndex:j];

CGPoint p = CGPointMake([point[0] floatValue], [point[1] floatValue]);

if (j == 0) {

[path moveToPoint:p];

}

else {

[path addLineToPoint:p];

}

}

}

((CAShapeLayer *)self.layer).path = path.CGPath;

_shouldDraw = NO;

}

#import <Foundation/Foundation.h>

#import <UIKit/UIKit.h>

@class NTESCADisplayLinkHolder;

@protocol NTESCADisplayLinkHolderDelegate <NSObject>

- (void)onDisplayLinkFire:(NTESCADisplayLinkHolder *)holder

duration:(NSTimeInterval)duration

displayLink:(CADisplayLink *)displayLink;

@end

@interface NTESCADisplayLinkHolder : NSObject

@property (nonatomic,weak  ) id<NTESCADisplayLinkHolderDelegate> delegate;

@property (nonatomic,assign) NSInteger frameInterval;

- (void)startCADisplayLinkWithDelegate: (id<NTESCADisplayLinkHolderDelegate>)delegate;

- (void)stop;

@end

#import "NTESCADisplayLinkHolder.h"

@implementation NTESCADisplayLinkHolder

{

CADisplayLink *_displayLink;

}

- (instancetype)init

{

if (self = [super init]) {

_frameInterval = 1;

}

return self;

}

- (void)dealloc

{

[self stop];

_delegate = nil;

}

- (void)startCADisplayLinkWithDelegate:(id<NTESCADisplayLinkHolderDelegate>)delegate

{

_delegate = delegate;

[self stop];

_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)];

[_displayLink setFrameInterval:_frameInterval];

[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];

}

- (void)stop

{

if (_displayLink){

[_displayLink invalidate];

_displayLink = nil;

}

}

- (void)onDisplayLink: (CADisplayLink *) displayLink

{

if (_delegate && [_delegate respondsToSelector:@selector(onDisplayLinkFire:duration:displayLink:)]){

[_delegate onDisplayLinkFire:self

duration:displayLink.duration

displayLink:displayLink];

}

}

画画例子:

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

{

if (!self.isConnect) {

return;

}

if (!self.sessionId) {

return;

}

CGPoint p = [[touches anyObject] locationInView:self.callView.myDrawView];

[self onPointCollected:p type:WhiteBoardCmdTypePointEnd];

}

- (void)onPointCollected:(CGPoint)p type:(WhiteBoardCmdType)type

{

//send to peer

NSString *cmd = [NSString stringWithFormat:@"%zd:%.3f,%.3f;", type, p.x/self.callView.myDrawView.frame.size.width, p.y/self.callView.myDrawView.frame.size.height];

[self addCmd:cmd];

//local render

NSArray *point = [NSArray arrayWithObjects:@(p.x), @(p.y), nil];

[self.callView.myDrawView addPoints:[NSMutableArray arrayWithObjects:point, nil]

isNewLine:(type == WhiteBoardCmdTypePointStart)];

}

- (void)addCmd:(NSString *)aCmd

{

[_cmdsLock lock];

[_cmds appendString:aCmd];

[_cmdsLock unlock];

if ([_cmds length]) {

[self sendCmds];

}

}

hui

iOS开发 教学白板,互动版本,画画功能实现(类似于你画我猜功能)相关推荐

  1. iOS开发判断当前系统版本

    如果你需要针对不同的iOS版本加载不同的资源文件,你可以使用NSFoundationVersionNumber来确定当前的系统版本. 如下: if (floor(NSFoundationVersion ...

  2. iOS开发内购详细版本说明

    转自:http://www.jianshu.com/p/c252b2ccb078 一.最近公司很多的项目用到了内购,抽空整理下内购的详细内容吧. 1.先从内购的iTunesConnect里配置说起吧, ...

  3. iOS开发常用代码片段:总有你用得上的功能

    使用方法:查看文章目录,查找需要的功能. 代码片段目录 1.禁止手机睡眠 2. 隐藏某行cell 3.禁用button高亮 4..切换window的根控制器 5.去除数组中重复的对象 6.给一个vie ...

  4. iOS开发 - 若把上线版本下架,重新提交新的版本,通过审核后显示下架状态

    如题,当你把之前的版本下架后,重新提交了一个包到App Store,显示审核的各种状态,但是当通过审核后,你发现自己的app是下架状态,显示被开发人员下架.不要慌,那是因为你的app保持了之前的下架状 ...

  5. ios开发 热搜词demo_手机app如何开发

    泛娱科技​www.cpdzapp.com 手机app开发流程为: 1.首先,制作一款APP,必须要有相关的idea,也就是说,第一步是APP的idea形成. 2.通过那些idea来进行APP的主要功能 ...

  6. iOS开发Swift语言学习教程-欧阳坚-专题视频课程

    iOS开发Swift语言学习教程-16345人已学习 课程介绍         Swift这套视频是针对有Objective-C/iOS基础,想转成Swift开发的学习视频,视频中从Swift语法,结 ...

  7. iOS开发教程之OC语言-欧阳坚-专题视频课程

    iOS开发教程之OC语言-34296人已学习 课程介绍         Objective-C是扩充C的面向对象编程语言,iOS开发是用的Objective-C语言,本专题更系统的讲解Objectiv ...

  8. android 教学白板功能,Android集成互动白板

    Android集成互动白板 注意:SDK版本3.6.5之后开始支持白板功能. 使用白板功能首先需要登录环信,登录成功之后才可以去调用api创建白板房间,创建成功之后会直接加入房间,不需要再去调用加入的 ...

  9. iOS开发之窥探UICollectionViewController(四) --一款功能强大的自定义瀑布流

    在上一篇博客中<iOS开发之窥探UICollectionViewController(三) --使用UICollectionView自定义瀑布流>,自定义瀑布流的列数,Cell的外边距,C ...

最新文章

  1. 将新主要功能部署到生产时要考虑的5件事情
  2. Maven本地缓存清理小工具
  3. C++两个队列实现一个栈
  4. 用syslinux启动u盘
  5. PHP-cli 日志彩色玩法 echo \033[1;33m Hello World. \033[0m \n;
  6. 在Java中使用FileChannel和ByteBuffer对文件进行读写
  7. C++笔记-ClassA a和ClassA a()的区别与联系
  8. [20180826]四校联考
  9. C++并发与多线程(三)单例设计模式与共享数据分析、call_once、condition_variable使用
  10. 小软件项目开发的管理
  11. 关于RJ45 网线接线问题
  12. 微信小程序开发之十 —— 点击事件
  13. 算法创作|栈的应用——括号匹配问题解决方法
  14. RFQ 、IFB、RFP 、RFI的区别是什么
  15. 大数据三个特点的理解
  16. 嵌入式系统下的Microwindows实现
  17. linux 下卸载torch,在Ubuntu14.04安装torch7笔记
  18. 简约木板背景论文答辩PPT模板
  19. 查看Ubuntu系统是多少位
  20. amd cpu linux 驱动,AMD最新显卡Linux版催化剂驱动下载

热门文章

  1. Yupoo!(又拍网)架构 是目前国内最大的图片服务提供商,整个网站构建于大量的开源软件之上
  2. mysql建立司机表,MYSQL进阶,生手变司机
  3. 管理的最高境界不是完美
  4. Cadence Allegro向导创建DIP排针封装图文教程及视频演示
  5. 【德勤报告:区块链变革媒体业有五种可能】
  6. 小米导航栏中的下载app弹出层
  7. 要想学好C语言,你必须得懂的基础知识大全!本文将带你深度学习
  8. 锁相放大器在TDLAS技术的应用
  9. java基于微信小程序的公交线路查询系统 uniapp 小程序
  10. matlab 阵列天线增益方向图,阵列天线方向图及其MATLAB仿真