7 视图 绘制 手势识别

矩形区域的视图,可以在其中绘制自定义内容以及从用户触控手势,多点触控中获取手势

创建一个自定义视图,它有自己定义的手势

视图基本上是构造块,代表屏幕上的一块矩形区域,定义了一个坐标空间,在这个坐标系中,你可以进行绘制,可以在其中添加触控事件,掌握它们的位置

它是分级的,可以在视图中嵌套视图,每个视图只有一个父视图,可以有多个子视图,而这些子视图就是一个个矩形,相互之间可以重叠,不要求它们平铺

或者相互独立,特定视图的子视图是完全自由的,子视图的顺序很重要,因为它们可以是透明的

其实可以在矩形区域外绘图,Xcode中有一个开关,或者说是UIVew的一个属性,clip my subViews,不要让我的子视图超出边界,可以按照自己的意愿将

绘制内容控制在一定范围内,

1 创建自定义视图

UIView是所有绘制操作的核心

可以通过代码实现添加或移除view

- (void)addSubView:(UIView *)aView;
- (void)removeFromSuperview;

self.view是UIViewController的顶级UIView

绘制或者处理触控事件时并不经常需要对其进行子类化,有时它们只是边界,只是用来定义一个坐标空间,


CGFloat CGSize CGPoint CGRect


绘制的单位都是点,而非像素点

CGRect bounds坐标系中绘制区域的原点以及宽度和高度,是你在自己视图中用自己的代码进行绘制时使用的矩形

CGRect frame指的是父视图坐标系中的一个矩形,完全包含了你的绘制区域,可以看到它是如何定位你的

center代表在父视图坐标系中所在位置的中心

视图可以旋转,包含它的矩形会变大



UIView中有一个方法叫作drawRect,你只要实现这个方法,就可以绘制自己想要的东西

很重要的一点,永远不要调用drawRect,它时由系统来调用,如果你想要重绘图,就调用setNeedDisplay,它会告诉系统,这个视图需要被重绘,系统会在合适的时间

调用drawRect

我如何实现自己的drawRect:?

方法是使用quartz库,叫作core graphics ,其中有很多C函数,也可以用UIBezierPath类,它可以将各种复杂形状放入一个大的路径,可以在屏幕上对其描边或者填充

Core Graphics的工作思路

你需要有一个可以绘制的context,你需要创建路径:三角形,正方形,或者任意形状,然后设置你想要的字体,颜色,线宽等,然后对刚才创建的路径进行描边或填充

UIBezierPath封装了上述全部操作,帮你处理好了context,创建路径的方法就是向UIBezierPath实例发送消息,它允许你设置线宽,颜色,然后调用它的方法进行描边和填充

通常情况下不用考虑context,context代表绘制的位置,对于一般绘制,UIKit会在调用drawRect前替你设置好了context,当执行drawRect后,context就可以使用了,

CGContextRef context = UIGraphicsGetCurrentContext();

在drawRect中调用这个方法,你会得到一个cookie,将它作为第一个参数,传递给core graphics函数,这些CG函数并不经常使用,只有在UIbezierPath无法达到目标时

绘制一张扑克牌

1 拖入一个view,调整合适尺寸,然后为其写一个UIView的子类:aCardView

首先考虑这个类的public API :花色,数字,反正面

@property (nonatomic) NSUInteger rank;
@property (strong, nonatomic) NSString *suit;
@property (nonatomic) BOOL faceUp;

更改所有public API的setter

- (void)setSuit:(NSString *)suit
{
    _suit = suit;
    [self setNeedsDisplay];//如果有人修改类suit,我就要告诉系统去重绘
}

- (void)setRank:(NSUInteger)rank
{
    _rank = rank;
    [self setNeedsDisplay];
}

- (void)setFaceUp:(BOOL)faceUp
{
    _faceUp = faceUp;
    [self setNeedsDisplay];
}

开始绘制,用UIbezierPath来实现

#define CORNER_FONT_STANDARD_HEIGHT 180.0
#define CORNER_RADIUS 12.0
//实现任意bounds下的绘制
- (CGFloat)cornerScaleFactor { return self.bounds.size.height / CORNER_FONT_STANDARD_HEIGHT; }
- (CGFloat)cornerRadius { return CORNER_RADIUS * [self cornerScaleFactor]; }
- (CGFloat)cornerOffset { return [self cornerRadius] / 3.0; }

// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
    UIBezierPath *roundedRect = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:[self cornerRadius]];
    
    [roundedRect addClip];//在roundedRect内绘图
    
    [[UIColor whiteColor] setFill];
    UIRectFill(self.bounds);//填充了这个矩形
    
    [[UIColor blackColor] setStroke];
    [roundedRect stroke];//在卡牌边缘加一圈黑色边框
}

设置背景和透明度

- (void)setup
{
    self.backgroundColor = nil;//不设置背景
    self.opaque = NO;//透明
    self.contentMode = UIViewContentModeRedraw;//bound变化了,调用drawRect
}
在awakeFromNib中执行它,因为在这个demo中,我要从storyboard中创建它

- (void)awakeFromNib
{
    [self setup];
}



下面是绘制牌角

用NSAttributedString,将这个左上角的字符串设置成 A 回车 梅花,然后放在左上角

在属性化字符串中有两项需要设置,一个是字体,这里用预设字体,二是需要将段落样式设为居中,让A 和梅花上下对齐居中,

- (NSString *)rankAsString
{
    return @[@"?", @"A", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10", @"J", @"Q", @"K"][self.rank];
}
- (void)drawCorners
{
    NSMutableParagraphStyle *paragraphStyle= [[NSMutableParagraphStyle alloc]init];
    paragraphStyle.alignment = NSTextAlignmentCenter;//设置居中格式
    
    UIFont *cornerFont = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
    cornerFont = [cornerFont fontWithSize:cornerFont.pointSize * [self cornerScaleFactor]];//字体大小随屏幕改变
    
    NSAttributedString *cornerText = [[NSAttributedString alloc]initWithString:[NSString stringWithFormat:@"%@\n%@", [self rankAsString], self.suit] attributes:@{NSFontAttributeName:cornerFont, NSParagraphStyleAttributeName:paragraphStyle}];
    CGRect textBounds;
    textBounds.origin = CGPointMake([self cornerOffset], [self cornerOffset]);
    textBounds.size = cornerText.size;
    [cornerText drawInRect:textBounds];//在textBounds中绘制cornerText
                                         
}

在storyboard中设置outlet

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
    self.aCardView.rank = 13;
    self.aCardView.suit = @"♥️";
}


然后将左上角的cornerText上下颠倒,然后放在右下角

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(context, self.bounds.size.width, self.bounds.size.height);
    CGContextRotateCTM(context, M_PI);
    [cornerText drawInRect:textBounds];

下一步绘制牌面

    UIImage *faceImage = [UIImage imageNamed:[NSString stringWithFormat:@"%@%@",[self rankAsString], self.suit]];
    if(faceImage){
        CGRect imageRect = CGRectInset(self.bounds, self.bounds.size.width * 0.1, self.bounds.size.height * 0.1);//缩放
        [faceImage drawInRect:imageRect];
    } else{
        [self drawPips];
    }



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值