搜索
您的当前位置:首页正文

UI进阶第七天

来源:二三娱乐

1.带有边框的圆形图片裁剪(实用)

一般我们会抽取一个分类,等用到的时候就直接调用.其实自己写一个也挺方便的.主要的思路是用到位图上下文的原理(一般需要用到图片的地方,如果你想要动它的话,一般都要开).然后就是设置路径(绘制圆形),然后就是裁剪.把图片绘制到上下文中.生成一张新的图片,然后直接用就ok乐.多余就不说了,直接上代码.

//0.设置边框宽度

//1.加载图片

//2.开启一个位图上下文(W = imageW + 2 * border H = imageH + 2 * border)

CGSizesize =CGSizeMake(image.size.width+2* borderWH, image.size.height+2* borderWH);

UIGraphicsBeginImageContextWithOptions(size,NO,0);

//3.绘制一个圆形的形状.

UIBezierPath*path = [UIBezierPathbezierPathWithOvalInRect:CGRectMake(0,0, size.width, size.height)];

[colorset];

[pathfill];

//4.设置一个小圆,并设置成裁剪区域

path = [UIBezierPathbezierPathWithOvalInRect:CGRectMake(borderWH, borderWH, image.size.width, image.size.height)];

//把路径设置成裁剪区域

[pathaddClip];

//5.把图片绘制到上下文当中.

[imagedrawAtPoint:CGPointMake(borderWH, borderWH)];

//6.从上下文当中生成一张图片

UIImage*newImage =UIGraphicsGetImageFromCurrentImageContext();

//7.关闭上下文.

UIGraphicsEndImageContext();

2.全屏截图(这个比较简单)

思路:当我们手指点击的时候,那么它就开启一张位图上下文,然后直接把VIew里面的内容用渲染的方式绘制到上下文中(不能直接绘制).然后就是生成一张新的图片,关闭上下文等.当然生成的图片怎么传输?这里只说了保存到桌面,用到的是二进流来进行传输

//1.开启位图上下文.

UIGraphicsBeginImageContextWithOptions(self.view.bounds.size,NO,0);

//2.把控制器View的内容绘制到上下文当中.

//layer是不能够直接绘制的.要用渲染的方法才能够让它绘制到上下文当中.

CGContextRefctx =UIGraphicsGetCurrentContext();

[self.view.layerrenderInContext:ctx];

//3.生成一张图片

UIImage*newImage =UIGraphicsGetImageFromCurrentImageContext();

//4.关闭上下文

UIGraphicsEndImageContext();

//把生成的图片写入到桌面.都是以二进流进行传输.

//怎么样把图片转成二进制流.

//image:要把哪一张图片转成二进制流

//compressionQuality:压缩质量.

NSData*data =UIImagePNGRepresentation(newImage);

[datawriteToFile:@"/Users/xmg/Desktop/newImage.png"atomically:YES];

3.图片截屏

其实跟全屏截图差不多,只是这里多了一个手势,而且我们要根据手势三个方法(开始,移动,结束)来进行相对应的操作.当然阴影部分制造是懒加载形式加载.当然也是开始的时候,我们就要获取开始的点,当移动的时候我们计算整个截取范围的尺寸(遮盖的frame),当结束的时候我们会生成一张新的图片(开启位图,裁剪等等).当然还要记得移除遮盖

@property(nonatomic,assign)CGPointstartP;

/**遮盖*/

@property(nonatomic,weak)UIView*coverView;

-(UIView*)coverView{

if(_coverView==nil) {

UIView*coverView = [[UIViewalloc]init];

coverView.backgroundColor= [UIColorblackColor];

coverView.alpha=0.7;

_coverView= coverView;

[self.viewaddSubview:coverView];

}

return_coverView;

}

