在UIScrollView中的UIView上绘制草图 [英] Sketch On UIView Within UIScrollView

查看:85
本文介绍了在UIScrollView中的UIView上绘制草图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尝试在UIScrollView中的子视图UIView上绘制草图时遇到问题.

I am having an issue when trying to sketch on a UIView that is a child view in a UIScrollView.

在缩放或滚动UIView时尝试在其上绘制草图时,会出现问题.看来我的草图代码(如下所示)没有考虑UIScrollViewUIView的缩放比例或缩放比例,因为线条模糊并且没有显示在应有的位置.请让我知道是否可以对我的代码执行某些操作或提供其他解决方案.

The problem occurs when you try to sketch on the UIView after it's been zoomed or scrolled on. It seems my sketch code (shown below) does not take into account the zoom or scale of the UIView within the UIScrollView because the lines blur and don't show up where they should. Please let me know if there is something that can be done to my code or provide another solution.

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

I should add that this code works fine if the UIView has not been zoomed or scrolled on. Also sheetDrawView is a subview of the UIScrollView.

推荐答案

创建了一个小型绘图应用程序(仅在iPhone 7 Plus 10.1 Simulator上进行了测试).

Created a small drawing application (Only tested on iPhone 7 Plus 10.1 Simulator).

首先,我创建了PalleteView.此视图使您可以选择绘制颜色.

First I created the PalleteView. This view allows you to select colours to draw with.

PaletteView.h:

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:

//
//  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,每个单元都有颜色.我对单元格的大小进行了硬编码.

It's a simple collectionView with each cell being coloured. I hardcoded the sizes of the cells.

接下来,我创建了DrawingView.这是用户将使用其手指进行绘制的视图.此视图一次只能处理一个手指.我首先想到了从GameDesign绘制到位图的想法.在游戏中,您想先将纹理绘制到内存中.然后,当您完成所有绘图时,便将该框架Blit到屏幕上.因为您不需要在每次操作后都更新屏幕,所以可以显着提高速度.而是在所有图形的末尾(当用户抬起手指时)更新屏幕.

Next I created the DrawingView. This is the view that the user will draw on using their finger. This view only handles ONE finger at a time drawing. I took the idea of drawing to a Bitmap first from GameDesign. In games, you want to draw textures to memory first. Then when you are finished doing all your drawing, you Blit that frame to the screen. This improves speed significantly because you aren't updating the screen after EVERY operation. Instead, you are updating the screen at the end of all drawing (when the user lifts their finger).

为此,我执行了以下操作:

To accomplish this, I did the following:

DrawingView.h:

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:

//
//  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位图.

I chose to use drawInRect:blendMode:alpha because that would allow you to draw with different blending options and alpha levels. For this example, I am drawing fully Opaque 32-bit BGRA bitmaps.

接下来,我创建了一个带有嵌入式ScrollView的控制器.这允许用户缩放/缩放视图并在放大/缩放的视图上绘制.缩小时,您会注意到图形是精确的(没有扭曲或缩放).

Next I created the controller with an embedded ScrollView. This allows the user to ZOOM-IN/Scale the view AND draw on the zoomed-in/scaled view. When you zoom back out, you will notice the drawing is exact (not distorted or scaled).

ViewController.h:

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:

//
//  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

这篇关于在UIScrollView中的UIView上绘制草图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