欢迎关注我的新浪微博: @立里童立里
通过Quartz 2D知识点制作了一个移动镜头的小Demo
实现的功能:
1. 移动镜头,如下图所示:
2. 调节镜头大小,如下图所示:
3. 调节速率,如图所示:(你觉得可能吗,展示不了,请看上图速度调节条)
4. 显示全图,如下图所示(由于图片超过了200K所以改了下尺寸):
5. 隐藏全图,回到镜头画面
6. 裁剪图片(只保留镜头笑下的图片,并保存到本地),如图所示:
7. 截取全图,如图所示:
8. 触摸停止或启动镜头,(无法展示,见谅)
源代码如下所示:
文件截图
FYViewController.m 文件代码
#define FYColor(r, g, b, a) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a/1.0]#define FYSaveTruPath [NSString stringWithFormat:@"/Users/tongfangyuan/Desktop/truncation/truncation_image/tru_image_%i.png",self.imageCounts]#import "FYViewController.h"#import "UIImage+FY.h"#import "FYView.h"@interface FYViewController ()// 底部工具栏@property (nonatomic, strong) UIView *BottomView;// 图片@property (nonatomic, strong) UIImageView *iconView;// 全图按钮@property (nonatomic, strong) UIButton *wholeBtn;@property (nonatomic, assign, getter = isShowImage) BOOL showImage;// 截图按钮@property (nonatomic, strong) UIButton *truncationBtn;// 保存截图模式@property (nonatomic, assign, getter = isTruncation) BOOL truncation;// FYView@property (strong, nonatomic) IBOutlet FYView *searchView;// 截图张数@property (nonatomic, assign) int imageCounts;@end@implementation FYViewController- (void)viewDidLoad{ [super viewDidLoad]; // 设置背景图片 _iconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"luffy"]]; self.view.backgroundColor = [UIColor blackColor]; // 1. 创建底部工具栏View _BottomView = [[UIView alloc]init]; _BottomView.backgroundColor = FYColor(201, 201, 201, 1); _BottomView.frame = CGRectMake(0, FYScreenH - FYDefaultH, FYScreenW, FYDefaultH); [self.view addSubview:_BottomView]; // 2. 创建全图按钮(打开或关闭全图按钮) _wholeBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, FYScreenW / 2, FYDefaultH)]; _wholeBtn.backgroundColor = [UIColor blueColor]; [_wholeBtn setTitle:@"显示全图" forState:UIControlStateNormal]; [_wholeBtn addTarget:self action:@selector(showWholeImage:) forControlEvents:UIControlEventTouchUpInside]; _showImage = YES; [self.BottomView addSubview:_wholeBtn]; // 3. 创建截图按钮 _truncationBtn = [[UIButton alloc] initWithFrame:CGRectMake(FYScreenW / 2, 0, FYScreenW / 2, FYDefaultH)]; [_truncationBtn setTitle:@"裁剪图片" forState:UIControlStateNormal]; [_truncationBtn addTarget:self action:@selector(truncationPicture) forControlEvents:UIControlEventTouchUpInside]; _truncation = NO; [self.BottomView addSubview:_truncationBtn]; }// 截取屏幕- (void)truncationPicture{ if (self.isTruncation) { // 截屏模式 // 截取全图 [self saveFullImage]; } else { // 裁剪模式 // 裁剪镜头下的图片 [self.searchView clipImage]; } }/** * 截取全图 */- (void)saveFullImage{ // 1. 截图 CGSize size = CGSizeMake(FYScreenW, FYScreenH - FYDefaultH); UIImage *newImage = [UIImage imageByTruncationInView:self.view WithSize:size]; // 2. 截屏计数器+1,保存图片 self.imageCounts++; NSData *data = UIImagePNGRepresentation(newImage); [data writeToFile:FYSaveTruPath atomically:YES];}// 显示或隐藏全图事件- (void)showWholeImage:(id)sender { if (self.isShowImage) { // 展开全图,停止镜头 // 1. 显示全图 [self showImage]; // 2. 更改两个按钮的主题 [_wholeBtn setTitle:@"隐藏全图" forState:UIControlStateNormal]; [_truncationBtn setTitle:@"截取全图" forState:UIControlStateNormal]; // 3. 更改模式 _showImage = NO; _truncation = YES; } else { // 关闭全图, 移动镜头 // 1. 隐藏全图 [self closeImage]; // 2. 更改两个按钮的主题 [_wholeBtn setTitle:@"显示全图" forState:UIControlStateNormal]; [_truncationBtn setTitle:@"裁剪图片" forState:UIControlStateNormal]; // 3. 更改模式 _showImage =YES; _truncation = NO; } }/** * 显示全图 */- (void)showImage{ // 1. 显示全图 _iconView.frame = CGRectMake(0, 0, 0, FYScreenH - FYDefaultH); [UIView animateWithDuration:1 animations:^{ _iconView.frame = CGRectMake(0, 0, FYScreenW, FYScreenH - FYDefaultH); }]; [self.view addSubview:_iconView]; _iconView.userInteractionEnabled = NO; // 2. 镜头停止滚动 [self.searchView stopScroll:nil];}/** * 隐藏全图 */- (void)closeImage{ // 1. 隐藏全图 _iconView.frame = CGRectMake(0, 0, FYScreenW, FYScreenH - FYDefaultH); [UIView animateWithDuration:1 animations:^{ _iconView.frame = CGRectMake(FYScreenW, 0, 0, FYScreenH - FYDefaultH); } completion:^(BOOL finished) { [self.searchView stopScroll:nil]; }]; _iconView.userInteractionEnabled = NO;}// 隐藏状态栏- (BOOL)prefersStatusBarHidden{ return YES;}@end
FYView.h 文件代码:
#import@interface FYView : UIView// 点击控制圆圈移动或停止- (void)stopScroll:(id)sender;// 裁剪图片- (void)clipImage;@end
FYView.m 文件代码:
#import "FYView.h"#import "UIImage+FY.h"#define FYImageRect CGRectMake(0, 0, FYScreenW, FYScreenH - FYDefaultH)#define FYSaveClipPath [NSString stringWithFormat:@"/Users/tongfangyuan/Desktop/truncation/clip_Image/clip_image_%i.png",self.imageCounts]@interface FYView ()// 保存圆圈坐标,直径, 移动距离@property (nonatomic, assign) CGFloat centerX;@property (nonatomic, assign) CGFloat centerY;@property (nonatomic, assign) CGFloat diameter;@property (nonatomic, assign) CGFloat moveDis;// 截图张数@property (nonatomic, assign) int imageCounts;// 保存累加值@property (nonatomic, assign) int countX;@property (nonatomic, assign) int countY;// 保存计时器状态@property (nonatomic, assign, getter = isTimerOn) BOOL timerOn;// 创建一个定时器@property (nonatomic, strong) NSTimer *timer;// 直径滑动条@property (weak, nonatomic) IBOutlet UISlider *mySlider;;// 速度滑动条@property (weak, nonatomic) IBOutlet UISlider *SpeedSlider;// 改变直径- (IBAction)changeMyRadius:(UISlider *)sender;// 改变速度- (IBAction)changeSpeed:(UISlider *)sender;@end@implementation FYView// moveDis(直径) get方法- (CGFloat)moveDis{ _moveDis = self.SpeedSlider.value; return _moveDis;}// diameter(移动距离) get 方法- (CGFloat)diameter{ _diameter = self.mySlider.value; [self setNeedsDisplay]; return _diameter;}- (void)drawRect:(CGRect)rect{ // 获取当前上下文 CGContextRef ref = UIGraphicsGetCurrentContext(); // 创建上下文栈 CGContextSaveGState(ref); CGContextAddEllipseInRect(ref, CGRectMake(self.centerX, self.centerY, self.diameter, self.diameter)); // 裁剪函数 CGContextClip(ref); // 渲染 CGContextStrokePath(ref); // 创建一个图片 UIImage *iconImage = [UIImage imageNamed:@"luffy"]; [iconImage drawInRect:FYImageRect]; // 恢复默认属性 CGContextRestoreGState(ref); // 再一次渲染 CGContextStrokePath(ref); [self addTimer]; [self addTimer];}/** * 裁剪 */- (void)clipImage{ // 创建图片 UIImage *image = [UIImage imageNamed:@"luffy"]; // 裁剪图片 CGRect rect = CGRectMake(self.centerX, self.centerY, self.diameter, self.diameter); UIImage *newImage = [UIImage imageWithClipImage:image inRect:rect]; // 存入数据 NSData *data = UIImagePNGRepresentation(newImage); self.imageCounts++; [data writeToFile:FYSaveClipPath atomically:YES]; }/** * 移动镜头 */- (void)searchImage{ // 判断X坐标位置 if (self.centerX <= 0) { // 到达最右边,圆圈X坐标减少 _countX = self.moveDis; } else if (self.centerX >= FYScreenW - self.diameter){ // 到达最左边,圆圈X坐标增加 _countX = - self.moveDis; } // 判断Y坐标位置 if (self.centerY <= 0) { // 到达最底部, 圆圈Y坐标减少 _countY = self.moveDis; } else if (self.centerY >= FYScreenH - self.diameter - FYDefaultH){ // 到达最顶部, 圆圈Y坐标增加 _countY = - self.moveDis; } _centerX += _countX; _centerY += _countY; [self setNeedsDisplay];}/* 触摸启动或停止计时器 */- (void)stopScroll:(id)sender { if (self.isTimerOn) { [self removeTimer]; } else { self.superview.backgroundColor = [UIColor whiteColor]; [self addTimer]; } }/** * 改变圆的直径 */- (IBAction)changeMyRadius:(UISlider *)sender { self.diameter = sender.value; }/** * 改变圆移动的速度 */- (IBAction)changeSpeed:(UISlider *)sender { self.moveDis = sender.value;}/** * 添加计时器 */- (void)addTimer{ self.timer = [NSTimer scheduledTimerWithTimeInterval:0.00025 target:self selector:@selector(searchImage) userInfo:nil repeats:NO]; self.timerOn = YES;}/** * 移除计时器 */- (void)removeTimer{ self.timerOn = NO; [self.timer invalidate]; self.timer = nil;}@end
UIImage+FY.h 文件代码如下:
#import#define FYScreenW 320#define FYScreenH 480#define FYDefaultH 44#define FYImageRect CGRectMake(0, 0, FYScreenW, FYScreenH - FYDefaultH)@interface UIImage (FY)/** * 裁剪图片 */+ (UIImage *)imageWithClipImage:(UIImage *)image inRect:(CGRect)rect;/** * 截取屏幕 */+ (UIImage *)imageByTruncationInView:(UIView *)view WithSize:(CGSize)size;@end
UIImage+FY.m 文件代码如下:
#import "UIImage+FY.h"@implementation UIImage (FY)/** * 裁剪图片 */+ (UIImage *)imageWithClipImage:(UIImage *)image inRect:(CGRect)rect{ // 创建上下文 CGSize size = CGSizeMake(FYScreenW, FYScreenH - FYDefaultH); UIGraphicsBeginImageContextWithOptions(size, NO, 0.0); // 获取当前上下文 CGContextRef ref = UIGraphicsGetCurrentContext(); CGContextAddEllipseInRect(ref, CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height)); // 执行裁剪 CGContextClip(ref); [image drawInRect:FYImageRect]; // 获取裁剪后的图片 UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); // 结束上下文 CGContextStrokePath(ref); return newImage;}/** * 截取屏幕 */+ (UIImage *)imageByTruncationInView:(UIView *)view WithSize:(CGSize)size{ // 1. 创建上下文 UIGraphicsBeginImageContextWithOptions(size, NO, 0.0); // 2. 调取方法截屏 [view.layer renderInContext:UIGraphicsGetCurrentContext()]; // 3. 获得截取的图片 UIImage *newIamge = UIGraphicsGetImageFromCurrentImageContext(); // 4. 渲染 UIGraphicsEndImageContext(); return newIamge;}@end
控件连线图:
提示:这个button是一个全透明的铺满屏幕的按钮(用来实现触摸停止或启动镜头功能)其 rect为
CGRectMake(0, 0, 320, 480); // 全透明,铺满屏幕的按钮
----------------------------------------
兴趣驱动iOS开发