12.2.3 点线模式(1)
使用Quartz 2D绘制线段或边框时,默认总是使用实线。如果希望使用点线进行绘制,可调用CGContextRef的CGContextSetLineDash(CGContextRef c,CGFloat phase, const CGFloat lengths[],size_t count)函数进行设置,该函数的第3个参数是点线模式的关键,该参数是一个CGFloat型数组(第4个参数通常用于指定该数组的长度),每个CGFloat值依次控制点线的实线长度、间距。比如该参数如下。
{2,3}:代表长为2的实线、距离为3的间距、长为2的实线、距离为3的间距……这种点线模式。
{2,3,1}:代表长为2的实线、距离为3的间距、长为1的实线、距离为2的间距、长为3的实线、距离为1的间距……这种点线模式。
{5,3,1,2}:代表长为5的实线、距离为3的间距、长为1的实线、距离为2的间距、长为5的实线、距离为3的间距、长为1的实线、距离为2的间距……这种点线模式。
通过第2个参数依次指定点线模式的实线长度、间距的重复模式,这样可以定义出任意形状的点线。
该方法的第2个参数用于指定点线的相位,该参数将会与第3个参数协同起作用,比如如下参数参数组合。
phase=1, lengths={2,3}:代表长为2的实线、距离为3的间距、长为2的实线、距离为3的间距。但开始绘制起点时只绘制长度为1的实线,因为phase为1就是控制该点线"移过"1个点。
phase=3, {5,3,1,2}:代表长为5的实线、距离为3的间距、长为1的实线、距离为2的间距、长为5的实线、距离为3的间距、长为1的实线、距离为2的间距。但开始绘制时只绘制长度为2的实线,因为phase为3就是控制该点线"移过"3个点。
下面介绍一个示例让读者对Quartz 2D的点线模式有更直观、深入的理解。首先创建一个Single View Application,该应用包含一个应用程序委托类、一个视图控制器类以及配套的Storyboard界面设计文件。为了通过该界面控制点线模式,在该界面上放置一个UISlider来控制phase参数,并添加一个按钮用于重设phase参数,还放置一个UIPickerView来控制lengths参数,该应用的设计界面如图12.3所示。
为了在程序中访问这些UI控件,将程序中的UIScrolllView绑定到控制器的scrollView IBOutlet属性,将UIPickerView绑定到控制器的picker IBOutlet属性,将UISlider绑定到phase IBOutlet属性,并为界面上按钮的Touch Up Inside事件绑定reset IBAction事件处理方法。
该控制器类的实现部分代码如下。
程序清单:codes/12/12.2/DashLineTest/DashLineTest/FKViewController.m
- @implementation FKViewController
- typedef struct {
- CGFloat pattern[5];
- size_t count;
- } Pattern;
- // 初始化多个点线模式
- static Pattern patterns[] = {
- {{10.0, 10.0}, 2},
- {{10.0, 20.0, 10.0}, 3},
- {{10.0, 20.0, 30.0}, 3},
- {{10.0, 20.0, 10.0, 30.0}, 4},
- {{10.0, 10.0, 20.0, 20.0}, 4},
- {{10.0, 10.0, 20.0, 30.0, 50.0}, 5},
- };
- static NSInteger patternCount = sizeof(patterns)
- / sizeof(patterns[0]);
- FKDashLineView* dashView;
- -(void)viewDidLoad
- {
- [super viewDidLoad];
- // 创建FKDashLineView自定义控件
- dashView = [[FKDashLineView alloc] initWithFrame:self.scrollView.bounds];
- [self.scrollView addSubview: dashView]; // 将FKDashLineView控件添加到scrollView中
- [dashView setDashPattern:patterns[0].pattern
- count:patterns[0].count];
- // 为UIPickerView设置dataSource、delegate属性
- selfself.picker.dataSource = self;
- selfself.picker.delegate = self;
- // 选中UIPickerView的第一行
- [self.picker selectRow:0 inComponent:0 animated:NO];
- // 为UIPickerView的Value Changed事件绑定事件监听器
- [self.phase addTarget:self action:@selector(dashPhase)
- forControlEvents:UIControlEventValueChanged];
- }
- -(void)dashPhase
- {
- // 将dashView的dahsPhase设置与UIPickerView的值相同
- dashView.dashPhase = self.phase.value;
- }
- -(IBAction)reset
- {
- dashView.dashPhase = 0.0; // 将dashView的dahsPhase设为0
- self.phase.value = 0.0; // 将界面上UIPickerView控件的值也设为0
- }
- // 该方法的返回值控制UIPickerView只包含一列
- -(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
- {
- return 1;
- }
- // 该方法的返回值控制UIPickerView包含多少个列表项
- -(NSInteger)pickerView:(UIPickerView *)pickerView
- numberOfRowsInComponent:(NSInteger)component
- {
- return patternCount;
- }
- // 该方法的返回值决定每个列表项所显示的文本
- -(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:
- (NSInteger)row forComponent:(NSInteger)component;
- {
- Pattern p = patterns[row]; // 获取patterns数组的第row个元素
- // 将第row个patterns数组元素的pattern成员所包含的count个值拼接起来
- // 作为第row个列表项所显示的文本
- NSMutableString *title = [NSMutableString
- stringWithFormat:@"%.0f", p.pattern[0]];
- for(size_t i = 1; i < p.count; ++i)
- {
- [title appendFormat:@"-%.0f", p.pattern[i]];
- }
- return title;
- }
- // 当用户选择UIPickView的指定列表项时,程序设置dashView的点线模式
- -(void)pickerView:(UIPickerView *)pickerView didSelectRow:
- (NSInteger)row inComponent:(NSInteger)component
- {
- [dashView setDashPattern:patterns[row].pattern
- count:patterns[row].count];
- }
- @end