最后更新时间:2025-05-19


绘制线

折线类QPolyline,由一组经纬度坐标组成,并以有序序列形式建立一系列的线段。本节介绍绘制折线的各个基本用法




一、基础线绘制

1、绘制折线

绘制折线需要使用两个基本的类:折线数据类QPolyline、折线视图类QPolylineView,基本使用步骤如下:

i. 创建QPolyline数据对象:

// 创建折线起始点、折点坐标
CLLocationCoordinate2D polylineCoords[6];
polylineCoords[0].latitude = 39.984864;
polylineCoords[0].longitude = 116.305756;

polylineCoords[1].latitude = 39.983618;
polylineCoords[1].longitude = 116.305848;

polylineCoords[2].latitude = 39.982347;
polylineCoords[2].longitude = 116.305966;

polylineCoords[3].latitude = 39.982412;
polylineCoords[3].longitude = 116.308111;

polylineCoords[4].latitude = 39.984122;
polylineCoords[4].longitude = 116.308224;

polylineCoords[5].latitude = 39.984955;
polylineCoords[5].longitude = 116.308099;
	
// 根据坐标点创建折线数据对象
QPolyline *polyline = [QPolyline polylineWithCoordinates:polylineCoords count:6];
// 将折线数据对象添加到地图中
[self.mapView addOverlay:polyline];

ii. 实现<QMapViewDelegate>协议的mapView:(QMapView *)mapView viewForOverlay:方法来创建折线视图:

- (QOverlayView *)mapView:(QMapView *)mapView viewForOverlay:(id<QOverlay>)overlay
{
	if ([overlay isKindOfClass:[QPolyline class]])
	{
		QPolylineView *polylineRender = [[QPolylineView alloc] initWithPolyline:overlay];
		// 设置线宽
		polylineRender.lineWidth   = 15;
		// 设置线段颜色
		polylineRender.strokeColor = [UIColor colorWithRed:0 green:0 blue:1 alpha:0.2];
		// 设置边框宽度
		polylineRender.borderWidth = 2;
		// 设置边框颜色
		polylineRender.borderColor = [UIColor grayColor];
		
		return polylineRender;
	}
	
	return nil;
}

iii. 效果如图所示:


2、绘制虚线

虚线的绘制方法与普通的折线绘制基本一样,不同的是在创建QPolylineView时,调用 setLineDashPattern: 方法设置虚线线段的样式,实线和虚线的线长序列(元素个数必须是偶数),示例如下:

- (QOverlayView *)mapView:(QMapView *)mapView viewForOverlay:(id<QOverlay>)overlay
{
    if ([overlay isKindOfClass:[QPolyline class]])
        {
        QPolylineView *polylineRender = [[QPolylineView alloc] initWithPolyline:overlay];
        polylineRender.lineWidth   = 6;
        polylineRender.strokeColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:.8];
        
        // 设置overlay虚线样式
        [polylineRender setLineDashPattern:[NSArray<NSNumber*> arrayWithObjects:[NSNumber numberWithInt:30],[NSNumber numberWithInt:30],[NSNumber numberWithInt:30],[NSNumber numberWithInt:30], nil]];
        
        return polylineRender;
        }
    
    return nil;
}

效果如下图所示:



二、绘制纹理线

自定义纹理折线类QTexturePolyline,可以对构成折线的每条线段进行自定义。 自定义纹理折线支持使用纹理图片的方式填充折线的线段,图片应为以1像素为单位的多行的图片;若设置了纹理图片,设置线段颜色类型将无效。 自定义纹理折线还支持在线段中绘制箭头,表示路线的前进方向,基本使用方法如下例所示:

1、纹理线属性