- (IBAction)pan:(UIPanGestureRecognizer*)pan {

CGPointcurP = [panlocationInView:pan.view];

if(pan.state==UIGestureRecognizerStateBegan) {

//获取当前手指的点.

self.startP= curP;

}elseif(pan.state==UIGestureRecognizerStateChanged){

CGFloatoffsetX = curP.x-self.startP.x;

CGFloatoffsetY = curP.y-self.startP.y;

CGRectrect =CGRectMake(self.startP.x,self.startP.y, offsetX, offsetY);

self.coverView.frame= rect;

}elseif(pan.state==UIGestureRecognizerStateEnded){

//开启一个跟UIimageView相同大小的上下文.

UIGraphicsBeginImageContextWithOptions(self.imageV.bounds.size,NO,0);

//self.coverView.frame

UIBezierPath*path = [UIBezierPathbezierPathWithRect:self.coverView.frame];

//把路径设置成裁剪区域

[pathaddClip];

//把UIImageView的内容渲染到上下文当中.

//获取上下文

CGContextRefctx =UIGraphicsGetCurrentContext();

[self.imageV.layerrenderInContext:ctx];

//[self.imageV.image drawAtPoint:CGPointZero];

//从上下文当中生成一张图片

UIImage*newImage =UIGraphicsGetImageFromCurrentImageContext();

//关闭上下文

UIGraphicsEndImageContext();

self.imageV.image= newImage;

//移除遮盖

[self.coverViewremoveFromSuperview];

}

}

4.图片擦擦擦(类似妄撮)

咳咳,回到正题上,不要被上面的图片所迷惑,其实它很简单,它只是2张图片重叠(一张是穿衣服,另一张是没穿衣服).放在最上面的当然是穿衣服的.然后就是他的方法很简单,只是用到一个手势和用到上下文里德擦除方法(当然也就是我们用到上下文的方法).当然手势的话也是拖动手势,而且我们要获取其中的擦除区域,也就是指定一个尺寸范围.直接上代码.

- (void)pan:(UIPanGestureRecognizer*)pan{

//确定的擦除的宽高

CGFloatrectWH =30;

//获取当前手指所在的点

CGPointcurP = [panlocationInView:self.imageV];

//确定的擦除的区域(-0.5是为了居中,想想你的擦除的原点)

CGFloatx = curP.x- rectWH *0.5;

CGFloaty = curP.y- rectWH *0.5;

CGRectrect =CGRectMake(x, y, rectWH, rectWH);

//最终生成一张图片

//开启一个位图上下文

UIGraphicsBeginImageContextWithOptions(self.imageV.bounds.size,NO,0);

//获取上下文

CGContextRefctx =UIGraphicsGetCurrentContext();

//把UIImageView的内容渲染到上下文当中.

[self.imageV.layerrenderInContext:ctx];

//擦除指定的区域.

CGContextClearRect(ctx, rect);

//生成一张新的图片

UIImage*newImage =UIGraphicsGetImageFromCurrentImageContext();

//关闭上下文

UIGraphicsEndImageContext();

}

5.手势解锁(重要,这里会教你如何添加手势路径,而且获得其中的密码)

1.这里用到的素材只有3个,一个是背景图片,其他2个分别圆形按钮(未选中状态)和圆形按钮(选中状态)

2.当然这里我们也是创建2个类,一个是全屏View(设置背景图片).一个是中间的大图片(设置按钮).

3.先说一下全屏View,也没多少难度.你只需把它绘制上去就ok了.当然也是从零点开始绘制.

-(void)drawRect:(CGRect)rect{

//1.加载图片

UIImage*image = [UIImageimageNamed:@"Home_refresh_bg"];

[imagedrawInRect:rect];

}

4.中间大图片(这个慢慢来)

首先,我们先设置好按钮的位置,先把按钮摆上去,当然这里设置它们各自的frame也是有一定的技巧的,先计算好它们的间距,再去计算好它们的行和列.然后根据各自所处于的行和列计算它们的x和y.

4.1.1我们先弄好借口,哈哈.如果是独立开发的话,这里可以忽略.(setup是初始化方法).

-(void)awakeFromNib{

//初始化

[selfsetUp];

}

-(instancetype)initWithFrame:(CGRect)frame{

if(self= [superinitWithFrame:frame]) {

//初始化

[selfsetUp];

}

returnself;

}

4.1.2接下来,我们当然是创建按钮了,里面我们需要用到按钮里面的一个属性tag,我们可以用它给按钮来排号,方便我们在后面根据它的标识来给它设置frame.当然我们还要取消按钮接收事件,不然的话后面做不了拖线什么的.所以我们就让事件处理交给父控件来处理.

