在 UIScrollView 内的 UIView 上绘制草图
Sketch On UIView Within UIScrollView
我在 UIView
上绘制草图时遇到问题,该 UIView
是 UIScrollView
中的子视图。
当您尝试在 UIView
上缩放或滚动后绘制草图时会出现此问题。似乎我的草图代码(如下所示)没有考虑 UIScrollView
中 UIView
的缩放或比例,因为线条模糊并且没有显示在它们应该出现的位置。请让我知道是否可以对我的代码执行某些操作或提供其他解决方案。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(@"Draw touchesBegan");
mouseSwipedPSVC = NO;
UITouch *touch = [touches anyObject];
lastPointPSVC = [touch locationInView:sheetDrawView];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
mouseSwipedPSVC = YES;
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:sheetDrawView];
UIGraphicsBeginImageContext(sheetDrawView.frame.size);
[drawImageView.image drawInRect:CGRectMake(0, 0, sheetDrawView.frame.size.width, sheetDrawView.frame.size.height)];
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPointPSVC.x, lastPointPSVC.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brushPSVC);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), redPSVC, greenPSVC, bluePSVC, 1.0);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeNormal);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImageView.image = UIGraphicsGetImageFromCurrentImageContext();
drawImageView.image = UIGraphicsGetImageFromCurrentImageContext();
[drawImageView setAlpha:opacityPSVC];
UIGraphicsEndImageContext();
lastPointPSVC = currentPoint;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if(!mouseSwipedPSVC) {
NSLog(@"Check 1");
UIGraphicsBeginImageContext(sheetDrawView.frame.size);
[drawImageView.image drawInRect:CGRectMake(0, 0, sheetDrawView.frame.size.width, sheetDrawView.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brushPSVC);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), redPSVC, greenPSVC, bluePSVC, opacityPSVC);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPointPSVC.x, lastPointPSVC.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), lastPointPSVC.x, lastPointPSVC.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
CGContextFlush(UIGraphicsGetCurrentContext());
drawImageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
}
我应该补充一点,如果 UIView
没有被缩放或滚动,这段代码工作正常。 sheetDrawView 也是 UIScrollView
.
的子视图
创建了一个小型绘图应用程序(仅在 iPhone 7 Plus 10.1 模拟器上测试)。
首先我创建了 PalleteView。此视图允许您使用 select 颜色进行绘图。
PaletteView.h:
//
// PaletteView.h
// DrawingIO
//
// Created by Brandon T on 2016-11-27.
// Copyright © 2016 XIO. All rights reserved.
//
#import <UIKit/UIKit.h>
@class PaletteView;
@protocol PaletteViewDelegate <NSObject>
- (void)didSelectColour:(PaletteView * _Nonnull)paletteView colour:(UIColor * _Nonnull)colour;
@end
@interface PaletteView : UIView
@property (nullable, nonatomic, weak) id<PaletteViewDelegate> delegate;
@end
PaletteView.m:
//
// PaletteView.m
// DrawingIO
//
// Created by Brandon T on 2016-11-27.
// Copyright © 2016 XIO. All rights reserved.
//
#import "PaletteView.h"
#define kPaletteViewCell @"kPaletteViewCell"
@interface PaletteView() <UICollectionViewDelegate, UICollectionViewDataSource>
@property (nonnull, nonatomic, strong) UICollectionView *collectionView;
@property (nonnull, nonatomic, strong) NSArray<NSArray<UIColor *> *> *colours;
@end
@implementation PaletteView
- (instancetype)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
[self initControls];
[self setTheme];
[self registerClasses];
[self doLayout];
}
return self;
}
- (void)initControls {
CGFloat idealWidth = (self.frame.size.width / 7.0) - (2.5 * 5.0);
CGFloat idealHeight = (self.frame.size.height / 2.0) - (2.5 * 5.0);
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.minimumLineSpacing = 5.0;
layout.minimumInteritemSpacing = 5.0;
layout.sectionInset = UIEdgeInsetsMake(5.0, 5.0, 5.0, 5.0);
layout.scrollDirection = UICollectionViewScrollDirectionVertical;
layout.itemSize = CGSizeMake(idealWidth, idealHeight);
self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
self.colours = @[@[[UIColor blackColor],
[UIColor darkGrayColor],
[UIColor lightGrayColor],
[UIColor whiteColor],
[UIColor grayColor],
[UIColor redColor],
[UIColor greenColor]],
@[[UIColor blueColor],
[UIColor cyanColor],
[UIColor yellowColor],
[UIColor magentaColor],
[UIColor orangeColor],
[UIColor purpleColor],
[UIColor brownColor]]];
}
- (void)setTheme {
[self.collectionView setDelegate:self];
[self.collectionView setDataSource:self];
[self.collectionView setAlwaysBounceHorizontal:YES];
[self.collectionView setDelaysContentTouches:NO];
[self.collectionView setShowsHorizontalScrollIndicator:NO];
[self.collectionView setShowsVerticalScrollIndicator:NO];
[self.collectionView setBackgroundColor:[UIColor colorWithRed:240.0/255.0 green:229.0/255.0 blue:227.0/255.0 alpha:1.0]];
}
- (void)registerClasses {
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:kPaletteViewCell];
}
- (void)doLayout {
[self addSubview:self.collectionView];
[self.collectionView.leftAnchor constraintEqualToAnchor:self.leftAnchor].active = YES;
[self.collectionView.rightAnchor constraintEqualToAnchor:self.rightAnchor].active = YES;
[self.collectionView.topAnchor constraintEqualToAnchor:self.topAnchor].active = YES;
[self.collectionView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor].active = YES;
[self.collectionView setTranslatesAutoresizingMaskIntoConstraints:NO];
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return self.colours.count; //Two rows of colours.
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [self.colours[section] count]; //7 colours per row in this example.
}
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kPaletteViewCell forIndexPath:indexPath];
NSArray *section = [self.colours objectAtIndex:indexPath.section];
[cell.contentView setBackgroundColor:section[indexPath.row]];
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
if ([self.delegate respondsToSelector:@selector(didSelectColour:colour:)]) {
NSArray *section = [self.colours objectAtIndex:indexPath.section];
[self.delegate didSelectColour:self colour:section[indexPath.row]];
}
}
@end
这是一个简单的 collectionView,每个单元格都有颜色。我硬编码了单元格的大小。
接下来我创建了 DrawingView。这是用户将使用他们的手指绘制的视图。此视图一次只处理一根手指绘图。我首先从 GameDesign 获得了绘制位图的想法。在游戏中,您希望首先将纹理绘制到内存中。然后当你完成所有的绘图时,你将该帧传输到屏幕上。这会显着提高速度,因为您不会在每次操作后更新屏幕。相反,您在所有绘图结束时更新屏幕(当用户抬起手指时)。
为此,我执行了以下操作:
DrawingView.h:
//
// DrawingView.h
// DrawingIO
//
// Created by Brandon T on 2016-11-27.
// Copyright © 2016 XIO. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface DrawingView : UIView
- (void)setPaletteColour:(UIColor * _Nonnull)colour;
@end
DrawingView.m:
//
// DrawingView.m
// DrawingIO
//
// Created by Brandon T on 2016-11-27.
// Copyright © 2016 XIO. All rights reserved.
//
#import "DrawingView.h"
@interface DrawingView()
@property (nonnull, nonatomic, strong) UIBezierPath *path;
@property (nonnull, nonatomic, strong) UIImage *bufferedImage;
@property (nonnull, nonatomic, strong) UIColor *strokeColour;
@end
@implementation DrawingView
- (instancetype)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
[self setPath:[UIBezierPath bezierPath]];
[self.path setLineWidth:1.0];
[self setStrokeColour:[UIColor blackColor]];
[self setMultipleTouchEnabled:NO];
}
return self;
}
- (void)setPaletteColour:(UIColor *)colour {
self.strokeColour = colour;
}
- (void)renderToBufferedImage {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0);
[self.strokeColour setStroke];
[self.bufferedImage drawAtPoint:CGPointZero];
[self.path stroke];
self.bufferedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
[self.path moveToPoint:[touch locationInView:self]];
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
[self.path addLineToPoint:[touch locationInView:self]];
[self setNeedsDisplay];
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
[self.path addLineToPoint:[touch locationInView:self]];
[self renderToBufferedImage];
[self setNeedsDisplay];
[self.path removeAllPoints];
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
[self.path addLineToPoint:[touch locationInView:self]];
[self renderToBufferedImage];
[self setNeedsDisplay];
[self.path removeAllPoints];
}
- (void)drawRect:(CGRect)rect {
[self.strokeColour setStroke];
[self.bufferedImage drawInRect:rect blendMode:kCGBlendModeNormal alpha:1.0];
[self.path stroke];
}
@end
我选择使用 drawInRect:blendMode:alpha
是因为这样您可以使用不同的混合选项和 alpha 级别进行绘制。对于这个例子,我正在绘制完全不透明的 32 位 BGRA 位图。
接下来我创建了带有嵌入式 ScrollView 的控制器。这允许用户 ZOOM-IN/Scale 视图并在 zoomed-in/scaled 视图上绘制。当您缩小时,您会注意到绘图是准确的(没有扭曲或缩放)。
ViewController.h:
//
// ViewController.h
// DrawingIO
//
// Created by Brandon T on 2016-11-27.
// Copyright © 2016 XIO. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
ViewController.m:
//
// ViewController.m
// DrawingIO
//
// Created by Brandon T on 2016-11-27.
// Copyright © 2016 XIO. All rights reserved.
//
#import "ViewController.h"
#import "PaletteView.h"
#import "DrawingView.h"
@interface ViewController () <UIScrollViewDelegate, PaletteViewDelegate>
@property (nonnull, nonatomic, strong) PaletteView *paletteView;
@property (nonnull, nonatomic, strong) DrawingView *drawingView;
@property (nonnull, nonatomic, strong) UIScrollView *scrollView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initControls];
[self setTheme];
[self doLayout];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)initControls {
self.paletteView = [[PaletteView alloc] initWithFrame:CGRectMake(0.0, 0.0, self.view.frame.size.width, 100.0)];
self.drawingView = [[DrawingView alloc] initWithFrame:self.view.frame];
self.scrollView = [[UIScrollView alloc] init];
}
- (void)setTheme {
[self.paletteView setDelegate:self];
[self.paletteView setBackgroundColor:[UIColor whiteColor]];
[self.drawingView setBackgroundColor:[UIColor whiteColor]];
[self.scrollView setDelegate:self];
[self.scrollView setScrollEnabled:NO];
[self.scrollView setMinimumZoomScale:1.0];
[self.scrollView setMaximumZoomScale:2.0];
}
- (void)doLayout {
[self.view addSubview:self.paletteView];
[self.view addSubview:self.scrollView];
[self.paletteView.leftAnchor constraintEqualToAnchor:self.view.leftAnchor].active = YES;
[self.paletteView.rightAnchor constraintEqualToAnchor:self.view.rightAnchor].active = YES;
[self.paletteView.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES;
[self.scrollView.leftAnchor constraintEqualToAnchor:self.view.leftAnchor].active = YES;
[self.scrollView.rightAnchor constraintEqualToAnchor:self.view.rightAnchor].active = YES;
[self.scrollView.topAnchor constraintEqualToAnchor:self.paletteView.bottomAnchor].active = YES;
[self.scrollView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES;
[self.scrollView setTranslatesAutoresizingMaskIntoConstraints:NO];
//Layout drawingView
[self.scrollView addSubview:self.drawingView];
}
- (nullable UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return self.drawingView;
}
- (void)didSelectColour:(PaletteView * _Nonnull)paletteView colour:(UIColor * _Nonnull)colour {
[self.drawingView setPaletteColour:colour];
}
@end
我在 UIView
上绘制草图时遇到问题,该 UIView
是 UIScrollView
中的子视图。
当您尝试在 UIView
上缩放或滚动后绘制草图时会出现此问题。似乎我的草图代码(如下所示)没有考虑 UIScrollView
中 UIView
的缩放或比例,因为线条模糊并且没有显示在它们应该出现的位置。请让我知道是否可以对我的代码执行某些操作或提供其他解决方案。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(@"Draw touchesBegan");
mouseSwipedPSVC = NO;
UITouch *touch = [touches anyObject];
lastPointPSVC = [touch locationInView:sheetDrawView];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
mouseSwipedPSVC = YES;
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:sheetDrawView];
UIGraphicsBeginImageContext(sheetDrawView.frame.size);
[drawImageView.image drawInRect:CGRectMake(0, 0, sheetDrawView.frame.size.width, sheetDrawView.frame.size.height)];
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPointPSVC.x, lastPointPSVC.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brushPSVC);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), redPSVC, greenPSVC, bluePSVC, 1.0);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeNormal);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImageView.image = UIGraphicsGetImageFromCurrentImageContext();
drawImageView.image = UIGraphicsGetImageFromCurrentImageContext();
[drawImageView setAlpha:opacityPSVC];
UIGraphicsEndImageContext();
lastPointPSVC = currentPoint;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if(!mouseSwipedPSVC) {
NSLog(@"Check 1");
UIGraphicsBeginImageContext(sheetDrawView.frame.size);
[drawImageView.image drawInRect:CGRectMake(0, 0, sheetDrawView.frame.size.width, sheetDrawView.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brushPSVC);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), redPSVC, greenPSVC, bluePSVC, opacityPSVC);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPointPSVC.x, lastPointPSVC.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), lastPointPSVC.x, lastPointPSVC.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
CGContextFlush(UIGraphicsGetCurrentContext());
drawImageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
}
我应该补充一点,如果 UIView
没有被缩放或滚动,这段代码工作正常。 sheetDrawView 也是 UIScrollView
.
创建了一个小型绘图应用程序(仅在 iPhone 7 Plus 10.1 模拟器上测试)。
首先我创建了 PalleteView。此视图允许您使用 select 颜色进行绘图。
PaletteView.h:
//
// PaletteView.h
// DrawingIO
//
// Created by Brandon T on 2016-11-27.
// Copyright © 2016 XIO. All rights reserved.
//
#import <UIKit/UIKit.h>
@class PaletteView;
@protocol PaletteViewDelegate <NSObject>
- (void)didSelectColour:(PaletteView * _Nonnull)paletteView colour:(UIColor * _Nonnull)colour;
@end
@interface PaletteView : UIView
@property (nullable, nonatomic, weak) id<PaletteViewDelegate> delegate;
@end
PaletteView.m:
//
// PaletteView.m
// DrawingIO
//
// Created by Brandon T on 2016-11-27.
// Copyright © 2016 XIO. All rights reserved.
//
#import "PaletteView.h"
#define kPaletteViewCell @"kPaletteViewCell"
@interface PaletteView() <UICollectionViewDelegate, UICollectionViewDataSource>
@property (nonnull, nonatomic, strong) UICollectionView *collectionView;
@property (nonnull, nonatomic, strong) NSArray<NSArray<UIColor *> *> *colours;
@end
@implementation PaletteView
- (instancetype)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
[self initControls];
[self setTheme];
[self registerClasses];
[self doLayout];
}
return self;
}
- (void)initControls {
CGFloat idealWidth = (self.frame.size.width / 7.0) - (2.5 * 5.0);
CGFloat idealHeight = (self.frame.size.height / 2.0) - (2.5 * 5.0);
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.minimumLineSpacing = 5.0;
layout.minimumInteritemSpacing = 5.0;
layout.sectionInset = UIEdgeInsetsMake(5.0, 5.0, 5.0, 5.0);
layout.scrollDirection = UICollectionViewScrollDirectionVertical;
layout.itemSize = CGSizeMake(idealWidth, idealHeight);
self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
self.colours = @[@[[UIColor blackColor],
[UIColor darkGrayColor],
[UIColor lightGrayColor],
[UIColor whiteColor],
[UIColor grayColor],
[UIColor redColor],
[UIColor greenColor]],
@[[UIColor blueColor],
[UIColor cyanColor],
[UIColor yellowColor],
[UIColor magentaColor],
[UIColor orangeColor],
[UIColor purpleColor],
[UIColor brownColor]]];
}
- (void)setTheme {
[self.collectionView setDelegate:self];
[self.collectionView setDataSource:self];
[self.collectionView setAlwaysBounceHorizontal:YES];
[self.collectionView setDelaysContentTouches:NO];
[self.collectionView setShowsHorizontalScrollIndicator:NO];
[self.collectionView setShowsVerticalScrollIndicator:NO];
[self.collectionView setBackgroundColor:[UIColor colorWithRed:240.0/255.0 green:229.0/255.0 blue:227.0/255.0 alpha:1.0]];
}
- (void)registerClasses {
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:kPaletteViewCell];
}
- (void)doLayout {
[self addSubview:self.collectionView];
[self.collectionView.leftAnchor constraintEqualToAnchor:self.leftAnchor].active = YES;
[self.collectionView.rightAnchor constraintEqualToAnchor:self.rightAnchor].active = YES;
[self.collectionView.topAnchor constraintEqualToAnchor:self.topAnchor].active = YES;
[self.collectionView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor].active = YES;
[self.collectionView setTranslatesAutoresizingMaskIntoConstraints:NO];
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return self.colours.count; //Two rows of colours.
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [self.colours[section] count]; //7 colours per row in this example.
}
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kPaletteViewCell forIndexPath:indexPath];
NSArray *section = [self.colours objectAtIndex:indexPath.section];
[cell.contentView setBackgroundColor:section[indexPath.row]];
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
if ([self.delegate respondsToSelector:@selector(didSelectColour:colour:)]) {
NSArray *section = [self.colours objectAtIndex:indexPath.section];
[self.delegate didSelectColour:self colour:section[indexPath.row]];
}
}
@end
这是一个简单的 collectionView,每个单元格都有颜色。我硬编码了单元格的大小。
接下来我创建了 DrawingView。这是用户将使用他们的手指绘制的视图。此视图一次只处理一根手指绘图。我首先从 GameDesign 获得了绘制位图的想法。在游戏中,您希望首先将纹理绘制到内存中。然后当你完成所有的绘图时,你将该帧传输到屏幕上。这会显着提高速度,因为您不会在每次操作后更新屏幕。相反,您在所有绘图结束时更新屏幕(当用户抬起手指时)。
为此,我执行了以下操作:
DrawingView.h:
//
// DrawingView.h
// DrawingIO
//
// Created by Brandon T on 2016-11-27.
// Copyright © 2016 XIO. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface DrawingView : UIView
- (void)setPaletteColour:(UIColor * _Nonnull)colour;
@end
DrawingView.m:
//
// DrawingView.m
// DrawingIO
//
// Created by Brandon T on 2016-11-27.
// Copyright © 2016 XIO. All rights reserved.
//
#import "DrawingView.h"
@interface DrawingView()
@property (nonnull, nonatomic, strong) UIBezierPath *path;
@property (nonnull, nonatomic, strong) UIImage *bufferedImage;
@property (nonnull, nonatomic, strong) UIColor *strokeColour;
@end
@implementation DrawingView
- (instancetype)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
[self setPath:[UIBezierPath bezierPath]];
[self.path setLineWidth:1.0];
[self setStrokeColour:[UIColor blackColor]];
[self setMultipleTouchEnabled:NO];
}
return self;
}
- (void)setPaletteColour:(UIColor *)colour {
self.strokeColour = colour;
}
- (void)renderToBufferedImage {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0);
[self.strokeColour setStroke];
[self.bufferedImage drawAtPoint:CGPointZero];
[self.path stroke];
self.bufferedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
[self.path moveToPoint:[touch locationInView:self]];
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
[self.path addLineToPoint:[touch locationInView:self]];
[self setNeedsDisplay];
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
[self.path addLineToPoint:[touch locationInView:self]];
[self renderToBufferedImage];
[self setNeedsDisplay];
[self.path removeAllPoints];
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
[self.path addLineToPoint:[touch locationInView:self]];
[self renderToBufferedImage];
[self setNeedsDisplay];
[self.path removeAllPoints];
}
- (void)drawRect:(CGRect)rect {
[self.strokeColour setStroke];
[self.bufferedImage drawInRect:rect blendMode:kCGBlendModeNormal alpha:1.0];
[self.path stroke];
}
@end
我选择使用 drawInRect:blendMode:alpha
是因为这样您可以使用不同的混合选项和 alpha 级别进行绘制。对于这个例子,我正在绘制完全不透明的 32 位 BGRA 位图。
接下来我创建了带有嵌入式 ScrollView 的控制器。这允许用户 ZOOM-IN/Scale 视图并在 zoomed-in/scaled 视图上绘制。当您缩小时,您会注意到绘图是准确的(没有扭曲或缩放)。
ViewController.h:
//
// ViewController.h
// DrawingIO
//
// Created by Brandon T on 2016-11-27.
// Copyright © 2016 XIO. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
ViewController.m:
//
// ViewController.m
// DrawingIO
//
// Created by Brandon T on 2016-11-27.
// Copyright © 2016 XIO. All rights reserved.
//
#import "ViewController.h"
#import "PaletteView.h"
#import "DrawingView.h"
@interface ViewController () <UIScrollViewDelegate, PaletteViewDelegate>
@property (nonnull, nonatomic, strong) PaletteView *paletteView;
@property (nonnull, nonatomic, strong) DrawingView *drawingView;
@property (nonnull, nonatomic, strong) UIScrollView *scrollView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initControls];
[self setTheme];
[self doLayout];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)initControls {
self.paletteView = [[PaletteView alloc] initWithFrame:CGRectMake(0.0, 0.0, self.view.frame.size.width, 100.0)];
self.drawingView = [[DrawingView alloc] initWithFrame:self.view.frame];
self.scrollView = [[UIScrollView alloc] init];
}
- (void)setTheme {
[self.paletteView setDelegate:self];
[self.paletteView setBackgroundColor:[UIColor whiteColor]];
[self.drawingView setBackgroundColor:[UIColor whiteColor]];
[self.scrollView setDelegate:self];
[self.scrollView setScrollEnabled:NO];
[self.scrollView setMinimumZoomScale:1.0];
[self.scrollView setMaximumZoomScale:2.0];
}
- (void)doLayout {
[self.view addSubview:self.paletteView];
[self.view addSubview:self.scrollView];
[self.paletteView.leftAnchor constraintEqualToAnchor:self.view.leftAnchor].active = YES;
[self.paletteView.rightAnchor constraintEqualToAnchor:self.view.rightAnchor].active = YES;
[self.paletteView.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES;
[self.scrollView.leftAnchor constraintEqualToAnchor:self.view.leftAnchor].active = YES;
[self.scrollView.rightAnchor constraintEqualToAnchor:self.view.rightAnchor].active = YES;
[self.scrollView.topAnchor constraintEqualToAnchor:self.paletteView.bottomAnchor].active = YES;
[self.scrollView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES;
[self.scrollView setTranslatesAutoresizingMaskIntoConstraints:NO];
//Layout drawingView
[self.scrollView addSubview:self.drawingView];
}
- (nullable UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return self.drawingView;
}
- (void)didSelectColour:(PaletteView * _Nonnull)paletteView colour:(UIColor * _Nonnull)colour {
[self.drawingView setPaletteColour:colour];
}
@end