属性 说明 适用纹理类型
drawType 默认为QTextureLineDrawType_SliceAsBackground. 添加完成后不支持修改
useGradient 是否使用渐变效果,渐变时, 以QSegmentColor的startIndex作为渐变点颜色标记位 QTextureLineDrawType_ColorLine
segmentColor 定义了各子线段的颜色,支持实时修改 QTextureLineDrawType_ColorLine
styleTextureImage 绘制线所采用的纹理,可为nil. 为nil时则采用默认样式的纹理 非QTextureLineDrawType_ColorLine
segmentStyle 定义了各子线段的样式,支持实时修改 非QTextureLineDrawType_ColorLine
drawSymbol 是否绘制箭头图标 QTextureLineDrawType_SliceAsBackground,QTextureLineDrawType_ColorLine
symbolImage 箭头图标。默认采用默认样式箭头 QTextureLineDrawType_SliceAsBackground,QTextureLineDrawType_ColorLine
symbolGap 箭头之间的间距. 单位:Point QTextureLineDrawType_SliceAsBackground,QTextureLineDrawType_ColorLine
eraseColor 擦掉时时采用的颜色. 默认为灰色(置灰) QTextureLineDrawType_ColorLine
footprintStep footprints之间的间距。 单位:Point TextureLineDrawType_FootPrint

2、基础纹理线

i. 创建QPolyline的子类QRouteOverlay,用于保存折线的分段信息,示例如下:

@interface QRouteOverlay : QPolyline

- (id)initWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count arrLine:(NSArray<QSegmentStyle*> *)arrLine;

// 保存折线每条线段的分段信息
@property(nonatomic, strong) NSMutableArray<QSegmentStyle *>* arrLine;

@end

@implementation QRouteOverlay

- (id)initWithCoordinates:(CLLocationCoordinate2D *)coordinateArray count:(NSUInteger)count arrLine:(NSArray<QSegmentStyle *> *)arrLine
{
	if (count == 0 || arrLine.count == 0) {
		return nil;
	}
	
	if (self = [super initWithCoordinates:coordinateArray count:count])
	{
		self.arrLine = [NSMutableArray array];
		[self.arrLine addObjectsFromArray:arrLine];
	}
	
	return self;
}

@end

ii. 添加分段纹理绘制折线数据:

const int COUNT = 6;
CLLocationCoordinate2D polylineCoords[COUNT];
polylineCoords[0].latitude = 39.984864;
polylineCoords[0].longitude = 116.305756;

polylineCoords[1].latitude = 39.983618;
polylineCoords[1].longitude = 116.305848;

polylineCoords[2].latitude = 39.982347;
polylineCoords[2].longitude = 116.305966;

polylineCoords[3].latitude = 39.982412;
polylineCoords[3].longitude = 116.308111;

polylineCoords[4].latitude = 39.984122;
polylineCoords[4].longitude = 116.308224;

polylineCoords[5].latitude = 39.984955;
polylineCoords[5].longitude = 116.308099;
	
NSMutableArray* routeLineArray = [NSMutableArray array];
// 创建分段样式
for (int i = 0; i < COUNT-1; i++)
{
	QSegmentStyle *subLine = [[QSegmentStyle alloc] init];
	subLine.startIndex = i;
	subLine.endIndex  = i+1;
	// 指定随机颜色: 如果使用了纹理图片,则取值为图片的像素值
	subLine.colorImageIndex = arc4random() % 6;
	[routeLineArray addObject:subLine];
}

// 创建分段纹理线段
QRouteOverlay *polyline = [[QRouteOverlay alloc] initWithCoordinates:polylineCoords count:COUNT arrLine:routeLineArray];

[self.mapView addOverlay:polyline];

iii. 实现代理方法,创建纹理折线视图,并开启箭头显示:

- (QOverlayView *)mapView:(QMapView *)mapView viewForOverlay:(id<QOverlay>)overlay
{
	if ([overlay isKindOfClass:[QRouteOverlay class]])
	{
		QRouteOverlay *ro = (QRouteOverlay*)overlay;
		QTexturePolylineView *polylineRender = [[QTexturePolylineView alloc] initWithPolyline:overlay];
		
		// 设置分段样式
		polylineRender.segmentStyle = ro.arrLine;
		
		if ([self.lines indexOfObject:overlay] == 0) {
			// 使用纹理图片
			polylineRender.styleTextureImage = [UIImage imageNamed:@"colorSample"];
		polylineRender.lineWidth = 10;
			// 开启箭头绘制
			polylineRender.drawSymbol = YES;
			// 设置箭头图片: 如果没有指定,则使用默认的箭头样式
			polylineRender.symbolImage = [UIImage imageNamed:@"arrow.png"];
			// 设置箭头之间的间距
			polylineRender.symbolGap = 30;
		}
		return polylineRender;
	}
	
	return nil
}