//初始化

- (void)setUp{

for(inti =0; i <9; i++) {

//创建按钮

UIButton*btn = [UIButtonbuttonWithType:UIButtonTypeCustom];

btn.tag= i;

//让按钮取消事件,让事件传给它的父控件.

btn.userInteractionEnabled=NO;

//设置正常状态图片

[btnsetImage:[UIImageimageNamed:@"gesture_node_normal"]forState:UIControlStateNormal];

//设置选中状态图片

[btnsetImage:[UIImageimageNamed:@"gesture_node_highlighted"]forState:UIControlStateSelected];

//添加按钮

[selfaddSubview:btn];

}

}

4.1.3然后就是设置它的frame.一般我们设置它的frame都是layoutsubviews里设置,当然所有按钮都是分开设置,由于按钮是存于View里面,我们只需根据子控件的数量和取出来里面的子控件,这里就多亏前面我们设置的tag.找到相对应的按钮.然后就是设置它们的frame.我们也是设置9次.我们用到也是间距的方法来计算,(简单的数学计算)直接看代码.

-(void)layoutSubviews{

[superlayoutSubviews];

CGFloatx =0;

CGFloaty =0;

CGFloatbtnWh =74;

intcloumn =3;

CGFloatmargin = (self.bounds.size.width- cloumn * btnWh) / (cloumn +1);

intcurCloumn =0;

intcurRow =0;

//取出所有的子控件,设置尺寸大小.

for(inti  =0; i

//取出每一个按钮

UIButton*btn =self.subviews[i];

//当前所在的列

curCloumn = i % cloumn;

//当前所在的行

curRow  = i / cloumn;

x = margin + curCloumn * (btnWh + margin);

y = curRow * (btnWh + margin);

//设置按钮尺寸

btn.frame=CGRectMake(x, y, btnWh, btnWh);

}

}

4.2.1手势方法,首先来到这里,我们要自定义2个方法(封装),一个是获取当前手指所在的点方法,一个是判断现在你手指的点在不在按钮身上,如果在的话,就返回按钮,如果不是的话就返回空值.

//根据一个touches集合获取当前手指所在的点

- (CGPoint)getCurrentPoint:(NSSet*)touches{

//获取当前手指所在的点

UITouch*touch =  [touchesanyObject];

return[touchlocationInView:self];

}

//根据传入的点,判断传入的点在不在按钮身上

- (UIButton*)btnRectContainsPoint:(CGPoint)point{

for(UIButton*btninself.subviews) {

if(CGRectContainsPoint(btn.frame, point)) {

returnbtn;

}

}

returnnil;

}

4.2.2然后我们就开始设置手势的方法,首先我们先定义一个属性来保存选中的按钮.然后后就是手势的运用,分别也就是开始,移动,结束.但我们手指开始点击的时候,那么就获取当前手指的点,然后就是判断当前手指的点在不在按钮身上,如果在的话,那么就设置按钮的selected属性.而移动的话,也是获取当前手指的点,然后就是判断在不在按钮身上,在的话就点亮按钮.当然这里要用到重绘方法(后面会说的).而结束的时候,就是我们取消全部选中状态,这里我们就用到之前定义的数组,直接把它遍历出来,然后取消它选中状态,最后也要把那个数组清空一下,方便后面使用然后再重绘.这里我们可以看到密码哦,也就是我们绘制手势的密码,用到按钮的tag属性,用string来给它拼接就可以了.我们直接打印出来就可以了.

//开始点击时,按钮成为选中状态

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event{

//获取当前手指所在的点

//UITouch *touch =  [touches anyObject];

//CGPoint curP = [touch locationInView:self];

CGPointcurP = [selfgetCurrentPoint:touches];

//判断当前点在不在按钮身上.

UIButton*btn = [selfbtnRectContainsPoint:curP];

if(btn && btn.selected==NO) {

//当前点在这个按钮上面.

//让按钮成为选中状态

btn.selected=YES;

//保存选中的按钮

[self.selectBtnArrayaddObject:btn];

}

}

