Создано небольшое приложение для рисования (тестируется только на iPhone 7 Plus 10.1 Simulator).
Сначала я создал PalleteView. Этот вид позволяет вам выбирать цвета для рисования.
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. Это представление, которое пользователь будет использовать, используя свой палец. Это представление обрабатывает только один палец во временном чертеже. Сначала я подумал о том, чтобы рисовать в Bitmap из 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
потому, что позволит вам рисовать с различными вариантами смешивания и альфа-уровнями. В этом примере я рисую полностью непрозрачные 32-битные растровые изображения BGRA.
Далее я создал контроллер со встроенным ScrollView. Это позволяет пользователю ZOOM-IN/Масштабировать представление и нарисовать увеличенный/масштабированный вид. Когда вы увеличите масштаб изображения, вы увидите, что рисунок является точным (не искаженным или масштабированным).
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.м:
//
// 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
Примените AffineTransform, чтобы масштабировать вид так же, как и масштаб scrollView. Затем попробуйте рисовать? – Brandon
Звучит неплохо. Можете ли вы предоставить примерный код для AffineTransform, с которым я могу работать, и я буду рад попробовать? – user2621075