注意:绘制箭头纹理时drawSymbol需要设置为YESsymbolImage属性如果不设置则采用默认箭头样式

iv. 效果如图所示:


3、 彩色线 (QTextureLineDrawType_ColorLine)

在mapView的绘制线代理方法中,创建QTexturePolylineView,设置drawType属性为QTextureLineDrawType_ColorLine可将线段设置不同的颜色

基础彩色线

关键代码如下:

- (QOverlayView *)mapView:(QMapView *)mapView viewForOverlay:(id<QOverlay>)overlay
{
    if ([overlay isKindOfClass:[QPolyline class]])
    {
		QPolyline *poly = (QPolyline*)overlay;
		QTexturePolylineView *polylineRender = [[QTexturePolylineView alloc] initWithPolyline:poly];	
		polylineRender.lineWidth = 11;	
		polylineRender.drawType = QTextureLineDrawType_ColorLine;
		polylineRender.segmentColor = [self createRandomSegmentColor:poly];
		return polylineRender;
    }
    
    return nil;
}

// 设置各线段颜色, 这里用的随机颜色
- (NSArray *)createRandomSegmentColor:(QPolyline *)line {
    int count = (int)line.pointCount;
    {
        NSMutableArray* segColors = [NSMutableArray array];
        for (int i = 0; i < count-1; i++) {
            QSegmentColor *style = [[QSegmentColor alloc] init];
            style.startIndex  = i;
            style.endIndex  = i+1;
#define randcolor   ((arc4random()%257)/255.0)
    
#define randomAlpha (((arc4random()% 10) + 5)/10.0)
            style.color = [UIColor colorWithRed:randcolor green:randcolor blue:randcolor alpha:randomAlpha];
            style.borderColor = [UIColor colorWithRed:randcolor green:randcolor blue:1 alpha:randomAlpha];
            [segColors addObject:style];
        }
        
        return segColors;
    }
}

效果如下:


渐变色线:

腾讯地图SDK自4.4.1版本开始,支持渐变色线功能,该功能可以在纹理折线 基础上实现线段颜色的渐变
基本使用步骤如下: 通过设置useGradientYES

核心代码如下:


- (QOverlayView *)mapView:(QMapView *)mapView viewForOverlay:(id<QOverlay>)overlay {
	if ([overlay isKindOfClass:[QPolyline class]]){
		QPolyline *poly = (QPolyline*)overlay;
		QTexturePolylineView *polylineRender = [[QTexturePolylineView alloc] initWithPolyline:poly];
		polylineRender.displayLevel = QOverlayLevelAboveLabels;
		polylineRender.lineWidth = 11;		
		polylineRender.useGradient = YES;
		polylineRender.drawType = QTextureLineDrawType_ColorLine;
		polylineRender.segmentColor = [self createRandomSegmentColor:poly];
		return polylineRender;
    }
    
    return nil;
}

- (NSArray *)createRandomSegmentColor:(QPolyline *)line {
    int count = (int)line.pointCount;
    {
        NSMutableArray* segColors = [NSMutableArray array];
        for (int i = 0; i < count-1; i++) {
            QSegmentColor *style = [[QSegmentColor alloc] init];
            style.startIndex  = i;
            style.endIndex  = i+1;
#define randcolor   ((arc4random()%257)/255.0)
            style.color = [UIColor colorWithRed:randcolor green:randcolor blue:randcolor alpha:1];
            [segColors addObject:style];
        }
        
        return segColors;
    }
}

效果如下

4、 分段彩色线 (QTextureLineDrawType_SliceAsBackground)

