UIScrollView中的UIView的素描

当我尝试在UIScrollView的子视图UIView上绘制草图时遇到问题。

UIView放大或滚动之后尝试在UIView上绘制草图时,会出现问题。 看起来我的草图代码(如下所示)没有考虑UIScrollView内的UIView的缩放或缩放,因为线条模糊,并没有显示他们应该在哪里。 请让我知道是否有什么可以做我的代码或提供另一种解决scheme。

 - (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的子视图。

创build一个小的绘图应用程序(仅在iPhone 7 Plus 10.1模拟器上testing)。

在这里输入图像说明

首先我创build了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,每个单元格被着色。 我硬编码的单元格的大小。

接下来我创build了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 

我select使用drawInRect:blendMode:alpha因为这将允许您使用不同的混合选项和alpha级别进行绘制。 对于这个例子,我绘制完全不透明的32位BGRA位图。

接下来,我创build了一个embedded式ScrollView的控制器。 这允许用户放大/缩放视图并在放大/缩放视图中绘制。 当你缩小,你会发现绘图是确切的(不失真或缩放)。

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