//移动过程当中,如果发现当前的点在按钮身上,让按钮成为选中状态.

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent*)event{

CGPointcurP = [selfgetCurrentPoint:touches];

self.curP= curP;

//判断当前点在不在按钮身上.

UIButton*btn = [selfbtnRectContainsPoint:curP];

if(btn && btn.selected==NO) {

//当前点在这个按钮上面.

//让按钮成为选中状态

btn.selected=YES;

//保存选中的按钮

[self.selectBtnArrayaddObject:btn];

}

//重绘

[selfsetNeedsDisplay];

}

//当手指松开时,所有的选中按钮取消选中状态.

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

//1.取消所有选中的按钮

NSMutableString*str = [NSMutableStringstring];

for(UIButton*btninself.selectBtnArray) {

btn.selected=NO;

[strappendFormat:@"%ld",btn.tag];

}

NSLog(@"%@",str);

//2.把所有的路径给清空.

[self.selectBtnArrayremoveAllObjects];

[selfsetNeedsDisplay];

}

4.2.3绘制方法,我们可以做一个小判断,如果数组里有值的话,我们就绘制路径,连线什么的,但没有值的直接恢复原样.而数组有值得话,我们用一个循环根据数组的数量;而且里面做一个判断,如果i=0,也就是第一个,那么它就作为起点,其他都是直接连到它们各自的中心点.

-(void)drawRect:(CGRect)rect{

if(self.selectBtnArray.count) {

//创建路径.添加线

UIBezierPath*path = [UIBezierPathbezierPath];

//判断选中的按钮是不是第一个按钮.如果是第一个按钮,就把第一个按钮的中心点,设置成路径的起点.

for(inti =0; i

//取出选中的每一个按钮

UIButton*btn =self.selectBtnArray[i];

//判断选中的按钮是不是第一个按钮

if(i ==0) {

//就把第一个按钮的中心点,设置成路径的起点.

[pathmoveToPoint:btn.center];

}else{

//直接添加一根线到按钮的中心点

[pathaddLineToPoint:btn.center];

}

}

//添加一根线到当前手指所在的点.

[pathaddLineToPoint:self.curP];

//设置线宽度

[pathsetLineWidth:10];

//设置y颜色

[[UIColorredColor]set];

//设置连接样式

[pathsetLineJoinStyle:kCGLineJoinRound];

[pathstroke];

}

5.画板功能

1.先说一下界面的搭建吧,首先最上面,我们可以用到toolBar,这个是帮我们自动布局的,我们只需添加item上去就可以,最后的item我们需要添加一个弹簧属性(flexible Space).而下面的需要我们手动自动布局了,需要有点麻烦,但你懂得,青年,慢慢来.这里就不多说了.

2.然后就是拖线,首先我们就是拖线拖到控制器里,然后再调用中间空白View类里面的方法就可以了.(先说基本的属性设置)

//清屏

- (IBAction)clear:(id)sender {

[self.drawViewclear];

}

//撤销

- (IBAction)undo:(id)sender {

[self.drawViewundo];

}

//橡皮擦

- (IBAction)erase:(id)sender {

[self.drawViewerase];

}

//设置线的宽度

- (IBAction)setLineWidth:(UISlider*)sender {

[self.drawViewsetLineWidth:sender.value];

}

//设置线的颜色

- (IBAction)setLineColor:(UIButton*)sender {

[self.drawViewsetLineColor:sender.backgroundColor];

}

3.然后我们在我们自定义的类里面实现它们的方法.

3.1首先我们先定义需要保存的属性(当前绘制的路径,保存所有绘制路径的数组,宽度,颜色)

/**当前绘制的路径*/

@property(nonatomic,strong)UIBezierPath*path;

/**保存的是所有绘制的路径*/

@property(nonatomic,strong)NSMutableArray*pathArray;

@property(nonatomic,assign)CGFloatwidth;

@property(nonatomic,strong)UIColor*color;

3.2当然又用到数组,我们会毫不犹豫用到的是懒加载,然后就是添加它们的移动手势,而且会调用手势的方法.

-(NSMutableArray*)pathArray{

if(_pathArray==nil) {

_pathArray= [NSMutableArrayarray];

}

return_pathArray;

}

-(void)awakeFromNib{

//添加移动手势

UIPanGestureRecognizer*pan = [[UIPanGestureRecognizeralloc]initWithTarget:selfaction:@selector(pan:)];

[selfaddGestureRecognizer:pan];

self.width=1;

self.color= [UIColorblackColor];

}

3.3移动手势的方法;首先我们是获取当前手指的点,然后根据手指移动的状态,先是设置它的起点,而且我们也要一开始设置线条的宽度和颜色.由于线条并没有颜色这个属性,所以需要我们自定义类,然后再给它添加颜色的属性.同时我们要把当前的路径添加数组里,而且保存现在的路径,方便后面连线.然后在移动过程中连接到当前手指所指的位置.最后就是要重绘一下.

- (void)pan:(UIPanGestureRecognizer*)pan{

//获取当前手指的点

CGPointcurP = [panlocationInView:self];

//手指开始的点是路径的起点

if(pan.state==UIGestureRecognizerStateBegan){

MyBezierPath*path = [[MyBezierPathalloc]init];

//设置线的宽度

[pathsetLineWidth:self.width];

//设置颜色.当发现系统的类,瞒足不了要求时,想到自定义类.

path.color=self.color;

//把当前路径给保存起来

[self.pathArrayaddObject:path];

self.path= path;

[pathmoveToPoint:curP];

}elseif(pan.state==UIGestureRecognizerStateChanged){

//添加一根线到当前手指的点

[self.pathaddLineToPoint:curP];

//重绘

[selfsetNeedsDisplay];

}

}

-(void)drawRect:(CGRect)rect{

//[self.path stroke];

//取出所有的路径,绘制出来

for(MyBezierPath*pathinself.pathArray) {

[path.colorset];

[pathstroke];

}

}

3.4然后就是功能实现:

//清屏

- (void)clear{

//清空所有的路径

[self.pathArrayremoveAllObjects];

//重绘

[selfsetNeedsDisplay];

}

//撤销

- (void)undo{

//清空最后一条路径

[self.pathArrayremoveLastObject];

[selfsetNeedsDisplay];

}

//设置线的宽度

- (void)setLineWidth:(CGFloat)lineWidth{

self.width= lineWidth;

}

//设置线的颜色

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

self.color= color;

}