将图片以1像素为单位按行切片,根据下标从图片选取1像素来绘制线路样式(最大支持16像素高)

核心代码如下:


- (QOverlayView *)mapView:(QMapView *)mapView viewForOverlay:(id<QOverlay>)overlay
{
    if ([overlay isKindOfClass:[QPolyline class]])
    {
        QPolyline *poly = (QPolyline*)overlay;
        QTexturePolylineView *render = nil;
        render = [self createSliceTextureline:poly];
        return render;
    }
    return nil;
}

- (QTexturePolylineView *)createSliceTextureline:(QPolyline *)line {
    QPolyline *poly = (QPolyline*)line;
    QTexturePolylineView *polylineRender = [[QTexturePolylineView alloc] initWithPolyline:poly];
    polylineRender.drawType = QTextureLineDrawType_SliceAsBackground;
    polylineRender.displayLevel = QOverlayLevelAboveLabels;
    polylineRender.styleTextureImage = [UIImage imageNamed:@"color_texture.png"];
    polylineRender.lineWidth = 20;
    polylineRender.segmentStyle = [self creatRandonSegStyle:line];
    
    return polylineRender;
}

- (NSArray *)creatRandonSegStyle:(QPolyline *)line {
    NSMutableArray<QSegmentStyle*> *styles = [NSMutableArray array];
    for (int i = 0; i < line.pointCount - 1; i++)
    {
        QSegmentStyle *color = [[QSegmentStyle alloc] init];
        color.startIndex = i;
        color.endIndex = i + 1;
        // 这里以纹理图片index=8的像素行为例,该像素是一个渐变效果
        color.colorImageIndex = 8;
        
        [styles addObject:color];
    }
    
    return styles;
}

纹理图片放大如图(实际每行高度为1像素)

效果如下

区别:相较于QTextureLineDrawType_ColorLineQTextureLineDrawType_SliceAsBackground可绘制更丰富的效果

5、 重复图片纹理线 (QTextureLineDrawType_RepeatDraw)

重复绘制整个图片

主要代码如下

- (QOverlayView *)mapView:(QMapView *)mapView viewForOverlay:(id<QOverlay>)overlay
{
    if ([overlay isKindOfClass:[QPolyline class]])
    {
        QPolyline *poly = (QPolyline*)overlay;
        QTexturePolylineView *render = [self createRepeatDrawTexturePolylineView:poly];
        return render;
    }
    
    return nil;
}

- (QTexturePolylineView *)createRepeatDrawTexturePolylineView:(id<QOverlay>)overlay
{
    if (overlay == nil) return nil;
    
    QTexturePolylineView *polylineView = [[QTexturePolylineView alloc] initWithPolyline:overlay];
    polylineView.drawType = QTextureLineDrawType_RepeatDraw;
    polylineView.displayLevel = QOverlayLevelAboveLabels;
    polylineView.lineWidth = 20;
    
    QPolyline *polyline = (QPolyline *)overlay;
    NSMutableArray<QSegmentStyle*> *styles = [NSMutableArray array];
    for (int i = 0; i < polyline.pointCount - 1; i++)
    {
        QSegmentStyle *color = [[QSegmentStyle alloc] init];
        color.startIndex = i;
        color.endIndex = i + 1;
        [styles addObject:color];
    }
    
    polylineView.segmentStyle = styles;
    
    polylineView.styleTextureImage = [UIImage imageNamed:@"foot.png"];
    
    return polylineView;
}

效果如下

6、 足迹纹理线 (QTextureLineDrawType_FootPrint)

以足迹的形式重复绘制整个图片

关键代码

- (QOverlayView *)mapView:(QMapView *)mapView viewForOverlay:(id<QOverlay>)overlay
{
    if ([overlay isKindOfClass:[QPolyline class]])
    {
        QPolyline *poly = (QPolyline*)overlay;
        QTexturePolylineView *render = [self createFootprintTexturePolylineView:poly];
        return render;
    }
    
    return nil;
}

