IOS实现的简单画板功能
发布时间 - 2026-01-11 00:28:33 点击率:次效果图
设计要求
1、画笔能设置大小、颜色
2、有清屏、撤销、橡皮擦、导入照片功能
3、能将绘好的画面保存到相册
实现思路
1、画笔的实现,我们可以通过监听用户的 平移手势 中创建 UIBezierPath 来实现线条的绘制
2、撤销功能,我们先来看下撤销功能,我们会想到用一个数组队列将用户的每一次的笔画都加入到数组中,然后撤销的时候只需要将最后添加进去的笔画pop掉,重新绘制就可以了
3、清屏功能就简单了,只需要将上面说到的那个数组清空重新绘制下就可以了
4、导入照片功能,可以用系统的 UIImagePickerController 选取照片得到UIImage,然后再将 UIImage 绘制到屏幕中就可以了
5、保存到相册功能,可以使用 UIGraphicsGetImageFromCurrentImageContext 获取当前的图片上下文,得到屏幕画面的 UIImage ,然后通过 UIImageWriteToSavedPhotosAlbum 写入到相册
具体代码实现
1、先画个界面
2、因为我们绘制线条会用到 UIBezierPath ,并且要能可设置颜色,但是UIBezierPath是没有设置颜色的属性,所以我们这里需要简单扩展一下,创建一个继承于 UIBezierPath 的子类 DrawPath
// // DrawPath.h // 画板 // // Created by xgao on 16/4/13. // Copyright © 2016年 xgao. All rights reserved. // #import <UIKit/UIKit.h> @interface DrawPath : UIBezierPath // 画笔颜色 @property(nonatomic,retain)UIColor* pathColor; @end
这个子类只需要扩展一个属性,就是 pathColor 用来保存画笔的颜色
// // DrawPath.m // 画板 // // Created by xgao on 16/4/13. // Copyright © 2016年 xgao. All rights reserved. // #import "DrawPath.h" @implementation DrawPath @end
DrawPath.m 里面不需要做其它功能
3、接到来我们对画板功能的实现封装一下,创建一个继承于UIView的 DrawView子类
// // DrawView.h // 画板 // // Created by xgao on 16/4/13. // Copyright © 2016年 xgao. All rights reserved. // #import <UIKit/UIKit.h> @interface DrawView : UIView // 画线的宽度 @property(nonatomic,assign)CGFloat lineWidth; // 线条颜色 @property(nonatomic,retain)UIColor* pathColor; // 加载背景图片 @property(nonatomic,strong)UIImage* image; // 清屏 - (void)clear; // 撤销 - (void)undo; // 橡皮擦 - (void)eraser; // 保存 - (void)save; @end
//
// DrawView.m
// 画板
//
// Created by xgao on 16/4/13.
// Copyright © 2016年 xgao. All rights reserved.
//
#import "DrawView.h"
#import "DrawPath.h"
@interface DrawView()
@property(nonatomic,strong) DrawPath* path;
// 线的数组
@property(nonatomic,strong) NSMutableArray* paths;
@end
@implementation DrawView
- (void)awakeFromNib{
[self setUp];
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setUp];
}
return self;
}
// 重绘UI
- (void)drawRect:(CGRect)rect {
for (DrawPath* path in self.paths) {
if ([path isKindOfClass:[UIImage class]]) {
// 画图片
UIImage* image = (UIImage*)path;
[image drawInRect:rect];
}else{
// 画线
// 设置画笔颜色
[path.pathColor set];
// 绘制
[path stroke];
}
}
}
// 懒加载属性
- (NSMutableArray*)paths{
if (_paths == nil) {
_paths = [NSMutableArray array];
}
return _paths;
}
// 重写image属性
- (void)setImage:(UIImage *)image{
_image = image;
// 将图片加入到线条数组中
[self.paths addObject:image];
[self setNeedsDisplay];
}
#pragma mark - Init
// 初始化
- (void)setUp{
// 添加平移手势
UIPanGestureRecognizer* panGes = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panGes:)];
[self addGestureRecognizer:panGes];
// 默认值
self.lineWidth = 1;
self.pathColor = [UIColor blackColor];
}
#pragma mark - Event
// 平移事件
- (void)panGes:(UIPanGestureRecognizer*)ges{
// 获取当前点
CGPoint curPoint = [ges locationInView:self];
if (ges.state == UIGestureRecognizerStateBegan) { // 开始移动
// 创建贝塞尔曲线
_path = [[DrawPath alloc]init];
// 设置线条宽度
_path.lineWidth = _lineWidth;
// 线条默认颜色
_path.pathColor = _pathColor;
// 设置起始点
[_path moveToPoint:curPoint];
[self.paths addObject:_path];
}
// 连线
[_path addLineToPoint:curPoint];
// 重绘
[self setNeedsDisplay];
}
#pragma mark - Method
// 清屏
- (void)clear{
[self.paths removeAllObjects];
[self setNeedsDisplay];
}
// 撤销
- (void)undo{
[self.paths removeLastObject];
[self setNeedsDisplay];
}
// 橡皮擦
- (void)eraser{
self.pathColor = [UIColor whiteColor];
[self setNeedsDisplay];
}
// 保存
- (void)save{
// ---- 截图操作
// 开启上下文
UIGraphicsBeginImageContextWithOptions(self.frame.size, NO, 0);
// 获取当前上下文
CGContextRef context = UIGraphicsGetCurrentContext();
// 渲染图层到上下文
[self.layer renderInContext:context];
// 从上下文中获取图片
UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
// 关闭上下文
UIGraphicsEndImageContext();
// ---- 保存图片
UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}
// 图片保存方法,必需写这个方法体,不能会保存不了图片
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo{
// 提示
UIAlertView* alert = [[UIAlertView alloc]initWithTitle:@"保存成功" message:nil delegate:nil cancelButtonTitle:@"ok" otherButtonTitles:nil, nil];
[alert show];
}
@end
4、接下来就是如果使用这个画板类了,直接上代码吧
//
// ViewController.m
// 画板
//
// Created by xgao on 16/4/13.
// Copyright © 2016年 xgao. All rights reserved.
//
#import "ViewController.h"
#import "DrawView.h"
@interface ViewController ()<UIImagePickerControllerDelegate,UINavigationControllerDelegate>
// 画板
@property (weak, nonatomic) IBOutlet DrawView *drawView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
#pragma mark - Event
// 线条宽度变化
- (IBAction)lineWidthChange:(UISlider*)sender {
_drawView.lineWidth = sender.value;
}
// 线条颜色变化
- (IBAction)pathColorChange:(UIButton*)sender {
_drawView.pathColor = sender.backgroundColor;
}
// 清屏
- (IBAction)clearAction:(id)sender {
[_drawView clear];
}
// 撤销
- (IBAction)undoAction:(id)sender {
[_drawView undo];
}
// 橡皮擦
- (IBAction)eraserAction:(id)sender {
[_drawView eraser];
}
// 照片
- (IBAction)pickerPhotoAction:(id)sender {
// 照片选择控制器
UIImagePickerController* picVC = [[UIImagePickerController alloc]init];
// 照片源
picVC.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
// 委托
picVC.delegate = self;
[self presentViewController:picVC animated:YES completion:nil];
}
// 保存
- (IBAction)saveAction:(id)sender {
[_drawView save];
}
#pragma mark - UIImagePickerControllerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(nullable NSDictionary<NSString *,id> *)editingInfo{
// 设置图片
_drawView.image = image;
// 关闭窗口
[self dismissViewControllerAnimated:YES completion:nil];
}
@end
到这里就差不多了,这个小功能实现的基本思路与具体代码我都已经放上来了,大家如果还有哪里不清楚的可以留言喔~~
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!
# ios
# 画板
# iOS简单画板开发案例分享
# 分享一个iOS下实现基本绘画板功能的简单方法
# 子类
# 只需
# 要将
# 创建一个
# 就可以
# 组中
# 加载
# 画线
# 来了
# 我都
# 可以用
# 说到
# 我们可以
# 不清楚
# 要做
# 重写
# 只需要
# 可以使用
# 不需
# 能将
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Linux网络带宽限制_tc配置实践解析【教程】
网站制作怎么样才能赚钱,用自己的电脑做服务器架设网站有什么利弊,能赚钱吗?
今日头条AI怎样推荐抢票工具_今日头条AI抢票工具推荐算法与筛选【技巧】
Laravel队列任务超时怎么办_Laravel Queue Timeout设置详解
弹幕视频网站制作教程下载,弹幕视频网站是什么意思?
湖南网站制作公司,湖南上善若水科技有限公司做什么的?
如何在搬瓦工VPS快速搭建网站?
Laravel如何实现邮件验证激活账户_Laravel内置MustVerifyEmail接口配置【步骤】
网站制作免费,什么网站能看正片电影?
Laravel怎么进行浏览器测试_Laravel Dusk自动化浏览器测试入门
JS中对数组元素进行增删改移的方法总结
Win11怎样安装网易有道词典_Win11安装词典教程【步骤】
如何在阿里云香港服务器快速搭建网站?
如何在橙子建站上传落地页?操作指南详解
Laravel怎么实现验证码(Captcha)功能
Laravel如何创建自定义Artisan命令?(代码示例)
Laravel怎么生成URL_Laravel路由命名与URL生成函数详解
标准网站视频模板制作软件,现在有哪个网站的视频编辑素材最齐全的,背景音乐、音效等?
Laravel怎么实现观察者模式Observer_Laravel模型事件监听与解耦开发【指南】
合肥制作网站的公司有哪些,合肥聚美网络科技有限公司介绍?
如何在宝塔面板创建新站点?
韩国代理服务器如何选?解析IP设置技巧与跨境访问优化指南
Laravel中的Facade(门面)到底是什么原理
Laravel路由Route怎么设置_Laravel基础路由定义与参数传递规则【详解】
为什么要用作用域操作符_php中访问类常量与静态属性的优势【解答】
用v-html解决Vue.js渲染中html标签不被解析的问题
,怎么在广州志愿者网站注册?
如何在阿里云服务器自主搭建网站?
如何选择可靠的免备案建站服务器?
如何确保FTP站点访问权限与数据传输安全?
如何快速上传自定义模板至建站之星?
Laravel N+1查询问题如何解决_Eloquent预加载(Eager Loading)优化数据库查询
C++时间戳转换成日期时间的步骤和示例代码
如何在云指建站中生成FTP站点?
Win11怎么开启自动HDR画质_Windows11显示设置HDR选项
如何用wdcp快速搭建高效网站?
Laravel如何获取当前用户信息_Laravel Auth门面获取用户ID
Laravel怎么实现微信登录_Laravel Socialite第三方登录集成
如何使用 jQuery 正确渲染 Instagram 风格的标签列表
EditPlus 正则表达式 实战(3)
jquery插件bootstrapValidator表单验证详解
绝密ChatGPT指令:手把手教你生成HR无法拒绝的求职信
网站建设整体流程解析,建站其实很容易!
Laravel Admin后台管理框架推荐_Laravel快速开发后台工具
如何用西部建站助手快速创建专业网站?
Laravel如何配置和使用缓存?(Redis代码示例)
阿里云网站搭建费用解析:服务器价格与建站成本优化指南
HTML5空格在Angular项目里怎么处理_Angular中空格的渲染问题【详解】
Laravel的契約(Contracts)是什么_深入理解Laravel Contracts与依赖倒置
Laravel如何实现API资源集合?(Resource Collection教程)