//橡皮擦

- (void)erase{

[selfsetLineColor:[UIColorwhiteColor]];

}

4.保存照片(也是截全屏功能一样,获取上下文,然后就是渲染.生成一张新的图片.最后就是把生成的图片写入到系统相册里面.)

//把生成的图片写入到系统相册

//注意:保存完毕执行的这方法必须得要是

//- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo

UIImageWriteToSavedPhotosAlbum(newImage,self,@selector(image:didFinishSavingWithError:contextInfo:),nil);

5.照片功能(当我们点击照片按钮的时候,系统会跳到系统相册里面,而我们从系统相册里选取照片).

这里也是用到代理和设置它的来源(遵守协议),当然这是系统的,我们只需创建一个UIImagePickerController,然后就是把modal出来.当然我们选择了一张照片后,系统会调用一个方法.

协议*

//照片(从系统相册当中选择一张照片)

- (IBAction)photo:(id)sender {

UIImagePickerController*pickVC = [[UIImagePickerControlleralloc]init];

//设置来源

pickVC.sourceType=UIImagePickerControllerSourceTypeSavedPhotosAlbum;

//UIImagePickerController如果实现代理方法,需要手动去关掉它.

pickVC.delegate=self;

//modal

[selfpresentViewController:pickVCanimated:YEScompletion:nil];

}

//当选择一张照片时调用

-(void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{

NSLog(@"%@",info);

UIImage*image = info[UIImagePickerControllerOriginalImage];

NSData*data =UIImagePNGRepresentation(image);

[datawriteToFile:@"/Users/xmg/Desktop/newImage.jpg"atomically:YES];

[selfdismissViewControllerAnimated:YEScompletion:nil];

}

6.涂鸦功能

咳咳,这个还没做,主要现在比较忙,可能这个是借口吧.我之前对着代码敲了一遍,但还是没实现出来.然后后面的任务比较繁琐.所以先搁置一边.等之后用得时候或者有空余时间就重新敲一遍,试试.请谅解.

Top