- (QTexturePolylineView *)createFootprintTexturePolylineView:(id<QOverlay>)overlay
{
    if (overlay == nil) return nil;
    
    QTexturePolylineView *polylineView = [[QTexturePolylineView alloc] initWithPolyline:overlay];
    polylineView.drawType = QTextureLineDrawType_FootPrint;
    polylineView.displayLevel = QOverlayLevelAboveLabels;
    polylineView.lineWidth = 20;
    
    QPolyline *polyline = (QPolyline *)overlay;
    NSMutableArray<QSegmentStyle*> *styles = [NSMutableArray array];
    for (int i = 0; i < polyline.pointCount - 1; i++)
    {
        QSegmentStyle *color = [[QSegmentStyle alloc] init];
        color.startIndex = i;
        color.endIndex = i + 1;
        
        color.colorImageIndex = i % 10;
        
        [styles addObject:color];
    }
    
    polylineView.segmentStyle = styles;
    
    polylineView.styleTextureImage = [UIImage imageNamed:@"foot.png"];
    
    return polylineView;
}

效果如下:

三、折线的擦除与置灰

擦除与置灰功能,必须在自定义纹理折线的基础上使用。该功能可以擦除折线中的某一条线段,或者将其置灰,示例代码如下:

// 创建线, 参考:添加分段纹理绘制折线数据
self.polyline = [[QRouteOverlay alloc] initWithCoordinates:polylineCoords count:COUNT arrLine:routeLineArray];

//擦除路线
-(void) handleEraseLine
{
    QTexturePolylineView *polylineView = (QTexturePolylineView *)[self.mapView viewForOverlay:self.polyline];
    [polylineView eraseFromStartToCurrentPoint:CLLocationCoordinate2DMake(39.984955, 116.308099) searchFrom:1 toColor:YES];
}

//置灰路线
- (void)handleTestAction
{
    QTexturePolylineView *polylineView = (QTexturePolylineView *)[self.mapView viewForOverlay:self.lines.firstObject];
    
    [polylineView eraseFromStartToCurrentPoint:CLLocationCoordinate2DMake(39.948517, 116.484256) searchFrom:1 toColor:NO];
    
    self.navigationItem.rightBarButtonItems.firstObject.enabled = NO;
}

效果如图所示:



四、动态路名

在创建QPolylineView时,text属性用于在折现线段上面绘制文字,可以用来显示路名。基本使用步骤如下:

  1. 创建分段文字

    // 创建分段文字
    NSMutableArray *segments = [NSMutableArray array];
    for (int i = 0; i < 5; i++) {
        QSegmentText *text = [[QSegmentText alloc] init];
        text.name = [NSString stringWithFormat:@"第%i条线", i + 1];
        text.startIndex = i;
        text.endIndex = i + 1;
        
        [segments addObject:text];
    }
    
  2. 创建文字样式

    // 创建样式
    QTextStyle *style = [[QTextStyle alloc] init];
    // 设置优先级为normal, 可以被其他高优先级的线遮盖
    style.priority = QTextPriority_High;
    style.textColor = [UIColor blackColor];
    style.strokeColor = [UIColor whiteColor];
    style.fontSize = 14;
    
  3. 创建QText对象,调整polylineView的显示层级,并设置文字

    // 创建QText
    QText *text = [[QText alloc] initWithSegments:segments];
    // 设置显示等级: 需要设置为 QOverlayLevelAboveBuildings 或 QOverlayLevelAboveRoads
    polylineView.displayLevel = QOverlayLevelAboveRoads;
    // 设置文字
    polylineView.text = text;
    
  4. 效果如图所示:

    注:如果线段的长度小于线上的文字长度,字会被隐藏,如图:


五、线的点击事件

实现<QMapViewDelegate>中的mapView: didTapOverlay:方法,点击折线覆盖物时调用该方法,示例代码如下:

- (void)mapView:(QMapView *)mapView didTapOverlay:(id<QOverlay>)overlay {
    if ([overlay isKindOfClass:[QPolyline class]]) {
        NSLog(@"折线点击事件");
    }
}

