最近学习了百度地图的多途径点路径(驾车路线规划),按照百度地图的Demo学习,实现了页面,唯一遇到的小问题就是在标注路线方向时,图标的旋转角度需要设置一下,否则全部都指向上面,代码如下:
// UIImage+Rotate.h
// UIImage的扩展类,用来设置图像的角度
#import <UIKit/UIKit.h>
@interface UIImage (Rotate)
- (UIImage*)imageRotatedByDegrees:(CGFloat)degrees;
@end
// UIImage+Rotate.m
#import "UIImage+Rotate.h"
@implementation UIImage (Rotate)
- (UIImage*)imageRotatedByDegrees:(CGFloat)degrees
{
CGFloat width = CGImageGetWidth(self.CGImage);
CGFloat height = CGImageGetHeight(self.CGImage);
CGSize rotatedSize;
rotatedSize.width = width;
rotatedSize.height = height;
UIGraphicsBeginImageContext(rotatedSize);
CGContextRef bitmap = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);
CGContextRotateCTM(bitmap, degrees * M_PI / 180);
CGContextRotateCTM(bitmap, M_PI);
CGContextScaleCTM(bitmap, -1.0, 1.0);
CGContextDrawImage(bitmap, CGRectMake(-rotatedSize.width/2, -rotatedSize.height/2, rotatedSize.width, rotatedSize.height), self.CGImage);
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
@end
// RouteAnnotation.h
// 自定义的annotation,继承自BMKPointAnnotation
#ifndef RouteAnnotation_h
#define RouteAnnotation_h
#import <BaiduMapAPI_Map/BMKMapComponent.h>
@interface RouteAnnotation : BMKPointAnnotation
///<0:起点 1:终点 2:公交 3:地铁 4:驾乘 5:途经点 6:楼梯、电梯
@property (nonatomic) NSInteger type;
@property (nonatomic) NSInteger degree;
//根据该RouteAnnotation中Type属性的值返回对应的BMKAnnotationView
- (BMKAnnotationView*)getRouteAnnotationView:(BMKMapView *)mapview;
@end
#endif /* RouteAnnotation_h */
// RouteAnnotation.m
#import "RouteAnnotation.h"
#import "UIImage+Rotate.h"
@implementation RouteAnnotation
@synthesize type = _type;
@synthesize degree = _degree;
- (BMKAnnotationView*)getRouteAnnotationView:(BMKMapView *)mapview
{
BMKAnnotationView* view = nil;
switch (_type) {
case 0:
{
/**
*根据指定标识查找一个可被复用的标注View,一般在delegate中使用,用此函数来代替新申请一个View
*@param identifier 指定标识
*@return 返回可被复用的标注View
*/
view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"start_node"];
if (view == nil) {
//标注view
view = [[BMKAnnotationView alloc] initWithAnnotation:self reuseIdentifier:@"start_node"];
//设置centerOffset改变view的位置
view.centerOffset = CGPointMake(0, -(view.frame.size.height * 0.5));
//在百度资源包中取出图像
NSBundle *bundle = [NSBundle bundleWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"mapapi.bundle"]];
NSString *file = [[bundle resourcePath] stringByAppendingPathComponent:@"images/icon_nav_start"];
//view显示的图像
view.image = [UIImage imageWithContentsOfFile:file];
}
}
break;
case 1:
{
/**
*根据指定标识查找一个可被复用的标注View,一般在delegate中使用,用此函数来代替新申请一个View
*@param identifier 指定标识
*@return 返回可被复用的标注View
*/
view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"end_node"];
if (view == nil) {
//标注view
view = [[BMKAnnotationView alloc]initWithAnnotation:self reuseIdentifier:@"end_node"];
//设置centerOffset改变view的位置
view.centerOffset = CGPointMake(0, -(view.frame.size.height * 0.5));
//在百度资源包中取出图像
NSBundle *bundle = [NSBundle bundleWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"mapapi.bundle"]];
NSString *file = [[bundle resourcePath] stringByAppendingPathComponent:@"images/icon_nav_end"];
//view显示的图像
view.image = [UIImage imageWithContentsOfFile:file];
}
}
break;
case 2:
{
/**
*根据指定标识查找一个可被复用的标注View,一般在delegate中使用,用此函数来代替新申请一个View
*@param identifier 指定标识
*@return 返回可被复用的标注View
*/
view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"bus_node"];
if (view == nil) {
//标注view
view = [[BMKAnnotationView alloc]initWithAnnotation:self reuseIdentifier:@"bus_node"];
//在百度资源包中取出图像
NSBundle *bundle = [NSBundle bundleWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"mapapi.bundle"]];
NSString *file = [[bundle resourcePath] stringByAppendingPathComponent:@"images/icon_nav_bus"];
//view显示的图像
view.image = [UIImage imageWithContentsOfFile:file];
}
}
break;
case 3:
{
/**
*根据指定标识查找一个可被复用的标注View,一般在delegate中使用,用此函数来代替新申请一个View
*@param identifier 指定标识
*@return 返回可被复用的标注View
*/
view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"rail_node"];
if (view == nil) {
//标注view
view = [[BMKAnnotationView alloc]initWithAnnotation:self reuseIdentifier:@"rail_node"];
//在百度资源包中取出图像
NSBundle *bundle = [NSBundle bundleWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"mapapi.bundle"]];
NSString *file = [[bundle resourcePath] stringByAppendingPathComponent:@"images/icon_nav_rail"];
//view显示的图像
view.image = [UIImage imageWithContentsOfFile:file];
}
}
break;
case 4:
{
/**
*根据指定标识查找一个可被复用的标注View,一般在delegate中使用,用此函数来代替新申请一个View
*@param identifier 指定标识
*@return 返回可被复用的标注View
*/
view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"route_node"];
if (view == nil) {
//标注view
view = [[BMKAnnotationView alloc]initWithAnnotation:self reuseIdentifier:@"route_node"];
} else {
[view setNeedsDisplay];
}
//在百度资源包中取出图像
NSBundle *bundle = [NSBundle bundleWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"mapapi.bundle"]];
NSString *file = [[bundle resourcePath] stringByAppendingPathComponent:@"images/icon_direction"];
//view显示的图像
UIImage *image = [UIImage imageWithContentsOfFile:file];
//设置图片角度
view.image = [image imageRotatedByDegrees:_degree];
}
break;
case 5:
{
/**
*根据指定标识查找一个可被复用的标注View,一般在delegate中使用,用此函数来代替新申请一个View
*@param identifier 指定标识
*@return 返回可被复用的标注View
*/
view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"waypoint_node"];
if (view == nil) {
//标注view
view = [[BMKAnnotationView alloc]initWithAnnotation:self reuseIdentifier:@"waypoint_node"];
} else {
[view setNeedsDisplay];
}
//在百度资源包中取出图像
NSBundle *bundle = [NSBundle bundleWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"mapapi.bundle"]];
NSString *file = [[bundle resourcePath] stringByAppendingPathComponent:@"images/icon_nav_waypoint"];
//view显示的图像
UIImage *image = [UIImage imageWithContentsOfFile:file];
//设置图片角度
view.image = [image imageRotatedByDegrees:_degree];
}
break;
case 6:
{
/**
*根据指定标识查找一个可被复用的标注View,一般在delegate中使用,用此函数来代替新申请一个View
*@param identifier 指定标识
*@return 返回可被复用的标注View
*/
view = [mapview dequeueReusableAnnotationViewWithIdentifier:@"stairs_node"];
if (view == nil) {
//标注view
view = [[BMKAnnotationView alloc]initWithAnnotation:self reuseIdentifier:@"stairs_node"];
}
//在百度资源包中取出图像
NSBundle *bundle = [NSBundle bundleWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"mapapi.bundle"]];
NSString *file = [[bundle resourcePath] stringByAppendingPathComponent:@"images/stairsIcon"];
//view显示的图像
view.image = [UIImage imageWithContentsOfFile:file];
}
break;
default:
break;
}
if (view) {
view.annotation = self;
view.canShowCallout = YES;
}
return view;
}
@end
// YSHPendPlanningTaskModel.h
// 模型
#import <Common/Common.h>
@protocol YSHPendPlanningTaskDataModel;
@interface YSHPendPlanningTaskDataModel : JSONModel
@property (nonatomic, copy) NSString *longitude;
@property (nonatomic, copy) NSString *latitude;
@property (nonatomic, assign) NSInteger is_send;
@property (nonatomic, assign) NSInteger is_have_start;
@property (nonatomic, copy) NSString *task_id;
@end
@interface YSHPendPlanningTaskModel : JSONModel
@property (nonatomic, assign) NSInteger code;
@property (nonatomic, copy) NSString *message;
@property (nonatomic, strong) NSArray <YSHPendPlanningTaskDataModel> *data;
@end
// YSHPendPlanningTaskModel.m
#import "YSHPendPlanningTaskModel.h"
@implementation YSHPendPlanningTaskDataModel
+(BOOL)propertyIsOptional:(NSString *)propertyName{
return YES;
}
@end
@implementation YSHPendPlanningTaskModel
+(BOOL)propertyIsOptional:(NSString *)propertyName{
return YES;
}
@end
// YSHRoutePlanController.h
#import <UIKit/UIKit.h>
@interface YSHRoutePlanController : UIViewController
@end
// YSHRoutePlanController.m
#import "YSHRoutePlanController.h"
#import "YSHPendPlanningTaskModel.h"
#import <BaiduMapAPI_Map/BMKMapComponent.h>
#import <BaiduMapAPI_Utils/BMKUtilsComponent.h>
#import <BaiduMapAPI_Search/BMKSearchComponent.h>
#import <BMKLocationKit/BMKLocationManager.h>
#import "RouteAnnotation.h"
#import "UIImage+Rotate.h"
//起点
static NSInteger const annotationStart = 0;
//终点
static NSInteger const annotationEnd = 1;
//驾车
static NSInteger const annotationDrive = 4;
//途径点
static NSInteger const annotationAfter = 5;
@interface YSHRoutePlanController ()<BMKMapViewDelegate,BMKRouteSearchDelegate,BMKLocationManagerDelegate>
@property (nonatomic, strong) YSHPendPlanningTaskModel *model;
@property (nonatomic, strong) NSMutableArray<YSHPendPlanningTaskDataModel *> *dataSource;
@property (nonatomic, copy) NSString *tripMethod;
@property (nonatomic, strong) BMKMapView *mapView;
@property (nonatomic, strong) BMKRouteSearch * routesearch;
@property (nonatomic, strong) BMKLocationManager *locService;
@property (nonatomic, strong) BMKRouteSearch *drivingRouteSearch;
@property (nonatomic, assign) CLLocationCoordinate2D startCoor;
@end
@implementation YSHRoutePlanController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = @"路线规划";
[self createMapView];
}
///请求数据
-(void)loadData{
self.tripMethod = [[NSUserDefaults standardUserDefaults]objectForKey:@"1001"];
NSInteger routeRule = 2;
if([self.tripMethod isEqualToString:@"骑行"]){
routeRule = 2;
}else if([self.tripMethod isEqualToString:@"驾车"]){
routeRule = 1;
}
YSURequest *request = [[YSURequest alloc]initWithUrl:[NSString stringWithFormat:@"%@%@",API_PEND_PLANNING_TASK,[YSHUtils getAccount]] andWhat:0];
[request setValue:@(routeRule) forKey:@"route_rule"];
[self addRequest:request];
}
///请求成功
-(void)onRequestSucceed:(NSDictionary *)response ofWhat:(NSInteger)what{
YSHPendPlanningTaskModel *model = [[YSHPendPlanningTaskModel alloc]initWithDictionary:response error:nil];
self.model = model;
[self.model.data enumerateObjectsUsingBlock:^(YSHPendPlanningTaskDataModel *dataModel,NSUInteger index,BOOL *stop){
[self.dataSource addObject:dataModel];
}];
[self setupDefaultData];
}
///请求失败
-(void)onRequestFailed:(YSURequestError *)error ofWhat:(NSInteger)what{
[self.view makeToast:@"网络请求异常"];
}
///创建地图
- (void)createMapView {
self.mapView = [[BMKMapView alloc] initWithFrame:CGRectZero];
[self.mapView setZoomLevel:12];// 地图比例尺级别
self.mapView.showMapScaleBar = YES;// 设定是否显式比例尺
self.mapView.delegate = self;
[self.view addSubview:_mapView];
[_mapView mas_makeConstraints:^(MASConstraintMaker *make){
make.edges.equalTo(self.view);
}];
[self initLocationService];
}
///初始化定位服务
-(void)initLocationService{
if (_locService==nil) {
_locService = [[BMKLocationManager alloc]init];
}
_locService.delegate = self;
//开始连续定位
[_locService startUpdatingLocation];
//设定是否显示定位图层
_mapView.showsUserLocation = YES;
//设定定位模式,默认BMKUserTrackingMode
_mapView.userTrackingMode = BMKUserTrackingModeNone;
//设定定位坐标系类型,默认为 BMKLocationCoordinateTypeGCJ02
_locService.coordinateType = BMKLocationCoordinateTypeBMK09LL;
}
- (void)viewWillAppear:(BOOL)animated {
//当mapView即将被显示的时候调用,恢复之前存储的mapView状态
[_mapView viewWillAppear];
_mapView.delegate = self;
}
- (void)viewWillDisappear:(BOOL)animated {
//当mapView即将被隐藏的时候调用,存储当前mapView的状态
[_mapView viewWillDisappear];
}
///设置驾车路线规划数据
- (void)setupDefaultData {
//实例化驾车查询基础信息类
BMKDrivingRoutePlanOption *drivingRoutePlanOption = [[BMKDrivingRoutePlanOption alloc] init];
//实例化线路检索节点信息类对象
BMKPlanNode *start = [[BMKPlanNode alloc]init];
//定位位置作为起点坐标
start.pt = self.startCoor;
//途径点坐标数组
NSMutableArray <BMKPlanNode *> *wayPointsArray = [[NSMutableArray alloc]init];
[self.dataSource enumerateObjectsUsingBlock:^(YSHPendPlanningTaskDataModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
//数据源中最后一个元素分为作为终点,不加入途径点数组
if(idx != self.dataSource.count - 1){
CLLocationCoordinate2D coor;
coor.latitude = [obj.latitude doubleValue];
coor.longitude = [obj.longitude doubleValue];
BMKPlanNode *after = [[BMKPlanNode alloc]init];
after.pt = coor;
[wayPointsArray addObject:after];
}
}];
drivingRoutePlanOption.wayPointsArray = wayPointsArray;
//在dataSource中取出终点坐标
CLLocationCoordinate2D endCoor;
YSHPendPlanningTaskDataModel *endLocation = [self.dataSource lastObject];
endCoor.latitude = [endLocation.latitude doubleValue];
endCoor.longitude = [endLocation.longitude doubleValue];
//实例化线路检索节点信息类对象
BMKPlanNode *end = [[BMKPlanNode alloc]init];
//终点坐标
end.pt = endCoor;
//检索的起点,可通过关键字、坐标两种方式指定。cityName和cityID同时指定时,优先使用cityID
drivingRoutePlanOption.from = start;
//检索的终点,可通过关键字、坐标两种方式指定。cityName和cityID同时指定时,优先使用cityID
drivingRoutePlanOption.to = end;
[self searchData:drivingRoutePlanOption];
}
///发送驾车路线检索
- (void)searchData:(BMKDrivingRoutePlanOption *)option {
//初始化BMKRouteSearch实例
_drivingRouteSearch = [[BMKRouteSearch alloc]init];
//设置驾车路径的规划
_drivingRouteSearch.delegate = self;
/*
线路检索节点信息类,一个路线检索节点可以通过经纬度坐标或城市名加地名确定
*/
//实例化线路检索节点信息类对象
BMKPlanNode *start = [[BMKPlanNode alloc]init];
//起点名称
start.name = option.from.name;
//起点坐标
start.pt = option.from.pt;
//起点所在城市,注:cityName和cityID同时指定时,优先使用cityID
start.cityName = option.from.cityName;
//起点所在城市ID,注:cityName和cityID同时指定时,优先使用cityID
if ((option.from.cityName.length > 0 && option.from.cityID != 0) || (option.from.cityName.length == 0 && option.from.cityID != 0)) {
start.cityID = option.from.cityID;
}
//实例化线路检索节点信息类对象
BMKPlanNode *end = [[BMKPlanNode alloc]init];
//终点名称
end.name = option.to.name;
//终点所在城市,注:cityName和cityID同时指定时,优先使用cityID
end.cityName = option.to.cityName;
//终点所在城市ID,注:cityName和cityID同时指定时,优先使用cityID
if ((option.to.cityName.length > 0 && option.to.cityID != 0) || (option.to.cityName.length == 0 && option.to.cityID != 0)) {
end.cityID = option.to.cityID;
}
//终点坐标
end.pt = option.to.pt;
//初始化请求参数类BMKDrivingRoutePlanOption的实例
BMKDrivingRoutePlanOption *drivingRoutePlanOption = [[BMKDrivingRoutePlanOption alloc]init];
//检索的起点,可通过关键字、坐标两种方式指定。cityName和cityID同时指定时,优先使用cityID
drivingRoutePlanOption.from = start;
//检索的终点,可通过关键字、坐标两种方式指定。cityName和cityID同时指定时,优先使用cityID
drivingRoutePlanOption.to = end;
//检索的途径点
drivingRoutePlanOption.wayPointsArray = option.wayPointsArray;
/*
驾车策略,默认使用BMK_DRIVING_TIME_FIRST
BMK_DRIVING_BLK_FIRST:躲避拥堵
BMK_DRIVING_TIME_FIRST:最短时间
BMK_DRIVING_DIS_FIRST:最短路程
BMK_DRIVING_FEE_FIRST:少走高速
*/
drivingRoutePlanOption.drivingPolicy = option.drivingPolicy;
/*
路线中每一个step的路况,默认使用BMK_DRIVING_REQUEST_TRAFFICE_TYPE_NONE
BMK_DRIVING_REQUEST_TRAFFICE_TYPE_NONE:不带路况
BMK_DRIVING_REQUEST_TRAFFICE_TYPE_PATH_AND_TRAFFICE:道路和路况
*/
drivingRoutePlanOption.drivingRequestTrafficType = option.drivingRequestTrafficType;
/**
发起驾乘路线检索请求,异步函数,返回结果在BMKRouteSearchDelegate的onGetDrivingRouteResult中
*/
BOOL flag = [_drivingRouteSearch drivingSearch:drivingRoutePlanOption];
if(flag) {
NSLog(@"驾车检索成功");
} else {
NSLog(@"驾车检索失败");
}
}
#pragma mark - BMKRouteSearchDelegate
/**
返回驾车路线检索结果
@param searcher 检索对象
@param result 检索结果,类型为BMKDrivingRouteResult
@param error 错误码 @see BMKSearchErrorCode
*/
- (void)onGetDrivingRouteResult:(BMKRouteSearch *)searcher result:(BMKDrivingRouteResult *)result errorCode:(BMKSearchErrorCode)error {
[_mapView removeOverlays:_mapView.overlays];
[_mapView removeAnnotations:_mapView.annotations];
if (error == BMK_SEARCH_NO_ERROR) {
//+polylineWithPoints: count:坐标点的个数
__block NSUInteger pointCount = 0;
//获取所有驾车路线中第一条路线
BMKDrivingRouteLine *routeline = (BMKDrivingRouteLine *)result.routes.firstObject;
//遍历驾车路线中的所有路段
[routeline.steps enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
//获取驾车路线中的每条路段
BMKDrivingStep *step = routeline.steps[idx];
//初始化标注类RouteAnnotation的实例,RouteAnnotation继承自BMKPointAnnotation
RouteAnnotation *annotation = [[RouteAnnotation alloc] init];
//设置标注的经纬度坐标为子路段的入口经纬度
annotation.coordinate = step.entrace.location;
//设置标注的标题为子路段的说明
annotation.title = step.entraceInstruction;
//设置标注的角度
annotation.degree = step.direction * 30;
//设置标注的类型
annotation.type = annotationDrive;
/**
当前地图添加标注,需要实现BMKMapViewDelegate的-mapView:viewForAnnotation:方法
来生成标注对应的View
@param annotation 要添加的标注
*/
[_mapView addAnnotation:annotation];
//统计路段所经过的地理坐标集合内点的个数
pointCount += step.pointsCount;
}];
//添加起点annotation
RouteAnnotation *annotation = [[RouteAnnotation alloc]init];
//设置标注的坐标
annotation.coordinate = self.startCoor;
//设置标注的类型
annotation.type = annotationStart;
//添加标注到地图
[_mapView addAnnotation:annotation];
[self.dataSource enumerateObjectsUsingBlock:^(YSHPendPlanningTaskDataModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
//创建终点的标注
if(idx == self.dataSource.count - 1){
CLLocationCoordinate2D coor;
coor.latitude = [obj.latitude doubleValue];
coor.longitude = [obj.longitude doubleValue];
RouteAnnotation *annotation = [[RouteAnnotation alloc]init];
//设置标注的坐标
annotation.coordinate = coor;
//设置标注的类型
annotation.type = annotationEnd;
//添加标注到地图
[_mapView addAnnotation:annotation];
}
//创建途径点标注
else{
CLLocationCoordinate2D coor;
coor.latitude = [obj.latitude doubleValue];
coor.longitude = [obj.longitude doubleValue];
RouteAnnotation *annotation = [[RouteAnnotation alloc]init];
//设置标注的坐标
annotation.coordinate = coor;
//设置标注的类型
annotation.type = annotationAfter;
//添加标注到地图
[_mapView addAnnotation:annotation];
}
}];
//+polylineWithPoints: count:指定的直角坐标点数组
BMKMapPoint *points = new BMKMapPoint[pointCount];
__block NSUInteger j = 0;
//遍历驾车路线中的所有路段
[routeline.steps enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
//获取驾车路线中的每条路段
BMKDrivingStep *step = routeline.steps[idx];
//遍历每条路段所经过的地理坐标集合点
for (NSUInteger i = 0; i < step.pointsCount; i ++) {
//将每条路段所经过的地理坐标点赋值给points
points[j].x = step.points[i].x;
points[j].y = step.points[i].y;
j ++;
}
}];
//根据指定直角坐标点生成一段折线
BMKPolyline *polyline = [BMKPolyline polylineWithPoints:points count:pointCount];
/**
向地图View添加Overlay,需要实现BMKMapViewDelegate的-mapView:viewForOverlay:方法
来生成标注对应的View
@param overlay 要添加的overlay
*/
[_mapView addOverlay:polyline];
//根据polyline设置地图范围
[self mapViewFitPolyline:polyline withMapView:self.mapView];
}
}
#pragma mark - BMKMapViewDelegate
/**
根据anntation生成对应的annotationView
@param mapView 地图View
@param annotation 指定的标注
@return 生成的标注View
*/
- (BMKAnnotationView *)mapView:(BMKMapView *)mapView viewForAnnotation:(id<BMKAnnotation>)annotation {
RouteAnnotation *routeAnnotation = (RouteAnnotation *)annotation;
if([routeAnnotation isKindOfClass:[BMKPointAnnotation class]]){
return [routeAnnotation getRouteAnnotationView:_mapView];
}
return nil;
}
/**
根据overlay生成对应的BMKOverlayView
@param mapView 地图View
@param overlay 指定的overlay
@return 生成的覆盖物View
*/
- (BMKOverlayView *)mapView:(BMKMapView *)mapView viewForOverlay:(id<BMKOverlay>)overlay {
if ([overlay isKindOfClass:[BMKPolyline class]]) {
//初始化一个overlay并返回相应的BMKPolylineView的实例
BMKPolylineView *polylineView = [[BMKPolylineView alloc] initWithOverlay:overlay];
//设置polylineView的填充色
polylineView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:1];
//设置polylineView的画笔(边框)颜色
polylineView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
//设置polygonView的线宽度
polylineView.lineWidth = 2.0;
return polylineView;
}
return nil;
}
///根据polyline设置地图范围
- (void)mapViewFitPolyline:(BMKPolyline *)polyline withMapView:(BMKMapView *)mapView {
double leftTop_x, leftTop_y, rightBottom_x, rightBottom_y;
if (polyline.pointCount < 1) {
return;
}
BMKMapPoint pt = polyline.points[0];
leftTop_x = pt.x;
leftTop_y = pt.y;
//左上方的点lefttop坐标(leftTop_x,leftTop_y)
rightBottom_x = pt.x;
rightBottom_y = pt.y;
//右底部的点rightbottom坐标(rightBottom_x,rightBottom_y)
for (int i = 1; i < polyline.pointCount; i++) {
BMKMapPoint point = polyline.points[I];
if (point.x < leftTop_x) {
leftTop_x = point.x;
}
if (point.x > rightBottom_x) {
rightBottom_x = point.x;
}
if (point.y < leftTop_y) {
leftTop_y = point.y;
}
if (point.y > rightBottom_y) {
rightBottom_y = point.y;
}
}
BMKMapRect rect;
rect.origin = BMKMapPointMake(leftTop_x , leftTop_y);
rect.size = BMKMapSizeMake(rightBottom_x - leftTop_x, rightBottom_y - leftTop_y);
UIEdgeInsets padding = UIEdgeInsetsMake(20, 10, 20, 10);
[mapView fitVisibleMapRect:rect edgePadding:padding withAnimated:YES];
}
#pragma make -- BMKLocationManagerDelegate
/**
* @brief 连续定位回调函数。
* @param manager 定位 BMKLocationManager 类。
* @param location 定位结果,参考BMKLocation。
* @param error 错误信息。
*/
- (void)BMKLocationManager:(BMKLocationManager *)manager didUpdateLocation:(BMKLocation *)location orError:(NSError *)error {
//停止连续定位
[_locService stopUpdatingLocation];
//当前地图的中心点,改变该值时,地图的比例尺级别不会发生变化
_mapView.centerCoordinate = location.location.coordinate;
//记录起点位置坐标
self.startCoor = location.location.coordinate;
//发送数据请求
[self loadData];
}
-(NSMutableArray<YSHPendPlanningTaskDataModel *> *)dataSource{
if(_dataSource == nil){
_dataSource = [[NSMutableArray alloc]init];
}
return _dataSource;
}
@end
效果如图:
后来样式需要调整,途径点用标签表示,可以弹出气泡,气泡样式要自定义的,大概这样:
// YSHRoutePlanPaoPaoView.h
//自定义的paopaoView
#import <BaiduMapAPI_Map/BMKMapComponent.h>
@interface YSHRoutePlanPaoPaoView : BMKActionPaopaoView
@end
// YSHRoutePlanPaoPaoView.m
#import "YSHRoutePlanPaoPaoView.h"
@implementation YSHRoutePlanPaoPaoView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self drawView];
}
return self;
}
- (void)drawView{
UIView *OwnPaoPaoView = [[UIView alloc]initWithFrame:self.frame];
UILabel *detailsLabel = [[UILabel alloc]initWithFrame:OwnPaoPaoView.frame];
detailsLabel.text = @"查看详情";
detailsLabel.textColor = [UIColor whiteColor];
detailsLabel.font = [YSHUiUtils fontSeven];
detailsLabel.textAlignment = NSTextAlignmentCenter;
detailsLabel.backgroundColor = HEXCOLOR(0x58bff);
[OwnPaoPaoView addSubview:detailsLabel];
[self addSubview:OwnPaoPaoView];
}
@end
// YSHRoutePlanController.m
#import "YSHRoutePlanController.h"
#import "YSHPendPlanningTaskModel.h"
#import <BaiduMapAPI_Map/BMKMapComponent.h>
#import <BaiduMapAPI_Utils/BMKUtilsComponent.h>
#import <BaiduMapAPI_Search/BMKSearchComponent.h>
#import <BMKLocationKit/BMKLocationManager.h>
#import "RouteAnnotation.h"
#import "UIImage+Rotate.h"
#import "YSHRoutePlanPaoPaoView.h"
//起点
static NSInteger const annotationStart = 0;
//终点
static NSInteger const annotationEnd = 1;
//驾车
static NSInteger const annotationDrive = 4;
//途径点
static NSInteger const annotationAfter = 5;
//发货
static NSInteger const send = 1;
//收货
static NSInteger const collect = 2;
@interface YSHRoutePlanController ()<BMKMapViewDelegate,BMKRouteSearchDelegate,BMKLocationManagerDelegate>
@property (nonatomic, strong) YSHPendPlanningTaskModel *model;
@property (nonatomic, strong) NSMutableArray<YSHPendPlanningTaskDataModel *> *dataSource;
@property (nonatomic, copy) NSString *tripMethod;
@property (nonatomic, strong) BMKMapView *mapView;
@property (nonatomic, strong) BMKRouteSearch * routesearch;
@property (nonatomic, strong) BMKLocationManager *locService;
@property (nonatomic, strong) BMKRouteSearch *drivingRouteSearch;
//记录起点坐标
@property (nonatomic, assign) CLLocationCoordinate2D startCoor;
//点击BMKAnnotationView标注时记录上一次点击的对象
@property (nonatomic, strong) BMKAnnotationView *annotationView;
@end
@implementation YSHRoutePlanController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = @"路线规划";
[self createMapView];
}
///请求数据
-(void)loadData{
self.tripMethod = [[NSUserDefaults standardUserDefaults]objectForKey:@"1001"];
NSInteger routeRule = 2;
if([self.tripMethod isEqualToString:@"骑行"]){
routeRule = 2;
}else if([self.tripMethod isEqualToString:@"驾车"]){
routeRule = 1;
}
YSURequest *request = [[YSURequest alloc]initWithUrl:[NSString stringWithFormat:@"%@%@",API_PEND_PLANNING_TASK,[YSHUtils getAccount]] andWhat:0];
[request setValue:@(routeRule) forKey:@"route_rule"];
[self addRequest:request];
}
///请求成功
-(void)onRequestSucceed:(NSDictionary *)response ofWhat:(NSInteger)what{
YSHPendPlanningTaskModel *model = [[YSHPendPlanningTaskModel alloc]initWithDictionary:response error:nil];
self.model = model;
[self.model.data enumerateObjectsUsingBlock:^(YSHPendPlanningTaskDataModel *dataModel,NSUInteger index,BOOL *stop){
[self.dataSource addObject:dataModel];
}];
[self setupDefaultData];
}
///请求失败
-(void)onRequestFailed:(YSURequestError *)error ofWhat:(NSInteger)what{
[self.view makeToast:@"网络请求异常"];
}
///创建地图
- (void)createMapView {
self.mapView = [[BMKMapView alloc] initWithFrame:CGRectZero];
[self.mapView setZoomLevel:12];// 地图比例尺级别
self.mapView.showMapScaleBar = YES;// 设定是否显式比例尺
self.mapView.delegate = self;
[self.view addSubview:_mapView];
[_mapView mas_makeConstraints:^(MASConstraintMaker *make){
make.edges.equalTo(self.view);
}];
[self initLocationService];
}
///初始化定位服务
-(void)initLocationService{
if (_locService==nil) {
_locService = [[BMKLocationManager alloc]init];
}
_locService.delegate = self;
//开始连续定位
[_locService startUpdatingLocation];
//设定是否显示定位图层
_mapView.showsUserLocation = YES;
//设定定位模式,默认BMKUserTrackingMode
_mapView.userTrackingMode = BMKUserTrackingModeNone;
//设定定位坐标系类型,默认为 BMKLocationCoordinateTypeGCJ02
_locService.coordinateType = BMKLocationCoordinateTypeBMK09LL;
}
- (void)viewWillAppear:(BOOL)animated {
//当mapView即将被显示的时候调用,恢复之前存储的mapView状态
[_mapView viewWillAppear];
_mapView.delegate = self;
}
- (void)viewWillDisappear:(BOOL)animated {
//当mapView即将被隐藏的时候调用,存储当前mapView的状态
[_mapView viewWillDisappear];
}
///设置驾车路线规划数据
- (void)setupDefaultData {
//实例化驾车查询基础信息类
BMKDrivingRoutePlanOption *drivingRoutePlanOption = [[BMKDrivingRoutePlanOption alloc] init];
//实例化线路检索节点信息类对象
BMKPlanNode *start = [[BMKPlanNode alloc]init];
//定位位置作为起点坐标
start.pt = self.startCoor;
//途径点坐标数组
NSMutableArray <BMKPlanNode *> *wayPointsArray = [[NSMutableArray alloc]init];
[self.dataSource enumerateObjectsUsingBlock:^(YSHPendPlanningTaskDataModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
//数据源中最后一个元素分为作为终点,不加入途径点数组
if(idx != self.dataSource.count - 1){
CLLocationCoordinate2D coor;
coor.latitude = [obj.latitude doubleValue];
coor.longitude = [obj.longitude doubleValue];
BMKPlanNode *after = [[BMKPlanNode alloc]init];
after.pt = coor;
[wayPointsArray addObject:after];
}
}];
drivingRoutePlanOption.wayPointsArray = wayPointsArray;
//在dataSource中取出终点坐标
CLLocationCoordinate2D endCoor;
YSHPendPlanningTaskDataModel *endLocation = [self.dataSource lastObject];
endCoor.latitude = [endLocation.latitude doubleValue];
endCoor.longitude = [endLocation.longitude doubleValue];
//实例化线路检索节点信息类对象
BMKPlanNode *end = [[BMKPlanNode alloc]init];
//终点坐标
end.pt = endCoor;
//检索的起点,可通过关键字、坐标两种方式指定。cityName和cityID同时指定时,优先使用cityID
drivingRoutePlanOption.from = start;
//检索的终点,可通过关键字、坐标两种方式指定。cityName和cityID同时指定时,优先使用cityID
drivingRoutePlanOption.to = end;
[self searchData:drivingRoutePlanOption];
}
///发送驾车路线检索
- (void)searchData:(BMKDrivingRoutePlanOption *)option {
//初始化BMKRouteSearch实例
_drivingRouteSearch = [[BMKRouteSearch alloc]init];
//设置驾车路径的规划
_drivingRouteSearch.delegate = self;
/*
线路检索节点信息类,一个路线检索节点可以通过经纬度坐标或城市名加地名确定
*/
//实例化线路检索节点信息类对象
BMKPlanNode *start = [[BMKPlanNode alloc]init];
//起点名称
start.name = option.from.name;
//起点坐标
start.pt = option.from.pt;
//起点所在城市,注:cityName和cityID同时指定时,优先使用cityID
start.cityName = option.from.cityName;
//起点所在城市ID,注:cityName和cityID同时指定时,优先使用cityID
if ((option.from.cityName.length > 0 && option.from.cityID != 0) || (option.from.cityName.length == 0 && option.from.cityID != 0)) {
start.cityID = option.from.cityID;
}
//实例化线路检索节点信息类对象
BMKPlanNode *end = [[BMKPlanNode alloc]init];
//终点名称
end.name = option.to.name;
//终点所在城市,注:cityName和cityID同时指定时,优先使用cityID
end.cityName = option.to.cityName;
//终点所在城市ID,注:cityName和cityID同时指定时,优先使用cityID
if ((option.to.cityName.length > 0 && option.to.cityID != 0) || (option.to.cityName.length == 0 && option.to.cityID != 0)) {
end.cityID = option.to.cityID;
}
//终点坐标
end.pt = option.to.pt;
//初始化请求参数类BMKDrivingRoutePlanOption的实例
BMKDrivingRoutePlanOption *drivingRoutePlanOption = [[BMKDrivingRoutePlanOption alloc]init];
//检索的起点,可通过关键字、坐标两种方式指定。cityName和cityID同时指定时,优先使用cityID
drivingRoutePlanOption.from = start;
//检索的终点,可通过关键字、坐标两种方式指定。cityName和cityID同时指定时,优先使用cityID
drivingRoutePlanOption.to = end;
//检索的途径点
drivingRoutePlanOption.wayPointsArray = option.wayPointsArray;
/*
驾车策略,默认使用BMK_DRIVING_TIME_FIRST
BMK_DRIVING_BLK_FIRST:躲避拥堵
BMK_DRIVING_TIME_FIRST:最短时间
BMK_DRIVING_DIS_FIRST:最短路程
BMK_DRIVING_FEE_FIRST:少走高速
*/
drivingRoutePlanOption.drivingPolicy = option.drivingPolicy;
/*
路线中每一个step的路况,默认使用BMK_DRIVING_REQUEST_TRAFFICE_TYPE_NONE
BMK_DRIVING_REQUEST_TRAFFICE_TYPE_NONE:不带路况
BMK_DRIVING_REQUEST_TRAFFICE_TYPE_PATH_AND_TRAFFICE:道路和路况
*/
drivingRoutePlanOption.drivingRequestTrafficType = option.drivingRequestTrafficType;
/**
发起驾乘路线检索请求,异步函数,返回结果在BMKRouteSearchDelegate的onGetDrivingRouteResult中
*/
BOOL flag = [_drivingRouteSearch drivingSearch:drivingRoutePlanOption];
if(flag) {
NSLog(@"驾车检索成功");
} else {
NSLog(@"驾车检索失败");
}
}
#pragma mark - BMKRouteSearchDelegate
/**
返回驾车路线检索结果
@param searcher 检索对象
@param result 检索结果,类型为BMKDrivingRouteResult
@param error 错误码 @see BMKSearchErrorCode
*/
- (void)onGetDrivingRouteResult:(BMKRouteSearch *)searcher result:(BMKDrivingRouteResult *)result errorCode:(BMKSearchErrorCode)error {
[_mapView removeOverlays:_mapView.overlays];
[_mapView removeAnnotations:_mapView.annotations];
if (error == BMK_SEARCH_NO_ERROR) {
//+polylineWithPoints: count:坐标点的个数
__block NSUInteger pointCount = 0;
//获取所有驾车路线中第一条路线
BMKDrivingRouteLine *routeline = (BMKDrivingRouteLine *)result.routes.firstObject;
//遍历驾车路线中的所有路段
[routeline.steps enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
//获取驾车路线中的每条路段
BMKDrivingStep *step = routeline.steps[idx];
//初始化标注类RouteAnnotation的实例,RouteAnnotation继承自BMKPointAnnotation
RouteAnnotation *annotation = [[RouteAnnotation alloc] init];
//设置标注的经纬度坐标为子路段的入口经纬度
annotation.coordinate = step.entrace.location;
//设置标注的标题为子路段的说明
annotation.title = step.entraceInstruction;
//设置标注的角度
annotation.degree = step.direction * 30;
//设置标注的类型
annotation.type = annotationDrive;
/**
当前地图添加标注,需要实现BMKMapViewDelegate的-mapView:viewForAnnotation:方法
来生成标注对应的View
@param annotation 要添加的标注
*/
[_mapView addAnnotation:annotation];
//统计路段所经过的地理坐标集合内点的个数
pointCount += step.pointsCount;
}];
//添加起点annotation
RouteAnnotation *annotation = [[RouteAnnotation alloc]init];
//设置标注的坐标
annotation.coordinate = self.startCoor;
//设置标注的类型
annotation.type = annotationStart;
//添加标注到地图
[_mapView addAnnotation:annotation];
[self.dataSource enumerateObjectsUsingBlock:^(YSHPendPlanningTaskDataModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
//创建终点的标注
if(idx == self.dataSource.count - 1){
CLLocationCoordinate2D coor;
coor.latitude = [obj.latitude doubleValue];
coor.longitude = [obj.longitude doubleValue];
RouteAnnotation *annotation = [[RouteAnnotation alloc]init];
//设置标注的坐标
annotation.coordinate = coor;
//设置标注的类型
annotation.type = annotationEnd;
//添加标注到地图
[_mapView addAnnotation:annotation];
}
//创建途径点标注
else{
CLLocationCoordinate2D coor;
coor.latitude = [obj.latitude doubleValue];
coor.longitude = [obj.longitude doubleValue];
RouteAnnotation *annotation = [[RouteAnnotation alloc]init];
//设置标注的坐标
annotation.coordinate = coor;
//设置标注的类型
annotation.type = annotationAfter;
annotation.title = @"查看详情";
annotation.is_send = obj.is_send;
annotation.is_have_start = obj.is_have_start;
annotation.task_id = obj.task_id;
annotation.index = idx;
//添加标注到地图
[_mapView addAnnotation:annotation];
}
}];
//+polylineWithPoints: count:指定的直角坐标点数组
BMKMapPoint *points = new BMKMapPoint[pointCount];
__block NSUInteger j = 0;
//遍历驾车路线中的所有路段
[routeline.steps enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
//获取驾车路线中的每条路段
BMKDrivingStep *step = routeline.steps[idx];
//遍历每条路段所经过的地理坐标集合点
for (NSUInteger i = 0; i < step.pointsCount; i ++) {
//将每条路段所经过的地理坐标点赋值给points
points[j].x = step.points[i].x;
points[j].y = step.points[i].y;
j ++;
}
}];
//根据指定直角坐标点生成一段折线
BMKPolyline *polyline = [BMKPolyline polylineWithPoints:points count:pointCount];
/**
向地图View添加Overlay,需要实现BMKMapViewDelegate的-mapView:viewForOverlay:方法
来生成标注对应的View
@param overlay 要添加的overlay
*/
[_mapView addOverlay:polyline];
//根据polyline设置地图范围
[self mapViewFitPolyline:polyline withMapView:self.mapView];
}
}
#pragma mark - BMKMapViewDelegate
/**
根据anntation生成对应的annotationView
@param mapView 地图View
@param annotation 指定的标注
@return 生成的标注View
*/
- (BMKAnnotationView *)mapView:(BMKMapView *)mapView viewForAnnotation:(id<BMKAnnotation>)annotation {
RouteAnnotation *routeAnnotation = (RouteAnnotation *)annotation;
if([routeAnnotation isKindOfClass:[BMKPointAnnotation class]]){
if(routeAnnotation.type == annotationAfter){
BMKAnnotationView *annotationView = [routeAnnotation getRouteAnnotationView:_mapView];
//view显示的图像
annotationView.image = [self pathPointImage:routeAnnotation];
//view被选中时会弹出气泡
annotationView.canShowCallout = YES;
//view在地图上拖动
annotationView.draggable = YES;
//设置显示级别,数值越大越优先展示
annotationView.displayPriority = BMKFeatureDisplayPriorityDefaultHigh;
return annotationView;
}
return [routeAnnotation getRouteAnnotationView:_mapView];
}
return nil;
}
/**
根据overlay生成对应的BMKOverlayView
@param mapView 地图View
@param overlay 指定的overlay
@return 生成的覆盖物View
*/
- (BMKOverlayView *)mapView:(BMKMapView *)mapView viewForOverlay:(id<BMKOverlay>)overlay {
if ([overlay isKindOfClass:[BMKPolyline class]]) {
//初始化一个overlay并返回相应的BMKPolylineView的实例
BMKPolylineView *polylineView = [[BMKPolylineView alloc] initWithOverlay:overlay];
//设置polylineView的填充色
polylineView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:1];
//设置polylineView的画笔(边框)颜色
polylineView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
//设置polygonView的线宽度
polylineView.lineWidth = 2.0;
return polylineView;
}
return nil;
}
/**
*当选中一个annotation views时,调用此接口
*当BMKAnnotation的title为nil,BMKAnnotationView的canShowCallout为NO时,不显示气泡,点击BMKAnnotationView会回调此接口。
*当气泡已经弹出,点击BMKAnnotationView不会继续回调此接口。
*@param mapView 地图View
*@param view 选中的annotation views
*/
- (void)mapView:(BMKMapView *)mapView didSelectAnnotationView:(BMKAnnotationView *)view {
if(self.annotationView){
[self.annotationView.paopaoView removeFromSuperview];
[self.annotationView setSelected:NO];
self.annotationView = nil;
}
//设置自定义的泡泡
YSHRoutePlanPaoPaoView *paopao = [[YSHRoutePlanPaoPaoView alloc]initWithFrame:CGRectMake(0, -5, 50, 25)];
//initWithCustomView需要传入继承自BMKActionPaopaoView的View,否则会返回null
view.paopaoView = [[BMKActionPaopaoView alloc] initWithCustomView:paopao];
self.annotationView = view;
[mapView mapForceRefresh];
}
/**
*当点击annotation view弹出的泡泡时,调用此接口
*@param mapView 地图View
*@param view 泡泡所属的annotation view
*/
- (void)mapView:(BMKMapView *)mapView annotationViewForBubble:(BMKAnnotationView *)view{
NSLog(@"点击了泡泡");
}
///根据polyline设置地图范围
- (void)mapViewFitPolyline:(BMKPolyline *)polyline withMapView:(BMKMapView *)mapView {
double leftTop_x, leftTop_y, rightBottom_x, rightBottom_y;
if (polyline.pointCount < 1) {
return;
}
BMKMapPoint pt = polyline.points[0];
leftTop_x = pt.x;
leftTop_y = pt.y;
//左上方的点lefttop坐标(leftTop_x,leftTop_y)
rightBottom_x = pt.x;
rightBottom_y = pt.y;
//右底部的点rightbottom坐标(rightBottom_x,rightBottom_y)
for (int i = 1; i < polyline.pointCount; i++) {
BMKMapPoint point = polyline.points[i];
if (point.x < leftTop_x) {
leftTop_x = point.x;
}
if (point.x > rightBottom_x) {
rightBottom_x = point.x;
}
if (point.y < leftTop_y) {
leftTop_y = point.y;
}
if (point.y > rightBottom_y) {
rightBottom_y = point.y;
}
}
BMKMapRect rect;
rect.origin = BMKMapPointMake(leftTop_x , leftTop_y);
rect.size = BMKMapSizeMake(rightBottom_x - leftTop_x, rightBottom_y - leftTop_y);
UIEdgeInsets padding = UIEdgeInsetsMake(20, 10, 20, 10);
[mapView fitVisibleMapRect:rect edgePadding:padding withAnimated:YES];
}
#pragma make -- BMKLocationManagerDelegate
/**
* @brief 连续定位回调函数。
* @param manager 定位 BMKLocationManager 类。
* @param location 定位结果,参考BMKLocation。
* @param error 错误信息。
*/
- (void)BMKLocationManager:(BMKLocationManager *)manager didUpdateLocation:(BMKLocation *)location orError:(NSError *)error {
//停止连续定位
[_locService stopUpdatingLocation];
//当前地图的中心点,改变该值时,地图的比例尺级别不会发生变化
_mapView.centerCoordinate = location.location.coordinate;
//记录起点位置坐标
self.startCoor = location.location.coordinate;
//发送数据请求
[self loadData];
}
///返回途径点坐标的图像
- (UIImage *)pathPointImage:(RouteAnnotation *)annotation{
NSString *labelContent = nil;
UILabel *label = [UILabel new];
if(annotation.is_send == send){
labelContent = [NSString stringWithFormat:@"%ld(发)",annotation.index + 1];
label.backgroundColor = HEXCOLOR(0x10c8a8);
}else if(annotation.is_send == collect){
labelContent = [NSString stringWithFormat:@"%ld(收)",annotation.index + 1];
label.backgroundColor = HEXCOLOR(0x58bff);
}
CGFloat labelWidth = 6*labelContent.length +6;
label.frame = CGRectMake(0, 0, labelWidth*3, 16*3);
label.text = labelContent;
label.textAlignment = NSTextAlignmentCenter;
label.textColor = [UIColor whiteColor];
label.font = [UIFont systemFontOfSize:10*3];
label.clipsToBounds = YES;
UIGraphicsBeginImageContext(label.bounds.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
[label.layer renderInContext:ctx];
UIImage* tImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return tImage;
}
-(NSMutableArray<YSHPendPlanningTaskDataModel *> *)dataSource{
if(_dataSource == nil){
_dataSource = [[NSMutableArray alloc]init];
}
return _dataSource;
}
@end