六、折线的更新

地图SDK4.3.9版本增加了线段更新功能,在之前版本中如果想要更改线段的坐标,需要先将原线段移除,然后创建新的QPolylineView对象。通过该能力可以解决频繁的修改线路,以致QPolylineView重复删除、添加造成的性能问题。

1、QPolylineView的更新

对于普通的线覆盖物,获取新的坐标点串,然后传入对应的个数,即可刷新该线覆盖物,示例代码如下:

// 创建新的坐标点数组
CLLocationCoordinate2D polylineCoords[6];
polylineCoords[0].latitude = 39.9542;
polylineCoords[0].longitude = 116.324;
	
polylineCoords[1].latitude = 39.9542;
polylineCoords[1].longitude = 116.444;
	
polylineCoords[2].latitude = 39.9142;
polylineCoords[2].longitude = 116.454;
	
polylineCoords[3].latitude = 39.9142;
polylineCoords[3].longitude = 116.334;
	
polylineCoords[4].latitude = 39.8542;
polylineCoords[4].longitude = 116.334;
	
polylineCoords[5].latitude = 39.8542;
polylineCoords[5].longitude = 116.434;

// 更新构成PolylineView的坐标
[_polylineView updateOverlayPoints:polylineCoords pointCount:6];

2、QTexturePolylineView

更新多段线覆盖物的时候,应当注意同时修改其线段对应的样式。如多段线覆盖物结尾新加一段线,修改示例如下:

CLLocationCoordinate2D polylineCoords[5];
polylineCoords[0].latitude = 39.9442;
polylineCoords[0].longitude = 116.324;

polylineCoords[1].latitude = 39.9442;
polylineCoords[1].longitude = 116.444;

polylineCoords[2].latitude = 39.9042;
polylineCoords[2].longitude = 116.454;

polylineCoords[3].latitude = 39.9042;
polylineCoords[3].longitude = 116.334;

// 新加的点
polylineCoords[4].latitude = 39.8442;
polylineCoords[4].longitude = 116.334;

// 获取需要修改的线覆盖物
QTexturePolylineView *pv = (QTexturePolylineView *)[self.mapView viewForOverlay:self.testLine];
// 修改线的样式
NSMutableArray *sg = [[NSMutableArray alloc] init];

QSegmentStyle *style = [[QSegmentStyle alloc] init];
style.startIndex = 0;
style.endIndex = 1;
style.colorImageIndex = 2;

[sg addObject:style];

QSegmentStyle *style2 = [[QSegmentStyle alloc] init];
style2.startIndex = 1;
style2.endIndex = 2;
style2.colorImageIndex = 4;

[sg addObject:style2];

QSegmentStyle *style3 = [[QSegmentStyle alloc] init];
style3.startIndex = 2;
style3.endIndex = 3;
style3.colorImageIndex = 5;

[sg addObject:style3];

// 新增的线段样式 QSegmentStyle *style4 = [[QSegmentStyle alloc] init];
style4.startIndex = 3;
style4.endIndex = 4;
style4.colorImageIndex = 6;

[sg addObject:style4];

// 更新坐标点信息 
[pv updateOverlayPoints:polylineCoords pointCount:5];

// 更新线段样式
pv.segmentStyle = sg;

线段的坐标点删除更新和上面示例同理。


七、常见问题

  1. 折线正常显示,但是路名文字没有显示:

    需保证最上层显示的文本信息中QTextStyle的priority属性为QTextPriority_High,以及对应的polylineView的displayLevel属性为QOverlayLevelAboveRoads或者QOverlayLevelAboveBuildings

  2. 两条折线的路名文字发生重叠如何解决:

    当绘制的两个polylineView相交时,两个polylineView的文本信息便有可能发生碰撞。需要显示的文本信息需将QTextStyle的priority属性设置为QTextPriority_High,不需要显示的文本信息则将QTextStyle的priority属性设置为QTextPriority_Normal。文本信息显示样式支持动态修改。

本页内容