Commit 8e01bae59a42a21f62dee69811dbb014b3ab476b
添加文件及资源
798 Bytes
1.38 KB
574 Bytes
1.02 KB
457 Bytes
795 Bytes
419 Bytes
803 Bytes
2.44 KB
4.66 KB
11.4 KB
23.3 KB
1.42 KB
2.09 KB
4.17 KB
1.99 KB
3.79 KB
7.8 KB
7.53 KB
6.4 KB
12.7 KB
6.36 KB
18.7 KB
4.14 KB
8.5 KB
3.12 KB
6.3 KB
1.89 KB
3.49 KB
5.19 KB
3.07 KB
5.89 KB
3.7 KB
7.25 KB
2.04 KB
3.71 KB
290 Bytes
553 Bytes
2.83 KB
6.34 KB
130 Bytes
207 Bytes
554 Bytes
867 Bytes
152 Bytes
439 Bytes
968 Bytes
1.79 KB
409 Bytes
751 Bytes
1.21 KB
3.51 KB
289 KB
626 KB
197 Bytes
632 Bytes
133 Bytes
384 Bytes
215 Bytes
721 Bytes
146 Bytes
499 Bytes
816 Bytes
1.53 KB
1.36 KB
2.6 KB
1.9 KB
3.74 KB
1.31 KB
2.82 KB
2.15 KB
4.38 KB
1.97 KB
3.91 KB
119 KB
175 KB
2.73 KB
6.3 KB
2.31 KB
6.51 KB
2.14 KB
5.9 KB
16.6 KB
31.9 KB
1.07 KB
2.04 KB
913 Bytes
1.56 KB
864 Bytes
1.44 KB
177 KB
256 KB
907 Bytes
1.75 KB
1.19 KB
2.33 KB
1009 Bytes
1.84 KB
3.96 KB
17.1 KB
7.53 KB
23.1 KB
1.19 KB
2.19 KB
341 Bytes
692 Bytes
1.6 KB
7.16 KB
1.39 KB
5.63 KB
| 1 | +// | ||
| 2 | +// CNStartRunningViewController.h | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/13. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import "CNCommonViewController.h" | ||
| 10 | +#import "CNLiveSportsDetailModel.h" | ||
| 11 | + | ||
| 12 | +@protocol CNStartRunningVCDelegate <NSObject> | ||
| 13 | + | ||
| 14 | +- (void)backToFrontVC; | ||
| 15 | + | ||
| 16 | +@end | ||
| 17 | +@interface CNStartRunningViewController : CNCommonViewController | ||
| 18 | +@property (nonatomic, weak) id<CNStartRunningVCDelegate> delegate; | ||
| 19 | +@property (nonatomic, strong) CNLiveSportsDetailModel *sportsDetailModel; | ||
| 20 | +@property (nonatomic, copy) NSString *eventID; | ||
| 21 | +@property (nonatomic, copy) NSString *eventName; | ||
| 22 | +@property (nonatomic, copy) NSString *pointsStr; | ||
| 23 | + | ||
| 24 | +@end | ||
| 25 | + |
| 1 | +// | ||
| 2 | +// CNStartRunningViewController.m | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/13. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import "CNStartRunningViewController.h" | ||
| 10 | +#import "CNRunEndCircleProgress.h" | ||
| 11 | +#import <CoreMotion/CoreMotion.h> | ||
| 12 | +#import <BaiduMapAPI_Base/BMKBaseComponent.h>//引入base相关所有的头文件 | ||
| 13 | +#import <BaiduMapAPI_Map/BMKMapComponent.h>//引入地图功能所有的头文件 | ||
| 14 | +#import <BMKLocationkit/BMKLocationComponent.h>//定位功能 | ||
| 15 | +#import "CNLinePointNode.h" | ||
| 16 | +#import "CNHistoryTrackParam.h" | ||
| 17 | +#import "CNHistoryViewModel.h" | ||
| 18 | +#import "CNHistoryTrackPoint.h" | ||
| 19 | +#import <BaiduTraceSDK/BaiduTraceSDK.h>//鹰眼服务 | ||
| 20 | +#import "CNTrackTableView.h" | ||
| 21 | +#import "CNTrackServiceManager.h" | ||
| 22 | +#import "CNTrackLoaclDataManager.h" | ||
| 23 | +#import "CNRunExitModel.h" | ||
| 24 | +#import "CNLiveUploadManager.h" | ||
| 25 | +#import <BaiduMapAPI_Utils/BMKUtilsComponent.h> | ||
| 26 | +#import "CNTrackUploadFailModel.h" | ||
| 27 | +#import "CNReUploadViewController.h" | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | +@interface CNStartRunningViewController () | ||
| 32 | +< | ||
| 33 | +BMKMapViewDelegate, | ||
| 34 | +BMKLocationManagerDelegate, | ||
| 35 | +BTKFenceDelegate, | ||
| 36 | +UITableViewDelegate, | ||
| 37 | +UITableViewDataSource, | ||
| 38 | +CNTrackServiceManagerDelegate | ||
| 39 | +> | ||
| 40 | +//倒计时 | ||
| 41 | +@property (nonatomic, strong) UIView *startCountdownView;//倒计时321 | ||
| 42 | +@property (nonatomic, strong) UILabel *startCountdownLab;//倒计时321 | ||
| 43 | +//倒计时结束后 | ||
| 44 | + | ||
| 45 | +@property (nonatomic, strong) UIView *fristBgView;//倒计时321 | ||
| 46 | +@property (nonatomic, strong) QMUIButton *backFirstBtn;//backFirstBtn | ||
| 47 | +@property (nonatomic, strong) UILabel *currentKMLab;//0.00公里 | ||
| 48 | + | ||
| 49 | +@property (nonatomic, strong) UILabel *gpsLab;//"GPS" | ||
| 50 | +@property (nonatomic, strong) UIImageView *currentGPSImgView;//"GPS"img | ||
| 51 | +@property (nonatomic, strong) UILabel *currentGPSLab;//GPS | ||
| 52 | + | ||
| 53 | +@property (nonatomic, strong) UIButton *detailMapBtn;//mapBtn | ||
| 54 | +@property (nonatomic, strong) UILabel *mapDesLab;//GPS | ||
| 55 | + | ||
| 56 | + | ||
| 57 | +@property (nonatomic, strong) UIImageView *speedImgView;//speed | ||
| 58 | +@property (nonatomic, strong) UILabel *currentSpeedLab; | ||
| 59 | +@property (nonatomic, strong) UILabel *speedDesLab; | ||
| 60 | + | ||
| 61 | +@property (nonatomic, strong) UIImageView *timeImgView;//time | ||
| 62 | +@property (nonatomic, strong) UILabel *currentTimeLab; | ||
| 63 | +@property (nonatomic, strong) UILabel *timeDesLab; | ||
| 64 | + | ||
| 65 | +@property (nonatomic, strong) UIImageView *stepImgView;//step | ||
| 66 | +@property (nonatomic, strong) UILabel *currentStepLab; | ||
| 67 | +@property (nonatomic, strong) UILabel *stepDesLab; | ||
| 68 | + | ||
| 69 | +@property (nonatomic, strong) QMUIButton *stopRunningBtn;//mapBtn | ||
| 70 | +@property (nonatomic, strong) QMUIButton *goonRunningBtn;//mapBtn | ||
| 71 | +@property (nonatomic, strong) UIView *endRunningBgView;//mapBtn | ||
| 72 | +@property (nonatomic, strong) QMUIButton *endRunningBtn;//mapBtn | ||
| 73 | +@property (nonatomic, strong) UIImageView *endTipView;//mapBtn | ||
| 74 | +@property (nonatomic, strong) UILabel *endTipLab;//mapBtn | ||
| 75 | +@property (strong, nonatomic) CNRunEndCircleProgress *progressView; | ||
| 76 | +@property (nonatomic, strong) UILongPressGestureRecognizer *longPress;//tap | ||
| 77 | +@property (nonatomic, strong) NSTimer *endTimer;//点击了结束按钮事件响应timer | ||
| 78 | +@property (nonatomic, strong) NSTimer *startRunningTimer;//跑步的累计时间 | ||
| 79 | + | ||
| 80 | +#pragma mark -- 地图.h | ||
| 81 | +@property (nonatomic, strong) BMKMapView *mapView;//地图 | ||
| 82 | +@property (nonatomic, strong) BMKPolyline *originalPolyLine; //当前界面的多边形(运动轨迹) | ||
| 83 | +@property (nonatomic, strong) BMKPointAnnotation *startAnnotation; //当前界面的标注 | ||
| 84 | +@property (nonatomic, strong) BMKPointAnnotation *endAnnotation; //当前界面的标注 | ||
| 85 | +@property (nonatomic, strong) QMUIButton *backBtn;//backBtn | ||
| 86 | +@property (nonatomic, strong) QMUIButton *GPSBtn;//backBtn | ||
| 87 | +@property (nonatomic, strong) QMUIButton *tipGPSBtn;//resetBtn | ||
| 88 | +@property (nonatomic, strong) QMUIButton *resetBtn;//resetBtn | ||
| 89 | +@property (nonatomic, strong) UIImageView *mapBottomView;//mapBottom | ||
| 90 | +@property (nonatomic, strong) UILabel *mapCurrentSpeedLab;//mapBottom | ||
| 91 | +@property (nonatomic, strong) UILabel *mapSpeedLab;//mapBottom | ||
| 92 | +@property (nonatomic, strong) UILabel *mapCurrentTimeLab;//mapBottom | ||
| 93 | +@property (nonatomic, strong) UILabel *mapTimeLab;//mapBottom | ||
| 94 | +@property (nonatomic, strong) UILabel *mapCurrentKMLab;//mapBottom | ||
| 95 | +@property (nonatomic, strong) UILabel *mapKMLab;//mapBottom | ||
| 96 | + | ||
| 97 | + | ||
| 98 | +#pragma mark -- 定位.h | ||
| 99 | +@property (nonatomic, strong) BMKLocationManager *locationManager;//定位管理 | ||
| 100 | +@property (nonatomic, strong) BMKUserLocation *userLocation; //当前位置对象 | ||
| 101 | + | ||
| 102 | +@property (nonatomic, assign) CNLocationGPSState gpsState; //gps信号状态 | ||
| 103 | +#pragma mark -- 定位画线.h | ||
| 104 | +@property (nonatomic, strong) BMKPolyline *stopBeforePolyLine; //停止前的路线 | ||
| 105 | +@property (nonatomic, assign) NSInteger recordReInTime; //停止前的路线 | ||
| 106 | + | ||
| 107 | +@property (nonatomic, strong) CLLocation *firstStopAfterLinePoint;//停止后的路线的第一个点 | ||
| 108 | +@property (nonatomic, strong) BMKPolyline *stopAfterPolyLine; //停止后的路线 | ||
| 109 | +@property (nonatomic, strong) BMKPolyline *frontStopAfterPolyLine; //停止后的前一半路线 | ||
| 110 | +//不退出控制器,暂停之前的线 | ||
| 111 | +@property (nonatomic, strong) BMKPolyline *noExitStopFrontPolyLine; //停止后的路线 | ||
| 112 | + | ||
| 113 | + | ||
| 114 | +@property (nonatomic, strong) NSMutableArray *locationPoints;//用于画线的集合 | ||
| 115 | +@property (nonatomic, strong) CLLocation *currentLocation;// 中间变量->location类型(地理位置) | ||
| 116 | + | ||
| 117 | +#pragma mark -- 本地地理围栏.h | ||
| 118 | + | ||
| 119 | +#pragma mark -- 结束view.h | ||
| 120 | +@property (nonatomic, strong) CNTrackTableView *tableView; | ||
| 121 | +@property (nonatomic, strong) UIButton *saveBtn; | ||
| 122 | +@property (nonatomic, strong) UIView *preSaveView; | ||
| 123 | +@property (nonatomic, strong) UIImageView *loadingSaveView; | ||
| 124 | + | ||
| 125 | +@property (nonatomic, strong) UILabel *successStateLab;//tableviewcell中的一个变量 | ||
| 126 | + | ||
| 127 | +#pragma mark -- 判断进入页面的方式.h | ||
| 128 | +@property (nonatomic, strong) CNRunExitModel *exitModel; | ||
| 129 | +@end | ||
| 130 | + | ||
| 131 | +@implementation CNStartRunningViewController{ | ||
| 132 | + BOOL _isStopEnd;//是否停止了长按结束按钮 | ||
| 133 | + double _pressEndBtnCurrentTime;//计时器走了多长时间(最长2,到2 isStopEnd置为yes) | ||
| 134 | + NSInteger _totalTime;//跑步累计时间,单位秒 | ||
| 135 | + NSInteger _startRunningDate; | ||
| 136 | + BOOL _isEndRunning; | ||
| 137 | + CGFloat angle; | ||
| 138 | + NSInteger _endRunningDate; | ||
| 139 | + UIImageView *_headImg;//用于长按了结束按钮后拖动的问题 | ||
| 140 | + | ||
| 141 | + NSInteger _stopDate;//暂停的时间 | ||
| 142 | + NSInteger _reStartDate;//重新开始的时间 | ||
| 143 | + NSInteger _lastStepCount;//最新的步数或起止步数 | ||
| 144 | + NSNumber *localFenceId; | ||
| 145 | + | ||
| 146 | + CNTrackUploadFailModel *failModel;//上传失败的model,存数据库 | ||
| 147 | + NSString *_endStatus; | ||
| 148 | + BOOL _isStopRun;//用于判断是否在此控制器中是否点击了暂停,通过此控制器返回或其他操作都不做处理 | ||
| 149 | + BOOL _isStopAnimation; | ||
| 150 | + | ||
| 151 | +} | ||
| 152 | + | ||
| 153 | + | ||
| 154 | +-(void)dealloc{ | ||
| 155 | + [[NSNotificationCenter defaultCenter] removeObserver:self]; | ||
| 156 | + if (_endTimer) { | ||
| 157 | + [_endTimer invalidate]; | ||
| 158 | + _endTimer = nil; | ||
| 159 | + } | ||
| 160 | + if (_startRunningTimer) { | ||
| 161 | + [_startRunningTimer invalidate]; | ||
| 162 | + _startRunningTimer = nil; | ||
| 163 | + } | ||
| 164 | + NSLog(@"CNStartRunningViewController 释放了"); | ||
| 165 | +} | ||
| 166 | + | ||
| 167 | +-(void)viewWillAppear:(BOOL)animated{ | ||
| 168 | + [super viewWillAppear:animated]; | ||
| 169 | + [self.navigationController setNavigationBarHidden:YES animated:animated]; | ||
| 170 | + [self.mapView viewWillAppear]; | ||
| 171 | + self.mapView.delegate = self; | ||
| 172 | + _locationManager.delegate = self; | ||
| 173 | + self.recordReInTime = [CNLiveTimeTools getNowTimestamp]; | ||
| 174 | +} | ||
| 175 | + | ||
| 176 | +-(void)viewWillDisappear:(BOOL)animated{ | ||
| 177 | + [super viewWillDisappear:animated]; | ||
| 178 | + [self.navigationController setNavigationBarHidden:NO animated:animated]; | ||
| 179 | + [self.mapView viewWillDisappear]; | ||
| 180 | + self.mapView.delegate = nil; | ||
| 181 | + if (_isEndRunning) { | ||
| 182 | + _locationManager.delegate = nil; | ||
| 183 | + } | ||
| 184 | +} | ||
| 185 | + | ||
| 186 | +- (void)viewDidAppear:(BOOL)animated{ | ||
| 187 | + [super viewDidAppear:animated]; | ||
| 188 | + //禁用返回手势 | ||
| 189 | + if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { | ||
| 190 | + self.navigationController.interactivePopGestureRecognizer.delegate = nil; | ||
| 191 | + self.navigationController.interactivePopGestureRecognizer.enabled = NO; | ||
| 192 | + } | ||
| 193 | +} | ||
| 194 | + | ||
| 195 | +-(void)viewDidDisappear:(BOOL)animated{ | ||
| 196 | + [super viewDidDisappear:animated]; | ||
| 197 | + self.navigationController.interactivePopGestureRecognizer.enabled = YES; | ||
| 198 | +} | ||
| 199 | + | ||
| 200 | +- (void)viewDidLoad { | ||
| 201 | + [super viewDidLoad]; | ||
| 202 | + NSString *str = [self.sportsDetailModel mj_JSONString]; | ||
| 203 | + [[NSUserDefaults standardUserDefaults] setObject:str forKey:@"CN_OLD_TRACK"]; | ||
| 204 | + | ||
| 205 | + [CNTrackServiceManager defaultManager].delegate = self; | ||
| 206 | + self.view.backgroundColor = [UIColor blackColor]; | ||
| 207 | + _isStopRun = NO; | ||
| 208 | + [self.view addSubview:self.mapView]; | ||
| 209 | + [self.locationManager startUpdatingLocation]; | ||
| 210 | + [self.locationManager startUpdatingHeading]; | ||
| 211 | + self.mapView.hidden = YES; | ||
| 212 | + self.exitModel = [[CNTrackLoaclDataManager shareManager]getExitModel:CNUserShareModelUid]; | ||
| 213 | + //查询一次服务器围栏:实时状态查询,是为了使服务器围栏监控生效 | ||
| 214 | + [self queryRealtimeStatus]; | ||
| 215 | + | ||
| 216 | + if (self.exitModel && self.exitModel.eventId.length > 0) { | ||
| 217 | + [self initData]; | ||
| 218 | + [self addFirstView]; | ||
| 219 | + [self startRunningTime]; | ||
| 220 | + }else{ | ||
| 221 | + [self startCountdown:^{ | ||
| 222 | + [self initData]; | ||
| 223 | + self.view.backgroundColor = [UIColor blackColor]; | ||
| 224 | + [self addFirstView]; | ||
| 225 | + [self startRunningTime]; | ||
| 226 | + }]; | ||
| 227 | + } | ||
| 228 | +} | ||
| 229 | +#pragma mark -- CNTrackServiceManagerDelegate | ||
| 230 | +-(void)currentPedometer:(CNRunExitModel *)model{ | ||
| 231 | + if (!model) { | ||
| 232 | + return; | ||
| 233 | + } | ||
| 234 | + double km = ([model.step integerValue])*60.0/100/1000; | ||
| 235 | + //不四舍五入 | ||
| 236 | + NSInteger tempStep = [model.step integerValue]; | ||
| 237 | + if (tempStep > 0) { | ||
| 238 | + self.currentStepLab.text = [NSString stringWithFormat:@"%ld",[model.step integerValue]];//步数 | ||
| 239 | + }else{ | ||
| 240 | + self.currentStepLab.text = @"0"; | ||
| 241 | + } | ||
| 242 | + self.exitModel.step = self.currentStepLab.text; | ||
| 243 | + NSDictionary *attributesNum = @{NSFontAttributeName:[UIFont boldSystemFontOfSize:70]}; | ||
| 244 | + NSDictionary *attributesKM = @{NSFontAttributeName:[UIFont systemFontOfSize:15]}; | ||
| 245 | + NSAttributedString *attributedString = [self attributedText:@[[NSString stringWithFormat:@"%.2f",floor((km)*100)/100],@" 公里"] attributeAttay:@[attributesNum,attributesKM]]; | ||
| 246 | + self.currentKMLab.attributedText = attributedString; | ||
| 247 | + self.currentSpeedLab.text = [self getPaceSpeed:_totalTime distance:km]; | ||
| 248 | + self.mapCurrentKMLab.text = [NSString stringWithFormat:@"%.2f",floor((km)*100)/100]; | ||
| 249 | + self.mapCurrentSpeedLab.text = [self getPaceSpeed:_totalTime distance:km]; | ||
| 250 | +} | ||
| 251 | +#pragma mark -- mapDelegate | ||
| 252 | +-(void)mapViewDidFinishLoading:(BMKMapView *)mapView{ | ||
| 253 | + //地图加载完成后,添加运营的线,添加终点的本地围栏 | ||
| 254 | + [self addMapOriginalLine]; | ||
| 255 | + //请求自己的历史轨迹 | ||
| 256 | + CNRunExitModel *tempM = [[CNTrackLoaclDataManager shareManager] getExitModel:CNUserShareModelUid]; | ||
| 257 | + if (tempM && [tempM.isStop isEqualToString:@"yes"]) { | ||
| 258 | + [self.locationPoints removeAllObjects]; | ||
| 259 | + [self queryTwoMineHistoryLine]; | ||
| 260 | + }else if (tempM){ | ||
| 261 | + [self queryOneMineHistoryLine]; | ||
| 262 | + } | ||
| 263 | + | ||
| 264 | + [self.mapView addSubview:self.backBtn]; | ||
| 265 | + [self.backBtn mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 266 | + make.left.equalTo(self.mapView).offset(10); | ||
| 267 | + make.top.equalTo(self.mapView).offset(kVerticalStatusHeight + 10); | ||
| 268 | + make.size.mas_equalTo(CGSizeMake(45, 45)); | ||
| 269 | + }]; | ||
| 270 | + [self.mapView addSubview:self.GPSBtn]; | ||
| 271 | + [self.GPSBtn mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 272 | + make.centerY.equalTo(self.backBtn); | ||
| 273 | + make.right.equalTo(self.mapView.mas_right).offset(-10); | ||
| 274 | + make.size.mas_equalTo(CGSizeMake(78, 29)); | ||
| 275 | + }]; | ||
| 276 | + [self.mapView addSubview:self.tipGPSBtn]; | ||
| 277 | + [self.tipGPSBtn mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 278 | + make.right.equalTo(self.GPSBtn.mas_right); | ||
| 279 | + make.top.equalTo(self.GPSBtn.mas_bottom); | ||
| 280 | + make.size.mas_equalTo(CGSizeMake(140, 36)); | ||
| 281 | + }]; | ||
| 282 | + [self addMapBottomView]; | ||
| 283 | +} | ||
| 284 | + | ||
| 285 | +//line delegate | ||
| 286 | +- (BMKOverlayView *)mapView:(BMKMapView *)mapView viewForOverlay:(id<BMKOverlay>)overlay { | ||
| 287 | + // if ([overlay isKindOfClass:[BMKCircle class]]) { | ||
| 288 | + // BMKCircleView *circleView = [[BMKCircleView alloc] initWithOverlay:overlay]; | ||
| 289 | + // circleView.fillColor = [[UIColor alloc] initWithRed:0 green:0 blue:1 alpha:0.3]; | ||
| 290 | + // circleView.strokeColor = [[UIColor alloc] initWithRed:0 green:0 blue:1 alpha:0]; | ||
| 291 | + // return circleView; | ||
| 292 | + // }else{ | ||
| 293 | + if ([overlay isKindOfClass:[BMKPolyline class]] && [overlay isEqual:self.originalPolyLine]) { | ||
| 294 | + BMKPolylineView *polylineView = [[BMKPolylineView alloc] initWithPolyline:(BMKPolyline *)overlay]; | ||
| 295 | + polylineView.lineWidth = 2; | ||
| 296 | + polylineView.strokeColor = [RGBOF(0x5BC4A4) colorWithAlphaComponent:1]; | ||
| 297 | + return polylineView; | ||
| 298 | + } else { | ||
| 299 | + BMKPolylineView *polylineView = [[BMKPolylineView alloc] initWithPolyline:(BMKPolyline *)overlay]; | ||
| 300 | + polylineView.lineWidth = 2; | ||
| 301 | + polylineView.strokeColor = [[UIColor redColor] colorWithAlphaComponent:1]; | ||
| 302 | + return polylineView; | ||
| 303 | + } | ||
| 304 | + | ||
| 305 | + return nil; | ||
| 306 | +} | ||
| 307 | +//annotation delegate | ||
| 308 | +- (BMKAnnotationView *)mapView:(BMKMapView *)mapView viewForAnnotation:(id<BMKAnnotation>)annotation { | ||
| 309 | + if ([annotation isKindOfClass:[BMKPointAnnotation class]]) { | ||
| 310 | + NSString *AnnotationViewID = @"startStopAnnotation"; | ||
| 311 | + BMKAnnotationView *annotationView = nil; | ||
| 312 | + if (annotationView == nil) { | ||
| 313 | + annotationView = [[BMKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID]; | ||
| 314 | + } | ||
| 315 | + UIImageView *bgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, -38/2+5, 68, 68)]; | ||
| 316 | + bgView.image = [UIImage imageNamed:@"map-fw"]; | ||
| 317 | + UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, -38/2+5, 30, 38)]; | ||
| 318 | + if (annotation == _startAnnotation) { | ||
| 319 | + imageView.image = [UIImage imageNamed:@"map_location-start"]; | ||
| 320 | + } else if (annotation == _endAnnotation){ | ||
| 321 | + imageView.image = [UIImage imageNamed:@"map_location-finish"]; | ||
| 322 | + } | ||
| 323 | + // else{ | ||
| 324 | + // annotationView.image = [UIImage imageNamed:@"icon_fence_center"]; | ||
| 325 | + // return annotationView; | ||
| 326 | + // } | ||
| 327 | + // if (annotation == _startAnnotation || annotation == _endAnnotation) { | ||
| 328 | + UIView *underView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 15, 7)]; | ||
| 329 | + underView.backgroundColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:0.5]; | ||
| 330 | + underView.centerX = imageView.centerX+2; | ||
| 331 | + underView.centerY = imageView.centerY+38/2-3; | ||
| 332 | + underView.layer.cornerRadius = 6; | ||
| 333 | + underView.layer.masksToBounds = YES; | ||
| 334 | + bgView.centerX = underView.centerX; | ||
| 335 | + bgView.centerY = underView.centerY - 8; | ||
| 336 | + [annotationView addSubview:bgView]; | ||
| 337 | + [annotationView addSubview:underView]; | ||
| 338 | + [annotationView addSubview:imageView]; | ||
| 339 | + annotationView.frame = CGRectMake(0, -38/2+5, 30, 38); | ||
| 340 | + annotationView.enabled3D = YES; | ||
| 341 | + annotationView.hidePaopaoWhenSingleTapOnMap = YES; | ||
| 342 | + annotationView.hidePaopaoWhenDoubleTapOnMap = YES; | ||
| 343 | + annotationView.hidePaopaoWhenTwoFingersTapOnMap = YES; | ||
| 344 | + annotationView.hidePaopaoWhenSelectOthers = YES; | ||
| 345 | + return annotationView; | ||
| 346 | + // } | ||
| 347 | + } | ||
| 348 | + return nil; | ||
| 349 | +} | ||
| 350 | + | ||
| 351 | +#pragma mark -- 定位delegate | ||
| 352 | +- (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager didFailWithError:(NSError * _Nullable)error { | ||
| 353 | + NSLog(@"定位失败"); | ||
| 354 | +} | ||
| 355 | + | ||
| 356 | +// 定位SDK中,方向变更的回调 | ||
| 357 | +- (void)BMKLocationManager:(BMKLocationManager *)manager didUpdateHeading:(CLHeading * _Nullable)heading{ | ||
| 358 | + if (!heading) { | ||
| 359 | + return; | ||
| 360 | + } | ||
| 361 | + self.userLocation.heading = heading; | ||
| 362 | + [self.mapView updateLocationData:self.userLocation]; | ||
| 363 | +} | ||
| 364 | + | ||
| 365 | +// 定位SDK中,位置变更的回调 | ||
| 366 | +- (void)BMKLocationManager:(BMKLocationManager *)manager didUpdateLocation:(BMKLocation *)location orError:(NSError *)error { | ||
| 367 | + if (error) { | ||
| 368 | + //不处理 | ||
| 369 | + } | ||
| 370 | + if (!location) { | ||
| 371 | + return; | ||
| 372 | + } | ||
| 373 | + CLLocationAccuracy gpsValue = location.location.horizontalAccuracy; | ||
| 374 | + if (gpsValue > 0 && gpsValue <= 20) {//gps信号好 | ||
| 375 | + self.gpsState = CNLocationGPSStateGood; | ||
| 376 | + }else if (gpsValue > 20 && gpsValue <= 60){//gps信号中 | ||
| 377 | + self.gpsState = CNLocationGPSStateMedium; | ||
| 378 | + }else if (gpsValue > 60 && gpsValue < 200){//gps信号差 | ||
| 379 | + self.gpsState = CNLocationGPSStatePoor; | ||
| 380 | + }else{//gps信号无 | ||
| 381 | + self.gpsState = CNLocationGPSStateNull; | ||
| 382 | + } | ||
| 383 | + self.userLocation.location = location.location; | ||
| 384 | + [self.mapView updateLocationData:self.userLocation];//动态更新我的位置数据 | ||
| 385 | + if (gpsValue < 100 && !_isStopRun) { | ||
| 386 | + if (!self.currentLocation) { | ||
| 387 | + self.currentLocation = location.location; | ||
| 388 | + } | ||
| 389 | + if (self.locationPoints.count == 0) { | ||
| 390 | + [self.locationPoints addObject:location.location]; | ||
| 391 | + } | ||
| 392 | + CLLocationDistance distance = [location.location distanceFromLocation:self.currentLocation]; | ||
| 393 | + if (distance < 3){ | ||
| 394 | + return; | ||
| 395 | + } | ||
| 396 | + [self.locationPoints addObject:location.location]; | ||
| 397 | + //画线 | ||
| 398 | + // 直接画stopAfter后的线,如果有暂停,就查出来后画before线,如果没有暂停,就查出来后直接附加到stopAfter线上 | ||
| 399 | + if (self.locationPoints.count > 1) { | ||
| 400 | + [self addStopAfterPolyLine]; | ||
| 401 | + self.currentLocation = location.location; | ||
| 402 | + } | ||
| 403 | + } | ||
| 404 | +} | ||
| 405 | + | ||
| 406 | +//权限改变 | ||
| 407 | +- (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{ | ||
| 408 | + if (status == kCLAuthorizationStatusDenied) { | ||
| 409 | + dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 410 | + QMUIAlertAction *action1 = [QMUIAlertAction actionWithTitle:@"确定" style:QMUIAlertActionStyleCancel handler:^(__kindof QMUIAlertController *aAlertController, QMUIAlertAction *action) { | ||
| 411 | + }]; | ||
| 412 | + QMUIAlertController *alertController = [QMUIAlertController alertControllerWithTitle:@"" message:@"无法获取你的位置信息。\n 请到手机系统的[隐私]->[定位服务]中打开定位服务,并允许网家家使用定位服务" preferredStyle:QMUIAlertControllerStyleAlert]; | ||
| 413 | + [alertController addAction:action1]; | ||
| 414 | + [alertController showWithAnimated:YES]; | ||
| 415 | + }); | ||
| 416 | + } | ||
| 417 | +} | ||
| 418 | + | ||
| 419 | +- (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager doRequestAlwaysAuthorization:(CLLocationManager * _Nonnull)locationManager{ | ||
| 420 | + [locationManager requestAlwaysAuthorization]; | ||
| 421 | +} | ||
| 422 | +#pragma mark -- private 历史轨迹 | ||
| 423 | +- (void)getHistoryPoints{ | ||
| 424 | + //请求自己的历史轨迹 | ||
| 425 | + if ([self.exitModel.isStop isEqualToString:@"yes"]) { | ||
| 426 | + [self queryTwoMineHistoryLine]; | ||
| 427 | + }else{ | ||
| 428 | + [self queryOneMineHistoryLine]; | ||
| 429 | + } | ||
| 430 | +} | ||
| 431 | + | ||
| 432 | +#pragma mark -- private 实时画轨迹 | ||
| 433 | +- (void)addStopAfterPolyLine{ | ||
| 434 | + if (self.firstStopAfterLinePoint) { | ||
| 435 | + [self.locationPoints insertObject:self.firstStopAfterLinePoint atIndex:0]; | ||
| 436 | + } | ||
| 437 | + CLLocationCoordinate2D coors[self.locationPoints.count]; | ||
| 438 | + NSInteger count = 0; | ||
| 439 | + for (size_t i = 0; i < self.locationPoints.count; i++) { | ||
| 440 | + CLLocation *location = [self.locationPoints objectAtIndex:i]; | ||
| 441 | + coors[i] = location.coordinate; | ||
| 442 | + count++; | ||
| 443 | + } | ||
| 444 | + self.stopAfterPolyLine = [BMKPolyline polylineWithCoordinates:coors count:count]; | ||
| 445 | + dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 446 | + if (self.stopAfterPolyLine) {// 防止重复绘制 | ||
| 447 | + [self.mapView removeOverlay:self.stopAfterPolyLine]; | ||
| 448 | + } | ||
| 449 | + [self.mapView addOverlay:self.stopAfterPolyLine]; | ||
| 450 | + }); | ||
| 451 | +} | ||
| 452 | + | ||
| 453 | +#pragma mark -- private map | ||
| 454 | +- (void)queryTwoMineHistoryLine{ | ||
| 455 | + CNRunExitModel *tempM = self.exitModel; | ||
| 456 | + CNHistoryTrackParam * paramInfo =[[CNHistoryTrackParam alloc]init]; | ||
| 457 | + [paramInfo setStartTime:[tempM.startTime integerValue]]; | ||
| 458 | + [paramInfo setEndTime:[tempM.stopTime integerValue]]; | ||
| 459 | + [paramInfo setEntityName:CNUserShareModelUid]; | ||
| 460 | + [paramInfo setIsProcessed:true]; | ||
| 461 | + BTKQueryTrackProcessOption *processOption = [[BTKQueryTrackProcessOption alloc] init]; | ||
| 462 | + processOption.radiusThreshold = 100; | ||
| 463 | + processOption.denoise = true; | ||
| 464 | + processOption.vacuate = true; | ||
| 465 | + processOption.mapMatch = false; | ||
| 466 | + processOption.transportMode = BTK_TRACK_PROCESS_OPTION_TRANSPORT_MODE_WALKING; | ||
| 467 | + paramInfo.processOption = processOption; | ||
| 468 | + paramInfo.supplementMode = BTK_TRACK_PROCESS_OPTION_SUPPLEMENT_MODE_WALKING; | ||
| 469 | + CNHistoryViewModel *vm = [[CNHistoryViewModel alloc] init]; | ||
| 470 | + vm.completionHandler = ^(NSArray *points) { | ||
| 471 | + if (points.count > 0) { | ||
| 472 | + NSMutableArray *mu = [NSMutableArray arrayWithCapacity:0]; | ||
| 473 | + for (CNHistoryTrackPoint *point in points) { | ||
| 474 | + CLLocation *location = [[CLLocation alloc] initWithLatitude:point.coordinate.latitude longitude:point.coordinate.longitude]; | ||
| 475 | + [mu addObject:location]; | ||
| 476 | + } | ||
| 477 | + //画线 | ||
| 478 | + CLLocationCoordinate2D coors[mu.count]; | ||
| 479 | + NSInteger count = 0; | ||
| 480 | + for (size_t i = 0; i < mu.count; i++) { | ||
| 481 | + CLLocation *location = [mu objectAtIndex:i]; | ||
| 482 | + coors[i] = location.coordinate; | ||
| 483 | + count++; | ||
| 484 | + } | ||
| 485 | + self.stopBeforePolyLine = [BMKPolyline polylineWithCoordinates:coors count:count]; | ||
| 486 | + dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 487 | + if (self.stopBeforePolyLine) {// 防止重复绘制 | ||
| 488 | + [self.mapView removeOverlay:self.stopBeforePolyLine]; | ||
| 489 | + } | ||
| 490 | + [self.mapView addOverlay:self.stopBeforePolyLine]; | ||
| 491 | + }); | ||
| 492 | + } | ||
| 493 | + }; | ||
| 494 | + [vm queryHistoryWithParam:paramInfo]; | ||
| 495 | + | ||
| 496 | + if (tempM.reStartTime.length == 0 || [tempM.reStartTime isEqualToString:@"<null>"]) { | ||
| 497 | + tempM.reStartTime = [NSString stringWithFormat:@"%ld",[CNLiveTimeTools getNowTimestamp]]; | ||
| 498 | + [[CNTrackLoaclDataManager shareManager] updateExitModel:tempM]; | ||
| 499 | + return; | ||
| 500 | + } | ||
| 501 | + CNHistoryTrackParam * paramInfo2 =[[CNHistoryTrackParam alloc]init]; | ||
| 502 | + [paramInfo2 setStartTime:[tempM.reStartTime integerValue]]; | ||
| 503 | + if (_isEndRunning) { | ||
| 504 | + [paramInfo2 setEndTime:_endRunningDate]; | ||
| 505 | + }else{ | ||
| 506 | + [paramInfo2 setEndTime:self.recordReInTime]; | ||
| 507 | + } | ||
| 508 | + [paramInfo2 setEntityName:CNUserShareModelUid]; | ||
| 509 | + [paramInfo2 setIsProcessed:true]; | ||
| 510 | + BTKQueryTrackProcessOption *processOption2 = [[BTKQueryTrackProcessOption alloc] init]; | ||
| 511 | + processOption2.radiusThreshold = 100; | ||
| 512 | + processOption2.denoise = true; | ||
| 513 | + processOption2.vacuate = true; | ||
| 514 | + processOption2.mapMatch = false; | ||
| 515 | + processOption2.transportMode = BTK_TRACK_PROCESS_OPTION_TRANSPORT_MODE_WALKING; | ||
| 516 | + paramInfo2.processOption = processOption; | ||
| 517 | + paramInfo2.supplementMode = BTK_TRACK_PROCESS_OPTION_SUPPLEMENT_MODE_WALKING; | ||
| 518 | + CNHistoryViewModel *vm2 = [[CNHistoryViewModel alloc] init]; | ||
| 519 | + vm2.completionHandler = ^(NSArray *points) { | ||
| 520 | + if (points.count > 0) { | ||
| 521 | + NSMutableArray *mu = [NSMutableArray arrayWithCapacity:0]; | ||
| 522 | + for (CNHistoryTrackPoint *point in points) { | ||
| 523 | + CLLocation *location = [[CLLocation alloc] initWithLatitude:point.coordinate.latitude longitude:point.coordinate.longitude]; | ||
| 524 | + [mu addObject:location]; | ||
| 525 | + } | ||
| 526 | + self.firstStopAfterLinePoint = [mu lastObject]; | ||
| 527 | + //画线 | ||
| 528 | + CLLocationCoordinate2D coors[mu.count]; | ||
| 529 | + NSInteger count = 0; | ||
| 530 | + for (size_t i = 0; i < mu.count; i++) { | ||
| 531 | + CLLocation *location = [mu objectAtIndex:i]; | ||
| 532 | + coors[i] = location.coordinate; | ||
| 533 | + count++; | ||
| 534 | + } | ||
| 535 | + self.frontStopAfterPolyLine = [BMKPolyline polylineWithCoordinates:coors count:count]; | ||
| 536 | + dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 537 | + if (self.frontStopAfterPolyLine) {// 防止重复绘制 | ||
| 538 | + [self.mapView removeOverlay:self.frontStopAfterPolyLine]; | ||
| 539 | + } | ||
| 540 | + [self.mapView addOverlay:self.frontStopAfterPolyLine]; | ||
| 541 | + }); | ||
| 542 | + } | ||
| 543 | + }; | ||
| 544 | + [vm2 queryHistoryWithParam:paramInfo2]; | ||
| 545 | +} | ||
| 546 | +- (void)queryOneMineHistoryLine{ | ||
| 547 | + CNRunExitModel *tempM = self.exitModel; | ||
| 548 | + CNHistoryTrackParam * paramInfo =[[CNHistoryTrackParam alloc]init]; | ||
| 549 | + [paramInfo setStartTime:[tempM.startTime integerValue]]; | ||
| 550 | + if (_isEndRunning) { | ||
| 551 | + [paramInfo setEndTime:_endRunningDate]; | ||
| 552 | + }else{ | ||
| 553 | + [paramInfo setEndTime:self.recordReInTime]; | ||
| 554 | + } | ||
| 555 | + [paramInfo setEntityName:CNUserShareModelUid]; | ||
| 556 | + [paramInfo setIsProcessed:true]; | ||
| 557 | + BTKQueryTrackProcessOption *processOption = [[BTKQueryTrackProcessOption alloc] init]; | ||
| 558 | + processOption.radiusThreshold = 100; | ||
| 559 | + processOption.denoise = true; | ||
| 560 | + processOption.vacuate = true; | ||
| 561 | + processOption.mapMatch = false; | ||
| 562 | + processOption.transportMode = BTK_TRACK_PROCESS_OPTION_TRANSPORT_MODE_WALKING; | ||
| 563 | + paramInfo.processOption = processOption; | ||
| 564 | + paramInfo.supplementMode = BTK_TRACK_PROCESS_OPTION_SUPPLEMENT_MODE_WALKING; | ||
| 565 | + CNHistoryViewModel *vm = [[CNHistoryViewModel alloc] init]; | ||
| 566 | + vm.completionHandler = ^(NSArray *points) { | ||
| 567 | + if (points.count > 0) { | ||
| 568 | + NSMutableArray *mu = [NSMutableArray arrayWithCapacity:0]; | ||
| 569 | + for (CNHistoryTrackPoint *point in points) { | ||
| 570 | + CLLocation *location = [[CLLocation alloc] initWithLatitude:point.coordinate.latitude longitude:point.coordinate.longitude]; | ||
| 571 | + [mu addObject:location]; | ||
| 572 | + } | ||
| 573 | + self.firstStopAfterLinePoint = [mu lastObject]; | ||
| 574 | + //画线 | ||
| 575 | + CLLocationCoordinate2D coors[mu.count]; | ||
| 576 | + NSInteger count = 0; | ||
| 577 | + for (size_t i = 0; i < mu.count; i++) { | ||
| 578 | + CLLocation *location = [mu objectAtIndex:i]; | ||
| 579 | + coors[i] = location.coordinate; | ||
| 580 | + count++; | ||
| 581 | + } | ||
| 582 | + self.frontStopAfterPolyLine = [BMKPolyline polylineWithCoordinates:coors count:count]; | ||
| 583 | + dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 584 | + if (self.frontStopAfterPolyLine) {// 防止重复绘制 | ||
| 585 | + [self.mapView removeOverlay:self.frontStopAfterPolyLine]; | ||
| 586 | + } | ||
| 587 | + [self.mapView addOverlay:self.frontStopAfterPolyLine]; | ||
| 588 | + }); | ||
| 589 | + } | ||
| 590 | + }; | ||
| 591 | + [vm queryHistoryWithParam:paramInfo]; | ||
| 592 | +} | ||
| 593 | + | ||
| 594 | +- (void)addMapOriginalLine{ | ||
| 595 | + CNHistoryTrackParam * paramInfo =[[CNHistoryTrackParam alloc]init]; | ||
| 596 | + [paramInfo setStartTime:[self.sportsDetailModel.startTime integerValue]]; | ||
| 597 | + [paramInfo setEndTime:[self.sportsDetailModel.endTime integerValue]]; | ||
| 598 | + [paramInfo setEntityName:self.sportsDetailModel.entityName]; | ||
| 599 | + [paramInfo setIsProcessed:true]; | ||
| 600 | + BTKQueryTrackProcessOption *processOption = [[BTKQueryTrackProcessOption alloc] init]; | ||
| 601 | + processOption.radiusThreshold = 100; | ||
| 602 | + processOption.denoise = true; | ||
| 603 | + processOption.vacuate = true; | ||
| 604 | + processOption.mapMatch = false; | ||
| 605 | + processOption.transportMode = BTK_TRACK_PROCESS_OPTION_TRANSPORT_MODE_WALKING; | ||
| 606 | + paramInfo.processOption = processOption; | ||
| 607 | + paramInfo.supplementMode = BTK_TRACK_PROCESS_OPTION_SUPPLEMENT_MODE_WALKING; | ||
| 608 | + CNHistoryViewModel *vm = [[CNHistoryViewModel alloc] init]; | ||
| 609 | + vm.completionHandler = ^(NSArray *points) { | ||
| 610 | + NSMutableArray *pointNodes = [NSMutableArray arrayWithCapacity:0]; | ||
| 611 | + for (CNHistoryTrackPoint *point in points) { | ||
| 612 | + CNLinePointNode *pointNode = [[CNLinePointNode alloc] init]; | ||
| 613 | + pointNode.coordinate = point.coordinate; | ||
| 614 | + [pointNodes addObject:pointNode]; | ||
| 615 | + } | ||
| 616 | + CLLocationCoordinate2D paths[pointNodes.count]; | ||
| 617 | + for (NSUInteger i = 0; i < pointNodes.count; i ++) { | ||
| 618 | + CNLinePointNode *node = pointNodes[i]; | ||
| 619 | + paths[i] = node.coordinate; | ||
| 620 | + } | ||
| 621 | + self.originalPolyLine = [BMKPolyline polylineWithCoordinates:paths count:pointNodes.count]; | ||
| 622 | + self->_startAnnotation = [[BMKPointAnnotation alloc] init]; | ||
| 623 | + self->_startAnnotation.coordinate = paths[0]; | ||
| 624 | + self->_startAnnotation.title = @"起点"; | ||
| 625 | + self->_endAnnotation = [[BMKPointAnnotation alloc] init]; | ||
| 626 | + self->_endAnnotation.coordinate = paths[pointNodes.count-1]; | ||
| 627 | + self->_endAnnotation.title = @"终点"; | ||
| 628 | + | ||
| 629 | + //确认终点后,先查询客服端围栏,后面再判断要不要添加客户端围栏 | ||
| 630 | + [self queryLocalFence]; | ||
| 631 | + dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 632 | + /** | ||
| 633 | + 向地图View添加Overlay,需要实现BMKMapViewDelegate的-mapView:viewForOverlay: | ||
| 634 | + 方法来生成标注对应的View | ||
| 635 | + | ||
| 636 | + @param overlay 要添加的overlay | ||
| 637 | + */ | ||
| 638 | + [self.mapView addOverlay:self.originalPolyLine]; | ||
| 639 | + //将标注添加到当前地图View中 | ||
| 640 | + [self->_mapView addAnnotation:self->_startAnnotation]; | ||
| 641 | + //将标注添加到当前地图View中 | ||
| 642 | + [self->_mapView addAnnotation:self->_endAnnotation]; | ||
| 643 | + [self mapViewFitPolyLine:self.originalPolyLine]; | ||
| 644 | + | ||
| 645 | + }); | ||
| 646 | + }; | ||
| 647 | + [vm queryHistoryWithParam:paramInfo]; | ||
| 648 | +} | ||
| 649 | + | ||
| 650 | +//根据polyline设置地图范围 | ||
| 651 | +- (void)mapViewFitPolyLine:(BMKPolyline *) polyLine { | ||
| 652 | + CGFloat leftTopX, leftTopY, rightBottomX, rightBottomY; | ||
| 653 | + if (polyLine.pointCount < 1) { | ||
| 654 | + return; | ||
| 655 | + } | ||
| 656 | + BMKMapPoint pt = polyLine.points[0]; | ||
| 657 | + // 左上角顶点 | ||
| 658 | + leftTopX = pt.x; | ||
| 659 | + leftTopY = pt.y; | ||
| 660 | + // 右下角顶点 | ||
| 661 | + rightBottomX = pt.x; | ||
| 662 | + rightBottomY = pt.y; | ||
| 663 | + for (int i = 1; i < polyLine.pointCount; i++) { | ||
| 664 | + BMKMapPoint pt = polyLine.points[i]; | ||
| 665 | + leftTopX = pt.x < leftTopX ? pt.x : leftTopX; | ||
| 666 | + leftTopY = pt.y < leftTopY ? pt.y : leftTopY; | ||
| 667 | + rightBottomX = pt.x > rightBottomX ? pt.x : rightBottomX; | ||
| 668 | + rightBottomY = pt.y > rightBottomY ? pt.y : rightBottomY; | ||
| 669 | + } | ||
| 670 | + BMKMapRect rect; | ||
| 671 | + rect.origin = BMKMapPointMake(leftTopX, leftTopY); | ||
| 672 | + rect.size = BMKMapSizeMake(rightBottomX - leftTopX, rightBottomY - leftTopY); | ||
| 673 | + UIEdgeInsets padding = UIEdgeInsetsMake(100, 50, 100, 50); | ||
| 674 | + [_mapView fitVisibleMapRect:rect edgePadding:padding withAnimated:YES]; | ||
| 675 | +} | ||
| 676 | + | ||
| 677 | +- (void)addMapBottomView{ | ||
| 678 | + [self.mapView addSubview:self.mapBottomView]; | ||
| 679 | + [self.mapBottomView mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 680 | + make.left.right.equalTo(self.mapView); | ||
| 681 | + make.bottom.equalTo(self.mapView.mas_bottom).offset(-kVerticalBottomSafeHeight); | ||
| 682 | + make.height.equalTo(@(130)); | ||
| 683 | + }]; | ||
| 684 | + | ||
| 685 | + [self.mapView addSubview:self.resetBtn]; | ||
| 686 | + [self.resetBtn mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 687 | + make.left.equalTo(self.mapView).offset(10); | ||
| 688 | + make.bottom.equalTo(self.mapBottomView.mas_top).offset(-20); | ||
| 689 | + make.size.mas_equalTo(CGSizeMake(48, 48)); | ||
| 690 | + }]; | ||
| 691 | + [self.mapBottomView addSubview:self.mapCurrentTimeLab]; | ||
| 692 | + [self.mapCurrentTimeLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 693 | + make.centerX.equalTo(self.mapBottomView); | ||
| 694 | + make.top.equalTo(self.mapBottomView).offset(27); | ||
| 695 | + }]; | ||
| 696 | + [self.mapBottomView addSubview:self.mapTimeLab]; | ||
| 697 | + [self.mapTimeLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 698 | + make.centerX.equalTo(self.mapBottomView); | ||
| 699 | + make.top.equalTo(self.mapCurrentTimeLab.mas_bottom).offset(21); | ||
| 700 | + }]; | ||
| 701 | + [self.mapBottomView addSubview:self.mapCurrentSpeedLab]; | ||
| 702 | + [self.mapCurrentSpeedLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 703 | + make.centerY.equalTo(self.mapCurrentTimeLab); | ||
| 704 | + make.left.equalTo(self.mapBottomView).offset(30); | ||
| 705 | + make.width.equalTo(@(SCREEN_WIDTH/3-40)); | ||
| 706 | + }]; | ||
| 707 | + [self.mapBottomView addSubview:self.mapSpeedLab]; | ||
| 708 | + [self.mapSpeedLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 709 | + make.centerY.equalTo(self.mapTimeLab); | ||
| 710 | + make.centerX.equalTo(self.mapCurrentSpeedLab); | ||
| 711 | + }]; | ||
| 712 | + [self.mapBottomView addSubview:self.mapCurrentKMLab]; | ||
| 713 | + [self.mapCurrentKMLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 714 | + make.centerY.equalTo(self.mapCurrentTimeLab); | ||
| 715 | + make.right.equalTo(self.mapBottomView.mas_right).offset(-40); | ||
| 716 | + }]; | ||
| 717 | + [self.mapBottomView addSubview:self.mapKMLab]; | ||
| 718 | + [self.mapKMLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 719 | + make.centerY.equalTo(self.mapTimeLab); | ||
| 720 | + make.centerX.equalTo(self.mapCurrentKMLab); | ||
| 721 | + }]; | ||
| 722 | +} | ||
| 723 | + | ||
| 724 | +-(void)setGpsState:(CNLocationGPSState)gpsState{ | ||
| 725 | + _gpsState = gpsState; | ||
| 726 | + switch (gpsState) { | ||
| 727 | + case CNLocationGPSStateGood:{ | ||
| 728 | + self.currentGPSImgView.image = [UIImage imageNamed:@"signal-good"]; | ||
| 729 | + self.currentGPSLab.hidden = YES; | ||
| 730 | + [self.GPSBtn setImage:[UIImage imageNamed:@"signal-good"] forState:UIControlStateNormal]; | ||
| 731 | + self.tipGPSBtn.hidden = YES; | ||
| 732 | + } | ||
| 733 | + break; | ||
| 734 | + case CNLocationGPSStateMedium:{ | ||
| 735 | + self.currentGPSImgView.image = [UIImage imageNamed:@"signal-mid"]; | ||
| 736 | + self.currentGPSLab.hidden = YES; | ||
| 737 | + [self.GPSBtn setImage:[UIImage imageNamed:@"signal-mid"] forState:UIControlStateNormal]; | ||
| 738 | + self.tipGPSBtn.hidden = YES; | ||
| 739 | + } | ||
| 740 | + break; | ||
| 741 | + case CNLocationGPSStatePoor:{ | ||
| 742 | + self.currentGPSImgView.image = [UIImage imageNamed:@"signal-low"]; | ||
| 743 | + self.currentGPSLab.hidden = NO; | ||
| 744 | + self.currentGPSLab.text = @"信号糟糕,数据准确度低"; | ||
| 745 | + [self.GPSBtn setImage:[UIImage imageNamed:@"signal-low"] forState:UIControlStateNormal]; | ||
| 746 | + self.tipGPSBtn.hidden = NO; | ||
| 747 | + [self.tipGPSBtn setTitle:@"信号糟糕,数据准确度低" forState:UIControlStateNormal]; | ||
| 748 | + } | ||
| 749 | + break; | ||
| 750 | + case CNLocationGPSStateNull:{ | ||
| 751 | + self.currentGPSImgView.image = [UIImage imageNamed:@"signal-none"]; | ||
| 752 | + self.currentGPSLab.hidden = NO; | ||
| 753 | + self.currentGPSLab.text = @"无信号,无法进行数据记录"; | ||
| 754 | + [self.GPSBtn setImage:[UIImage imageNamed:@"signal-none"] forState:UIControlStateNormal]; | ||
| 755 | + self.tipGPSBtn.hidden = NO; | ||
| 756 | + [self.tipGPSBtn setTitle:@"无信号,无法进行数据记录" forState:UIControlStateNormal]; | ||
| 757 | + } | ||
| 758 | + break; | ||
| 759 | + default: | ||
| 760 | + break; | ||
| 761 | + } | ||
| 762 | +} | ||
| 763 | + | ||
| 764 | +- (void)backBtnAction:(id)sender{ | ||
| 765 | + if (_isEndRunning) { | ||
| 766 | + [[NSNotificationCenter defaultCenter] removeObserver:self name:TrackServiceOperationResultNotification object:nil]; | ||
| 767 | + if (_endTimer) { | ||
| 768 | + [_endTimer invalidate]; | ||
| 769 | + _endTimer = nil; | ||
| 770 | + } | ||
| 771 | + if (_startRunningTimer) { | ||
| 772 | + [_startRunningTimer invalidate]; | ||
| 773 | + _startRunningTimer = nil; | ||
| 774 | + } | ||
| 775 | + if ([self.delegate respondsToSelector:@selector(backToFrontVC)]) { | ||
| 776 | + [self.delegate backToFrontVC]; | ||
| 777 | + } | ||
| 778 | + [self.navigationController popViewControllerAnimated:YES]; | ||
| 779 | + }else{ | ||
| 780 | + self.mapView.hidden = YES; | ||
| 781 | + self.fristBgView.hidden = NO; | ||
| 782 | + } | ||
| 783 | +} | ||
| 784 | + | ||
| 785 | +- (void)resetBtnAction:(id)sender{ | ||
| 786 | + [self.mapView setCenterCoordinate:self.userLocation.location.coordinate animated:YES]; | ||
| 787 | +} | ||
| 788 | +#pragma mark -- private 本地地理围栏 | ||
| 789 | +//删除客户端地理围栏 | ||
| 790 | +- (void)deleteLocalFence{ | ||
| 791 | + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | ||
| 792 | + // 构建请求对象 | ||
| 793 | + BTKDeleteLocalFenceRequest *request = [[BTKDeleteLocalFenceRequest alloc] initWithMonitoredObject:CNUserShareModelUid fenceIDs:nil tag:2]; | ||
| 794 | + // 删除客户端地理围栏 | ||
| 795 | + [[BTKFenceAction sharedInstance] deleteLocalFenceWith:request delegate:self]; | ||
| 796 | + }); | ||
| 797 | +} | ||
| 798 | +//删除本地地理围栏的回调 | ||
| 799 | +-(void)onDeleteLocalFence:(NSData *)response{ | ||
| 800 | + NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingAllowFragments error:nil]; | ||
| 801 | + if (nil == dict) { | ||
| 802 | + NSLog(@"Local Fence Delete格式转换出错"); | ||
| 803 | + } | ||
| 804 | + if (0 != [dict[@"status"] intValue]) { | ||
| 805 | + NSLog(@"客户端地理围栏删除返回错误"); | ||
| 806 | + } | ||
| 807 | + if (_isEndRunning) { | ||
| 808 | + return; | ||
| 809 | + } | ||
| 810 | + // 查询一次 | ||
| 811 | + [self queryLocalFence]; | ||
| 812 | +} | ||
| 813 | +- (void)queryLocalFence { | ||
| 814 | + // 查询所有以当前登录Entity为监控对象的客户端地理围栏 | ||
| 815 | + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | ||
| 816 | + BTKQueryLocalFenceRequest *request = [[BTKQueryLocalFenceRequest alloc] initWithMonitoredObject:CNUserShareModelUid fenceIDs:nil tag:1]; | ||
| 817 | + [[BTKFenceAction sharedInstance] queryLocalFenceWith:request delegate:self]; | ||
| 818 | + }); | ||
| 819 | +} | ||
| 820 | + | ||
| 821 | +/** | ||
| 822 | + 查询客户端围栏实体的回调方法 | ||
| 823 | + @param response 符合条件的客户端地理围栏 | ||
| 824 | + */ | ||
| 825 | +-(void)onQueryLocalFence:(NSData *)response { | ||
| 826 | + NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingAllowFragments error:nil]; | ||
| 827 | + if (_isEndRunning) { | ||
| 828 | + //如果结束跑步,地理围栏相关的都不执行了 | ||
| 829 | + return; | ||
| 830 | + } | ||
| 831 | + BOOL isError = false; | ||
| 832 | + if (nil == dict) { | ||
| 833 | + NSLog(@"Local Fence List查询格式转换出错"); | ||
| 834 | + | ||
| 835 | + } | ||
| 836 | + if (0 != [dict[@"status"] intValue]) { | ||
| 837 | + NSLog(@"客户端本地地理围栏查询返回错误"); | ||
| 838 | + isError = YES; | ||
| 839 | + } | ||
| 840 | + if (isError) { | ||
| 841 | + //上面出错就直接删除 | ||
| 842 | + [self deleteLocalFence]; | ||
| 843 | + return; | ||
| 844 | + } | ||
| 845 | + // 如果之前没有创建过客户端围栏的话,查出来的结果就是0个围栏。这时候弹窗提示用户,去新建一个客户端围栏 | ||
| 846 | + NSInteger size = [dict[@"size"] intValue]; | ||
| 847 | + if (size == 0) { | ||
| 848 | + NSLog(@"还没有创建过客户端围栏"); | ||
| 849 | + //创建本地围栏 | ||
| 850 | + [self createLocalFence]; | ||
| 851 | + return; | ||
| 852 | + } | ||
| 853 | + //全部删除客户端地理围栏 | ||
| 854 | + if ([dict[@"fences"] isKindOfClass:[NSArray class]] && ((NSArray *)dict[@"fences"]).count > 0) { | ||
| 855 | + //删除所有后再删除的回调里查询 | ||
| 856 | + [self deleteLocalFence]; | ||
| 857 | + } | ||
| 858 | +} | ||
| 859 | + | ||
| 860 | +//添加本地地理围栏(圆形) | ||
| 861 | +- (void)createLocalFence{ | ||
| 862 | + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | ||
| 863 | + BTKLocalCircleFence *fence = [[BTKLocalCircleFence alloc] initWithCenter:self.endAnnotation.coordinate radius:20 coordType:BTK_COORDTYPE_GCJ02 denoiseAccuracy:20 fenceName:@"localFence" monitoredObject:CNUserShareModelUid]; | ||
| 864 | + BTKCreateLocalFenceRequest *request = [[BTKCreateLocalFenceRequest alloc] initWithLocalCircleFence:fence tag:1]; | ||
| 865 | + [[BTKFenceAction sharedInstance] createLocalFenceWith:request delegate:self]; | ||
| 866 | + }); | ||
| 867 | +} | ||
| 868 | + | ||
| 869 | +//创建本地围栏的回调 | ||
| 870 | +- (void)onCreateLocalFence:(NSData *)response{ | ||
| 871 | + NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingAllowFragments error:nil]; | ||
| 872 | + if (nil == dict) { | ||
| 873 | + NSLog(@"Local Fence Create 格式转换出错"); | ||
| 874 | + return; | ||
| 875 | + } | ||
| 876 | + if (0 != [dict[@"status"] intValue]) { | ||
| 877 | + NSLog(@"Local Fence Create 返回错误"); | ||
| 878 | + //创建失败,重新创建 | ||
| 879 | + return; | ||
| 880 | + } | ||
| 881 | + if (!dict[@"fence_id"]) { | ||
| 882 | + return; | ||
| 883 | + } | ||
| 884 | + localFenceId = [NSNumber numberWithFloat:[dict[@"fence_id"] floatValue]]; | ||
| 885 | + //创建成功后查询一次本地围栏的实时状态,目的是使本地地理围栏生效 | ||
| 886 | + if (localFenceId) { | ||
| 887 | + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | ||
| 888 | + BTKQueryLocalFenceStatusRequest *request = [[BTKQueryLocalFenceStatusRequest alloc] initWithMonitoredObject:CNUserShareModelUid fenceIDs:@[self->localFenceId] tag:1]; | ||
| 889 | + [[BTKFenceAction sharedInstance] queryLocalFenceStatusWith:request delegate:self]; | ||
| 890 | + | ||
| 891 | +// #pragma mark -- TODO 把客户端地理围栏画出来 | ||
| 892 | +// BMKPointAnnotation *centerAnnotation = [[BMKPointAnnotation alloc] init]; | ||
| 893 | +// centerAnnotation.coordinate = self.endAnnotation.coordinate; | ||
| 894 | +// centerAnnotation.title = @"圆心"; | ||
| 895 | +// BMKCircle *radiusCircle = [[BMKCircle alloc] init]; | ||
| 896 | +// radiusCircle.coordinate = self.endAnnotation.coordinate; | ||
| 897 | +//// double radius = [self.radiusTextField.text doubleValue]; | ||
| 898 | +//// if (fabs(radius) > DBL_EPSILON) { | ||
| 899 | +//// radiusCircle.radius = radius; | ||
| 900 | +//// } else { | ||
| 901 | +// radiusCircle.radius = 10.0; | ||
| 902 | +// [self.mapView addAnnotation:centerAnnotation]; | ||
| 903 | +// [self.mapView addOverlay:radiusCircle]; | ||
| 904 | + | ||
| 905 | +// } | ||
| 906 | + }); | ||
| 907 | + } | ||
| 908 | +} | ||
| 909 | + | ||
| 910 | +/** | ||
| 911 | + 查询监控对象和客户端地理围栏的位置关系的回调方法 | ||
| 912 | + | ||
| 913 | + @param response 查询结果 | ||
| 914 | + */ | ||
| 915 | +-(void)onQueryLocalFenceStatus:(NSData *)response{ | ||
| 916 | + if (_isStopRun) { | ||
| 917 | + return; | ||
| 918 | + } | ||
| 919 | + NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingAllowFragments error:nil]; | ||
| 920 | + if (nil == dict) { | ||
| 921 | + NSLog(@"Local Fence Query格式转换出错"); | ||
| 922 | + return; | ||
| 923 | + } | ||
| 924 | + if (0 != [dict[@"status"] intValue]) { | ||
| 925 | + NSLog(@"客户端地理围栏删除返回错误"); | ||
| 926 | + } | ||
| 927 | + //不做成功和失败的处理,目的是使监控本地地理围栏生效 | ||
| 928 | +} | ||
| 929 | + | ||
| 930 | +//查询本地围栏的警报历史记录,是否经过过终点 | ||
| 931 | +- (void)queryLocalHistoryAlarm{ | ||
| 932 | + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | ||
| 933 | + BTKQueryLocalFenceHistoryAlarmRequest *request = [[BTKQueryLocalFenceHistoryAlarmRequest alloc] initWithMonitoredObject:CNUserShareModelUid fenceIDs:@[self->localFenceId] startTime:self->_startRunningDate endTime:self->_endRunningDate tag:1]; | ||
| 934 | + // 发起查询请求 | ||
| 935 | + [[BTKFenceAction sharedInstance] queryLocalFenceHistoryAlarmWith:request delegate:self]; | ||
| 936 | + }); | ||
| 937 | +} | ||
| 938 | + | ||
| 939 | +/** | ||
| 940 | + 查询客户端地理围栏历史报警信息的回调方法 | ||
| 941 | + | ||
| 942 | + @param response 查询结果 | ||
| 943 | + */ | ||
| 944 | +-(void)onQueryLocalFenceHistoryAlarm:(NSData *)response{ | ||
| 945 | + BOOL errorOrNoMessage = false; | ||
| 946 | + NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingAllowFragments error:nil]; | ||
| 947 | + if (nil == dict) { | ||
| 948 | + errorOrNoMessage = YES; | ||
| 949 | + } | ||
| 950 | + if (dict && 0 != [dict[@"status"] intValue]) { | ||
| 951 | + NSLog(@"Query Local Fence History Alarm 返回错误"); | ||
| 952 | + //历史报警查询失败 | ||
| 953 | + errorOrNoMessage = YES; | ||
| 954 | + } | ||
| 955 | + if (dict && 0 == [dict[@"size"] intValue]) { | ||
| 956 | + //过去24小时内没有报警信息 | ||
| 957 | + errorOrNoMessage = YES; | ||
| 958 | + } | ||
| 959 | + if (errorOrNoMessage) {//表示没有查询到或有错误,就不继续处理了,按照下面说明处理 | ||
| 960 | + //使用当前位置查询距离终点的距离,如果距离在范围内,则认为经过了终点 | ||
| 961 | + [self judgeSuccessTrack]; | ||
| 962 | + return; | ||
| 963 | + } | ||
| 964 | + // 解析数据 | ||
| 965 | +// NSMutableArray *alarmInfoText = [NSMutableArray arrayWithCapacity:[dict[@"size"] intValue]]; | ||
| 966 | + BOOL isEnterLocal = false; | ||
| 967 | + for (NSDictionary *alarm in dict[@"alarms"]) { | ||
| 968 | +// NSString *fenceName = alarm[@"fence_name"]; | ||
| 969 | +// NSString *monitoredObject = alarm[@"monitored_person"]; | ||
| 970 | +// NSString *action = nil; | ||
| 971 | + if ([alarm[@"action"] isEqualToString:@"enter"]) { | ||
| 972 | +// action = @"进入"; | ||
| 973 | + isEnterLocal = YES;//表示进入过本地地理围栏 | ||
| 974 | + break; | ||
| 975 | + } else if ([alarm[@"action"] isEqualToString:@"exit"]) { | ||
| 976 | +// action = @"离开"; | ||
| 977 | + } | ||
| 978 | + } | ||
| 979 | + if (!isEnterLocal) {//如果没有进入本地地理围栏的结果,则使用距离判断 | ||
| 980 | + [self judgeSuccessTrack]; | ||
| 981 | + }else{ | ||
| 982 | + //经过了终点 | ||
| 983 | + [self queryCurrentRunningEndPoint:^(NSArray *points) { | ||
| 984 | + __block int successCount = 0; | ||
| 985 | + __block NSMutableArray *mutArr = [NSMutableArray arrayWithArray:points]; | ||
| 986 | + for (CNLiveSportsCoordinatesModel *pointNode in self.sportsDetailModel.latLongitude) { | ||
| 987 | + CLLocation *originLocation = [[CLLocation alloc] initWithLatitude:[pointNode.latitude doubleValue] longitude:[pointNode.longitude doubleValue]]; | ||
| 988 | + [mutArr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { | ||
| 989 | + CNHistoryTrackPoint *minePoint = obj; | ||
| 990 | + CLLocation *currentLocation = [[CLLocation alloc] initWithLatitude:minePoint.coordinate.latitude longitude:minePoint.coordinate.longitude]; | ||
| 991 | + CLLocationDistance distance = [originLocation distanceFromLocation:currentLocation]; | ||
| 992 | + if (distance < 50) {//表示这个点已经完成 | ||
| 993 | + [mutArr removeObjectsInRange:NSMakeRange(0, idx+1)]; | ||
| 994 | + successCount ++; | ||
| 995 | + *stop = YES; | ||
| 996 | + } | ||
| 997 | + }]; | ||
| 998 | + } | ||
| 999 | + if (successCount*1.000/self.sportsDetailModel.latLongitude.count*1.000 > 0.70) {//大于60%则认为任务完成 | ||
| 1000 | + dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 1001 | + self->_endStatus = @"路线完成"; | ||
| 1002 | + | ||
| 1003 | + self.successStateLab.text = self->_endStatus; | ||
| 1004 | + [self uploadData:YES img:nil]; | ||
| 1005 | + }); | ||
| 1006 | + }else{ | ||
| 1007 | + dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 1008 | + self->_endStatus = @"路线未完成"; | ||
| 1009 | + self.successStateLab.text = self->_endStatus; | ||
| 1010 | + [self uploadData:NO img:nil]; | ||
| 1011 | + }); | ||
| 1012 | + } | ||
| 1013 | + }]; | ||
| 1014 | + } | ||
| 1015 | +} | ||
| 1016 | + | ||
| 1017 | +#pragma mark -- private 服务端地理围栏 : 超出或进入围栏警报 | ||
| 1018 | +//服务端 | ||
| 1019 | +-(void)serviceGetPushMessageHandler:(NSNotification *)notification { | ||
| 1020 | + if (_isEndRunning || _isStopRun) {//暂停或结束都不接收通知 | ||
| 1021 | + return; | ||
| 1022 | + } | ||
| 1023 | + NSDictionary *info = notification.userInfo; | ||
| 1024 | + NSDictionary *dict = info[@"message"]; | ||
| 1025 | +// dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 1026 | +// [QMUITips showInfo:str inView:AppKeyWindow hideAfterDelay:2]; | ||
| 1027 | +// }); | ||
| 1028 | +// NSDictionary *dict = @{ | ||
| 1029 | +// @"action":action, | ||
| 1030 | +// @"fenceType":fenceType, | ||
| 1031 | +// @"fenceID":fenceID | ||
| 1032 | +// }; | ||
| 1033 | + NSString *action = dict[@"action"];//进入/离开 | ||
| 1034 | + NSString *fenceType = dict[@"fenceType"];//围栏类型 | ||
| 1035 | + NSString *fenceID = dict[@"fenceID"];//围栏id | ||
| 1036 | + | ||
| 1037 | + if ([fenceType isEqualToString:@"服务端围栏"] && [fenceID isEqualToString:[NSString stringWithFormat:@"%@",self.sportsDetailModel.fenceId]]) { | ||
| 1038 | + if ([action isEqualToString:@"离开"]) { | ||
| 1039 | + dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 1040 | + UIAlertController *actionAlert = [UIAlertController alertControllerWithTitle:nil message:@"您已偏离路径轨迹\n请您及时回归路径" preferredStyle:UIAlertControllerStyleAlert]; | ||
| 1041 | + UIAlertAction *action = [UIAlertAction actionWithTitle:@"我知道了" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { | ||
| 1042 | + }]; | ||
| 1043 | + [actionAlert addAction:action]; | ||
| 1044 | + [self presentViewController:actionAlert animated:YES completion:nil]; | ||
| 1045 | + }); | ||
| 1046 | + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | ||
| 1047 | + AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); | ||
| 1048 | + AVSpeechSynthesizer *voice= [[AVSpeechSynthesizer alloc]init]; | ||
| 1049 | + AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc]initWithString:@"您已偏离路径轨迹,请您及时回归路径"]; | ||
| 1050 | + AVSpeechSynthesisVoice *language = [AVSpeechSynthesisVoice voiceWithLanguage:@"zh-CN"]; | ||
| 1051 | + utterance.voice= language; | ||
| 1052 | + [voice speakUtterance:utterance]; | ||
| 1053 | + }); | ||
| 1054 | + }else{//进入 | ||
| 1055 | + dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 1056 | + UIAlertController *actionAlert = [UIAlertController alertControllerWithTitle:nil message:@"您已回归路径轨迹\n继续参与运动吧" preferredStyle:UIAlertControllerStyleAlert]; | ||
| 1057 | + UIAlertAction *action = [UIAlertAction actionWithTitle:@"我知道了" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { | ||
| 1058 | + }]; | ||
| 1059 | + [actionAlert addAction:action]; | ||
| 1060 | + [self presentViewController:actionAlert animated:YES completion:nil]; | ||
| 1061 | + }); | ||
| 1062 | + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | ||
| 1063 | + AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); | ||
| 1064 | + AVSpeechSynthesizer *voice= [[AVSpeechSynthesizer alloc]init]; | ||
| 1065 | + AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc]initWithString:@"您已回归路径轨迹,继续参与运动吧"]; | ||
| 1066 | + AVSpeechSynthesisVoice *language = [AVSpeechSynthesisVoice voiceWithLanguage:@"zh-CN"]; | ||
| 1067 | + utterance.voice= language; | ||
| 1068 | + [voice speakUtterance:utterance]; | ||
| 1069 | + }); | ||
| 1070 | + } | ||
| 1071 | + }else if ([fenceType isEqualToString:@"客户端围栏"] && [fenceID isEqualToString:[NSString stringWithFormat:@"%@",localFenceId?localFenceId:@""]] && [action isEqualToString:@"进入"]){//客户端 | ||
| 1072 | + CNRunExitModel *model = [[CNTrackLoaclDataManager shareManager]getExitModel:CNUserShareModelUid]; | ||
| 1073 | + if ([model.step isEqualToString:@"<null>"] || [model.step intValue] <= 100) { | ||
| 1074 | + return; | ||
| 1075 | + } | ||
| 1076 | + BOOL b = [[NSUserDefaults standardUserDefaults] boolForKey:@"isShowOnce"]; | ||
| 1077 | + if (b) { | ||
| 1078 | + return; | ||
| 1079 | + } | ||
| 1080 | + [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"isShowOnce"]; | ||
| 1081 | + //已经到达目的地 弹窗 | ||
| 1082 | + dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 1083 | + UIAlertController *actionAlert = [UIAlertController alertControllerWithTitle:nil message:@"您已经到达终点附近\n可以结束运动了" preferredStyle:UIAlertControllerStyleAlert]; | ||
| 1084 | + UIAlertAction *action = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { | ||
| 1085 | + self.fristBgView.hidden = NO; | ||
| 1086 | + self.mapView.hidden = YES; | ||
| 1087 | + }]; | ||
| 1088 | + [actionAlert addAction:action]; | ||
| 1089 | + [self presentViewController:actionAlert animated:YES completion:nil]; | ||
| 1090 | + }); | ||
| 1091 | + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | ||
| 1092 | + AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); | ||
| 1093 | + AVSpeechSynthesizer *voice= [[AVSpeechSynthesizer alloc]init]; | ||
| 1094 | + AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc]initWithString:@"您已经到达终点附近,可以结束运动了"]; | ||
| 1095 | + AVSpeechSynthesisVoice *language = [AVSpeechSynthesisVoice voiceWithLanguage:@"zh-CN"]; | ||
| 1096 | + utterance.voice= language; | ||
| 1097 | + [voice speakUtterance:utterance]; | ||
| 1098 | + }); | ||
| 1099 | + | ||
| 1100 | + } | ||
| 1101 | +} | ||
| 1102 | + | ||
| 1103 | +#pragma mark -- privat 地理围栏:围栏实时状态查询 | ||
| 1104 | +- (void)queryRealtimeStatus{ | ||
| 1105 | + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | ||
| 1106 | + BTKQueryServerFenceStatusRequest *request = [[BTKQueryServerFenceStatusRequest alloc] initWithMonitoredObject:CNUserShareModelUid fenceIDs:@[self.sportsDetailModel.fenceId] ServiceID:BDMapServiceID tag:1]; | ||
| 1107 | + // 发起查询请求 | ||
| 1108 | + [[BTKFenceAction sharedInstance] queryServerFenceStatusWith:request delegate:self]; | ||
| 1109 | + }); | ||
| 1110 | +} | ||
| 1111 | +#pragma mark -- 围栏 | ||
| 1112 | +//实时查询一次监控对象在服务端地理围栏内外的回调方法 | ||
| 1113 | +-(void)onQueryServerFenceStatus:(NSData *)response{ | ||
| 1114 | + NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingAllowFragments error:nil]; | ||
| 1115 | + if (nil == dict) { | ||
| 1116 | + NSLog(@"Server Fence List查询格式转换出错"); | ||
| 1117 | + return; | ||
| 1118 | + } | ||
| 1119 | + if ([dict[@"message"] isEqualToString:@"成功"]) { | ||
| 1120 | +// NSArray *arrr = dict[@"monitored_statuses"]; | ||
| 1121 | +// NSDictionary *dictt = arrr[0]; | ||
| 1122 | +// NSString *ssttt = dictt[@"monitored_status"]; | ||
| 1123 | +// [QMUITips showWithText:[NSString stringWithFormat:@"%@___单次查询围栏内外的回调方法",ssttt] inView:self.mapView hideAfterDelay:1.5]; | ||
| 1124 | + }else{ | ||
| 1125 | +// [QMUITips showWithText:@"错误内外的回调方法" inView:self.mapView hideAfterDelay:1.5]; | ||
| 1126 | + } | ||
| 1127 | + | ||
| 1128 | + //查询一次本地地理围栏的状态 | ||
| 1129 | + //创建成功后查询一次本地围栏的实时状态,目的是使本地地理围栏生效 | ||
| 1130 | + if (localFenceId) { | ||
| 1131 | + //本地地理围栏存在,查询一次本地地理围栏的实时状态 | ||
| 1132 | + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | ||
| 1133 | + BTKQueryLocalFenceStatusRequest *request = [[BTKQueryLocalFenceStatusRequest alloc] initWithMonitoredObject:CNUserShareModelUid fenceIDs:@[self->localFenceId] tag:1]; | ||
| 1134 | + [[BTKFenceAction sharedInstance] queryLocalFenceStatusWith:request delegate:self]; | ||
| 1135 | + }); | ||
| 1136 | + } | ||
| 1137 | +// else{ | ||
| 1138 | +// //本地地理围栏不存在,先创建一个本地地理围栏,然后再查实时状态 | ||
| 1139 | +// [self queryLocalFence]; | ||
| 1140 | +// } | ||
| 1141 | +} | ||
| 1142 | +////查询监控对象的服务端围栏报警信息的回调方法 | ||
| 1143 | +//-(void)onQueryServerFenceHistoryAlarm:(NSData *)response{ | ||
| 1144 | +// NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingAllowFragments error:nil]; | ||
| 1145 | +// if (nil == dict) { | ||
| 1146 | +// NSLog(@"Server Fence List查询格式转换出错"); | ||
| 1147 | +// return; | ||
| 1148 | +// } | ||
| 1149 | +// if (dict[@"message"]) { | ||
| 1150 | +// // [QMUITips showWithText:dict[@"message"] inView:self.mapView hideAfterDelay:5]; | ||
| 1151 | +// }else{ | ||
| 1152 | +// [QMUITips showWithText:@"错误报警信息的回调方法" inView:self.mapView hideAfterDelay:5]; | ||
| 1153 | +// } | ||
| 1154 | +//} | ||
| 1155 | + | ||
| 1156 | +#pragma mark -- private | ||
| 1157 | +- (void)initData{ | ||
| 1158 | + [CNTrackServiceManager defaultManager].isStartRecord = YES; | ||
| 1159 | + //禁止左滑返回 | ||
| 1160 | +// #pragma mark -- TODO 是否有必须禁止左滑 | ||
| 1161 | + | ||
| 1162 | + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(serviceGetPushMessageHandler:) name:TrackServiceGetPushMessageNotification object:nil];//服务端地理围栏的警报通知 | ||
| 1163 | +// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(runningFromBgToBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil]; | ||
| 1164 | + //app进入后台 | ||
| 1165 | +// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(runningToBackground) name:UIApplicationDidEnterBackgroundNotification object:nil]; | ||
| 1166 | + | ||
| 1167 | + //gps信号状态初始化 | ||
| 1168 | + self.gpsState = CNLocationGPSStateNull; | ||
| 1169 | + [CNTrackServiceManager defaultManager].isClickGoOn = NO;//处理暂停的逻辑 | ||
| 1170 | + //跑步已经用时 | ||
| 1171 | + if (self.exitModel.eventId.length > 0) { | ||
| 1172 | + if (self.exitModel.step.length > 0 && ![self.exitModel.step isEqualToString:@"<null>"]) { | ||
| 1173 | + _lastStepCount = [self.exitModel.step integerValue]; | ||
| 1174 | + }else{ | ||
| 1175 | + _lastStepCount = 0; | ||
| 1176 | + } | ||
| 1177 | + _startRunningDate = [self.exitModel.startTime integerValue]; | ||
| 1178 | + double km = _lastStepCount*60.0/100/1000; | ||
| 1179 | + NSDictionary *attributesNum = @{NSFontAttributeName:[UIFont boldSystemFontOfSize:70]}; | ||
| 1180 | + NSDictionary *attributesKM = @{NSFontAttributeName:[UIFont systemFontOfSize:15]}; | ||
| 1181 | + NSAttributedString *attributedString = [self attributedText:@[[NSString stringWithFormat:@"%.2f",floor((km)*100)/100],@" 公里"] attributeAttay:@[attributesNum,attributesKM]]; | ||
| 1182 | + self.currentKMLab.attributedText = attributedString; | ||
| 1183 | + self.mapCurrentKMLab.text = [NSString stringWithFormat:@"%.2f",floor((km)*100)/100]; | ||
| 1184 | + self.currentStepLab.text = [NSString stringWithFormat:@"%ld",_lastStepCount]; | ||
| 1185 | + | ||
| 1186 | + if ([self.exitModel.isStop isEqualToString:@"yes"]) {//重新进入后,处理出去前得暂停逻辑 | ||
| 1187 | + //现在的时间减去开始的时间,获取间隔的秒给_totalTime赋值 | ||
| 1188 | + _stopDate = [self.exitModel.stopTime integerValue]; | ||
| 1189 | + NSTimeInterval intervalS = [[NSDate dateWithTimeIntervalSince1970:_startRunningDate] timeIntervalSinceDate:[NSDate dateWithTimeIntervalSince1970:_stopDate]]; | ||
| 1190 | + _totalTime = labs((NSInteger)intervalS); | ||
| 1191 | + if (self.exitModel.reStartTime.length > 0 && ![self.exitModel.reStartTime isEqualToString:@"<null>"]){ | ||
| 1192 | + _reStartDate = [self.exitModel.reStartTime integerValue]; | ||
| 1193 | + NSTimeInterval reIntervalS = [[NSDate dateWithTimeIntervalSince1970:_reStartDate] timeIntervalSinceDate:[NSDate dateWithTimeIntervalSince1970:[CNLiveTimeTools getNowTimestamp]]]; | ||
| 1194 | + _totalTime += labs((NSInteger)reIntervalS); | ||
| 1195 | + }else{ | ||
| 1196 | + self.exitModel.reStartTime = [NSString stringWithFormat:@"%ld",(long)[CNLiveTimeTools getNowTimestamp]]; | ||
| 1197 | + _reStartDate = [self.exitModel.reStartTime integerValue]; | ||
| 1198 | + [[CNTrackLoaclDataManager shareManager]updateExitModel:self.exitModel]; | ||
| 1199 | + } | ||
| 1200 | + self.mapCurrentSpeedLab.text = [self getPaceSpeed:_totalTime distance:km]; | ||
| 1201 | + | ||
| 1202 | + self.currentSpeedLab.text = [self getPaceSpeed:_totalTime distance:km]; | ||
| 1203 | + //记录步数 | ||
| 1204 | + [[CNTrackServiceManager defaultManager] recordStep:[NSDate date] isUser:YES]; | ||
| 1205 | + }else{ | ||
| 1206 | + //现在的时间减去开始的时间,获取间隔的秒给_totalTime赋值 | ||
| 1207 | + NSDate *startDate = [NSDate dateWithTimeIntervalSince1970:[CNLiveTimeTools getNowTimestamp]]; | ||
| 1208 | + NSDate *date2 = [NSDate dateWithTimeIntervalSince1970:[self.exitModel.startTime integerValue]]; | ||
| 1209 | + NSInteger intervalS = [startDate timeIntervalSinceDate:date2]; | ||
| 1210 | + _totalTime = labs((NSInteger)intervalS); | ||
| 1211 | + self.mapCurrentSpeedLab.text = [self getPaceSpeed:_totalTime distance:km]; | ||
| 1212 | + | ||
| 1213 | + self.currentSpeedLab.text = [self getPaceSpeed:_totalTime distance:km]; | ||
| 1214 | + //记录步数 | ||
| 1215 | + [[CNTrackServiceManager defaultManager] recordStep:[NSDate date] isUser:YES]; | ||
| 1216 | + } | ||
| 1217 | + }else{ | ||
| 1218 | + _totalTime = 0; | ||
| 1219 | + _lastStepCount = 0; | ||
| 1220 | + //持久记录开始时间 | ||
| 1221 | + self.exitModel = [[CNRunExitModel alloc] init]; | ||
| 1222 | + self.exitModel.eventId = self.eventID; | ||
| 1223 | + self.exitModel.userId = CNUserShareModelUid; | ||
| 1224 | + _startRunningDate = [CNLiveTimeTools getNowTimestamp]; | ||
| 1225 | + self.exitModel.startTime = [NSString stringWithFormat:@"%ld",(long)_startRunningDate]; | ||
| 1226 | + [[CNTrackLoaclDataManager shareManager] insertExitModel:self.exitModel]; | ||
| 1227 | + NSDate *date = [NSDate dateWithTimeIntervalSince1970:_startRunningDate]; | ||
| 1228 | + //记录步数 | ||
| 1229 | + [[CNTrackServiceManager defaultManager] recordStep:date isUser:YES]; | ||
| 1230 | + } | ||
| 1231 | +} | ||
| 1232 | + | ||
| 1233 | +- (void)runningFromBgToBecomeActive{ | ||
| 1234 | +// //清空地图上自己的轨迹,清空array | ||
| 1235 | +// dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 1236 | +// [self.mapView removeOverlay:self.stopBeforePolyLine]; | ||
| 1237 | +// [self.mapView removeOverlay:self.stopAfterPolyLine]; | ||
| 1238 | +// [self.mapView removeOverlay:self.frontStopAfterPolyLine]; | ||
| 1239 | +// [self.locationPoints removeAllObjects]; | ||
| 1240 | +// }); | ||
| 1241 | +// //查询历史轨迹 | ||
| 1242 | +// [self getHistoryPoints]; | ||
| 1243 | +// | ||
| 1244 | +// if (_isEndRunning) { | ||
| 1245 | +// [[CNTrackServiceManager defaultManager] stopGather]; | ||
| 1246 | +// }else{ | ||
| 1247 | +// //控制鹰眼服务 | ||
| 1248 | +// if (![CNTrackServiceManager defaultManager].isServiceStarted) { | ||
| 1249 | +// // 开启服务之间先配置轨迹服务的基础信息 | ||
| 1250 | +// BTKServiceOption *basicInfoOption = [[BTKServiceOption alloc] initWithAK:AK mcode:MCODE serviceID:serviceID keepAlive:YES]; | ||
| 1251 | +// [[BTKAction sharedInstance] initInfo:basicInfoOption]; | ||
| 1252 | +// // 开启服务 | ||
| 1253 | +// BTKStartServiceOption *startServiceOption = [[BTKStartServiceOption alloc] initWithEntityName:CNUserShareModelUid]; | ||
| 1254 | +// [[CNTrackServiceManager defaultManager] startServiceWithOption:startServiceOption]; | ||
| 1255 | +// }else{ | ||
| 1256 | +// if (![CNTrackServiceManager defaultManager].isGatherStarted) { | ||
| 1257 | +// [[CNTrackServiceManager defaultManager] startGather]; | ||
| 1258 | +// } | ||
| 1259 | +// } | ||
| 1260 | +// //实时查询一次两个围栏 | ||
| 1261 | +// [self queryRealtimeStatus]; | ||
| 1262 | +// //创建成功后查询一次本地围栏的实时状态,目的是使本地地理围栏生效 | ||
| 1263 | +// dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | ||
| 1264 | +// if (self->localFenceId) { | ||
| 1265 | +// BTKQueryLocalFenceStatusRequest *request = [[BTKQueryLocalFenceStatusRequest alloc] initWithMonitoredObject:CNUserShareModelUid fenceIDs:@[self->localFenceId] tag:1]; | ||
| 1266 | +// [[BTKFenceAction sharedInstance] queryLocalFenceStatusWith:request delegate:self]; | ||
| 1267 | +// } | ||
| 1268 | +// }); | ||
| 1269 | +// } | ||
| 1270 | + | ||
| 1271 | +} | ||
| 1272 | + | ||
| 1273 | +//- (void)runningToBackground{ | ||
| 1274 | +// //app进入后台的时候记录一下数据 | ||
| 1275 | +// | ||
| 1276 | +//} | ||
| 1277 | + | ||
| 1278 | +//判断是否完成了规划的路线 | ||
| 1279 | +- (void)judgeSuccessTrack{ | ||
| 1280 | + [self queryCurrentRunningEndPoint:^(NSArray *points) { | ||
| 1281 | + __block int successCount = 0; | ||
| 1282 | + __block NSMutableArray *mutArr = [NSMutableArray arrayWithArray:points]; | ||
| 1283 | + //逆序遍历自己的轨迹点和终点做比较,差值小于20说明经过了终点 | ||
| 1284 | + __block BOOL isPassEndADD = false; | ||
| 1285 | + [mutArr enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { | ||
| 1286 | + CNHistoryTrackPoint *minePoint = obj; | ||
| 1287 | + CLLocation *minP = [[CLLocation alloc] initWithLatitude:minePoint.coordinate.latitude longitude:minePoint.coordinate.longitude]; | ||
| 1288 | + CLLocation *endP = [[CLLocation alloc] initWithLatitude:self.endAnnotation.coordinate.latitude longitude:self.endAnnotation.coordinate.longitude]; | ||
| 1289 | + CLLocationDistance distance = [minP distanceFromLocation:endP]; | ||
| 1290 | + if (distance < 20) {//完成了 | ||
| 1291 | + isPassEndADD = YES; | ||
| 1292 | + *stop = YES; | ||
| 1293 | + } | ||
| 1294 | + }]; | ||
| 1295 | + if (!isPassEndADD) { | ||
| 1296 | + //没经过终点说明没完成,直接请求服务器接口 | ||
| 1297 | + [self uploadData:NO img:nil]; | ||
| 1298 | + }else{ | ||
| 1299 | + for (CNLiveSportsCoordinatesModel *pointNode in self.sportsDetailModel.latLongitude) { | ||
| 1300 | + CLLocation *originLocation = [[CLLocation alloc] initWithLatitude:[pointNode.latitude doubleValue] longitude:[pointNode.longitude doubleValue]]; | ||
| 1301 | + [mutArr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { | ||
| 1302 | + CNHistoryTrackPoint *minePoint = obj; | ||
| 1303 | + CLLocation *currentLocation = [[CLLocation alloc] initWithLatitude:minePoint.coordinate.latitude longitude:minePoint.coordinate.longitude]; | ||
| 1304 | + CLLocationDistance distance = [originLocation distanceFromLocation:currentLocation]; | ||
| 1305 | + if (distance < 50) {//表示这个点已经完成 | ||
| 1306 | + [mutArr removeObjectsInRange:NSMakeRange(0, idx+1)]; | ||
| 1307 | + successCount ++; | ||
| 1308 | + *stop = YES; | ||
| 1309 | + } | ||
| 1310 | + }]; | ||
| 1311 | + } | ||
| 1312 | + if (successCount*1.000/self.sportsDetailModel.latLongitude.count*1.000 > 0.70) {//大于70%则认为任务完成 | ||
| 1313 | + dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 1314 | + self->_endStatus = @"路线完成"; | ||
| 1315 | + self.successStateLab.text = self->_endStatus; | ||
| 1316 | + [self uploadData:YES img:nil]; | ||
| 1317 | + }); | ||
| 1318 | + | ||
| 1319 | + }else{ | ||
| 1320 | + dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 1321 | + self->_endStatus = @"路线未完成"; | ||
| 1322 | + self.successStateLab.text = self->_endStatus; | ||
| 1323 | + [self uploadData:NO img:nil]; | ||
| 1324 | + }); | ||
| 1325 | + } | ||
| 1326 | + } | ||
| 1327 | + }]; | ||
| 1328 | +} | ||
| 1329 | + | ||
| 1330 | +- (void)alertEndSelect:(BOOL)isSuccessTrack img:(NSString *)imgUrlStr{ | ||
| 1331 | + //弹窗,无网络,是否暂存,是否重试 | ||
| 1332 | + dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 1333 | + UIAlertController *actionAlert = [UIAlertController alertControllerWithTitle:nil message:@"上传数据失败\n是否重试" preferredStyle:UIAlertControllerStyleAlert]; | ||
| 1334 | + UIAlertAction *action = [UIAlertAction actionWithTitle:@"重试" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { | ||
| 1335 | + [self uploadData:isSuccessTrack img:imgUrlStr]; | ||
| 1336 | + }]; | ||
| 1337 | + [actionAlert addAction:action]; | ||
| 1338 | + UIAlertAction *action1 = [UIAlertAction actionWithTitle:@"暂存" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { | ||
| 1339 | + if (self->_endTimer) { | ||
| 1340 | + [self->_endTimer invalidate]; | ||
| 1341 | + self->_endTimer = nil; | ||
| 1342 | + } | ||
| 1343 | + if (self->_startRunningTimer) { | ||
| 1344 | + [self->_startRunningTimer invalidate]; | ||
| 1345 | + self->_startRunningTimer = nil; | ||
| 1346 | + } | ||
| 1347 | + [CNTrackServiceManager defaultManager].isStartRecord = NO; | ||
| 1348 | + //长按结束了,删除数据库中的逻辑辅助数据 | ||
| 1349 | + [[CNTrackLoaclDataManager shareManager] deleteExitModel:CNUserShareModelUid]; | ||
| 1350 | + //更新上一页的最底部的按钮状态:发通知 | ||
| 1351 | + [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveSport_DetailUplaod object:nil]; | ||
| 1352 | + //跳转到失败列表 | ||
| 1353 | + CNReUploadViewController *vc = [[CNReUploadViewController alloc] init]; | ||
| 1354 | + vc.isNeedBack = YES; | ||
| 1355 | + self->_isStopAnimation = YES; | ||
| 1356 | + [self.navigationController pushViewController:vc animated:YES]; | ||
| 1357 | + }]; | ||
| 1358 | + [actionAlert addAction:action1]; | ||
| 1359 | + [self presentViewController:actionAlert animated:YES completion:nil]; | ||
| 1360 | + }); | ||
| 1361 | +} | ||
| 1362 | + | ||
| 1363 | +- (void)uploadData:(BOOL)isSuccessTrack img:(NSString *)imgUrlStr{ | ||
| 1364 | + if (![CNLiveNetworking isNetworking]) { | ||
| 1365 | + [self alertEndSelect:isSuccessTrack img:imgUrlStr]; | ||
| 1366 | + return; | ||
| 1367 | + } | ||
| 1368 | + self.exitModel = [[CNTrackLoaclDataManager shareManager] getExitModel:CNUserShareModelUid]; | ||
| 1369 | + NSString *strUrl = CNSportsChinaSaveRecordUrl; | ||
| 1370 | + BOOL _isTempStop = NO; | ||
| 1371 | + if (self.exitModel.isStop.length>0 && ![self.exitModel.isStop isEqualToString:@"<null>"]) { | ||
| 1372 | + _isTempStop = YES; | ||
| 1373 | + } | ||
| 1374 | + NSString *_tempPace = [self.currentSpeedLab.text isEqualToString:@"--"]?@"0":self.currentSpeedLab.text; | ||
| 1375 | + NSString *_tempStep = [self.currentStepLab.text isEqualToString:@"--"]?@"0":self.currentStepLab.text; | ||
| 1376 | + | ||
| 1377 | + NSDictionary *dict = @{ | ||
| 1378 | + @"eventId":self.eventID, | ||
| 1379 | + @"sid":CNUserShareModelUid, | ||
| 1380 | + @"employTime":[NSString stringWithFormat:@"%ld",(long)_totalTime], | ||
| 1381 | + @"mileage":self.mapCurrentKMLab.text, | ||
| 1382 | + @"pace":_tempPace, | ||
| 1383 | + @"step":_tempStep, | ||
| 1384 | + //@"roadmap":imgUrlStr, | ||
| 1385 | + @"startTime":[NSString stringWithFormat:@"%ld",(long)_startRunningDate], | ||
| 1386 | + @"endTime":[NSString stringWithFormat:@"%ld",(long)_endRunningDate], | ||
| 1387 | + @"isPause":_isTempStop?@"1":@"0", | ||
| 1388 | + @"pauseTime":_isTempStop?self.exitModel.stopTime:@"", | ||
| 1389 | + @"continueTime":_isTempStop?self.exitModel.reStartTime:@"", | ||
| 1390 | + @"completeStatus":isSuccessTrack?@"1":@"0" | ||
| 1391 | + }; | ||
| 1392 | + | ||
| 1393 | + [CNLiveNetworking requestNetworkWithMethod:CNLiveRequestMethodPOST URLString:strUrl Param:dict CacheType:CNLiveNetworkCacheTypeNetworkOnly CompletionBlock:^(NSURLSessionTask *requestTask, id responseObject, NSError *error) { | ||
| 1394 | + if (error) { | ||
| 1395 | + //弹窗,是否暂存,是否重试 | ||
| 1396 | + [self alertEndSelect:isSuccessTrack img:imgUrlStr]; | ||
| 1397 | + }else{ | ||
| 1398 | + if ([responseObject isKindOfClass:[NSDictionary class]]) { | ||
| 1399 | + NSString *resultCode = [NSString stringWithFormat:@"%@", responseObject[@"errorCode"]]; | ||
| 1400 | + if ([resultCode isEqualToString:@"0"]) { | ||
| 1401 | + //长按结束了,删除数据库中的逻辑辅助数据 | ||
| 1402 | + [[CNTrackLoaclDataManager shareManager] deleteExitModel:CNUserShareModelUid]; | ||
| 1403 | + [[CNTrackLoaclDataManager shareManager] deleteFUploadModel:self->failModel]; | ||
| 1404 | + //更新上一页的最底部的按钮状态:发通知 | ||
| 1405 | + [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveSport_DetailUplaod object:nil]; | ||
| 1406 | + [self afterLongPress]; | ||
| 1407 | + }else{ | ||
| 1408 | + //弹窗,是否暂存,是否重试 | ||
| 1409 | + [self alertEndSelect:isSuccessTrack img:imgUrlStr]; | ||
| 1410 | + } | ||
| 1411 | + }else{ | ||
| 1412 | + [QMUITips showInfo:@"服务异常,请重试" inView:AppKeyWindow hideAfterDelay:1.5]; | ||
| 1413 | + } | ||
| 1414 | + } | ||
| 1415 | + }]; | ||
| 1416 | +} | ||
| 1417 | + | ||
| 1418 | +#pragma mark -- private 长按结束后的UI处理 | ||
| 1419 | +- (void)afterLongPress{ | ||
| 1420 | + dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 1421 | + self.backBtn.userInteractionEnabled = YES; | ||
| 1422 | + [self.preSaveView removeAllSubviews]; | ||
| 1423 | + [self.preSaveView removeFromSuperview]; | ||
| 1424 | + self.saveBtn.hidden = NO; | ||
| 1425 | + self->_isStopAnimation = YES; | ||
| 1426 | + }); | ||
| 1427 | +} | ||
| 1428 | + | ||
| 1429 | +- (void)backFirstBtnAction{ | ||
| 1430 | + if (_endTimer) { | ||
| 1431 | + [_endTimer invalidate]; | ||
| 1432 | + _endTimer = nil; | ||
| 1433 | + } | ||
| 1434 | + if (_startRunningTimer) { | ||
| 1435 | + [_startRunningTimer invalidate]; | ||
| 1436 | + _startRunningTimer = nil; | ||
| 1437 | + } | ||
| 1438 | + if ([self.delegate respondsToSelector:@selector(backToFrontVC)]) { | ||
| 1439 | + [self.delegate backToFrontVC]; | ||
| 1440 | + } | ||
| 1441 | + [self.navigationController popViewControllerAnimated:YES]; | ||
| 1442 | +} | ||
| 1443 | + | ||
| 1444 | +- (NSString *)getPaceSpeed:(double)second distance:(double)distance{ | ||
| 1445 | + if (distance != 0) { | ||
| 1446 | + //计算分 | ||
| 1447 | + int minute = (int) (second / distance / 60); | ||
| 1448 | + //获取秒 | ||
| 1449 | + double miaoMin = ((double) (second / distance / 60)) - ((int) (second / distance / 60)); | ||
| 1450 | + int miao = (int) (miaoMin * 60); | ||
| 1451 | + return [NSString stringWithFormat:@"%d′%d″",minute,miao]; | ||
| 1452 | + } else { | ||
| 1453 | + return @"0"; | ||
| 1454 | + } | ||
| 1455 | +} | ||
| 1456 | + | ||
| 1457 | +- (void)startRunningTime{ | ||
| 1458 | + | ||
| 1459 | + self.startRunningTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(cumulativeTiming) userInfo:nil repeats:YES]; | ||
| 1460 | +} | ||
| 1461 | + | ||
| 1462 | +- (void)cumulativeTiming{ | ||
| 1463 | + _totalTime ++; | ||
| 1464 | + self.currentTimeLab.text = [CNLiveTimeTools getMMSSFromSS:[NSString stringWithFormat:@"%ld",(long)_totalTime]]; | ||
| 1465 | + self.mapCurrentTimeLab.text = [CNLiveTimeTools getMMSSFromSS:[NSString stringWithFormat:@"%ld",(long)_totalTime]]; | ||
| 1466 | +} | ||
| 1467 | + | ||
| 1468 | +// 获取带有不同样式的文字内容 | ||
| 1469 | +//stringArray 字符串数组 | ||
| 1470 | +//attributeAttay 样式数组 | ||
| 1471 | +- (NSAttributedString *)attributedText:(NSArray*)stringArray attributeAttay:(NSArray *)attributeAttay{ | ||
| 1472 | + // 定义要显示的文字内容 | ||
| 1473 | + NSString * string = [stringArray componentsJoinedByString:@""];//拼接传入的字符串数组 | ||
| 1474 | + // 通过要显示的文字内容来创建一个带属性样式的字符串对象 | ||
| 1475 | + NSMutableAttributedString * result = [[NSMutableAttributedString alloc] initWithString:string]; | ||
| 1476 | + for(NSInteger i = 0; i < stringArray.count; i++){ | ||
| 1477 | + // 将某一范围内的字符串设置样式 | ||
| 1478 | + [result setAttributes:attributeAttay[i] range:[string rangeOfString:stringArray[i]]]; | ||
| 1479 | + } | ||
| 1480 | + // 返回已经设置好了的带有样式的文字 | ||
| 1481 | + return [[NSAttributedString alloc] initWithAttributedString:result]; | ||
| 1482 | +} | ||
| 1483 | + | ||
| 1484 | +- (void)addFirstView{ | ||
| 1485 | + [self.view addSubview:self.fristBgView]; | ||
| 1486 | + [self.fristBgView mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1487 | + make.left.right.top.bottom.equalTo(self.view); | ||
| 1488 | + }]; | ||
| 1489 | + [self.fristBgView addSubview:self.backFirstBtn]; | ||
| 1490 | + [self.backFirstBtn mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1491 | + make.top.equalTo(self.fristBgView).offset(kVerticalStatusHeight+10); | ||
| 1492 | + make.left.equalTo(self.fristBgView).offset(5); | ||
| 1493 | + make.size.mas_equalTo(CGSizeMake(40, 40)); | ||
| 1494 | + }]; | ||
| 1495 | + UIImageView *imageV = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"top_back_white"]]; | ||
| 1496 | + [self.backFirstBtn addSubview:imageV]; | ||
| 1497 | + [imageV mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1498 | + make.centerY.equalTo(self.backFirstBtn); | ||
| 1499 | + make.right.equalTo(self.backFirstBtn).offset(-5); | ||
| 1500 | + make.size.mas_equalTo(CGSizeMake(12, 20)); | ||
| 1501 | + }]; | ||
| 1502 | + [self.fristBgView addSubview:self.currentKMLab]; | ||
| 1503 | + [self.currentKMLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1504 | + make.centerX.equalTo(self.view); | ||
| 1505 | + make.top.equalTo(self.view).offset(130); | ||
| 1506 | + }]; | ||
| 1507 | + | ||
| 1508 | + NSDictionary *attributesNum = @{NSFontAttributeName:[UIFont boldSystemFontOfSize:70]}; | ||
| 1509 | + NSDictionary *attributesKM = @{NSFontAttributeName:[UIFont systemFontOfSize:15]}; | ||
| 1510 | + NSAttributedString *attributedString = [self attributedText:@[self.mapCurrentKMLab.text,@" 公里"] | ||
| 1511 | + attributeAttay:@[attributesNum,attributesKM]]; | ||
| 1512 | + self.currentKMLab.attributedText = attributedString; | ||
| 1513 | + | ||
| 1514 | + | ||
| 1515 | + [self.fristBgView addSubview:self.gpsLab]; | ||
| 1516 | + [self.gpsLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1517 | + make.left.equalTo(self.view).offset(25); | ||
| 1518 | + make.top.equalTo(self.currentKMLab.mas_bottom).offset(100); | ||
| 1519 | + }]; | ||
| 1520 | + [self.fristBgView addSubview:self.currentGPSImgView]; | ||
| 1521 | + [self.currentGPSImgView mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1522 | + make.centerY.equalTo(self.gpsLab); | ||
| 1523 | + make.left.equalTo(self.gpsLab.mas_right).offset(10); | ||
| 1524 | + }]; | ||
| 1525 | + [self.fristBgView addSubview:self.currentGPSLab]; | ||
| 1526 | + [self.currentGPSLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1527 | + make.centerY.equalTo(self.gpsLab); | ||
| 1528 | + make.left.equalTo(self.currentGPSImgView.mas_right).offset(10); | ||
| 1529 | + }]; | ||
| 1530 | + [self.fristBgView addSubview:self.detailMapBtn]; | ||
| 1531 | + [self.detailMapBtn mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1532 | + make.centerY.equalTo(self.gpsLab); | ||
| 1533 | + make.right.equalTo(self.view.mas_right).offset(-25); | ||
| 1534 | + make.width.height.equalTo(@(52)); | ||
| 1535 | + }]; | ||
| 1536 | + self.detailMapBtn.layer.cornerRadius = 52/2; | ||
| 1537 | + self.detailMapBtn.layer.masksToBounds = YES; | ||
| 1538 | + [self.fristBgView addSubview:self.mapDesLab]; | ||
| 1539 | + [self.mapDesLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1540 | + make.centerX.equalTo(self.detailMapBtn); | ||
| 1541 | + make.top.equalTo(self.detailMapBtn.mas_bottom).offset(10); | ||
| 1542 | + }]; | ||
| 1543 | + [self.fristBgView addSubview:self.speedImgView]; | ||
| 1544 | + [self.speedImgView mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1545 | + make.top.equalTo(self.mapDesLab.mas_bottom).offset(25); | ||
| 1546 | + make.left.equalTo(self.view).offset(45); | ||
| 1547 | + make.size.mas_equalTo(CGSizeMake(26, 23)); | ||
| 1548 | + }]; | ||
| 1549 | + [self.fristBgView addSubview:self.currentSpeedLab]; | ||
| 1550 | + [self.currentSpeedLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1551 | + make.centerX.equalTo(self.speedImgView); | ||
| 1552 | + make.top.equalTo(self.speedImgView.mas_bottom).offset(20); | ||
| 1553 | + make.width.equalTo(@(SCREEN_WIDTH/3-40)); | ||
| 1554 | + }]; | ||
| 1555 | + [self.fristBgView addSubview:self.speedDesLab]; | ||
| 1556 | + [self.speedDesLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1557 | + make.centerX.equalTo(self.speedImgView); | ||
| 1558 | + make.top.equalTo(self.currentSpeedLab.mas_bottom).offset(20); | ||
| 1559 | + }]; | ||
| 1560 | + [self.fristBgView addSubview:self.timeImgView]; | ||
| 1561 | + [self.timeImgView mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1562 | + make.centerX.equalTo(self.view); | ||
| 1563 | + make.centerY.equalTo(self.speedImgView); | ||
| 1564 | + make.size.mas_equalTo(CGSizeMake(23, 25)); | ||
| 1565 | + }]; | ||
| 1566 | + [self.fristBgView addSubview:self.currentTimeLab]; | ||
| 1567 | + [self.currentTimeLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1568 | + make.centerX.equalTo(self.timeImgView); | ||
| 1569 | + make.centerY.equalTo(self.currentSpeedLab); | ||
| 1570 | + }]; | ||
| 1571 | + [self.fristBgView addSubview:self.timeDesLab]; | ||
| 1572 | + [self.timeDesLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1573 | + make.centerX.equalTo(self.timeImgView); | ||
| 1574 | + make.centerY.equalTo(self.speedDesLab); | ||
| 1575 | + }]; | ||
| 1576 | + [self.fristBgView addSubview:self.stepImgView]; | ||
| 1577 | + [self.stepImgView mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1578 | + make.centerY.equalTo(self.speedImgView); | ||
| 1579 | + make.right.equalTo(self.view.mas_right).offset(-45); | ||
| 1580 | + make.size.mas_equalTo(CGSizeMake(26, 24)); | ||
| 1581 | + }]; | ||
| 1582 | + [self.fristBgView addSubview:self.currentStepLab]; | ||
| 1583 | + [self.currentStepLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1584 | + make.centerX.equalTo(self.stepImgView); | ||
| 1585 | + make.centerY.equalTo(self.currentSpeedLab); | ||
| 1586 | + }]; | ||
| 1587 | + [self.fristBgView addSubview:self.stepDesLab]; | ||
| 1588 | + [self.stepDesLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1589 | + make.centerX.equalTo(self.stepImgView); | ||
| 1590 | + make.centerY.equalTo(self.speedDesLab); | ||
| 1591 | + }]; | ||
| 1592 | + [self.fristBgView addSubview:self.stopRunningBtn]; | ||
| 1593 | + [self.stopRunningBtn mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1594 | + make.top.equalTo(self.timeDesLab.mas_bottom).offset(60); | ||
| 1595 | + make.size.mas_equalTo(CGSizeMake(90, 90)); | ||
| 1596 | + make.centerX.equalTo(self.view).offset(-SCREEN_WIDTH/4+SCREEN_WIDTH/16); | ||
| 1597 | + }]; | ||
| 1598 | + self.stopRunningBtn.layer.cornerRadius = 90/2; | ||
| 1599 | + self.stopRunningBtn.layer.masksToBounds = YES; | ||
| 1600 | + | ||
| 1601 | + [self.fristBgView addSubview:self.goonRunningBtn]; | ||
| 1602 | + self.goonRunningBtn.hidden = YES; | ||
| 1603 | + [self.goonRunningBtn mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1604 | + make.top.equalTo(self.timeDesLab.mas_bottom).offset(60); | ||
| 1605 | + make.size.mas_equalTo(CGSizeMake(90, 90)); | ||
| 1606 | + make.centerX.equalTo(self.view).offset(-SCREEN_WIDTH/4+SCREEN_WIDTH/16); | ||
| 1607 | + }]; | ||
| 1608 | + self.goonRunningBtn.layer.cornerRadius = 90/2; | ||
| 1609 | + self.goonRunningBtn.layer.masksToBounds = YES; | ||
| 1610 | + [self.fristBgView addSubview:self.endRunningBgView]; | ||
| 1611 | + [self.endRunningBgView mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1612 | + make.top.equalTo(self.timeDesLab.mas_bottom).offset(60); | ||
| 1613 | + make.size.mas_equalTo(CGSizeMake(90, 90)); | ||
| 1614 | + make.centerX.equalTo(self.view).offset(SCREEN_WIDTH/4-SCREEN_WIDTH/16); | ||
| 1615 | + }]; | ||
| 1616 | + self.endRunningBgView.layer.cornerRadius = 90/2; | ||
| 1617 | + self.endRunningBgView.layer.masksToBounds = YES; | ||
| 1618 | + [self.fristBgView addSubview:self.endRunningBtn]; | ||
| 1619 | + [self.endRunningBtn addGestureRecognizer:self.longPress]; | ||
| 1620 | + [self.endRunningBtn mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1621 | + make.top.equalTo(self.timeDesLab.mas_bottom).offset(60); | ||
| 1622 | + make.size.mas_equalTo(CGSizeMake(90, 90)); | ||
| 1623 | + make.centerX.equalTo(self.view).offset(SCREEN_WIDTH/4-SCREEN_WIDTH/16); | ||
| 1624 | + }]; | ||
| 1625 | + self.endRunningBtn.layer.cornerRadius = 90/2; | ||
| 1626 | + self.endRunningBtn.layer.masksToBounds = YES; | ||
| 1627 | + [self.fristBgView addSubview:self.endTipView]; | ||
| 1628 | + self.endTipView.hidden = YES; | ||
| 1629 | + [self.endTipView mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1630 | + make.bottom.equalTo(self.endRunningBtn.mas_top); | ||
| 1631 | + make.centerX.equalTo(self.endRunningBtn); | ||
| 1632 | + make.size.mas_equalTo(CGSizeMake(72, 33)); | ||
| 1633 | + }]; | ||
| 1634 | + [self.endTipView addSubview:self.endTipLab]; | ||
| 1635 | + [self.endTipLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1636 | + make.centerX.equalTo(self.endTipView); | ||
| 1637 | + make.top.equalTo(self.endTipView).offset(6); | ||
| 1638 | + }]; | ||
| 1639 | +} | ||
| 1640 | +- (void)showMapView:(UIButton *)btn{ | ||
| 1641 | + self.fristBgView.hidden = YES; | ||
| 1642 | + self.mapView.hidden = NO; | ||
| 1643 | +} | ||
| 1644 | +- (void)stopRunningBtnAction:(UIButton *)btn{ | ||
| 1645 | + if ([self.exitModel.stopCount integerValue] == 1) { | ||
| 1646 | +// [QMUITips showInfo:@"当前无法暂停" inView:self.view hideAfterDelay:1.5]; | ||
| 1647 | + UIAlertController *actionAlert = [UIAlertController alertControllerWithTitle:nil message:@"当前无法暂停" preferredStyle:UIAlertControllerStyleAlert]; | ||
| 1648 | + UIAlertAction *action = [UIAlertAction actionWithTitle:@"好" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { | ||
| 1649 | + | ||
| 1650 | + }]; | ||
| 1651 | + [actionAlert addAction:action]; | ||
| 1652 | + [self presentViewController:actionAlert animated:YES completion:nil]; | ||
| 1653 | + return; | ||
| 1654 | + } | ||
| 1655 | + | ||
| 1656 | + UIAlertController *actionAlert = [UIAlertController alertControllerWithTitle:nil message:@"固定赛事只可暂停一次\n是否确定使用" preferredStyle:UIAlertControllerStyleAlert]; | ||
| 1657 | + UIAlertAction *action = [UIAlertAction actionWithTitle:@"否" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { | ||
| 1658 | + }]; | ||
| 1659 | + [actionAlert addAction:action]; | ||
| 1660 | + UIAlertAction *action1 = [UIAlertAction actionWithTitle:@"是" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { | ||
| 1661 | + [QMUITips showLoadingInView:AppKeyWindow]; | ||
| 1662 | + [CNTrackServiceManager defaultManager].isStartRecord = NO; | ||
| 1663 | + self->_stopDate = [CNLiveTimeTools getNowTimestamp]; | ||
| 1664 | + self.exitModel.eventId = self.eventID; | ||
| 1665 | + self.exitModel.startTime = [NSString stringWithFormat:@"%ld",self->_startRunningDate]; | ||
| 1666 | + self.exitModel.stopTime = [NSString stringWithFormat:@"%ld",self->_stopDate]; | ||
| 1667 | + self.exitModel.step = self.currentStepLab.text; | ||
| 1668 | + self.exitModel.isStop = @"yes"; | ||
| 1669 | + self.exitModel.stopCount = @"1"; | ||
| 1670 | + [[CNTrackLoaclDataManager shareManager]updateExitModel:self.exitModel]; | ||
| 1671 | + self.stopRunningBtn.hidden = YES; | ||
| 1672 | + self.goonRunningBtn.hidden = NO; | ||
| 1673 | + //暂停时间和步数 | ||
| 1674 | + self.startRunningTimer.fireDate = [NSDate distantFuture]; | ||
| 1675 | + [CNTrackServiceManager defaultManager].isStartRecord = NO; | ||
| 1676 | + //控制鹰眼服务 | ||
| 1677 | + [[CNTrackServiceManager defaultManager] stopGather]; | ||
| 1678 | + self->_isStopRun = YES; | ||
| 1679 | + NSArray *arr = self.locationPoints; | ||
| 1680 | + [self.locationPoints removeAllObjects]; | ||
| 1681 | + CLLocationCoordinate2D coors[arr.count]; | ||
| 1682 | + NSInteger count = 0; | ||
| 1683 | + for (size_t i = 0; i < arr.count; i++) { | ||
| 1684 | + CLLocation *location = [arr objectAtIndex:i]; | ||
| 1685 | + coors[i] = location.coordinate; | ||
| 1686 | + count++; | ||
| 1687 | + } | ||
| 1688 | + self.noExitStopFrontPolyLine = [BMKPolyline polylineWithCoordinates:coors count:count]; | ||
| 1689 | + if (self.noExitStopFrontPolyLine) {// 防止重复绘制 | ||
| 1690 | + [self.mapView removeOverlay:self.noExitStopFrontPolyLine]; | ||
| 1691 | + } | ||
| 1692 | + if (self.stopAfterPolyLine) { | ||
| 1693 | + [self.mapView removeOverlay:self.stopAfterPolyLine]; | ||
| 1694 | + } | ||
| 1695 | + [self.mapView addOverlay:self.noExitStopFrontPolyLine]; | ||
| 1696 | + [QMUITips hideAllTips]; | ||
| 1697 | + }]; | ||
| 1698 | + [actionAlert addAction:action1]; | ||
| 1699 | + [self presentViewController:actionAlert animated:YES completion:nil]; | ||
| 1700 | +} | ||
| 1701 | + | ||
| 1702 | +- (void)goonRunningBtnAction:(UIButton *)btn{ | ||
| 1703 | + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(serviceResultHandler:) name:TrackServiceOperationResultNotification object:nil];//两个服务的通知 | ||
| 1704 | + //控制鹰眼服务 | ||
| 1705 | + if (![CNTrackServiceManager defaultManager].isServiceStarted) { | ||
| 1706 | + // 开启服务之间先配置轨迹服务的基础信息 | ||
| 1707 | + BTKServiceOption *basicInfoOption = [[BTKServiceOption alloc] initWithAK:BDMapAK mcode:BDMapMCODE serviceID:BDMapServiceID keepAlive:YES]; | ||
| 1708 | + [[BTKAction sharedInstance] initInfo:basicInfoOption]; | ||
| 1709 | + // 开启服务 | ||
| 1710 | + BTKStartServiceOption *startServiceOption = [[BTKStartServiceOption alloc] initWithEntityName:CNUserShareModelUid]; | ||
| 1711 | + [[CNTrackServiceManager defaultManager] startServiceWithOption:startServiceOption]; | ||
| 1712 | + }else{ | ||
| 1713 | + if (![CNTrackServiceManager defaultManager].isGatherStarted) { | ||
| 1714 | + [[CNTrackServiceManager defaultManager] startGather]; | ||
| 1715 | + }else{ | ||
| 1716 | + [CNTrackServiceManager defaultManager].isStartRecord = YES; | ||
| 1717 | + [self.startRunningTimer setFireDate:[NSDate date]]; | ||
| 1718 | +// [self startRunningTime]; | ||
| 1719 | + _isStopRun = NO; | ||
| 1720 | + [CNTrackServiceManager defaultManager].isClickGoOn = YES; | ||
| 1721 | + | ||
| 1722 | + //实时查询一次两个围栏 | ||
| 1723 | + [self queryRealtimeStatus]; | ||
| 1724 | + if ([self.exitModel.isStop isEqualToString:@"yes"]) { | ||
| 1725 | + if (self.exitModel.reStartTime.length > 0 && ![self.exitModel.reStartTime isEqualToString:@"<null>"]) { | ||
| 1726 | + _reStartDate = [self.exitModel.reStartTime integerValue]; | ||
| 1727 | + self.exitModel.reStartTime = [NSString stringWithFormat:@"%ld",_reStartDate]; | ||
| 1728 | + [[CNTrackLoaclDataManager shareManager] updateExitModel:self.exitModel]; | ||
| 1729 | + }else{ | ||
| 1730 | + _reStartDate = [CNLiveTimeTools getNowTimestamp]; | ||
| 1731 | + self.exitModel.reStartTime = [NSString stringWithFormat:@"%ld",_reStartDate]; | ||
| 1732 | + [[CNTrackLoaclDataManager shareManager] updateExitModel:self.exitModel]; | ||
| 1733 | + } | ||
| 1734 | + } | ||
| 1735 | + self.stopRunningBtn.hidden = NO; | ||
| 1736 | + self.goonRunningBtn.hidden = YES; | ||
| 1737 | + // self.startRunningTimer.fireDate = [NSDate distantPast]; | ||
| 1738 | + //记录步数 | ||
| 1739 | + [[CNTrackServiceManager defaultManager] recordStep:[NSDate date] isUser:YES]; | ||
| 1740 | + } | ||
| 1741 | + } | ||
| 1742 | +} | ||
| 1743 | + | ||
| 1744 | +- (void)serviceResultHandler:(NSNotification *)notification { | ||
| 1745 | + dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 1746 | + NSDictionary *info = notification.userInfo; | ||
| 1747 | + ServiceOperationType type = (ServiceOperationType)[info[@"type"] unsignedIntValue]; | ||
| 1748 | + NSString *title = info[@"title"]; | ||
| 1749 | + NSString *message = info[@"message"]; | ||
| 1750 | + switch (type) { | ||
| 1751 | + case TRACK_SERVICE_OPERATION_TYPE_START_SERVICE: | ||
| 1752 | + { | ||
| 1753 | + if ([title isEqualToString:@"轨迹服务开启失败"]) { | ||
| 1754 | + UIAlertController *actionAlert = [UIAlertController alertControllerWithTitle:nil message:@"服务异常,请重试。" preferredStyle:UIAlertControllerStyleAlert]; | ||
| 1755 | + UIAlertAction *action = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { | ||
| 1756 | + }]; | ||
| 1757 | + [actionAlert addAction:action]; | ||
| 1758 | + [self presentViewController:actionAlert animated:YES completion:nil]; | ||
| 1759 | + }else{ | ||
| 1760 | + //开始服务成功,开启采集服务 | ||
| 1761 | + if (![CNTrackServiceManager defaultManager].isGatherStarted) { | ||
| 1762 | + [[CNTrackServiceManager defaultManager] startGather]; | ||
| 1763 | + } | ||
| 1764 | + } | ||
| 1765 | + } | ||
| 1766 | + break; | ||
| 1767 | + case TRACK_SERVICE_OPERATION_TYPE_STOP_SERVICE: | ||
| 1768 | + { | ||
| 1769 | + //服务停止失败 | ||
| 1770 | + if ([title isEqualToString:@"轨迹服务停止失败"]) { | ||
| 1771 | + NSLog(@"轨迹服务停止失败"); | ||
| 1772 | + if ([CNTrackServiceManager defaultManager].isServiceStarted) { | ||
| 1773 | + [[CNTrackServiceManager defaultManager] stopService];//停止服务 | ||
| 1774 | + } | ||
| 1775 | + }else{ | ||
| 1776 | + NSLog(@"轨迹服务停止成功"); | ||
| 1777 | + //停止更新位置 | ||
| 1778 | + if (self->_isEndRunning) { | ||
| 1779 | + @try { | ||
| 1780 | + [self.locationManager stopUpdatingLocation]; | ||
| 1781 | + [self.locationManager stopUpdatingHeading]; | ||
| 1782 | + } @catch (NSException *exception) { | ||
| 1783 | + NSLog(@"CNStartRunningViewController.m 崩溃了"); | ||
| 1784 | + } | ||
| 1785 | + } | ||
| 1786 | + } | ||
| 1787 | + } | ||
| 1788 | + break; | ||
| 1789 | + case TRACK_SERVICE_OPERATION_TYPE_START_GATHER: | ||
| 1790 | + { | ||
| 1791 | + if ([title isEqualToString:@"开始采集失败"]) { | ||
| 1792 | + if ([message isEqualToString:@"没有开启后台定位权限"] || [message isEqualToString:@"没有开启系统定位服务"]){ | ||
| 1793 | + UIAlertController *actionAlert = [UIAlertController alertControllerWithTitle:@"无法获取你的位置信息" message:@"请到手机系统的[隐私]->[定位服务]->[网家家]中打开定位服务,并勾选\"始终\"选项" preferredStyle:UIAlertControllerStyleAlert]; | ||
| 1794 | + UIAlertAction *action = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { | ||
| 1795 | + }]; | ||
| 1796 | + [actionAlert addAction:action]; | ||
| 1797 | + [self presentViewController:actionAlert animated:YES completion:nil]; | ||
| 1798 | + }else if([message isEqualToString:@"已经在采集轨迹,请勿重复开始"]){ | ||
| 1799 | + [CNTrackServiceManager defaultManager].isStartRecord = YES; | ||
| 1800 | + [self.startRunningTimer setFireDate:[NSDate date]]; | ||
| 1801 | +// [self startRunningTime]; | ||
| 1802 | + self->_isStopRun = NO; | ||
| 1803 | + [CNTrackServiceManager defaultManager].isClickGoOn = YES; | ||
| 1804 | + | ||
| 1805 | + //实时查询一次两个围栏 | ||
| 1806 | + [self queryRealtimeStatus]; | ||
| 1807 | + if ([self.exitModel.isStop isEqualToString:@"yes"]) { | ||
| 1808 | + if (self.exitModel.reStartTime.length > 0 && ![self.exitModel.reStartTime isEqualToString:@"<null>"]) { | ||
| 1809 | + self->_reStartDate = [self.exitModel.reStartTime integerValue]; | ||
| 1810 | + self.exitModel.reStartTime = [NSString stringWithFormat:@"%ld",self->_reStartDate]; | ||
| 1811 | + [[CNTrackLoaclDataManager shareManager] updateExitModel:self.exitModel]; | ||
| 1812 | + }else{ | ||
| 1813 | + self->_reStartDate = [CNLiveTimeTools getNowTimestamp]; | ||
| 1814 | + self.exitModel.reStartTime = [NSString stringWithFormat:@"%ld",self->_reStartDate]; | ||
| 1815 | + [[CNTrackLoaclDataManager shareManager] updateExitModel:self.exitModel]; | ||
| 1816 | + } | ||
| 1817 | + } | ||
| 1818 | + self.stopRunningBtn.hidden = NO; | ||
| 1819 | + self.goonRunningBtn.hidden = YES; | ||
| 1820 | + // self.startRunningTimer.fireDate = [NSDate distantPast]; | ||
| 1821 | + //记录步数 | ||
| 1822 | + [[CNTrackServiceManager defaultManager] recordStep:[NSDate date] isUser:YES]; | ||
| 1823 | + }else{ | ||
| 1824 | + UIAlertController *actionAlert = [UIAlertController alertControllerWithTitle:nil message:@"服务异常,请重试。" preferredStyle:UIAlertControllerStyleAlert]; | ||
| 1825 | + UIAlertAction *action = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { | ||
| 1826 | + }]; | ||
| 1827 | + [actionAlert addAction:action]; | ||
| 1828 | + [self presentViewController:actionAlert animated:YES completion:nil]; | ||
| 1829 | + } | ||
| 1830 | + }else{ | ||
| 1831 | + [CNTrackServiceManager defaultManager].isStartRecord = YES; | ||
| 1832 | + [self.startRunningTimer setFireDate:[NSDate date]]; | ||
| 1833 | +// [self startRunningTime]; | ||
| 1834 | + self->_isStopRun = NO; | ||
| 1835 | + [CNTrackServiceManager defaultManager].isClickGoOn = YES; | ||
| 1836 | + | ||
| 1837 | + //实时查询一次两个围栏 | ||
| 1838 | + [self queryRealtimeStatus]; | ||
| 1839 | + if ([self.exitModel.isStop isEqualToString:@"yes"]) { | ||
| 1840 | + if (self.exitModel.reStartTime.length > 0 && ![self.exitModel.reStartTime isEqualToString:@"<null>"]) { | ||
| 1841 | + self->_reStartDate = [self.exitModel.reStartTime integerValue]; | ||
| 1842 | + self.exitModel.reStartTime = [NSString stringWithFormat:@"%ld",self->_reStartDate]; | ||
| 1843 | + [[CNTrackLoaclDataManager shareManager] updateExitModel:self.exitModel]; | ||
| 1844 | + }else{ | ||
| 1845 | + self->_reStartDate = [CNLiveTimeTools getNowTimestamp]; | ||
| 1846 | + self.exitModel.reStartTime = [NSString stringWithFormat:@"%ld",self->_reStartDate]; | ||
| 1847 | + [[CNTrackLoaclDataManager shareManager] updateExitModel:self.exitModel]; | ||
| 1848 | + } | ||
| 1849 | + } | ||
| 1850 | + self.stopRunningBtn.hidden = NO; | ||
| 1851 | + self.goonRunningBtn.hidden = YES; | ||
| 1852 | + // self.startRunningTimer.fireDate = [NSDate distantPast]; | ||
| 1853 | + //记录步数 | ||
| 1854 | + [[CNTrackServiceManager defaultManager] recordStep:[NSDate date] isUser:YES]; | ||
| 1855 | + } | ||
| 1856 | + } | ||
| 1857 | + break; | ||
| 1858 | + case TRACK_SERVICE_OPERATION_TYPE_STOP_GATHER: | ||
| 1859 | + { | ||
| 1860 | + //采集停止失败 | ||
| 1861 | + if ([title isEqualToString:@"停止采集失败"]) { | ||
| 1862 | + NSLog(@"停止采集失败"); | ||
| 1863 | + if ([CNTrackServiceManager defaultManager].isGatherStarted) { | ||
| 1864 | + [[CNTrackServiceManager defaultManager] stopGather];//重新停止采集 | ||
| 1865 | + }else{ | ||
| 1866 | + if ([CNTrackServiceManager defaultManager].isServiceStarted) { | ||
| 1867 | + [[CNTrackServiceManager defaultManager] stopService];//停止服务 | ||
| 1868 | + } | ||
| 1869 | + } | ||
| 1870 | + }else{//采集停止成功后,停止服务 | ||
| 1871 | + NSLog(@"停止采集成功"); | ||
| 1872 | + if ([CNTrackServiceManager defaultManager].isServiceStarted) { | ||
| 1873 | + [[CNTrackServiceManager defaultManager] stopService];//停止服务 | ||
| 1874 | + } | ||
| 1875 | + } | ||
| 1876 | + } | ||
| 1877 | + break; | ||
| 1878 | + default:{ | ||
| 1879 | + UIAlertController *actionAlert = [UIAlertController alertControllerWithTitle:nil message:@"服务异常,请重试。" preferredStyle:UIAlertControllerStyleAlert]; | ||
| 1880 | + UIAlertAction *action = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { | ||
| 1881 | + }]; | ||
| 1882 | + [actionAlert addAction:action]; | ||
| 1883 | + [self presentViewController:actionAlert animated:YES completion:nil]; | ||
| 1884 | + } | ||
| 1885 | + break; | ||
| 1886 | + } | ||
| 1887 | + }); | ||
| 1888 | +} | ||
| 1889 | + | ||
| 1890 | + | ||
| 1891 | +- (void)endRunningBtnAction:(UIButton *)btn{ | ||
| 1892 | + self.endTipView.hidden = NO; | ||
| 1893 | + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ | ||
| 1894 | + self.endTipView.hidden = YES; | ||
| 1895 | + }); | ||
| 1896 | +} | ||
| 1897 | + | ||
| 1898 | +- (void)longPressAction:(UILongPressGestureRecognizer *)longPress{ | ||
| 1899 | + if (longPress.state == UIGestureRecognizerStateBegan) { | ||
| 1900 | + self.endRunningBgView.transform = CGAffineTransformScale(self.endRunningBtn.transform, 1.2,1.2); | ||
| 1901 | + _isStopEnd = NO; | ||
| 1902 | + [self addProgressViewByAutoLayout]; | ||
| 1903 | + //开始计时 | ||
| 1904 | + _pressEndBtnCurrentTime = 0;//计时器归零 | ||
| 1905 | + self.endTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(cycleProgressRecord) userInfo:nil repeats:YES]; | ||
| 1906 | + }else if (longPress.state == UIGestureRecognizerStateCancelled || longPress.state == UIGestureRecognizerStateEnded || longPress.state == UIGestureRecognizerStateFailed){ | ||
| 1907 | + _isStopEnd = YES; | ||
| 1908 | + } | ||
| 1909 | +} | ||
| 1910 | +//添加cycle | ||
| 1911 | +- (void)addProgressViewByAutoLayout { | ||
| 1912 | + self.progressView = [[CNRunEndCircleProgress alloc] initWithFrame:CGRectZero pathBackColor:[UIColor grayColor] pathFillColor:[UIColor whiteColor] startAngle:0 strokeWidth:20]; | ||
| 1913 | + self.progressView.backgroundColor = [UIColor clearColor]; | ||
| 1914 | + [self.endRunningBtn addSubview:self.progressView]; | ||
| 1915 | + | ||
| 1916 | + [self.progressView mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 1917 | + make.centerX.centerY.equalTo(self.endRunningBtn); | ||
| 1918 | + make.size.mas_equalTo(CGSizeMake(90, 90)); | ||
| 1919 | + }]; | ||
| 1920 | + self.progressView.startAngle = 270; | ||
| 1921 | + self.progressView.reduceAngle = 0; | ||
| 1922 | + self.progressView.strokeWidth = 2; | ||
| 1923 | + self.progressView.duration = 2; | ||
| 1924 | + self.progressView.showPoint = NO; | ||
| 1925 | + self.progressView.showProgressText = NO; | ||
| 1926 | + self.progressView.increaseFromLast = YES; | ||
| 1927 | +} | ||
| 1928 | +- (void)cycleProgressRecord{ | ||
| 1929 | + if (_isStopEnd || _pressEndBtnCurrentTime >= 1.5) { | ||
| 1930 | + if (_pressEndBtnCurrentTime >= 1.5) { | ||
| 1931 | + self.endTipView.hidden = YES; | ||
| 1932 | + _isEndRunning = YES; | ||
| 1933 | + //持久记录结束时间 | ||
| 1934 | + _endRunningDate = [CNLiveTimeTools getNowTimestamp]; | ||
| 1935 | + self.backBtn.userInteractionEnabled = NO; | ||
| 1936 | + [self afterLongPressDealAction];//长按结束后的处理 | ||
| 1937 | + }else{ | ||
| 1938 | + self.endTipView.hidden = NO; | ||
| 1939 | + } | ||
| 1940 | + self.endRunningBgView.transform = CGAffineTransformIdentity; | ||
| 1941 | + _pressEndBtnCurrentTime = 0; | ||
| 1942 | + _isStopEnd = YES; | ||
| 1943 | + [self.progressView removeAllSubviews]; | ||
| 1944 | + [self.progressView removeFromSuperview]; | ||
| 1945 | + if ([self.endTimer isValid]){//停止计时器 | ||
| 1946 | + [self.endTimer invalidate]; | ||
| 1947 | + self.endTimer = nil; | ||
| 1948 | + return; | ||
| 1949 | + } | ||
| 1950 | + } | ||
| 1951 | + _pressEndBtnCurrentTime += 0.15; | ||
| 1952 | + self.progressView.progress = _pressEndBtnCurrentTime/1.5; | ||
| 1953 | + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ | ||
| 1954 | + self.endTipView.hidden = YES; | ||
| 1955 | + }); | ||
| 1956 | +} | ||
| 1957 | + | ||
| 1958 | +#pragma mark -- private 长按结束后的事件处理 | ||
| 1959 | +- (void)afterLongPressDealAction{ | ||
| 1960 | + [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"isShowOnce"]; | ||
| 1961 | + //(删除本地地理围栏;待定)停止服务端地理围栏;停止服务; | ||
| 1962 | + //停止轨迹服务;停止定位、画线;停止计步器,暂停时间 | ||
| 1963 | + //停止服务端采集服务,去回调中停止另一个服务 | ||
| 1964 | + [self deleteLocalFence];//删除地理围栏 | ||
| 1965 | + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(serviceResultHandler:) name:TrackServiceOperationResultNotification object:nil];//两个服务的通知 | ||
| 1966 | + [[CNTrackServiceManager defaultManager] stopGather];//停止鹰眼服务 | ||
| 1967 | + | ||
| 1968 | + self.startRunningTimer.fireDate = [NSDate distantFuture]; | ||
| 1969 | + [CNTrackServiceManager defaultManager].isStartRecord = NO; | ||
| 1970 | + //把自己从地图中移除 | ||
| 1971 | + self.mapView.showsUserLocation = NO; | ||
| 1972 | + //下面是UI | ||
| 1973 | + self.fristBgView.hidden = YES;//隐藏主页面 | ||
| 1974 | + self.mapView.hidden = NO;//展示主界面 | ||
| 1975 | + [self.GPSBtn removeFromSuperview];//移除map上的gps | ||
| 1976 | + [self.tipGPSBtn removeFromSuperview];//移除map上的gps提示 | ||
| 1977 | + [self.mapBottomView removeFromSuperview];//移除地图底部的view | ||
| 1978 | + [self.resetBtn removeFromSuperview];//移除重新定位按钮 | ||
| 1979 | + | ||
| 1980 | + //先往失败列表存一下,上传成功后再删除 | ||
| 1981 | + failModel = [[CNTrackUploadFailModel alloc] init]; | ||
| 1982 | + failModel.userId = CNUserShareModelUid; | ||
| 1983 | + failModel.eventId = self.eventID; | ||
| 1984 | + failModel.eventName = self.sportsDetailModel.title; | ||
| 1985 | + failModel.startTime = self.exitModel.startTime; | ||
| 1986 | + failModel.endTime = [NSString stringWithFormat:@"%ld",(long)_endRunningDate]; | ||
| 1987 | + if ([self.exitModel.isStop isEqualToString:@"yes"]) { | ||
| 1988 | + failModel.isStop = @"yes"; | ||
| 1989 | + failModel.stopTime = self.exitModel.stopTime; | ||
| 1990 | + failModel.reStartTime = self.exitModel.reStartTime; | ||
| 1991 | + } | ||
| 1992 | + failModel.totalKM = self.mapCurrentKMLab.text; | ||
| 1993 | + failModel.totalTime = [NSString stringWithFormat:@"%ld",(long)_totalTime]; | ||
| 1994 | + failModel.speed = self.currentSpeedLab.text; | ||
| 1995 | + failModel.totalStep = self.currentStepLab.text; | ||
| 1996 | + NSDictionary *dict = @{@"lat":[NSNumber numberWithDouble:_endAnnotation.coordinate.latitude],@"long":[NSNumber numberWithDouble:_endAnnotation.coordinate.longitude]}; | ||
| 1997 | + failModel.endCoordsDictStr = [dict mj_JSONString]; | ||
| 1998 | + | ||
| 1999 | + failModel.pointsArrStr = self.pointsStr; | ||
| 2000 | + failModel.startLoaction = self.sportsDetailModel.startLocation; | ||
| 2001 | + failModel.endLocation = self.sportsDetailModel.endLocation; | ||
| 2002 | + [[CNTrackLoaclDataManager shareManager] insertFUploadModel:failModel]; | ||
| 2003 | + | ||
| 2004 | + [self.mapView addSubview:self.preSaveView]; | ||
| 2005 | + [self.preSaveView mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2006 | + make.left.right.bottom.equalTo(self.mapView); | ||
| 2007 | + make.height.equalTo(@(49+kVerticalBottomSafeHeight)); | ||
| 2008 | + }]; | ||
| 2009 | + [self.preSaveView addSubview:self.loadingSaveView]; | ||
| 2010 | + [self.loadingSaveView mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2011 | + make.width.height.equalTo(@(24)); | ||
| 2012 | + make.centerY.equalTo(self.preSaveView).offset(-kVerticalBottomSafeHeight/2); | ||
| 2013 | + make.centerX.equalTo(self.preSaveView).offset(-28); | ||
| 2014 | + }]; | ||
| 2015 | + | ||
| 2016 | + UILabel *lab = [[UILabel alloc] init]; | ||
| 2017 | + lab.text = @"保存中"; | ||
| 2018 | + lab.textAlignment = NSTextAlignmentLeft; | ||
| 2019 | + lab.textColor = kWhiteColor; | ||
| 2020 | + lab.font = [UIFont systemFontOfSize:18]; | ||
| 2021 | + [self.preSaveView addSubview:lab]; | ||
| 2022 | + [lab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2023 | + make.centerY.equalTo(self.preSaveView).offset(-kVerticalBottomSafeHeight/2); | ||
| 2024 | + make.left.equalTo(self.loadingSaveView.mas_right).offset(2); | ||
| 2025 | + }]; | ||
| 2026 | + [self startAnimation];//转圈 | ||
| 2027 | + [self.mapView addSubview:self.saveBtn]; | ||
| 2028 | + [self.saveBtn mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2029 | + make.left.right.bottom.equalTo(self.mapView); | ||
| 2030 | + make.height.equalTo(@(49+kVerticalBottomSafeHeight)); | ||
| 2031 | + }]; | ||
| 2032 | + self.saveBtn.titleEdgeInsets = UIEdgeInsetsMake(-kVerticalBottomSafeHeight, 0, 0, 0); | ||
| 2033 | + self.saveBtn.hidden = YES; | ||
| 2034 | + [self.mapView addSubview:self.tableView]; | ||
| 2035 | + UIView *headerView = [UIView new]; | ||
| 2036 | + headerView.backgroundColor = [UIColor clearColor]; | ||
| 2037 | + headerView.frame = CGRectMake(0, 0, SCREEN_WIDTH, 345); | ||
| 2038 | + self.tableView.tableHeaderView = headerView; | ||
| 2039 | + [headerView addSubview:self.backBtn]; | ||
| 2040 | + self.tableView.view = self.backBtn; | ||
| 2041 | + [self.backBtn mas_updateConstraints:^(MASConstraintMaker *make) { | ||
| 2042 | + make.left.top.equalTo(headerView).offset(10); | ||
| 2043 | + make.size.mas_equalTo(CGSizeMake(45, 45)); | ||
| 2044 | + }]; | ||
| 2045 | + [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2046 | + make.left.right.equalTo(self.mapView); | ||
| 2047 | + make.bottom.equalTo(self.mapView.mas_bottom).offset(-49-kVerticalBottomSafeHeight); | ||
| 2048 | + make.top.equalTo(self.mapView); | ||
| 2049 | + }]; | ||
| 2050 | + if (localFenceId) { | ||
| 2051 | + //判断是否经过了终点 | ||
| 2052 | + [self queryLocalHistoryAlarm]; | ||
| 2053 | + }else{ | ||
| 2054 | + [self judgeSuccessTrack]; | ||
| 2055 | + } | ||
| 2056 | + | ||
| 2057 | +} | ||
| 2058 | + | ||
| 2059 | +#pragma mark -- 自己的历史轨迹 | ||
| 2060 | +- (void)queryCurrentRunningEndPoint:(void(^)(NSArray *))handle{ | ||
| 2061 | + NSMutableArray *tempArray = [NSMutableArray arrayWithCapacity:0]; | ||
| 2062 | + if ([self.exitModel.isStop isEqualToString:@"yes"]) { | ||
| 2063 | + CNHistoryTrackParam * paramInfo =[[CNHistoryTrackParam alloc]init]; | ||
| 2064 | + [paramInfo setStartTime:[self.exitModel.startTime integerValue]]; | ||
| 2065 | + [paramInfo setEndTime:[self.exitModel.stopTime integerValue]]; | ||
| 2066 | + [paramInfo setEntityName:CNUserShareModelUid]; | ||
| 2067 | + [paramInfo setIsProcessed:true]; | ||
| 2068 | + BTKQueryTrackProcessOption *processOption = [[BTKQueryTrackProcessOption alloc] init]; | ||
| 2069 | + processOption.radiusThreshold = 100; | ||
| 2070 | + processOption.denoise = true; | ||
| 2071 | + processOption.vacuate = true; | ||
| 2072 | + processOption.mapMatch = false; | ||
| 2073 | + processOption.transportMode = BTK_TRACK_PROCESS_OPTION_TRANSPORT_MODE_WALKING; | ||
| 2074 | + paramInfo.processOption = processOption; | ||
| 2075 | + paramInfo.supplementMode = BTK_TRACK_PROCESS_OPTION_SUPPLEMENT_MODE_WALKING; | ||
| 2076 | + CNHistoryViewModel *vm = [[CNHistoryViewModel alloc] init]; | ||
| 2077 | + vm.completionHandler = ^(NSArray *points) { | ||
| 2078 | + [tempArray addObjectsFromArray:points]; | ||
| 2079 | + if (self.exitModel.reStartTime.length > 0 && ![self.exitModel.reStartTime isEqualToString:@"<null>"]) { | ||
| 2080 | + CNHistoryTrackParam * paramInfo2 =[[CNHistoryTrackParam alloc]init]; | ||
| 2081 | + [paramInfo2 setStartTime:[self.exitModel.reStartTime integerValue]]; | ||
| 2082 | + [paramInfo2 setEndTime:self->_endRunningDate]; | ||
| 2083 | + [paramInfo2 setEntityName:CNUserShareModelUid]; | ||
| 2084 | + [paramInfo2 setIsProcessed:true]; | ||
| 2085 | + BTKQueryTrackProcessOption *processOption2 = [[BTKQueryTrackProcessOption alloc] init]; | ||
| 2086 | + processOption2.radiusThreshold = 100; | ||
| 2087 | + processOption2.denoise = true; | ||
| 2088 | + processOption2.vacuate = true; | ||
| 2089 | + processOption2.mapMatch = false; | ||
| 2090 | + processOption2.transportMode = BTK_TRACK_PROCESS_OPTION_TRANSPORT_MODE_WALKING; | ||
| 2091 | + paramInfo2.processOption = processOption; | ||
| 2092 | + paramInfo2.supplementMode = BTK_TRACK_PROCESS_OPTION_SUPPLEMENT_MODE_WALKING; | ||
| 2093 | + CNHistoryViewModel *vm2 = [[CNHistoryViewModel alloc] init]; | ||
| 2094 | + vm2.completionHandler = ^(NSArray *points) { | ||
| 2095 | + [tempArray addObjectsFromArray:points]; | ||
| 2096 | + handle(tempArray); | ||
| 2097 | + }; | ||
| 2098 | + [vm2 queryHistoryWithParam:paramInfo2]; | ||
| 2099 | + }else{ | ||
| 2100 | + handle(tempArray); | ||
| 2101 | + } | ||
| 2102 | + }; | ||
| 2103 | + [vm queryHistoryWithParam:paramInfo]; | ||
| 2104 | + }else{ | ||
| 2105 | + CNHistoryTrackParam * paramInfo =[[CNHistoryTrackParam alloc]init]; | ||
| 2106 | + [paramInfo setStartTime:[self.exitModel.startTime integerValue]]; | ||
| 2107 | + [paramInfo setEndTime:_endRunningDate]; | ||
| 2108 | + [paramInfo setEntityName:CNUserShareModelUid]; | ||
| 2109 | + [paramInfo setIsProcessed:true]; | ||
| 2110 | + BTKQueryTrackProcessOption *processOption = [[BTKQueryTrackProcessOption alloc] init]; | ||
| 2111 | + processOption.radiusThreshold = 100; | ||
| 2112 | + processOption.denoise = true; | ||
| 2113 | + processOption.vacuate = true; | ||
| 2114 | + processOption.mapMatch = false; | ||
| 2115 | + processOption.transportMode = BTK_TRACK_PROCESS_OPTION_TRANSPORT_MODE_WALKING; | ||
| 2116 | + paramInfo.processOption = processOption; | ||
| 2117 | + paramInfo.supplementMode = BTK_TRACK_PROCESS_OPTION_SUPPLEMENT_MODE_WALKING; | ||
| 2118 | + CNHistoryViewModel *vm = [[CNHistoryViewModel alloc] init]; | ||
| 2119 | + vm.completionHandler = ^(NSArray *points) { | ||
| 2120 | + [tempArray addObjectsFromArray:points]; | ||
| 2121 | + handle(tempArray); | ||
| 2122 | + }; | ||
| 2123 | + [vm queryHistoryWithParam:paramInfo]; | ||
| 2124 | + } | ||
| 2125 | + | ||
| 2126 | +} | ||
| 2127 | + | ||
| 2128 | +//保存中转圈 | ||
| 2129 | +- (void)startAnimation{ | ||
| 2130 | + CGAffineTransform endAngle = CGAffineTransformMakeRotation(angle * (M_PI / 180.0f)); | ||
| 2131 | + __weak typeof(self) weakSelf = self; | ||
| 2132 | + [UIView animateWithDuration:0.01 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{ | ||
| 2133 | + weakSelf.loadingSaveView.transform = endAngle; | ||
| 2134 | + } completion:^(BOOL finished) { | ||
| 2135 | + __strong typeof(weakSelf) strongSelf = weakSelf; | ||
| 2136 | + self->angle += 2; | ||
| 2137 | + if (!self->_isStopAnimation) { | ||
| 2138 | + [strongSelf startAnimation]; | ||
| 2139 | + } | ||
| 2140 | + }]; | ||
| 2141 | +} | ||
| 2142 | + | ||
| 2143 | +- (void)saveBtnAction:(id)sender{ | ||
| 2144 | + [[NSNotificationCenter defaultCenter] removeObserver:self name:TrackServiceOperationResultNotification object:nil]; | ||
| 2145 | + | ||
| 2146 | + if (_endTimer) { | ||
| 2147 | + [_endTimer invalidate]; | ||
| 2148 | + _endTimer = nil; | ||
| 2149 | + } | ||
| 2150 | + if (_startRunningTimer) { | ||
| 2151 | + [_startRunningTimer invalidate]; | ||
| 2152 | + _startRunningTimer = nil; | ||
| 2153 | + } | ||
| 2154 | + [CNTrackServiceManager defaultManager].isStartRecord = NO; | ||
| 2155 | + if ([self.delegate respondsToSelector:@selector(backToFrontVC)]) { | ||
| 2156 | + [self.delegate backToFrontVC]; | ||
| 2157 | + } | ||
| 2158 | + [self.navigationController popViewControllerAnimated:YES]; | ||
| 2159 | +} | ||
| 2160 | + | ||
| 2161 | +- (void)startCountdown:(void(^)(void))handle{ | ||
| 2162 | + [self.view addSubview:self.startCountdownView]; | ||
| 2163 | + [self.startCountdownView addSubview:self.startCountdownLab]; | ||
| 2164 | + self.startCountdownLab.center = self.startCountdownView.center; | ||
| 2165 | + __block int startIndex = 3; | ||
| 2166 | + [UIView animateWithDuration:0.4 delay:0.5 options:UIViewAnimationOptionCurveEaseIn animations:^{ | ||
| 2167 | + self.startCountdownLab.text = [NSString stringWithFormat:@"%d",startIndex]; | ||
| 2168 | + self.startCountdownLab.transform = CGAffineTransformScale(self.startCountdownLab.transform, 2,2); | ||
| 2169 | + } completion:^(BOOL finished) { | ||
| 2170 | + self.startCountdownLab.hidden = YES; | ||
| 2171 | + self.startCountdownLab.transform = CGAffineTransformIdentity; | ||
| 2172 | + startIndex --;//2 | ||
| 2173 | + [UIView animateWithDuration:0.4 delay:0.5 options:UIViewAnimationOptionCurveEaseIn animations:^{ | ||
| 2174 | + self.startCountdownLab.hidden = NO; | ||
| 2175 | + self.startCountdownLab.text = [NSString stringWithFormat:@"%d",startIndex]; | ||
| 2176 | + self.startCountdownLab.transform =CGAffineTransformScale(self.startCountdownLab.transform, 2,2); | ||
| 2177 | + } completion:^(BOOL finished) { | ||
| 2178 | + self.startCountdownLab.hidden = YES; | ||
| 2179 | + self.startCountdownLab.transform =CGAffineTransformIdentity; | ||
| 2180 | + startIndex --;//1 | ||
| 2181 | + [UIView animateWithDuration:0.4 delay:0.5 options:UIViewAnimationOptionCurveEaseIn animations:^{ | ||
| 2182 | + self.startCountdownLab.hidden = NO; | ||
| 2183 | + self.startCountdownLab.text = [NSString stringWithFormat:@"%d",startIndex]; | ||
| 2184 | + self.startCountdownLab.transform =CGAffineTransformScale(self.startCountdownLab.transform, 2,2); | ||
| 2185 | + } completion:^(BOOL finished) { | ||
| 2186 | + [UIView animateWithDuration:0.4 delay:0.5 options:UIViewAnimationOptionCurveEaseIn animations:^{ | ||
| 2187 | + [self.startCountdownView removeAllSubviews]; | ||
| 2188 | + [self.startCountdownView removeFromSuperview]; | ||
| 2189 | + } completion:^(BOOL finished) { | ||
| 2190 | + if (handle) { | ||
| 2191 | + handle(); | ||
| 2192 | + } | ||
| 2193 | + }]; | ||
| 2194 | + }]; | ||
| 2195 | + }]; | ||
| 2196 | + }]; | ||
| 2197 | +} | ||
| 2198 | +#pragma mark -- tableviewdelegate | ||
| 2199 | +-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{ | ||
| 2200 | + if (_isEndRunning) { | ||
| 2201 | + CGRect rect = [_headImg convertRect:_headImg.bounds toView:AppKeyWindow]; | ||
| 2202 | + self.tableView.receiverHeight = rect.origin.y; | ||
| 2203 | + } | ||
| 2204 | +} | ||
| 2205 | + | ||
| 2206 | +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { | ||
| 2207 | + return 3; | ||
| 2208 | +} | ||
| 2209 | + | ||
| 2210 | +-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ | ||
| 2211 | + | ||
| 2212 | + static NSString *cellid = @"cellid"; | ||
| 2213 | + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; | ||
| 2214 | + UIImageView *bgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"jl-bg"]]; | ||
| 2215 | + if (!cell) { | ||
| 2216 | + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellid]; | ||
| 2217 | + cell.backgroundColor = [UIColor clearColor]; | ||
| 2218 | + [cell addSubview:bgView]; | ||
| 2219 | + } | ||
| 2220 | + cell.selectionStyle = UITableViewCellSelectionStyleNone; | ||
| 2221 | + | ||
| 2222 | + switch (indexPath.row) { | ||
| 2223 | + case 0: | ||
| 2224 | + { | ||
| 2225 | + [self first:bgView cell:cell]; | ||
| 2226 | + } | ||
| 2227 | + break; | ||
| 2228 | + case 1: | ||
| 2229 | + { | ||
| 2230 | + [self second:bgView cell:cell]; | ||
| 2231 | + } | ||
| 2232 | + break; | ||
| 2233 | + case 2: | ||
| 2234 | + { | ||
| 2235 | + [self third:bgView cell:cell]; | ||
| 2236 | + } | ||
| 2237 | + break; | ||
| 2238 | + default: | ||
| 2239 | + break; | ||
| 2240 | + } | ||
| 2241 | + return cell; | ||
| 2242 | +} | ||
| 2243 | + | ||
| 2244 | +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ | ||
| 2245 | + CGFloat height = 0; | ||
| 2246 | + switch (indexPath.row) { | ||
| 2247 | + case 0: | ||
| 2248 | + height = 250; | ||
| 2249 | + break; | ||
| 2250 | + case 1: | ||
| 2251 | + height = 130; | ||
| 2252 | + break; | ||
| 2253 | + case 2: | ||
| 2254 | + height = 260; | ||
| 2255 | + break; | ||
| 2256 | + default: | ||
| 2257 | + break; | ||
| 2258 | + } | ||
| 2259 | + return height; | ||
| 2260 | +} | ||
| 2261 | + | ||
| 2262 | +- (void)first:(UIImageView *)bgView cell:(UITableViewCell *)cell{ | ||
| 2263 | + [bgView mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2264 | + make.left.right.bottom.equalTo(cell); | ||
| 2265 | + make.top.equalTo(cell).offset(20); | ||
| 2266 | + }]; | ||
| 2267 | + _headImg = [[UIImageView alloc] init]; | ||
| 2268 | + [_headImg sd_setImageWithURL:[NSURL URLWithString:CNUserShareModel.faceUrl] placeholderImage:[UIImage imageNamed:@"TOUXIANG"]]; | ||
| 2269 | + [cell addSubview:_headImg]; | ||
| 2270 | + [_headImg mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2271 | + make.top.equalTo(cell).offset(3); | ||
| 2272 | + make.left.equalTo(bgView.mas_left).offset(25); | ||
| 2273 | + make.width.height.equalTo(@(50)); | ||
| 2274 | + }]; | ||
| 2275 | + _headImg.layer.cornerRadius = 25; | ||
| 2276 | + _headImg.layer.masksToBounds = YES; | ||
| 2277 | + _headImg.layer.borderWidth = 2; | ||
| 2278 | + _headImg.layer.borderColor = [UIColor whiteColor].CGColor; | ||
| 2279 | + | ||
| 2280 | + UILabel *headLab = [[UILabel alloc]init]; | ||
| 2281 | + headLab.text = CNUserShareModel.nickname; | ||
| 2282 | + headLab.font = [UIFont systemFontOfSize:13]; | ||
| 2283 | + headLab.textAlignment = NSTextAlignmentLeft; | ||
| 2284 | + headLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0]; | ||
| 2285 | + [cell addSubview:headLab]; | ||
| 2286 | + [headLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2287 | + make.left.equalTo(self->_headImg.mas_right).offset(10); | ||
| 2288 | + make.right.equalTo(bgView.mas_right).offset(-18); | ||
| 2289 | + make.bottom.equalTo(self->_headImg.mas_bottom); | ||
| 2290 | + }]; | ||
| 2291 | + | ||
| 2292 | + UIView *lineView = [[UIView alloc] init]; | ||
| 2293 | + lineView.backgroundColor = KGrayLineColor; | ||
| 2294 | + [bgView addSubview:lineView]; | ||
| 2295 | + [lineView mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2296 | + make.left.equalTo(self->_headImg.mas_left); | ||
| 2297 | + make.right.equalTo(bgView.mas_right).offset(-25); | ||
| 2298 | + make.centerY.equalTo(bgView).offset(7); | ||
| 2299 | + make.height.equalTo(@(0.5)); | ||
| 2300 | + }]; | ||
| 2301 | + | ||
| 2302 | + UILabel *timeLab = [[UILabel alloc] init]; | ||
| 2303 | + NSDate *date = [NSDate dateWithTimeIntervalSince1970:_endRunningDate]; | ||
| 2304 | + | ||
| 2305 | + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; | ||
| 2306 | + [formatter setDateFormat:@"yyyy/MM/dd HH:mm"]; | ||
| 2307 | + NSString *dateString = [formatter stringFromDate: date]; | ||
| 2308 | + timeLab.text = dateString; | ||
| 2309 | + timeLab.font = [UIFont systemFontOfSize:10]; | ||
| 2310 | + timeLab.textColor = [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1.0]; | ||
| 2311 | + timeLab.textAlignment = NSTextAlignmentLeft; | ||
| 2312 | + [bgView addSubview:timeLab]; | ||
| 2313 | + [timeLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2314 | + make.left.equalTo(lineView); | ||
| 2315 | + make.bottom.equalTo(lineView.mas_top).offset(-13); | ||
| 2316 | + }]; | ||
| 2317 | + | ||
| 2318 | + UILabel *addressLab = [[UILabel alloc] init]; | ||
| 2319 | + addressLab.text = self.sportsDetailModel.title; | ||
| 2320 | + addressLab.font = [UIFont systemFontOfSize:15]; | ||
| 2321 | + addressLab.numberOfLines = 0; | ||
| 2322 | + addressLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0]; | ||
| 2323 | + addressLab.textAlignment = NSTextAlignmentLeft; | ||
| 2324 | + [addressLab sizeToFit]; | ||
| 2325 | + [bgView addSubview:addressLab]; | ||
| 2326 | + [addressLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2327 | + make.left.equalTo(lineView); | ||
| 2328 | + make.bottom.equalTo(timeLab.mas_top).offset(-10); | ||
| 2329 | + make.width.equalTo(@(SCREEN_WIDTH/2)); | ||
| 2330 | + }]; | ||
| 2331 | + | ||
| 2332 | + UIView *tempView = [UIView new]; | ||
| 2333 | + [bgView addSubview:tempView]; | ||
| 2334 | + [tempView mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2335 | + make.top.equalTo(addressLab.mas_top); | ||
| 2336 | + make.bottom.equalTo(timeLab.mas_bottom); | ||
| 2337 | + make.left.right.equalTo(bgView); | ||
| 2338 | + }]; | ||
| 2339 | + | ||
| 2340 | + UILabel *totalKMLab = [[UILabel alloc] init]; | ||
| 2341 | + NSDictionary *attributesNum = @{NSFontAttributeName:[UIFont boldSystemFontOfSize:45]}; | ||
| 2342 | + NSDictionary *attributesKM = @{NSFontAttributeName:[UIFont systemFontOfSize:10]}; | ||
| 2343 | + NSAttributedString *attributedString = [self attributedText:@[self.mapCurrentKMLab.text,@" 公里"] attributeAttay:@[attributesNum,attributesKM]]; | ||
| 2344 | + totalKMLab.attributedText = attributedString; | ||
| 2345 | + totalKMLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0]; | ||
| 2346 | + totalKMLab.textAlignment = NSTextAlignmentRight; | ||
| 2347 | + [bgView addSubview:totalKMLab]; | ||
| 2348 | + [totalKMLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2349 | + make.centerY.equalTo(tempView); | ||
| 2350 | + make.right.equalTo(lineView.mas_right); | ||
| 2351 | + }]; | ||
| 2352 | + UILabel *endSpeedLab = [[UILabel alloc] init]; | ||
| 2353 | + endSpeedLab.text = self.currentSpeedLab.text; | ||
| 2354 | + endSpeedLab.font = [UIFont boldSystemFontOfSize:24]; | ||
| 2355 | + endSpeedLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0]; | ||
| 2356 | + endSpeedLab.textAlignment = NSTextAlignmentCenter; | ||
| 2357 | + [bgView addSubview:endSpeedLab]; | ||
| 2358 | + [endSpeedLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2359 | + make.centerX.equalTo(bgView).offset(-SCREEN_WIDTH/2/2); | ||
| 2360 | + make.top.equalTo(lineView.mas_bottom).offset(12); | ||
| 2361 | + }]; | ||
| 2362 | + | ||
| 2363 | + | ||
| 2364 | + UILabel *endSpeedNameLab = [[UILabel alloc] init]; | ||
| 2365 | + endSpeedNameLab.text = @"配速"; | ||
| 2366 | + endSpeedNameLab.font = [UIFont systemFontOfSize:15]; | ||
| 2367 | + endSpeedNameLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0]; | ||
| 2368 | + endSpeedNameLab.textAlignment = NSTextAlignmentCenter; | ||
| 2369 | + [bgView addSubview:endSpeedNameLab]; | ||
| 2370 | + [endSpeedNameLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2371 | + make.centerX.equalTo(endSpeedLab); | ||
| 2372 | + make.top.equalTo(endSpeedLab.mas_bottom).offset(12); | ||
| 2373 | + }]; | ||
| 2374 | + | ||
| 2375 | + UILabel *endTotalTimeLab = [[UILabel alloc] init]; | ||
| 2376 | + endTotalTimeLab.text = self.currentTimeLab.text; | ||
| 2377 | + endTotalTimeLab.font = [UIFont boldSystemFontOfSize:24]; | ||
| 2378 | + endTotalTimeLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0]; | ||
| 2379 | + endTotalTimeLab.textAlignment = NSTextAlignmentCenter; | ||
| 2380 | + [bgView addSubview:endTotalTimeLab]; | ||
| 2381 | + [endTotalTimeLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2382 | + make.centerY.equalTo(endSpeedLab); | ||
| 2383 | + make.centerX.equalTo(bgView).offset(SCREEN_WIDTH/2/2); | ||
| 2384 | + }]; | ||
| 2385 | + | ||
| 2386 | + UILabel *endTimeNameLab = [[UILabel alloc] init]; | ||
| 2387 | + endTimeNameLab.text = @"用时"; | ||
| 2388 | + endTimeNameLab.font = [UIFont systemFontOfSize:15]; | ||
| 2389 | + endTimeNameLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0]; | ||
| 2390 | + endTimeNameLab.textAlignment = NSTextAlignmentCenter; | ||
| 2391 | + [bgView addSubview:endTimeNameLab]; | ||
| 2392 | + [endTimeNameLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2393 | + make.centerY.equalTo(endSpeedNameLab); | ||
| 2394 | + make.centerX.equalTo(endTotalTimeLab); | ||
| 2395 | + }]; | ||
| 2396 | +} | ||
| 2397 | +- (void)second:(UIImageView *)bgView cell:(UITableViewCell *)cell{ | ||
| 2398 | + [bgView mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2399 | + make.top.bottom.left.right.equalTo(cell); | ||
| 2400 | + }]; | ||
| 2401 | + UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"sport-step record"]]; | ||
| 2402 | + [bgView addSubview:imgView]; | ||
| 2403 | + [imgView mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2404 | + make.left.equalTo(bgView).offset(25); | ||
| 2405 | + make.top.equalTo(bgView).offset(15); | ||
| 2406 | + make.size.mas_equalTo(CGSizeMake(16, 17)); | ||
| 2407 | + }]; | ||
| 2408 | + UILabel *stepNameLab = [[UILabel alloc] init]; | ||
| 2409 | + stepNameLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0]; | ||
| 2410 | + stepNameLab.font = [UIFont systemFontOfSize:12]; | ||
| 2411 | + stepNameLab.text = @"总步数"; | ||
| 2412 | + stepNameLab.textAlignment = NSTextAlignmentLeft; | ||
| 2413 | + [bgView addSubview:stepNameLab]; | ||
| 2414 | + [stepNameLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2415 | + make.left.equalTo(imgView.mas_right).offset(10); | ||
| 2416 | + make.bottom.equalTo(imgView.mas_bottom); | ||
| 2417 | + }]; | ||
| 2418 | + | ||
| 2419 | + UILabel *totalStepLab = [[UILabel alloc] init]; | ||
| 2420 | + NSDictionary *attributesNum = @{NSFontAttributeName:[UIFont boldSystemFontOfSize:28],NSForegroundColorAttributeName:[UIColor colorWithRed:35/255.0 green:212/255.0 blue:30/255.0 alpha:1.0]}; | ||
| 2421 | + NSDictionary *attributesKM = @{NSFontAttributeName:[UIFont systemFontOfSize:12],NSForegroundColorAttributeName:[UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0]}; | ||
| 2422 | + NSAttributedString *attributedString = [self attributedText:@[self.currentStepLab.text,@" 步"] attributeAttay:@[attributesNum,attributesKM]]; | ||
| 2423 | + totalStepLab.attributedText = attributedString; | ||
| 2424 | + totalStepLab.textAlignment = NSTextAlignmentCenter; | ||
| 2425 | + [bgView addSubview:totalStepLab]; | ||
| 2426 | + [totalStepLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2427 | + make.centerX.centerY.equalTo(bgView); | ||
| 2428 | + }]; | ||
| 2429 | +} | ||
| 2430 | + | ||
| 2431 | +- (void)third:(UIImageView *)bgView cell:(UITableViewCell *)cell{ | ||
| 2432 | + [bgView mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2433 | + make.top.bottom.left.right.equalTo(cell); | ||
| 2434 | + }]; | ||
| 2435 | + UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"sport-route"]]; | ||
| 2436 | + [bgView addSubview:imgView]; | ||
| 2437 | + [imgView mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2438 | + make.left.equalTo(bgView).offset(25); | ||
| 2439 | + make.top.equalTo(bgView).offset(25); | ||
| 2440 | + make.size.mas_equalTo(CGSizeMake(18, 18)); | ||
| 2441 | + }]; | ||
| 2442 | + UILabel *stepNameLab = [[UILabel alloc] init]; | ||
| 2443 | + stepNameLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0]; | ||
| 2444 | + stepNameLab.font = [UIFont systemFontOfSize:12]; | ||
| 2445 | + stepNameLab.text = @"跑步路线"; | ||
| 2446 | + stepNameLab.textAlignment = NSTextAlignmentLeft; | ||
| 2447 | + [bgView addSubview:stepNameLab]; | ||
| 2448 | + [stepNameLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2449 | + make.left.equalTo(imgView.mas_right).offset(10); | ||
| 2450 | + make.bottom.equalTo(imgView.mas_bottom); | ||
| 2451 | + }]; | ||
| 2452 | + | ||
| 2453 | + UIView *green = [[UIView alloc] init]; | ||
| 2454 | + green.backgroundColor = [UIColor greenColor]; | ||
| 2455 | + [bgView addSubview:green]; | ||
| 2456 | + [green mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2457 | + make.left.equalTo(imgView); | ||
| 2458 | + make.top.equalTo(imgView.mas_bottom).offset(19); | ||
| 2459 | + make.width.height.equalTo(@(6)); | ||
| 2460 | + }]; | ||
| 2461 | + green.layer.cornerRadius = 3; | ||
| 2462 | + green.layer.masksToBounds = YES; | ||
| 2463 | + | ||
| 2464 | + UILabel *qiLab = [[UILabel alloc] init]; | ||
| 2465 | + qiLab.text = @"(起)"; | ||
| 2466 | + qiLab.textAlignment = NSTextAlignmentCenter; | ||
| 2467 | + qiLab.textColor = [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1.0]; | ||
| 2468 | + qiLab.font = [UIFont systemFontOfSize:12]; | ||
| 2469 | + [bgView addSubview:qiLab]; | ||
| 2470 | + [qiLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2471 | + make.centerY.equalTo(green); | ||
| 2472 | + make.left.equalTo(green.mas_right).offset(9); | ||
| 2473 | + }]; | ||
| 2474 | + UILabel *qiADDLab = [[UILabel alloc] init]; | ||
| 2475 | + qiADDLab.text = self.sportsDetailModel.startLocation; | ||
| 2476 | + qiADDLab.textAlignment = NSTextAlignmentLeft; | ||
| 2477 | + qiADDLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0]; | ||
| 2478 | + qiADDLab.font = [UIFont systemFontOfSize:14]; | ||
| 2479 | + [bgView addSubview:qiADDLab]; | ||
| 2480 | + [qiADDLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2481 | + make.centerY.equalTo(green); | ||
| 2482 | + make.left.equalTo(qiLab.mas_right).offset(9); | ||
| 2483 | + }]; | ||
| 2484 | + UIView *line1 = [[UIView alloc] init]; | ||
| 2485 | + line1.backgroundColor = [UIColor colorWithRed:196/255.0 green:196/255.0 blue:196/255.0 alpha:1.0]; | ||
| 2486 | + [bgView addSubview:line1]; | ||
| 2487 | + [line1 mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2488 | + make.centerX.equalTo(green); | ||
| 2489 | + make.top.equalTo(green.mas_bottom).offset(3); | ||
| 2490 | + make.height.equalTo(@(25)); | ||
| 2491 | + make.width.equalTo(@(1)); | ||
| 2492 | + }]; | ||
| 2493 | + | ||
| 2494 | + UIView *red = [[UIView alloc] init]; | ||
| 2495 | + red.backgroundColor = [UIColor colorWithRed:250/255.0 green:82/255.0 blue:52/255.0 alpha:1.0]; | ||
| 2496 | + [bgView addSubview:red]; | ||
| 2497 | + [red mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2498 | + make.centerX.equalTo(green); | ||
| 2499 | + make.top.equalTo(line1.mas_bottom).offset(3); | ||
| 2500 | + make.width.height.equalTo(@(6)); | ||
| 2501 | + }]; | ||
| 2502 | + red.layer.cornerRadius = 3; | ||
| 2503 | + red.layer.masksToBounds = YES; | ||
| 2504 | + UILabel *zhiLab = [[UILabel alloc] init]; | ||
| 2505 | + zhiLab.text = @"(止)"; | ||
| 2506 | + zhiLab.textAlignment = NSTextAlignmentCenter; | ||
| 2507 | + zhiLab.textColor = [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1.0]; | ||
| 2508 | + zhiLab.font = [UIFont systemFontOfSize:12]; | ||
| 2509 | + [bgView addSubview:zhiLab]; | ||
| 2510 | + [zhiLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2511 | + make.centerY.equalTo(red); | ||
| 2512 | + make.centerX.equalTo(qiLab); | ||
| 2513 | + }]; | ||
| 2514 | + UILabel *zhiADDLab = [[UILabel alloc] init]; | ||
| 2515 | + zhiADDLab.text = self.sportsDetailModel.endLocation; | ||
| 2516 | + zhiADDLab.textAlignment = NSTextAlignmentLeft; | ||
| 2517 | + zhiADDLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0]; | ||
| 2518 | + zhiADDLab.font = [UIFont systemFontOfSize:14]; | ||
| 2519 | + [bgView addSubview:zhiADDLab]; | ||
| 2520 | + [zhiADDLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2521 | + make.centerY.equalTo(red); | ||
| 2522 | + make.left.equalTo(qiADDLab); | ||
| 2523 | + }]; | ||
| 2524 | + UIView *line2 = [[UIView alloc] init]; | ||
| 2525 | + line2.backgroundColor = [UIColor colorWithRed:196/255.0 green:196/255.0 blue:196/255.0 alpha:1.0]; | ||
| 2526 | + [bgView addSubview:line2]; | ||
| 2527 | + [line2 mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2528 | + make.centerX.equalTo(green); | ||
| 2529 | + make.top.equalTo(red.mas_bottom).offset(3); | ||
| 2530 | + make.height.equalTo(@(25)); | ||
| 2531 | + make.width.equalTo(@(1)); | ||
| 2532 | + }]; | ||
| 2533 | + | ||
| 2534 | + UIView *gray1 = [[UIView alloc] init]; | ||
| 2535 | + gray1.backgroundColor = [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1.0]; | ||
| 2536 | + [bgView addSubview:gray1]; | ||
| 2537 | + [gray1 mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2538 | + make.centerX.equalTo(green); | ||
| 2539 | + make.top.equalTo(line2.mas_bottom).offset(3); | ||
| 2540 | + make.width.height.equalTo(@(4)); | ||
| 2541 | + }]; | ||
| 2542 | + gray1.layer.cornerRadius = 2; | ||
| 2543 | + gray1.layer.masksToBounds = YES; | ||
| 2544 | + UILabel *timeLab = [[UILabel alloc] init]; | ||
| 2545 | + timeLab.text = self.currentTimeLab.text; | ||
| 2546 | + timeLab.textAlignment = NSTextAlignmentLeft; | ||
| 2547 | + timeLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0]; | ||
| 2548 | + timeLab.font = [UIFont boldSystemFontOfSize:18]; | ||
| 2549 | + [bgView addSubview:timeLab]; | ||
| 2550 | + [timeLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2551 | + make.centerY.equalTo(gray1); | ||
| 2552 | + make.left.equalTo(qiLab); | ||
| 2553 | + }]; | ||
| 2554 | + UILabel *timeNameLab = [[UILabel alloc] init]; | ||
| 2555 | + timeNameLab.text = @"跑步记录时长"; | ||
| 2556 | + timeNameLab.textAlignment = NSTextAlignmentLeft; | ||
| 2557 | + timeNameLab.textColor = [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1.0]; | ||
| 2558 | + timeNameLab.font = [UIFont systemFontOfSize:11]; | ||
| 2559 | + [bgView addSubview:timeNameLab]; | ||
| 2560 | + [timeNameLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2561 | + make.left.equalTo(qiLab); | ||
| 2562 | + make.top.equalTo(timeLab.mas_bottom).offset(6); | ||
| 2563 | + }]; | ||
| 2564 | + UIView *line3 = [[UIView alloc] init]; | ||
| 2565 | + line3.backgroundColor = [UIColor colorWithRed:196/255.0 green:196/255.0 blue:196/255.0 alpha:1.0]; | ||
| 2566 | + [bgView addSubview:line3]; | ||
| 2567 | + [line3 mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2568 | + make.centerX.equalTo(green); | ||
| 2569 | + make.top.equalTo(gray1.mas_bottom).offset(3); | ||
| 2570 | + make.height.equalTo(@(55)); | ||
| 2571 | + make.width.equalTo(@(1)); | ||
| 2572 | + }]; | ||
| 2573 | + UIView *gray2 = [[UIView alloc] init]; | ||
| 2574 | + gray2.backgroundColor = [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1.0]; | ||
| 2575 | + [bgView addSubview:gray2]; | ||
| 2576 | + [gray2 mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2577 | + make.centerX.equalTo(green); | ||
| 2578 | + make.top.equalTo(line3.mas_bottom).offset(3); | ||
| 2579 | + make.width.height.equalTo(@(4)); | ||
| 2580 | + }]; | ||
| 2581 | + gray2.layer.cornerRadius = 2; | ||
| 2582 | + gray2.layer.masksToBounds = YES; | ||
| 2583 | + self.successStateLab = [[UILabel alloc] init]; | ||
| 2584 | + self.successStateLab.text = _endStatus.length>0?_endStatus:@"路线未完成"; | ||
| 2585 | + self.successStateLab.textAlignment = NSTextAlignmentLeft; | ||
| 2586 | + self.successStateLab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0]; | ||
| 2587 | + self.successStateLab.font = [UIFont systemFontOfSize:11]; | ||
| 2588 | + [bgView addSubview:self.successStateLab]; | ||
| 2589 | + [self.successStateLab mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 2590 | + make.centerY.equalTo(gray2); | ||
| 2591 | + make.left.equalTo(qiLab); | ||
| 2592 | + }]; | ||
| 2593 | +} | ||
| 2594 | +#pragma mark -- lazy | ||
| 2595 | +-(UIView *)startCountdownView{ | ||
| 2596 | + if (!_startCountdownView) { | ||
| 2597 | + _startCountdownView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)]; | ||
| 2598 | + _startCountdownView.backgroundColor = [UIColor colorWithRed:91/255.0 green:196/255.0 blue:164/255.0 alpha:1.0]; | ||
| 2599 | + } | ||
| 2600 | + return _startCountdownView; | ||
| 2601 | +} | ||
| 2602 | + | ||
| 2603 | +- (UILabel *)startCountdownLab{ | ||
| 2604 | + if (!_startCountdownLab) { | ||
| 2605 | + _startCountdownLab = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 150)]; | ||
| 2606 | + _startCountdownLab.textColor = [UIColor whiteColor]; | ||
| 2607 | + _startCountdownLab.font = [UIFont boldSystemFontOfSize:110]; | ||
| 2608 | + _startCountdownLab.textAlignment = NSTextAlignmentCenter; | ||
| 2609 | + } | ||
| 2610 | + return _startCountdownLab; | ||
| 2611 | +} | ||
| 2612 | + | ||
| 2613 | +-(QMUIButton *)backFirstBtn{ | ||
| 2614 | + if(!_backFirstBtn){ | ||
| 2615 | + _backFirstBtn = [[QMUIButton alloc] init]; | ||
| 2616 | +// [_backFirstBtn setBackgroundImage:[UIImage imageNamed:@"top_back_white"] forState:UIControlStateNormal]; | ||
| 2617 | +// [_backFirstBtn setImage:[UIImage imageNamed:@"top_back"] forState:UIControlStateNormal]; | ||
| 2618 | +// _backFirstBtn.imageEdgeInsets = UIEdgeInsetsMake(-5, -3, 0, 0); | ||
| 2619 | + [_backFirstBtn addTarget:self action:@selector(backFirstBtnAction) forControlEvents:UIControlEventTouchUpInside]; | ||
| 2620 | + } | ||
| 2621 | + return _backFirstBtn; | ||
| 2622 | +} | ||
| 2623 | + | ||
| 2624 | +-(UILabel *)currentKMLab{ | ||
| 2625 | + if (!_currentKMLab) { | ||
| 2626 | + _currentKMLab = [[UILabel alloc] init]; | ||
| 2627 | + _currentKMLab.font = [UIFont boldSystemFontOfSize:70]; | ||
| 2628 | + _currentKMLab.textColor = kWhiteColor; | ||
| 2629 | + _currentKMLab.text = @"0.00"; | ||
| 2630 | + _currentKMLab.textAlignment = NSTextAlignmentCenter; | ||
| 2631 | + } | ||
| 2632 | + return _currentKMLab; | ||
| 2633 | +} | ||
| 2634 | + | ||
| 2635 | +-(UILabel *)gpsLab{ | ||
| 2636 | + if (!_gpsLab) { | ||
| 2637 | + _gpsLab = [[UILabel alloc] init]; | ||
| 2638 | + _gpsLab.font = [UIFont boldSystemFontOfSize:18]; | ||
| 2639 | + _gpsLab.text = @"GPS"; | ||
| 2640 | + _gpsLab.textColor = kWhiteColor; | ||
| 2641 | + _gpsLab.textAlignment = NSTextAlignmentCenter; | ||
| 2642 | + } | ||
| 2643 | + return _gpsLab; | ||
| 2644 | +} | ||
| 2645 | +-(UIImageView *)currentGPSImgView{ | ||
| 2646 | + if (!_currentGPSImgView) { | ||
| 2647 | + _currentGPSImgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"signal-low"]]; | ||
| 2648 | + } | ||
| 2649 | + return _currentGPSImgView; | ||
| 2650 | +} | ||
| 2651 | +-(UILabel *)currentGPSLab{ | ||
| 2652 | + if (!_currentGPSLab) { | ||
| 2653 | + _currentGPSLab = [[UILabel alloc] init]; | ||
| 2654 | + _currentGPSLab.font = [UIFont systemFontOfSize:10]; | ||
| 2655 | + _currentGPSLab.text = @"信号槽糕,数据准确度低"; | ||
| 2656 | + _currentGPSLab.textColor = [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1.0]; | ||
| 2657 | + _currentGPSLab.textAlignment = NSTextAlignmentLeft; | ||
| 2658 | + | ||
| 2659 | + } | ||
| 2660 | + return _currentGPSLab; | ||
| 2661 | +} | ||
| 2662 | +-(UIButton *)detailMapBtn{ | ||
| 2663 | + if (!_detailMapBtn) { | ||
| 2664 | + _detailMapBtn = [[UIButton alloc] init]; | ||
| 2665 | + [_detailMapBtn setImage:[UIImage imageNamed:@"startRunning_map"] forState:UIControlStateNormal]; | ||
| 2666 | + [_detailMapBtn addTarget:self action:@selector(showMapView:) forControlEvents:UIControlEventTouchUpInside]; | ||
| 2667 | + } | ||
| 2668 | + return _detailMapBtn; | ||
| 2669 | +} | ||
| 2670 | +-(UILabel *)mapDesLab{ | ||
| 2671 | + if (!_mapDesLab) { | ||
| 2672 | + _mapDesLab = [[UILabel alloc] init]; | ||
| 2673 | + _mapDesLab.font = [UIFont systemFontOfSize:10]; | ||
| 2674 | + _mapDesLab.text = @"点击查看轨迹"; | ||
| 2675 | + _mapDesLab.textColor = [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1.0]; | ||
| 2676 | + _mapDesLab.textAlignment = NSTextAlignmentCenter; | ||
| 2677 | + } | ||
| 2678 | + return _mapDesLab; | ||
| 2679 | +} | ||
| 2680 | +-(UIImageView *)speedImgView{ | ||
| 2681 | + if (!_speedImgView) { | ||
| 2682 | + _speedImgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"sport-speed"]]; | ||
| 2683 | + } | ||
| 2684 | + return _speedImgView; | ||
| 2685 | +} | ||
| 2686 | +-(UILabel *)currentSpeedLab{ | ||
| 2687 | + if (!_currentSpeedLab) { | ||
| 2688 | + _currentSpeedLab = [[UILabel alloc] init]; | ||
| 2689 | + _currentSpeedLab.font = [UIFont systemFontOfSize:24]; | ||
| 2690 | + _currentSpeedLab.textColor = kWhiteColor; | ||
| 2691 | + _currentSpeedLab.text = @"--"; | ||
| 2692 | + _currentSpeedLab.textAlignment = NSTextAlignmentCenter; | ||
| 2693 | + } | ||
| 2694 | + return _currentSpeedLab; | ||
| 2695 | +} | ||
| 2696 | +-(UILabel *)speedDesLab{ | ||
| 2697 | + if (!_speedDesLab) { | ||
| 2698 | + _speedDesLab = [[UILabel alloc] init]; | ||
| 2699 | + _speedDesLab.font = [UIFont systemFontOfSize:15]; | ||
| 2700 | + _speedDesLab.textColor = [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1.0]; | ||
| 2701 | + _speedDesLab.text = @"配速"; | ||
| 2702 | + _speedDesLab.textAlignment = NSTextAlignmentCenter; | ||
| 2703 | + } | ||
| 2704 | + return _speedDesLab; | ||
| 2705 | +} | ||
| 2706 | +-(UIImageView *)timeImgView{ | ||
| 2707 | + if (!_timeImgView) { | ||
| 2708 | + _timeImgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"sport-time cost"]]; | ||
| 2709 | + } | ||
| 2710 | + return _timeImgView; | ||
| 2711 | +} | ||
| 2712 | +-(UILabel *)currentTimeLab{ | ||
| 2713 | + if (!_currentTimeLab) { | ||
| 2714 | + _currentTimeLab = [[UILabel alloc] init]; | ||
| 2715 | + _currentTimeLab.font = [UIFont systemFontOfSize:24]; | ||
| 2716 | + _currentTimeLab.textColor = kWhiteColor; | ||
| 2717 | + _currentTimeLab.text = @"00:00:00"; | ||
| 2718 | + _currentTimeLab.textAlignment = NSTextAlignmentCenter; | ||
| 2719 | + } | ||
| 2720 | + return _currentTimeLab; | ||
| 2721 | +} | ||
| 2722 | +-(UILabel *)timeDesLab{ | ||
| 2723 | + if (!_timeDesLab) { | ||
| 2724 | + _timeDesLab = [[UILabel alloc] init]; | ||
| 2725 | + _timeDesLab.font = [UIFont systemFontOfSize:15]; | ||
| 2726 | + _timeDesLab.textColor = [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1.0]; | ||
| 2727 | + _timeDesLab.text = @"用时"; | ||
| 2728 | + _timeDesLab.textAlignment = NSTextAlignmentCenter; | ||
| 2729 | + } | ||
| 2730 | + return _timeDesLab; | ||
| 2731 | +} | ||
| 2732 | +-(UIImageView *)stepImgView{ | ||
| 2733 | + if (!_stepImgView) { | ||
| 2734 | + _stepImgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"sport-step"]]; | ||
| 2735 | + } | ||
| 2736 | + return _stepImgView; | ||
| 2737 | +} | ||
| 2738 | +-(UILabel *)currentStepLab{ | ||
| 2739 | + if (!_currentStepLab) { | ||
| 2740 | + _currentStepLab = [[UILabel alloc] init]; | ||
| 2741 | + _currentStepLab.font = [UIFont systemFontOfSize:24]; | ||
| 2742 | + _currentStepLab.textColor = kWhiteColor; | ||
| 2743 | + _currentStepLab.text = @"--"; | ||
| 2744 | + _currentStepLab.textAlignment = NSTextAlignmentCenter; | ||
| 2745 | + } | ||
| 2746 | + return _currentStepLab; | ||
| 2747 | +} | ||
| 2748 | +-(UILabel *)stepDesLab{ | ||
| 2749 | + if (!_stepDesLab) { | ||
| 2750 | + _stepDesLab = [[UILabel alloc] init]; | ||
| 2751 | + _stepDesLab.font = [UIFont systemFontOfSize:15]; | ||
| 2752 | + _stepDesLab.textColor = [UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1.0]; | ||
| 2753 | + _stepDesLab.text = @"步"; | ||
| 2754 | + _stepDesLab.textAlignment = NSTextAlignmentCenter; | ||
| 2755 | + } | ||
| 2756 | + return _stepDesLab; | ||
| 2757 | +} | ||
| 2758 | +-(QMUIButton *)stopRunningBtn{ | ||
| 2759 | + if (!_stopRunningBtn) { | ||
| 2760 | + _stopRunningBtn = [[QMUIButton alloc] init]; | ||
| 2761 | + _stopRunningBtn.imagePosition = QMUIButtonImagePositionTop; | ||
| 2762 | + _stopRunningBtn.spacingBetweenImageAndTitle = 8; | ||
| 2763 | + [_stopRunningBtn setBackgroundImage:[UIImage imageWithColor:kWhiteColor] forState:UIControlStateNormal]; | ||
| 2764 | + [_stopRunningBtn setImage:[UIImage imageNamed:@"pbjs-time out"] forState:UIControlStateNormal]; | ||
| 2765 | + [_stopRunningBtn setTitle:@"暂停" forState:UIControlStateNormal]; | ||
| 2766 | + [_stopRunningBtn setTitleColor:kBlackColor forState:UIControlStateNormal]; | ||
| 2767 | + _stopRunningBtn.titleLabel.font = [UIFont systemFontOfSize:13]; | ||
| 2768 | + [_stopRunningBtn addTarget:self action:@selector(stopRunningBtnAction:) forControlEvents:UIControlEventTouchUpInside]; | ||
| 2769 | + } | ||
| 2770 | + return _stopRunningBtn; | ||
| 2771 | +} | ||
| 2772 | + | ||
| 2773 | +-(QMUIButton *)goonRunningBtn{ | ||
| 2774 | + if (!_goonRunningBtn) { | ||
| 2775 | + _goonRunningBtn = [[QMUIButton alloc] init]; | ||
| 2776 | + _goonRunningBtn.imagePosition = QMUIButtonImagePositionTop; | ||
| 2777 | + _goonRunningBtn.spacingBetweenImageAndTitle = 8; | ||
| 2778 | + [_goonRunningBtn setBackgroundImage:[UIImage imageWithColor:[UIColor colorWithRed:91/255.0 green:196/255.0 blue:164/255.0 alpha:1.0]] forState:UIControlStateNormal]; | ||
| 2779 | + [_goonRunningBtn setImage:[UIImage imageNamed:@"pbjs-play"] forState:UIControlStateNormal]; | ||
| 2780 | + [_goonRunningBtn setTitle:@"继续" forState:UIControlStateNormal]; | ||
| 2781 | + [_goonRunningBtn setTitleColor:kWhiteColor forState:UIControlStateNormal]; | ||
| 2782 | + _goonRunningBtn.titleLabel.font = [UIFont systemFontOfSize:13]; | ||
| 2783 | + | ||
| 2784 | + [_goonRunningBtn addTarget:self action:@selector(goonRunningBtnAction:) forControlEvents:UIControlEventTouchUpInside]; | ||
| 2785 | + } | ||
| 2786 | + return _goonRunningBtn; | ||
| 2787 | +} | ||
| 2788 | + | ||
| 2789 | +-(UIView *)endRunningBgView{ | ||
| 2790 | + if (!_endRunningBgView) { | ||
| 2791 | + _endRunningBgView = [[UIView alloc] init]; | ||
| 2792 | + _endRunningBgView.backgroundColor = [UIColor colorWithRed:250/255.0 green:112/255.0 blue:112/255.0 alpha:1.0]; | ||
| 2793 | + } | ||
| 2794 | + return _endRunningBgView; | ||
| 2795 | +} | ||
| 2796 | + | ||
| 2797 | +-(QMUIButton *)endRunningBtn{ | ||
| 2798 | + if (!_endRunningBtn) { | ||
| 2799 | + _endRunningBtn = [[QMUIButton alloc] init]; | ||
| 2800 | + _endRunningBtn.imagePosition = QMUIButtonImagePositionTop; | ||
| 2801 | + _endRunningBtn.spacingBetweenImageAndTitle = 8; | ||
| 2802 | + [_endRunningBtn setBackgroundImage:[UIImage imageWithColor:[UIColor colorWithRed:250/255.0 green:112/255.0 blue:112/255.0 alpha:1.0]] forState:UIControlStateNormal]; | ||
| 2803 | + [_endRunningBtn setImage:[UIImage imageNamed:@"pbjs-finish"] forState:UIControlStateNormal]; | ||
| 2804 | + [_endRunningBtn setTitle:@"结束" forState:UIControlStateNormal]; | ||
| 2805 | + _endRunningBtn.titleLabel.font = [UIFont systemFontOfSize:13]; | ||
| 2806 | + [_endRunningBtn setTitleColor:kWhiteColor forState:UIControlStateNormal]; | ||
| 2807 | + [_endRunningBtn addTarget:self action:@selector(endRunningBtnAction:) forControlEvents:UIControlEventTouchUpInside]; | ||
| 2808 | + } | ||
| 2809 | + return _endRunningBtn; | ||
| 2810 | +} | ||
| 2811 | + | ||
| 2812 | +-(UILongPressGestureRecognizer *)longPress{ | ||
| 2813 | + if (!_longPress) { | ||
| 2814 | + _longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressAction:)]; | ||
| 2815 | + } | ||
| 2816 | + return _longPress; | ||
| 2817 | +} | ||
| 2818 | + | ||
| 2819 | +- (UIImageView *)endTipView{ | ||
| 2820 | + if (!_endTipView) { | ||
| 2821 | + _endTipView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"press finish"]]; | ||
| 2822 | + } | ||
| 2823 | + return _endTipView; | ||
| 2824 | +} | ||
| 2825 | + | ||
| 2826 | +-(UILabel *)endTipLab{ | ||
| 2827 | + if (!_endTipLab) { | ||
| 2828 | + _endTipLab = [[UILabel alloc] init]; | ||
| 2829 | + _endTipLab.text = @"长按结束"; | ||
| 2830 | + _endTipLab.textAlignment = NSTextAlignmentCenter; | ||
| 2831 | + _endTipLab.textColor = kBlackColor; | ||
| 2832 | + _endTipLab.font = [UIFont systemFontOfSize:12]; | ||
| 2833 | + } | ||
| 2834 | + return _endTipLab; | ||
| 2835 | +} | ||
| 2836 | + | ||
| 2837 | +-(BMKMapView *)mapView{ | ||
| 2838 | + if (!_mapView) { | ||
| 2839 | + _mapView = [[BMKMapView alloc] init]; | ||
| 2840 | + _mapView.frame =CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); | ||
| 2841 | + _mapView.delegate = self; | ||
| 2842 | + _mapView.zoomLevel = 19;//缩放等级4-21 | ||
| 2843 | + _mapView.showMapScaleBar = NO;//显示比例尺 | ||
| 2844 | + _mapView.showsUserLocation = YES;//显示定位图层 | ||
| 2845 | + // //显示我的位置,我的位置图标和地图都不会旋转 | ||
| 2846 | + _mapView.userTrackingMode = BMKUserTrackingModeHeading; | ||
| 2847 | + // //更换我的位置图标 | ||
| 2848 | + // // self.mapView是BMKMapView对象 | ||
| 2849 | + BMKLocationViewDisplayParam *param = [[BMKLocationViewDisplayParam alloc] init]; | ||
| 2850 | + // //定位图标名称,需要将该图片放到 mapapi.bundle/images 目录下 | ||
| 2851 | + // // param.locationViewImgName = @"icon_nav_bus"; | ||
| 2852 | + // //用户自定义定位图标,V4.2.1以后支持 | ||
| 2853 | + param.locationViewImage = [UIImage imageNamed:@"map_dw"]; | ||
| 2854 | + //根据配置参数更新定位图层样式 | ||
| 2855 | + //设置显示精度圈,默认YES | ||
| 2856 | + param.isAccuracyCircleShow = NO; | ||
| 2857 | + //精度圈 边框颜色 | ||
| 2858 | +// param.accuracyCircleStrokeColor = kWhiteColor; | ||
| 2859 | +// //精度圈 填充颜色 | ||
| 2860 | +// param.accuracyCircleFillColor = kWhiteColor; | ||
| 2861 | + [_mapView updateLocationViewWithParam:param]; | ||
| 2862 | + } | ||
| 2863 | + return _mapView; | ||
| 2864 | +} | ||
| 2865 | + | ||
| 2866 | +-(QMUIButton *)backBtn{ | ||
| 2867 | + if(!_backBtn){ | ||
| 2868 | + _backBtn = [[QMUIButton alloc] init]; | ||
| 2869 | + [_backBtn setBackgroundImage:[UIImage imageNamed:@"back-bg"] forState:UIControlStateNormal]; | ||
| 2870 | + [_backBtn setImage:[UIImage imageNamed:@"top_back"] forState:UIControlStateNormal]; | ||
| 2871 | + _backBtn.imageEdgeInsets = UIEdgeInsetsMake(-5, -3, 0, 0); | ||
| 2872 | + [_backBtn addTarget:self action:@selector(backBtnAction:) forControlEvents:UIControlEventTouchUpInside]; | ||
| 2873 | + } | ||
| 2874 | + return _backBtn; | ||
| 2875 | +} | ||
| 2876 | + | ||
| 2877 | +- (QMUIButton *)GPSBtn{ | ||
| 2878 | + if(!_GPSBtn){ | ||
| 2879 | + _GPSBtn = [[QMUIButton alloc] init]; | ||
| 2880 | + [_GPSBtn setBackgroundImage:[UIImage imageNamed:@"gps-bg"] forState:UIControlStateNormal]; | ||
| 2881 | + [_GPSBtn setTitle:@"GPS " forState:UIControlStateNormal]; | ||
| 2882 | + [_GPSBtn setTitleColor:kBlackColor forState:UIControlStateNormal]; | ||
| 2883 | + _GPSBtn.titleLabel.font = [UIFont systemFontOfSize:10]; | ||
| 2884 | + [_GPSBtn setImage:[UIImage imageNamed:@"signal-low"] forState:UIControlStateNormal]; | ||
| 2885 | + _GPSBtn.imagePosition = QMUIButtonImagePositionRight; | ||
| 2886 | + _GPSBtn.imageEdgeInsets = UIEdgeInsetsMake(-3, 0, 0, 0); | ||
| 2887 | + _GPSBtn.titleEdgeInsets = UIEdgeInsetsMake(-3, 0, 0, 0); | ||
| 2888 | + } | ||
| 2889 | + return _GPSBtn; | ||
| 2890 | +} | ||
| 2891 | + | ||
| 2892 | +- (QMUIButton *)tipGPSBtn{ | ||
| 2893 | + if(!_tipGPSBtn){ | ||
| 2894 | + _tipGPSBtn = [[QMUIButton alloc] init]; | ||
| 2895 | + [_tipGPSBtn setBackgroundImage:[UIImage imageNamed:@"map-signal-tx"] forState:UIControlStateNormal]; | ||
| 2896 | + [_tipGPSBtn setTitle:@"信号糟糕,数据准确度低" forState:UIControlStateNormal]; | ||
| 2897 | + [_tipGPSBtn setTitleColor:kBlackColor forState:UIControlStateNormal]; | ||
| 2898 | + _tipGPSBtn.titleLabel.font = [UIFont systemFontOfSize:10]; | ||
| 2899 | + _tipGPSBtn.titleEdgeInsets = UIEdgeInsetsMake(-1, 0, 0, 0); | ||
| 2900 | + } | ||
| 2901 | + return _tipGPSBtn; | ||
| 2902 | +} | ||
| 2903 | +-(BMKLocationManager *)locationManager{ | ||
| 2904 | + if (!_locationManager) { | ||
| 2905 | + //初始化实例 | ||
| 2906 | + _locationManager = [[BMKLocationManager alloc] init]; | ||
| 2907 | + //设置delegate | ||
| 2908 | + _locationManager.delegate = self; | ||
| 2909 | + //设置返回位置的坐标系类型 | ||
| 2910 | + _locationManager.coordinateType = BMKLocationCoordinateTypeGCJ02; | ||
| 2911 | + //设置距离过滤参数:10米 | ||
| 2912 | + _locationManager.distanceFilter = 1.0f; | ||
| 2913 | + //设置预期精度参数:10米 | ||
| 2914 | + _locationManager.desiredAccuracy = kCLLocationAccuracyBest; | ||
| 2915 | + //设置应用位置类型:步行、骑行等 | ||
| 2916 | + _locationManager.activityType = CLActivityTypeFitness; | ||
| 2917 | + //设置是否自动停止位置更新 | ||
| 2918 | + _locationManager.pausesLocationUpdatesAutomatically = NO; | ||
| 2919 | + //设置是否允许后台定位 | ||
| 2920 | + _locationManager.allowsBackgroundLocationUpdates = YES; | ||
| 2921 | + //设置位置获取超时时间 | ||
| 2922 | +// _locationManager.locationTimeout = 10; | ||
| 2923 | + //设置获取地址信息超时时间 | ||
| 2924 | + // _locationManager.reGeocodeTimeout = 3; | ||
| 2925 | + } | ||
| 2926 | + return _locationManager; | ||
| 2927 | +} | ||
| 2928 | + | ||
| 2929 | +- (BMKUserLocation *)userLocation{ | ||
| 2930 | + if (!_userLocation) { | ||
| 2931 | + _userLocation = [[BMKUserLocation alloc] init]; | ||
| 2932 | + } | ||
| 2933 | + return _userLocation; | ||
| 2934 | +} | ||
| 2935 | + | ||
| 2936 | +-(QMUIButton *)resetBtn{ | ||
| 2937 | + if(!_resetBtn){ | ||
| 2938 | + _resetBtn = [[QMUIButton alloc] init]; | ||
| 2939 | + [_resetBtn setBackgroundImage:[UIImage imageNamed:@"back-bg"] forState:UIControlStateNormal]; | ||
| 2940 | + [_resetBtn setImage:[UIImage imageNamed:@"map_location"] forState:UIControlStateNormal]; | ||
| 2941 | + _resetBtn.imageEdgeInsets = UIEdgeInsetsMake(-4.5, -0.5, 0, 0); | ||
| 2942 | + [_resetBtn addTarget:self action:@selector(resetBtnAction:) forControlEvents:UIControlEventTouchUpInside]; | ||
| 2943 | + } | ||
| 2944 | + return _resetBtn; | ||
| 2945 | +} | ||
| 2946 | + | ||
| 2947 | +-(UIImageView *)mapBottomView{ | ||
| 2948 | + if (!_mapBottomView) { | ||
| 2949 | + _mapBottomView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"jl-bg"]]; | ||
| 2950 | + } | ||
| 2951 | + return _mapBottomView; | ||
| 2952 | +} | ||
| 2953 | +-(UILabel *)mapCurrentSpeedLab{ | ||
| 2954 | + if (!_mapCurrentSpeedLab) { | ||
| 2955 | + _mapCurrentSpeedLab = [[UILabel alloc] init]; | ||
| 2956 | + _mapCurrentSpeedLab.text = @"--"; | ||
| 2957 | + _mapCurrentSpeedLab.font = [UIFont boldSystemFontOfSize:24]; | ||
| 2958 | + _mapCurrentSpeedLab.textColor = kBlackColor; | ||
| 2959 | + _mapCurrentSpeedLab.textAlignment = NSTextAlignmentCenter; | ||
| 2960 | + } | ||
| 2961 | + return _mapCurrentSpeedLab; | ||
| 2962 | +} | ||
| 2963 | +-(UILabel *)mapSpeedLab{ | ||
| 2964 | + if (!_mapSpeedLab) { | ||
| 2965 | + _mapSpeedLab = [[UILabel alloc] init]; | ||
| 2966 | + _mapSpeedLab.text = @"配速"; | ||
| 2967 | + _mapSpeedLab.font = [UIFont systemFontOfSize:15]; | ||
| 2968 | + _mapSpeedLab.textColor = kBlackColor; | ||
| 2969 | + _mapSpeedLab.textAlignment = NSTextAlignmentCenter; | ||
| 2970 | + } | ||
| 2971 | + return _mapSpeedLab; | ||
| 2972 | +} | ||
| 2973 | +-(UILabel *)mapCurrentTimeLab{ | ||
| 2974 | + if (!_mapCurrentTimeLab) { | ||
| 2975 | + _mapCurrentTimeLab = [[UILabel alloc] init]; | ||
| 2976 | + _mapCurrentTimeLab.text = @"00:00:00"; | ||
| 2977 | + _mapCurrentTimeLab.font = [UIFont boldSystemFontOfSize:24]; | ||
| 2978 | + _mapCurrentTimeLab.textColor = kBlackColor; | ||
| 2979 | + _mapCurrentTimeLab.textAlignment = NSTextAlignmentCenter; | ||
| 2980 | + } | ||
| 2981 | + return _mapCurrentTimeLab; | ||
| 2982 | +} | ||
| 2983 | +-(UILabel *)mapTimeLab{ | ||
| 2984 | + if (!_mapTimeLab) { | ||
| 2985 | + _mapTimeLab = [[UILabel alloc] init]; | ||
| 2986 | + _mapTimeLab.text = @"用时"; | ||
| 2987 | + _mapTimeLab.font = [UIFont systemFontOfSize:15]; | ||
| 2988 | + _mapTimeLab.textColor = kBlackColor; | ||
| 2989 | + _mapTimeLab.textAlignment = NSTextAlignmentCenter; | ||
| 2990 | + } | ||
| 2991 | + return _mapTimeLab; | ||
| 2992 | +} | ||
| 2993 | + | ||
| 2994 | +-(UIView *)fristBgView{ | ||
| 2995 | + if (!_fristBgView) { | ||
| 2996 | + _fristBgView = [[UIView alloc] init]; | ||
| 2997 | + _fristBgView.backgroundColor = kBlackColor; | ||
| 2998 | + } | ||
| 2999 | + return _fristBgView; | ||
| 3000 | +} | ||
| 3001 | +-(UILabel *)mapCurrentKMLab{ | ||
| 3002 | + if (!_mapCurrentKMLab) { | ||
| 3003 | + _mapCurrentKMLab = [[UILabel alloc] init]; | ||
| 3004 | + _mapCurrentKMLab.text = @"0.00"; | ||
| 3005 | + _mapCurrentKMLab.font = [UIFont boldSystemFontOfSize:24]; | ||
| 3006 | + _mapCurrentKMLab.textColor = kBlackColor; | ||
| 3007 | + _mapCurrentKMLab.textAlignment = NSTextAlignmentCenter; | ||
| 3008 | + } | ||
| 3009 | + return _mapCurrentKMLab; | ||
| 3010 | +} | ||
| 3011 | +-(UILabel *)mapKMLab{ | ||
| 3012 | + if (!_mapKMLab) { | ||
| 3013 | + _mapKMLab = [[UILabel alloc] init]; | ||
| 3014 | + _mapKMLab.text = @"距离(km)"; | ||
| 3015 | + _mapKMLab.font = [UIFont systemFontOfSize:15]; | ||
| 3016 | + _mapKMLab.textColor = kBlackColor; | ||
| 3017 | + _mapKMLab.textAlignment = NSTextAlignmentCenter; | ||
| 3018 | + } | ||
| 3019 | + return _mapKMLab; | ||
| 3020 | +} | ||
| 3021 | + | ||
| 3022 | +-(CNTrackTableView *)tableView{ | ||
| 3023 | + if (!_tableView) { | ||
| 3024 | + _tableView = [[CNTrackTableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped]; | ||
| 3025 | + _tableView.dataSource = self; | ||
| 3026 | + _tableView.delegate = self; | ||
| 3027 | + _tableView.receiverHeight = 345; | ||
| 3028 | +// [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"]; | ||
| 3029 | + _tableView.backgroundColor = [UIColor colorWithRed:0/255.0 green:0/255.0 blue:0/255.0 alpha:0.2]; | ||
| 3030 | + _tableView.separatorStyle = UITableViewCellSeparatorStyleNone; | ||
| 3031 | +// _tableView.separatorColor = [UIColor clearColor]; | ||
| 3032 | + _tableView.showsVerticalScrollIndicator = NO; | ||
| 3033 | + | ||
| 3034 | + } | ||
| 3035 | + return _tableView; | ||
| 3036 | +} | ||
| 3037 | +-(UIView *)preSaveView{ | ||
| 3038 | + if (!_preSaveView) { | ||
| 3039 | + _preSaveView = [[UIView alloc] init]; | ||
| 3040 | + _preSaveView.backgroundColor = RGBOF(0x5BC4A4); | ||
| 3041 | + } | ||
| 3042 | + return _preSaveView; | ||
| 3043 | +} | ||
| 3044 | +-(UIImageView *)loadingSaveView{ | ||
| 3045 | + if (!_loadingSaveView) { | ||
| 3046 | + _loadingSaveView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"track_loading"]]; | ||
| 3047 | + } | ||
| 3048 | + return _loadingSaveView; | ||
| 3049 | +} | ||
| 3050 | +-(UIButton *)saveBtn{ | ||
| 3051 | + if (!_saveBtn) { | ||
| 3052 | + _saveBtn = [[UIButton alloc] init]; | ||
| 3053 | + [_saveBtn setTitle:@"完成" forState:UIControlStateNormal]; | ||
| 3054 | + _saveBtn.backgroundColor = RGBOF(0x5BC4A4); | ||
| 3055 | + _saveBtn.userInteractionEnabled = YES; | ||
| 3056 | + _saveBtn.titleLabel.font = [UIFont systemFontOfSize:18]; | ||
| 3057 | + [_saveBtn addTarget:self action:@selector(saveBtnAction:) forControlEvents:UIControlEventTouchUpInside]; | ||
| 3058 | + } | ||
| 3059 | + return _saveBtn; | ||
| 3060 | +} | ||
| 3061 | +-(NSMutableArray *)locationPoints{ | ||
| 3062 | + if (!_locationPoints) { | ||
| 3063 | + _locationPoints = [NSMutableArray arrayWithCapacity:0]; | ||
| 3064 | + } | ||
| 3065 | + return _locationPoints; | ||
| 3066 | +} | ||
| 3067 | +@end |
| 1 | +// | ||
| 2 | +// CNRunExitModel.h | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/24. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import <Foundation/Foundation.h> | ||
| 10 | + | ||
| 11 | +NS_ASSUME_NONNULL_BEGIN | ||
| 12 | + | ||
| 13 | +@interface CNRunExitModel : NSObject | ||
| 14 | +//用户id | ||
| 15 | +@property (nonatomic, copy) NSString *userId; | ||
| 16 | + | ||
| 17 | +//赛事id | ||
| 18 | +@property (nonatomic, copy) NSString *eventId; | ||
| 19 | + | ||
| 20 | +//开始时间 | ||
| 21 | +@property (nonatomic, copy) NSString *startTime; | ||
| 22 | + | ||
| 23 | +//当前步数 30s存一次 | ||
| 24 | +@property (nonatomic, copy) NSString *step; | ||
| 25 | +//是否暂停 | ||
| 26 | +@property (nonatomic, copy) NSString *isStop; | ||
| 27 | + | ||
| 28 | +//暂停时间 | ||
| 29 | +@property (nonatomic, copy) NSString *stopTime; | ||
| 30 | +//重新开始的时间 | ||
| 31 | +@property (nonatomic, copy) NSString *reStartTime; | ||
| 32 | +//暂停次数 | ||
| 33 | +@property (nonatomic, copy) NSString *stopCount; | ||
| 34 | + | ||
| 35 | + | ||
| 36 | + | ||
| 37 | + | ||
| 38 | +////////////////////////////////////////////////// | ||
| 39 | +//记录哪一天 | ||
| 40 | +@property (nonatomic, copy) NSString *time; | ||
| 41 | + | ||
| 42 | +//开始的地点 | ||
| 43 | +@property (nonatomic, copy) NSString *startAdd; | ||
| 44 | + | ||
| 45 | +//结束地点 | ||
| 46 | +@property (nonatomic, copy) NSString *stopAdd; | ||
| 47 | + | ||
| 48 | +//卡路里 | ||
| 49 | +@property (nonatomic, copy) NSString *calorie; | ||
| 50 | + | ||
| 51 | +//服务器赛道数据 | ||
| 52 | +@property (nonatomic, copy) NSString *eventData; | ||
| 53 | + | ||
| 54 | +// 根据数据库查询结果初始化 | ||
| 55 | +- (instancetype)initWithFMResultSet:(FMResultSet *)resultSet; | ||
| 56 | +@end | ||
| 57 | + | ||
| 58 | +NS_ASSUME_NONNULL_END |
| 1 | +// | ||
| 2 | +// CNRunExitModel.m | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/24. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import "CNRunExitModel.h" | ||
| 10 | + | ||
| 11 | +@implementation CNRunExitModel | ||
| 12 | +- (instancetype)initWithFMResultSet:(FMResultSet *)resultSet | ||
| 13 | +{ | ||
| 14 | + if (!resultSet) return nil; | ||
| 15 | + _userId = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"userId"]]; | ||
| 16 | + _eventId = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"eventId"]]; | ||
| 17 | + _startTime = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"startTime"]]; | ||
| 18 | + _step = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"step"]]; | ||
| 19 | + _time = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"time"]]; | ||
| 20 | + _isStop = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"isStop"]]; | ||
| 21 | + _stopTime = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"stopTime"]]; | ||
| 22 | + _reStartTime = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"reStartTime"]]; | ||
| 23 | + _stopCount = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"stopCount"]]; | ||
| 24 | + _startAdd = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"startAdd"]]; | ||
| 25 | + _stopAdd = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"stopAdd"]]; | ||
| 26 | + _calorie = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"calorie"]]; | ||
| 27 | + _eventData = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"eventData"]]; | ||
| 28 | + return self; | ||
| 29 | +} | ||
| 30 | +@end |
| 1 | +// | ||
| 2 | +// CNRunToolModel.h | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/7/4. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import <Foundation/Foundation.h> | ||
| 10 | +@class CNRunToolPointModel; | ||
| 11 | +NS_ASSUME_NONNULL_BEGIN | ||
| 12 | + | ||
| 13 | +@interface CNRunToolModel : NSObject | ||
| 14 | +@property (nonatomic, copy) NSString *userId; | ||
| 15 | +@property (nonatomic, copy) NSString *eventId; | ||
| 16 | +@property (nonatomic, copy) NSString *startTime; | ||
| 17 | +@property (nonatomic, copy) NSString *step; | ||
| 18 | +@property (nonatomic, copy) NSString *endTime; | ||
| 19 | +@property (nonatomic, copy) NSString *pointsStr; | ||
| 20 | +@property (nonatomic, copy) NSString *pointsCount; | ||
| 21 | +@property (nonatomic, copy) NSString *endRun; | ||
| 22 | +- (instancetype)initWithFMResultSet:(FMResultSet *)resultSet; | ||
| 23 | +@end | ||
| 24 | + | ||
| 25 | +NS_ASSUME_NONNULL_END |
| 1 | +// | ||
| 2 | +// CNRunToolModel.m | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/7/4. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import "CNRunToolModel.h" | ||
| 10 | + | ||
| 11 | +@implementation CNRunToolModel | ||
| 12 | +- (instancetype)initWithFMResultSet:(FMResultSet *)resultSet | ||
| 13 | +{ | ||
| 14 | + if (!resultSet) return nil; | ||
| 15 | + _userId = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"userId"]]; | ||
| 16 | + _eventId = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"eventId"]]; | ||
| 17 | + _startTime = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"startTime"]]; | ||
| 18 | + _step = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"step"]]; | ||
| 19 | + _endTime = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"endTime"]]; | ||
| 20 | + _pointsStr = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"pointsStr"]]; | ||
| 21 | + _pointsCount = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"pointsCount"]]; | ||
| 22 | + _endRun = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"endRun"]]; | ||
| 23 | + | ||
| 24 | + return self; | ||
| 25 | +} | ||
| 26 | +@end |
| 1 | +// | ||
| 2 | +// CNRunToolPointModel.h | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/7/4. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import <Foundation/Foundation.h> | ||
| 10 | + | ||
| 11 | +NS_ASSUME_NONNULL_BEGIN | ||
| 12 | +/**打点的model*/ | ||
| 13 | +@interface CNRunToolPointModel : NSObject | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +//经度 | ||
| 17 | +@property (nonatomic, copy) NSString *latitude; | ||
| 18 | +//纬度 | ||
| 19 | +@property (nonatomic, copy) NSString *longitude; | ||
| 20 | + | ||
| 21 | +//地点名称 | ||
| 22 | +@property (nonatomic, copy) NSString *pointName; | ||
| 23 | +@end | ||
| 24 | + | ||
| 25 | +NS_ASSUME_NONNULL_END |
| 1 | +// | ||
| 2 | +// CNTrackLoaclDataManager.h | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/21. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import <Foundation/Foundation.h> | ||
| 10 | +@class CNRunExitModel; | ||
| 11 | +@class CNTrackUploadFailModel; | ||
| 12 | +@class CNRunToolModel; | ||
| 13 | + | ||
| 14 | +@interface CNTrackLoaclDataManager : NSObject | ||
| 15 | +// 获取单例 | ||
| 16 | ++ (instancetype)shareManager; | ||
| 17 | + | ||
| 18 | +// 插入数据 | ||
| 19 | +- (void)insertExitModel:(CNRunExitModel *)model; | ||
| 20 | + | ||
| 21 | +// 根据user id获取数据 | ||
| 22 | +- (CNRunExitModel *)getExitModel:(NSString *)userId; | ||
| 23 | + | ||
| 24 | +// 更新数据 | ||
| 25 | +- (void)updateExitModel:(CNRunExitModel *)model; | ||
| 26 | + | ||
| 27 | +// 删除数据 | ||
| 28 | +- (void)deleteExitModel:(NSString *)userId; | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | +// 插入数据 | ||
| 33 | +- (void)insertFUploadModel:(CNTrackUploadFailModel *)model; | ||
| 34 | + | ||
| 35 | +// 根据user id获取数据list 并排序 | ||
| 36 | +- (NSArray *)getFUploadModel:(NSString *)userId; | ||
| 37 | + | ||
| 38 | +// 删除单条数据,由开始时间 | ||
| 39 | +- (void)deleteFUploadModel:(CNTrackUploadFailModel *)model; | ||
| 40 | + | ||
| 41 | + | ||
| 42 | +- (void)insertRunToolModel:(CNRunToolModel *)model; | ||
| 43 | +- (void)updateRunToolModel:(CNRunToolModel *)model; | ||
| 44 | +- (CNRunToolModel *)getRunToolModel:(NSString *)userId; | ||
| 45 | +- (void)deleteRunToolModel:(CNRunToolModel *)model; | ||
| 46 | +//- (CNLiveAlbumAudioListModel *)getWaitingModel; // 获取第一条等待的数据 | ||
| 47 | +//- (CNLiveAlbumAudioListModel *)getLastDownloadingModel; // 获取最后一条正在下载的数据 | ||
| 48 | +//- (NSArray<CNLiveAlbumAudioListModel *> *)getAllCacheData; // 获取所有数据 | ||
| 49 | +//- (NSArray<CNLiveAlbumAudioListModel *> *)getAllDownloadingData; // 根据lastStateTime倒叙获取所有正在下载的数据 | ||
| 50 | +//- (NSArray<CNLiveAlbumAudioListModel *> *)getAllDownloadedData; // 获取所有下载完成的数据 | ||
| 51 | +//- (NSArray<CNLiveAlbumAudioListModel *> *)getAllUnDownloadedData; // 获取所有未下载完成的数据(包含正在下载、等待、暂停、错误) | ||
| 52 | +//- (NSArray<CNLiveAlbumAudioListModel *> *)getAllWaitingData; // 获取所有等待下载的数据 | ||
| 53 | +//- (CNLiveAlbumAudioListModel *)getModelwithActivityId:(NSString *)activityId; //根据ativityId获取数据 | ||
| 54 | +// | ||
| 55 | +// | ||
| 56 | +//// 更新数据 | ||
| 57 | +//- (void)updateWithModel:(CNLiveAlbumAudioListModel *)model option:(CNDBUpdateOption)option; | ||
| 58 | +// | ||
| 59 | +//// 删除数据 | ||
| 60 | +//- (void)deleteModelWithUrl:(NSString *)activityId; | ||
| 61 | +@end | ||
| 62 | + | ||
| 63 | + |
| 1 | +// | ||
| 2 | +// CNTrackLoaclDataManager.m | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/21. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import "CNTrackLoaclDataManager.h" | ||
| 10 | +#import "CNRunExitModel.h" | ||
| 11 | +#import "CNTrackUploadFailModel.h" | ||
| 12 | +#import "CNRunToolModel.h" | ||
| 13 | + | ||
| 14 | +@interface CNTrackLoaclDataManager () | ||
| 15 | +@property (nonatomic, strong) FMDatabaseQueue *dbQueue; | ||
| 16 | +@property (nonatomic, copy) NSString *uploadFailPath; | ||
| 17 | +@property (nonatomic, copy) NSString *runExitPath; | ||
| 18 | +@property (nonatomic, copy) NSString *runToolPath; | ||
| 19 | + | ||
| 20 | +@end | ||
| 21 | + | ||
| 22 | +@implementation CNTrackLoaclDataManager | ||
| 23 | ++ (instancetype)shareManager | ||
| 24 | +{ | ||
| 25 | + static CNTrackLoaclDataManager *manager = nil; | ||
| 26 | + | ||
| 27 | + static dispatch_once_t onceToken; | ||
| 28 | + dispatch_once(&onceToken, ^{ | ||
| 29 | + manager = [[self alloc] init]; | ||
| 30 | + }); | ||
| 31 | + | ||
| 32 | + return manager; | ||
| 33 | +} | ||
| 34 | + | ||
| 35 | +- (instancetype)init | ||
| 36 | +{ | ||
| 37 | + if (self = [super init]) { | ||
| 38 | + _runExitPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"CNTrackRunExit.sqlite"]; | ||
| 39 | + _uploadFailPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"CNTrackUploadFail.sqlite"]; | ||
| 40 | + _runToolPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"CNTrackRunTool.sqlite"]; | ||
| 41 | + [self createUploadFailedDB]; | ||
| 42 | + [self createRunExitDB]; | ||
| 43 | + [self createRunToolDB]; | ||
| 44 | + } | ||
| 45 | + return self; | ||
| 46 | +} | ||
| 47 | + | ||
| 48 | + | ||
| 49 | +//创建上传失败的数据库 | ||
| 50 | +- (void)createUploadFailedDB{ | ||
| 51 | + // 数据库文件路径 | ||
| 52 | + NSString *path = self.uploadFailPath; | ||
| 53 | + // 创建队列对象,内部会自动创建一个数据库, 并且自动打开 | ||
| 54 | + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:path]; | ||
| 55 | + | ||
| 56 | + [_dbQueue inDatabase:^(FMDatabase *db) { | ||
| 57 | + // 创表 | ||
| 58 | + BOOL result = [db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_UploadFail (id integer PRIMARY KEY AUTOINCREMENT, userId text, eventId text,eventName text,startTime text,endTime text,isStop text,stopTime text,reStartTime text,totalKM text,totalTime text,speed text,totalStep text,endCoordsDictStr text,pointsArrStr text,startLoaction text,endLocation text)"]; | ||
| 59 | + // if (![db columnExists:@"channelName" inTableWithName:@"t_videoCaches"] ) { //新添字段,先判断数据里有没有,没有,添加 | ||
| 60 | + // NSString *channelName = [NSString stringWithFormat:@"ALTER TABLE %@ ADD %@ INTEGER",@"t_videoCaches",@"channelName"]; | ||
| 61 | + // BOOL isSuccess = [db executeUpdate:channelName]; | ||
| 62 | + // if (isSuccess) { | ||
| 63 | + // NSLog(@"插入成功"); | ||
| 64 | + // }else { | ||
| 65 | + // NSLog(@"插入失败"); | ||
| 66 | + // } | ||
| 67 | + // } | ||
| 68 | + if (result) { | ||
| 69 | + NSLog(@"UploadFail数据表创建成功"); | ||
| 70 | + }else { | ||
| 71 | + NSLog(@"UploadFail数据表创建失败"); | ||
| 72 | + } | ||
| 73 | + }]; | ||
| 74 | +} | ||
| 75 | +//创建APP退出或返回功能的数据库 | ||
| 76 | +- (void)createRunExitDB{ | ||
| 77 | + // 数据库文件路径 | ||
| 78 | + NSString *path = self.runExitPath; | ||
| 79 | + // 创建队列对象,内部会自动创建一个数据库, 并且自动打开 | ||
| 80 | + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:path]; | ||
| 81 | + | ||
| 82 | + [_dbQueue inDatabase:^(FMDatabase *db) { | ||
| 83 | + // 创表 | ||
| 84 | + BOOL result = [db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_RunExit (id integer PRIMARY KEY AUTOINCREMENT, userId text, eventId text,startTime text,step text,time text,isStop text,stopTime text,reStartTime text,stopCount text,startAdd text,stopAdd text,calorie text,eventData text)"]; | ||
| 85 | +// if (![db columnExists:@"channelName" inTableWithName:@"t_videoCaches"] ) { //新添字段,先判断数据里有没有,没有,添加 | ||
| 86 | +// NSString *channelName = [NSString stringWithFormat:@"ALTER TABLE %@ ADD %@ INTEGER",@"t_videoCaches",@"channelName"]; | ||
| 87 | +// BOOL isSuccess = [db executeUpdate:channelName]; | ||
| 88 | +// if (isSuccess) { | ||
| 89 | +// NSLog(@"插入成功"); | ||
| 90 | +// }else { | ||
| 91 | +// NSLog(@"插入失败"); | ||
| 92 | +// } | ||
| 93 | +// } | ||
| 94 | + if (result) { | ||
| 95 | + NSLog(@"runExit数据表创建成功"); | ||
| 96 | + }else { | ||
| 97 | + NSLog(@"runExit数据表创建失败"); | ||
| 98 | + } | ||
| 99 | + }]; | ||
| 100 | +} | ||
| 101 | + | ||
| 102 | +- (void)createRunToolDB{ | ||
| 103 | + // 数据库文件路径 | ||
| 104 | + NSString *path = self.runToolPath; | ||
| 105 | + // 创建队列对象,内部会自动创建一个数据库, 并且自动打开 | ||
| 106 | + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:path]; | ||
| 107 | + | ||
| 108 | + [_dbQueue inDatabase:^(FMDatabase *db) { | ||
| 109 | + // 创表 | ||
| 110 | + BOOL result = [db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_RunTool (id integer PRIMARY KEY AUTOINCREMENT, userId text, eventId text,startTime text,step text,endTime text,pointsStr text,pointsCount text,endRun text)"]; | ||
| 111 | + if (result) { | ||
| 112 | + NSLog(@"runTool数据表创建成功"); | ||
| 113 | + }else { | ||
| 114 | + NSLog(@"runTool数据表创建失败"); | ||
| 115 | + } | ||
| 116 | + }]; | ||
| 117 | +} | ||
| 118 | + | ||
| 119 | +#pragma mark - 插入一条数据 | ||
| 120 | +- (void)insertExitModel:(CNRunExitModel *)model | ||
| 121 | +{ | ||
| 122 | + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.runExitPath]; | ||
| 123 | + [_dbQueue inDatabase:^(FMDatabase *db) { | ||
| 124 | + BOOL result = [db executeUpdate:@"INSERT INTO t_RunExit (userId,eventId,startTime,step,time,isStop,stopTime,reStartTime,stopCount,startAdd,stopAdd,calorie,eventData) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)", model.userId.length>0?model.userId :@"", | ||
| 125 | + model.eventId.length>0?model.eventId:@"", | ||
| 126 | + model.startTime.length>0?model.startTime:@"", | ||
| 127 | + model.step.length>0?model.step:@"", | ||
| 128 | + model.time.length>0?model.time:@"", | ||
| 129 | + model.isStop.length>0?model.isStop:@"", | ||
| 130 | + model.stopTime.length>0?model.stopTime:@"", | ||
| 131 | + model.reStartTime.length>0?model.reStartTime:@"", | ||
| 132 | + model.stopCount.length>0?model.stopCount:@"", | ||
| 133 | + model.startAdd.length>0?model.startAdd:@"", | ||
| 134 | + model.stopAdd.length>0?model.stopAdd:@"", | ||
| 135 | + model.calorie.length>0?model.calorie:@"", | ||
| 136 | + model.eventData.length>0?model.eventData :@""];//,model.schedule ?model.schedule:@"",model.channelName ? model.channelName:@"",model.time ? model.time:@"",model.url, model.resumeData, [NSNumber numberWithInteger:model.totalFileSize], [NSNumber numberWithInteger:model.tmpFileSize], [NSNumber numberWithInteger:model.state], [NSNumber numberWithFloat:model.progress], [NSNumber numberWithDouble:0], [NSNumber numberWithInteger:0], [NSNumber numberWithInteger:0],model.fileSize]; | ||
| 137 | + if (result) { | ||
| 138 | + NSLog(@"插入成功"); | ||
| 139 | + }else { | ||
| 140 | + NSLog(@"插入失败"); | ||
| 141 | + } | ||
| 142 | + }]; | ||
| 143 | +} | ||
| 144 | + | ||
| 145 | +// 根据赛事id获取数据 | ||
| 146 | +- (CNRunExitModel *)getExitModel:(NSString *)userId{ | ||
| 147 | + __block CNRunExitModel *model = nil; | ||
| 148 | + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.runExitPath]; | ||
| 149 | + [_dbQueue inDatabase:^(FMDatabase *db) { | ||
| 150 | + FMResultSet *resultSet = [db executeQuery:@"SELECT * FROM t_RunExit WHERE userId = ?", userId]; | ||
| 151 | + while ([resultSet next]) { | ||
| 152 | + model = [[CNRunExitModel alloc] initWithFMResultSet:resultSet]; | ||
| 153 | + } | ||
| 154 | + }]; | ||
| 155 | + return model; | ||
| 156 | +} | ||
| 157 | + | ||
| 158 | +// 更新数据 | ||
| 159 | +- (void)updateExitModel:(CNRunExitModel *)model{ | ||
| 160 | + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.runExitPath]; | ||
| 161 | + [_dbQueue inDatabase:^(FMDatabase *db) { | ||
| 162 | + BOOL result = [db executeUpdate:@"UPDATE t_RunExit SET eventId = ?, startTime = ?, step = ?, time = ?, isStop = ?, stopTime = ?,reStartTime = ?,stopCount = ?, startAdd = ?, stopAdd = ? ,calorie = ? ,eventData = ? WHERE userId = ?", model.eventId, model.startTime,model.step,model.time,model.isStop,model.stopTime,model.reStartTime,model.stopCount, | ||
| 163 | + model.startAdd,model.stopAdd,model.calorie,model.eventData,model.userId]; | ||
| 164 | + if (result) { | ||
| 165 | + NSLog(@"更新成功"); | ||
| 166 | + }else { | ||
| 167 | + NSLog(@"更新失败"); | ||
| 168 | + } | ||
| 169 | + }]; | ||
| 170 | +} | ||
| 171 | + | ||
| 172 | +// 删除数据 | ||
| 173 | +- (void)deleteExitModel:(NSString *)userId{ | ||
| 174 | + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.runExitPath]; | ||
| 175 | + [_dbQueue inDatabase:^(FMDatabase *db) { // where 后面跟的是条件 | ||
| 176 | + BOOL result = [db executeUpdate:@"DELETE FROM t_RunExit WHERE userId = ?", userId]; | ||
| 177 | + if (result) { | ||
| 178 | + NSLog(@"删除成功"); | ||
| 179 | + }else { | ||
| 180 | + NSLog(@"删除失败"); | ||
| 181 | + } | ||
| 182 | + }]; | ||
| 183 | +} | ||
| 184 | + | ||
| 185 | +// 插入数据 | ||
| 186 | +- (void)insertFUploadModel:(CNTrackUploadFailModel *)model{ | ||
| 187 | + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.uploadFailPath]; | ||
| 188 | + [_dbQueue inDatabase:^(FMDatabase *db) { | ||
| 189 | + BOOL result = [db executeUpdate:@"INSERT INTO t_UploadFail (userId,eventId,eventName,startTime,endTime,isStop,stopTime,reStartTime,totalKM,totalTime,speed,totalStep,endCoordsDictStr,pointsArrStr,startLoaction,endLocation) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?,?,?,?)", | ||
| 190 | + model.userId.length>0?model.userId :@"", | ||
| 191 | + model.eventId.length>0?model.eventId:@"", model.eventName.length>0?model.eventName:@"", | ||
| 192 | + model.startTime.length>0?model.startTime:@"", | ||
| 193 | + model.endTime.length>0?model.endTime:@"", | ||
| 194 | + model.isStop.length>0?model.isStop:@"", | ||
| 195 | + model.stopTime.length>0?model.stopTime:@"", | ||
| 196 | + model.reStartTime.length>0?model.reStartTime:@"", | ||
| 197 | + model.totalKM.length>0?model.totalKM:@"", | ||
| 198 | + model.totalTime.length>0?model.totalTime:@"", | ||
| 199 | + model.speed.length>0?model.speed:@"", | ||
| 200 | + model.totalStep.length>0?model.totalStep:@"",model.endCoordsDictStr.length>0?model.endCoordsDictStr:@"",model.pointsArrStr.length>0?model.pointsArrStr:@"",model.startLoaction.length>0?model.startLoaction:@"",model.endLocation.length>0?model.endLocation:@""]; | ||
| 201 | + if (result) { | ||
| 202 | + NSLog(@"插入成功"); | ||
| 203 | + }else { | ||
| 204 | + NSLog(@"插入失败"); | ||
| 205 | + } | ||
| 206 | + }]; | ||
| 207 | +} | ||
| 208 | + | ||
| 209 | +// 根据user id获取数据list 并排序 | ||
| 210 | +- (NSArray *)getFUploadModel:(NSString *)userId{ | ||
| 211 | +// order by lastStateTime desc | ||
| 212 | + __block NSArray<CNTrackUploadFailModel *> *array = nil; | ||
| 213 | + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.uploadFailPath]; | ||
| 214 | + [_dbQueue inDatabase:^(FMDatabase *db) { | ||
| 215 | + FMResultSet *resultSet = [db executeQuery:@"SELECT * FROM t_UploadFail WHERE userId = ?", userId]; | ||
| 216 | + NSMutableArray *tmpArr = [NSMutableArray array]; | ||
| 217 | + while ([resultSet next]) { | ||
| 218 | + [tmpArr addObject:[[CNTrackUploadFailModel alloc] initWithFMResultSet:resultSet]]; | ||
| 219 | + } | ||
| 220 | + array = tmpArr; | ||
| 221 | + }]; | ||
| 222 | + return array; | ||
| 223 | +} | ||
| 224 | + | ||
| 225 | +// 删除单条数据,由开始时间 | ||
| 226 | +- (void)deleteFUploadModel:(CNTrackUploadFailModel *)model{ | ||
| 227 | + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.uploadFailPath]; | ||
| 228 | + [_dbQueue inDatabase:^(FMDatabase *db) { // where 后面跟的是条件 | ||
| 229 | + BOOL result = [db executeUpdate:@"DELETE FROM t_UploadFail WHERE startTime = ?", model.startTime]; | ||
| 230 | + if (result) { | ||
| 231 | + NSLog(@"删除成功"); | ||
| 232 | + }else { | ||
| 233 | + NSLog(@"删除失败"); | ||
| 234 | + } | ||
| 235 | + }]; | ||
| 236 | +} | ||
| 237 | + | ||
| 238 | +- (void)insertRunToolModel:(CNRunToolModel *)model | ||
| 239 | +{ | ||
| 240 | + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.runToolPath]; | ||
| 241 | + [_dbQueue inDatabase:^(FMDatabase *db) { | ||
| 242 | + BOOL result = [db executeUpdate:@"INSERT INTO t_RunTool (userId,eventId,startTime,step,endTime,pointsStr,pointsCount,endRun) VALUES (?, ?, ?,?, ?, ?,?,?)", model.userId.length>0?model.userId :@"", | ||
| 243 | + model.eventId.length>0?model.eventId:@"", | ||
| 244 | + model.startTime.length>0?model.startTime:@"", | ||
| 245 | + model.step.length>0?model.step:@"", | ||
| 246 | + model.endTime.length>0?model.endTime:@"", | ||
| 247 | + model.pointsStr.length>0?model.pointsStr:@"",model.pointsCount.length>0?model.pointsCount:@"",model.endRun.length>0?model.endRun:@""]; | ||
| 248 | + if (result) { | ||
| 249 | + NSLog(@"插入成功"); | ||
| 250 | + }else { | ||
| 251 | + NSLog(@"插入失败"); | ||
| 252 | + } | ||
| 253 | + }]; | ||
| 254 | +} | ||
| 255 | + | ||
| 256 | +// 更新数据 | ||
| 257 | +- (void)updateRunToolModel:(CNRunToolModel *)model{ | ||
| 258 | + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.runToolPath]; | ||
| 259 | + [_dbQueue inDatabase:^(FMDatabase *db) { | ||
| 260 | + BOOL result = [db executeUpdate:@"UPDATE t_RunTool SET eventId = ?, startTime = ?,step = ?, endTime = ?, pointsStr = ?, pointsCount = ?,endRun = ? WHERE userId = ?", model.eventId, model.startTime,model.step,model.endTime,model.pointsStr,model.pointsCount,model.endRun,model.userId]; | ||
| 261 | + if (result) { | ||
| 262 | + NSLog(@"更新成功"); | ||
| 263 | + }else { | ||
| 264 | + NSLog(@"更新失败"); | ||
| 265 | + } | ||
| 266 | + }]; | ||
| 267 | +} | ||
| 268 | + | ||
| 269 | +// 根据赛事id获取数据 | ||
| 270 | +- (CNRunToolModel *)getRunToolModel:(NSString *)userId{ | ||
| 271 | + __block CNRunToolModel *model = nil; | ||
| 272 | + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.runToolPath]; | ||
| 273 | + [_dbQueue inDatabase:^(FMDatabase *db) { | ||
| 274 | + FMResultSet *resultSet = [db executeQuery:@"SELECT * FROM t_RunTool WHERE userId = ?", userId]; | ||
| 275 | + while ([resultSet next]) { | ||
| 276 | + model = [[CNRunToolModel alloc] initWithFMResultSet:resultSet]; | ||
| 277 | + } | ||
| 278 | + }]; | ||
| 279 | + return model; | ||
| 280 | +} | ||
| 281 | + | ||
| 282 | +// 删除单条数据 | ||
| 283 | +- (void)deleteRunToolModel:(CNRunToolModel *)model{ | ||
| 284 | + _dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.runToolPath]; | ||
| 285 | + [_dbQueue inDatabase:^(FMDatabase *db) { // where 后面跟的是条件 | ||
| 286 | + BOOL result = [db executeUpdate:@"DELETE FROM t_RunTool WHERE userId = ?", model.userId]; | ||
| 287 | + if (result) { | ||
| 288 | + NSLog(@"删除成功"); | ||
| 289 | + }else { | ||
| 290 | + NSLog(@"删除失败"); | ||
| 291 | + } | ||
| 292 | + }]; | ||
| 293 | +} | ||
| 294 | + | ||
| 295 | + | ||
| 296 | +@end | ||
| 297 | + |
| 1 | +// | ||
| 2 | +// CNTrackUploadFailModel.h | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/26. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import <Foundation/Foundation.h> | ||
| 10 | + | ||
| 11 | + | ||
| 12 | +@interface CNTrackUploadFailModel : NSObject | ||
| 13 | +//用户id | ||
| 14 | +@property (nonatomic, copy) NSString *userId; | ||
| 15 | + | ||
| 16 | +//赛事id | ||
| 17 | +@property (nonatomic, copy) NSString *eventId; | ||
| 18 | + | ||
| 19 | +//赛事名称 | ||
| 20 | +@property (nonatomic, copy) NSString *eventName; | ||
| 21 | + | ||
| 22 | +//开始时间 | ||
| 23 | +@property (nonatomic, copy) NSString *startTime; | ||
| 24 | + | ||
| 25 | +//结束时间 | ||
| 26 | +@property (nonatomic, copy) NSString *endTime; | ||
| 27 | + | ||
| 28 | +//是否暂停 | ||
| 29 | +@property (nonatomic, copy) NSString *isStop; | ||
| 30 | + | ||
| 31 | +//暂停时间 | ||
| 32 | +@property (nonatomic, copy) NSString *stopTime; | ||
| 33 | + | ||
| 34 | +//重新开始的时间 | ||
| 35 | +@property (nonatomic, copy) NSString *reStartTime; | ||
| 36 | + | ||
| 37 | +//公里 | ||
| 38 | +@property (nonatomic, copy) NSString *totalKM; | ||
| 39 | + | ||
| 40 | +//用时 | ||
| 41 | +@property (nonatomic, copy) NSString *totalTime; | ||
| 42 | + | ||
| 43 | +//配速 | ||
| 44 | +@property (nonatomic, copy) NSString *speed; | ||
| 45 | + | ||
| 46 | +//步数 | ||
| 47 | +@property (nonatomic, copy) NSString *totalStep; | ||
| 48 | + | ||
| 49 | +//赛事的终点坐标是个字典 | ||
| 50 | +@property (nonatomic, copy) NSString *endCoordsDictStr; | ||
| 51 | + | ||
| 52 | +//运营打的点 | ||
| 53 | +@property (nonatomic, copy) NSString *pointsArrStr; | ||
| 54 | + | ||
| 55 | +//---- | ||
| 56 | +//开始的地点 | ||
| 57 | +@property (nonatomic, copy) NSString *startLoaction; | ||
| 58 | +//结束的地点 | ||
| 59 | +@property (nonatomic, copy) NSString *endLocation; | ||
| 60 | + | ||
| 61 | +// 根据数据库查询结果初始化 | ||
| 62 | +- (instancetype)initWithFMResultSet:(FMResultSet *)resultSet; | ||
| 63 | +@end | ||
| 64 | + |
| 1 | +// | ||
| 2 | +// CNTrackUploadFailModel.m | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/26. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import "CNTrackUploadFailModel.h" | ||
| 10 | + | ||
| 11 | +@implementation CNTrackUploadFailModel | ||
| 12 | +- (instancetype)initWithFMResultSet:(FMResultSet *)resultSet | ||
| 13 | +{ | ||
| 14 | + if (!resultSet) return nil; | ||
| 15 | + _userId = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"userId"]]; | ||
| 16 | + _eventId = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"eventId"]]; | ||
| 17 | + _eventName = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"eventName"]]; | ||
| 18 | + _startTime = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"startTime"]]; | ||
| 19 | + _endTime = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"endTime"]]; | ||
| 20 | + _isStop = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"isStop"]]; | ||
| 21 | + _stopTime = [NSString stringWithFormat:@"%@",[resultSet objectForColumn:@"stopTime"]]; | ||
| 22 | + _reStartTime = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"reStartTime"]]; | ||
| 23 | + _totalKM = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"totalKM"]]; | ||
| 24 | + _totalTime = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"totalTime"]]; | ||
| 25 | + _speed = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"speed"]]; | ||
| 26 | + _totalStep = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"totalStep"]]; | ||
| 27 | + _endCoordsDictStr = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"endCoordsDictStr"]]; | ||
| 28 | + _pointsArrStr = [NSString stringWithFormat:@"%@", [resultSet objectForColumn:@"pointsArrStr"]]; | ||
| 29 | + return self; | ||
| 30 | +} | ||
| 31 | +@end |
| 1 | +// | ||
| 2 | +// CNTraceConst.h | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/5. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import <Foundation/Foundation.h> | ||
| 10 | + | ||
| 11 | +NS_ASSUME_NONNULL_BEGIN | ||
| 12 | +/** CNLocationGPSState 枚举识别GPS信号状态 | ||
| 13 | + * | ||
| 14 | + */ | ||
| 15 | +typedef NS_ENUM(int, CNLocationGPSState) { | ||
| 16 | + CNLocationGPSStateGood = 0, ///GPS好 | ||
| 17 | + CNLocationGPSStateMedium, ///GPS中 | ||
| 18 | + CNLocationGPSStatePoor, ///GPS差 | ||
| 19 | + CNLocationGPSStateNull ///GPS无 | ||
| 20 | +}; | ||
| 21 | + | ||
| 22 | +@interface CNTraceConst : NSObject | ||
| 23 | +//FOUNDATION_EXPORT NSString * const AK; | ||
| 24 | +//FOUNDATION_EXPORT NSString * const MCODE; | ||
| 25 | +//FOUNDATION_EXPORT NSUInteger const serviceID; | ||
| 26 | +FOUNDATION_EXPORT NSString * const TrackServiceOperationResultNotification; | ||
| 27 | +FOUNDATION_EXPORT NSString * const TrackServiceGetPushMessageNotification; | ||
| 28 | + | ||
| 29 | +@end | ||
| 30 | + | ||
| 31 | +NS_ASSUME_NONNULL_END |
| 1 | +// | ||
| 2 | +// CNTraceConst.m | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/5. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import "CNTraceConst.h" | ||
| 10 | + | ||
| 11 | +@implementation CNTraceConst | ||
| 12 | + | ||
| 13 | +//#ifdef Environment_ON | ||
| 14 | +//////////////////////////////正式 | ||
| 15 | +// | ||
| 16 | +//#ifdef IPA_APPSTORE | ||
| 17 | +//// 正式企业 | ||
| 18 | +//// 填写你在API控制台申请的iOS类型的AK | ||
| 19 | +//NSString * const AK = @"1249woAM397jz6uGFEfXY4MxRxfkGtIN"; | ||
| 20 | +// | ||
| 21 | +////填写你在API控制台申请iOS类型AK时指定的Bundle Identifier | ||
| 22 | +//NSString * const MCODE = @"com.cnlive.CNLiveNetAddInHouse"; | ||
| 23 | +// | ||
| 24 | +//NSUInteger const serviceID = 214690; | ||
| 25 | +// | ||
| 26 | +//#else | ||
| 27 | +//// 正式个人 | ||
| 28 | +//// 填写你在API控制台申请的iOS类型的AK | ||
| 29 | +//NSString * const AK = @"KbQoyL7KebOF1CvHWHqKa61pf8nMhUL4"; | ||
| 30 | +// | ||
| 31 | +////填写你在API控制台申请iOS类型AK时指定的Bundle Identifier | ||
| 32 | +//NSString * const MCODE = @"com.cnlive.CNLiveNetAdd"; | ||
| 33 | +// | ||
| 34 | +//NSUInteger const serviceID = 214690; | ||
| 35 | +// | ||
| 36 | +//#endif | ||
| 37 | +// | ||
| 38 | +//#else | ||
| 39 | +////////////////////////////////////////测试 | ||
| 40 | +// | ||
| 41 | +//#ifdef IPA_APPSTORE | ||
| 42 | +//// 测试企业 | ||
| 43 | +//// 填写你在API控制台申请的iOS类型的AK | ||
| 44 | +//NSString * const AK = @"Nb4bz9t32YnmTkqVKrNHtToPQAwWvjzK"; | ||
| 45 | +// | ||
| 46 | +////填写你在API控制台申请iOS类型AK时指定的Bundle Identifier | ||
| 47 | +//NSString * const MCODE = @"com.cnlive.CNLiveNetAddInHouse.debug"; | ||
| 48 | +//// 填写你在鹰眼轨迹管理台创建的鹰眼服务对应的ID | ||
| 49 | +//NSUInteger const serviceID = 213511; | ||
| 50 | +// | ||
| 51 | +//#else | ||
| 52 | +//// 测试个人 | ||
| 53 | +//// 填写你在API控制台申请的iOS类型的AK | ||
| 54 | +//NSString * const AK = @"jjrZsIZYalD5IPOkjzCOOqkApKLtn8LW"; | ||
| 55 | +// | ||
| 56 | +////填写你在API控制台申请iOS类型AK时指定的Bundle Identifier | ||
| 57 | +//NSString * const MCODE = @"com.cnlive.CNLiveNetAdd.debug"; | ||
| 58 | +//// 填写你在鹰眼轨迹管理台创建的鹰眼服务对应的ID | ||
| 59 | +//NSUInteger const serviceID = 213511; | ||
| 60 | +// | ||
| 61 | +//#endif | ||
| 62 | +// | ||
| 63 | +//#endif | ||
| 64 | + | ||
| 65 | + | ||
| 66 | + | ||
| 67 | + | ||
| 68 | + | ||
| 69 | + | ||
| 70 | + | ||
| 71 | +NSString * const TrackServiceOperationResultNotification = @"TrackServiceOperationResultNotification"; | ||
| 72 | + | ||
| 73 | +NSString * const TrackServiceGetPushMessageNotification = @"TrackServiceGetPushMessageNotification"; | ||
| 74 | + | ||
| 75 | +@end |
| 1 | +// | ||
| 2 | +// CNTrackServiceManager.h | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/10. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import <Foundation/Foundation.h> | ||
| 10 | + | ||
| 11 | +typedef NS_ENUM(NSUInteger, ServiceOperationType) { | ||
| 12 | + TRACK_SERVICE_OPERATION_TYPE_START_SERVICE, | ||
| 13 | + TRACK_SERVICE_OPERATION_TYPE_STOP_SERVICE, | ||
| 14 | + TRACK_SERVICE_OPERATION_TYPE_START_GATHER, | ||
| 15 | + TRACK_SERVICE_OPERATION_TYPE_STOP_GATHER, | ||
| 16 | +}; | ||
| 17 | +@class CNRunExitModel; | ||
| 18 | + | ||
| 19 | +@protocol CNTrackServiceManagerDelegate <NSObject> | ||
| 20 | + | ||
| 21 | +- (void)currentPedometer:(CNRunExitModel *)model; | ||
| 22 | +- (void)currentToolPedometer:(NSInteger)stepCount; | ||
| 23 | + | ||
| 24 | +@end | ||
| 25 | +@interface CNTrackServiceManager : NSObject <BTKTraceDelegate> | ||
| 26 | + | ||
| 27 | +@property (nonatomic, weak) id <CNTrackServiceManagerDelegate>delegate; | ||
| 28 | ++(CNTrackServiceManager *)defaultManager; | ||
| 29 | +@property (nonatomic, assign) BOOL isStartRecord; | ||
| 30 | + | ||
| 31 | +@property (nonatomic, assign) BOOL noAcceptFenceNotify; | ||
| 32 | +@property (nonatomic, assign) BOOL isClickGoOn; | ||
| 33 | + | ||
| 34 | +/** | ||
| 35 | + 标志是否已经开启轨迹服务 | ||
| 36 | + */ | ||
| 37 | +@property (nonatomic, assign) BOOL isServiceStarted; | ||
| 38 | + | ||
| 39 | +/** | ||
| 40 | + 标志是否已经开始采集 | ||
| 41 | + */ | ||
| 42 | +@property (nonatomic, assign) BOOL isGatherStarted; | ||
| 43 | + | ||
| 44 | +/** | ||
| 45 | + 开启轨迹服务 | ||
| 46 | + | ||
| 47 | + @param startServiceOption 开启服务的选项 | ||
| 48 | + */ | ||
| 49 | +-(void)startServiceWithOption:(BTKStartServiceOption *)startServiceOption; | ||
| 50 | + | ||
| 51 | +/** | ||
| 52 | + 停止轨迹服务 | ||
| 53 | + */ | ||
| 54 | +-(void)stopService; | ||
| 55 | + | ||
| 56 | +/** | ||
| 57 | + 开始采集 | ||
| 58 | + */ | ||
| 59 | +-(void)startGather; | ||
| 60 | + | ||
| 61 | +/** | ||
| 62 | + 停止采集 | ||
| 63 | + */ | ||
| 64 | +-(void)stopGather; | ||
| 65 | + | ||
| 66 | + | ||
| 67 | + | ||
| 68 | +////////////////// | ||
| 69 | + | ||
| 70 | +- (void)recordStep:(NSDate *)date isUser:(BOOL)isU; | ||
| 71 | +@end |
| 1 | +// | ||
| 2 | +// CNTrackServiceManager.m | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/10. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import "CNTrackServiceManager.h" | ||
| 10 | +#import <UserNotifications/UserNotifications.h> | ||
| 11 | +#import <CoreMotion/CoreMotion.h> | ||
| 12 | +#import "CNRunExitModel.h" | ||
| 13 | +#import "CNTrackLoaclDataManager.h" | ||
| 14 | +#import "CNRunToolModel.h" | ||
| 15 | + | ||
| 16 | +#define GLOBAL_QUEUE dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) | ||
| 17 | + | ||
| 18 | +static NSString * const YYPushMessageNotificationIdentifier = @"YYPushMessageNotificationIdentifier"; | ||
| 19 | + | ||
| 20 | +@implementation CNTrackServiceManager{ | ||
| 21 | + CMPedometer *_pedometer;//计步器 | ||
| 22 | + NSInteger _lastStepCount;//最新的步数或起止步数 | ||
| 23 | + BOOL _isUser; | ||
| 24 | +} | ||
| 25 | + | ||
| 26 | ++(CNTrackServiceManager *)defaultManager { | ||
| 27 | + static CNTrackServiceManager *manager = nil; | ||
| 28 | + static dispatch_once_t onceToken; | ||
| 29 | + dispatch_once(&onceToken, ^{ | ||
| 30 | + manager = [[CNTrackServiceManager alloc] init]; | ||
| 31 | + }); | ||
| 32 | + return manager; | ||
| 33 | +} | ||
| 34 | + | ||
| 35 | +-(instancetype)init { | ||
| 36 | + self = [super init]; | ||
| 37 | + if (self) { | ||
| 38 | + _isServiceStarted = FALSE; | ||
| 39 | + _isGatherStarted = FALSE; | ||
| 40 | + } | ||
| 41 | + return self; | ||
| 42 | +} | ||
| 43 | + | ||
| 44 | +#pragma mark private function | ||
| 45 | +-(void)startServiceWithOption:(BTKStartServiceOption *)startServiceOption { | ||
| 46 | + dispatch_async(GLOBAL_QUEUE, ^{ | ||
| 47 | + [[BTKAction sharedInstance] startService:startServiceOption delegate:self]; | ||
| 48 | + [[BTKAction sharedInstance] changeGatherAndPackIntervals:2 packInterval:10 delegate:self]; | ||
| 49 | + [[BTKAction sharedInstance] setLocationAttributeWithActivityType:CLActivityTypeFitness desiredAccuracy:kCLLocationAccuracyBest distanceFilter:1]; | ||
| 50 | + }); | ||
| 51 | +} | ||
| 52 | + | ||
| 53 | +-(void)stopService { | ||
| 54 | + dispatch_async(GLOBAL_QUEUE, ^{ | ||
| 55 | + [[BTKAction sharedInstance] stopService:self]; | ||
| 56 | + }); | ||
| 57 | +} | ||
| 58 | + | ||
| 59 | +-(void)startGather { | ||
| 60 | + dispatch_async(GLOBAL_QUEUE, ^{ | ||
| 61 | + [[BTKAction sharedInstance] startGather:self]; | ||
| 62 | + }); | ||
| 63 | +} | ||
| 64 | + | ||
| 65 | +-(void)stopGather { | ||
| 66 | + dispatch_async(GLOBAL_QUEUE, ^{ | ||
| 67 | + [[BTKAction sharedInstance] stopGather:self]; | ||
| 68 | + }); | ||
| 69 | +} | ||
| 70 | + | ||
| 71 | +#pragma mark - BTKTraceDelegate | ||
| 72 | +-(void)onStartService:(BTKServiceErrorCode)error { | ||
| 73 | + // 维护状态标志 | ||
| 74 | + if (error == BTK_START_SERVICE_SUCCESS || error == BTK_START_SERVICE_SUCCESS_BUT_OFFLINE) { | ||
| 75 | + NSLog(@"轨迹服务开启成功"); | ||
| 76 | + self.isServiceStarted = TRUE; | ||
| 77 | + } else { | ||
| 78 | + NSLog(@"轨迹服务开启失败"); | ||
| 79 | + } | ||
| 80 | + // 构造广播内容 | ||
| 81 | + NSString *title = nil; | ||
| 82 | + NSString *message = nil; | ||
| 83 | + switch (error) { | ||
| 84 | + case BTK_START_SERVICE_SUCCESS: | ||
| 85 | + title = @"轨迹服务开启成功"; | ||
| 86 | + message = @"成功登录到服务端"; | ||
| 87 | + break; | ||
| 88 | + case BTK_START_SERVICE_SUCCESS_BUT_OFFLINE: | ||
| 89 | + title = @"轨迹服务开启成功"; | ||
| 90 | + message = @"当前网络不畅,未登录到服务端。网络恢复后SDK会自动重试"; | ||
| 91 | + break; | ||
| 92 | + case BTK_START_SERVICE_PARAM_ERROR: | ||
| 93 | + title = @"轨迹服务开启失败"; | ||
| 94 | + message = @"参数错误,点击右上角设置按钮设置参数"; | ||
| 95 | + break; | ||
| 96 | + case BTK_START_SERVICE_INTERNAL_ERROR: | ||
| 97 | + title = @"轨迹服务开启失败"; | ||
| 98 | + message = @"SDK服务内部出现错误"; | ||
| 99 | + break; | ||
| 100 | + case BTK_START_SERVICE_NETWORK_ERROR: | ||
| 101 | + title = @"轨迹服务开启失败"; | ||
| 102 | + message = @"网络异常"; | ||
| 103 | + break; | ||
| 104 | + case BTK_START_SERVICE_AUTH_ERROR: | ||
| 105 | + title = @"轨迹服务开启失败"; | ||
| 106 | + message = @"鉴权失败,请检查AK和MCODE等配置信息"; | ||
| 107 | + break; | ||
| 108 | + case BTK_START_SERVICE_IN_PROGRESS: | ||
| 109 | + title = @"轨迹服务开启失败"; | ||
| 110 | + message = @"正在开启服务,请稍后再试"; | ||
| 111 | + break; | ||
| 112 | + case BTK_SERVICE_ALREADY_STARTED_ERROR: | ||
| 113 | + title = @"轨迹服务开启失败"; | ||
| 114 | + message = @"已经成功开启服务,请勿重复开启"; | ||
| 115 | + break; | ||
| 116 | + default: | ||
| 117 | + title = @"轨迹服务开启失败"; | ||
| 118 | + message = @"轨迹服务开启结果未知"; | ||
| 119 | + break; | ||
| 120 | + } | ||
| 121 | + NSDictionary *info = @{@"type":@(TRACK_SERVICE_OPERATION_TYPE_START_SERVICE), | ||
| 122 | + @"title":title, | ||
| 123 | + @"message":message, | ||
| 124 | + }; | ||
| 125 | + // 发送广播 | ||
| 126 | + [[NSNotificationCenter defaultCenter] postNotificationName:TrackServiceOperationResultNotification object:nil userInfo:info]; | ||
| 127 | +} | ||
| 128 | + | ||
| 129 | +-(void)onStopService:(BTKServiceErrorCode)error { | ||
| 130 | + // 维护状态标志 | ||
| 131 | + if (error == BTK_STOP_SERVICE_NO_ERROR) { | ||
| 132 | + NSLog(@"轨迹服务停止成功"); | ||
| 133 | + self.isServiceStarted = FALSE; | ||
| 134 | + } else { | ||
| 135 | + NSLog(@"轨迹服务停止失败"); | ||
| 136 | + } | ||
| 137 | + // 构造广播内容 | ||
| 138 | + NSString *title = nil; | ||
| 139 | + NSString *message = nil; | ||
| 140 | + switch (error) { | ||
| 141 | + case BTK_STOP_SERVICE_NO_ERROR: | ||
| 142 | + title = @"轨迹服务停止成功"; | ||
| 143 | + message = @"SDK已停止工作"; | ||
| 144 | + break; | ||
| 145 | + case BTK_STOP_SERVICE_NOT_YET_STARTED_ERROR: | ||
| 146 | + title = @"轨迹服务停止失败"; | ||
| 147 | + message = @"还没有开启服务,无法停止服务"; | ||
| 148 | + break; | ||
| 149 | + case BTK_STOP_SERVICE_IN_PROGRESS: | ||
| 150 | + title = @"轨迹服务停止失败"; | ||
| 151 | + message = @"正在停止服务,请稍后再试"; | ||
| 152 | + break; | ||
| 153 | + default: | ||
| 154 | + title = @"轨迹服务停止失败"; | ||
| 155 | + message = @"轨迹服务停止结果未知"; | ||
| 156 | + break; | ||
| 157 | + } | ||
| 158 | + NSDictionary *info = @{@"type":@(TRACK_SERVICE_OPERATION_TYPE_STOP_SERVICE), | ||
| 159 | + @"title":title, | ||
| 160 | + @"message":message, | ||
| 161 | + }; | ||
| 162 | + // 发送广播 | ||
| 163 | + [[NSNotificationCenter defaultCenter] postNotificationName:TrackServiceOperationResultNotification object:nil userInfo:info]; | ||
| 164 | +} | ||
| 165 | + | ||
| 166 | +-(void)onStartGather:(BTKGatherErrorCode)error { | ||
| 167 | + // 维护状态标志 | ||
| 168 | + if (error == BTK_START_GATHER_SUCCESS) { | ||
| 169 | + NSLog(@"开始采集成功"); | ||
| 170 | + self.isGatherStarted = TRUE; | ||
| 171 | + } else { | ||
| 172 | + NSLog(@"开始采集失败"); | ||
| 173 | + } | ||
| 174 | + // 构造广播内容 | ||
| 175 | + NSString *title = nil; | ||
| 176 | + NSString *message = nil; | ||
| 177 | + switch (error) { | ||
| 178 | + case BTK_START_GATHER_SUCCESS: | ||
| 179 | + title = @"开始采集成功"; | ||
| 180 | + message = @"开始采集成功"; | ||
| 181 | + break; | ||
| 182 | + case BTK_GATHER_ALREADY_STARTED_ERROR: | ||
| 183 | + title = @"开始采集失败"; | ||
| 184 | + message = @"已经在采集轨迹,请勿重复开始"; | ||
| 185 | + break; | ||
| 186 | + case BTK_START_GATHER_BEFORE_START_SERVICE_ERROR: | ||
| 187 | + title = @"开始采集失败"; | ||
| 188 | + message = @"开始采集必须在开始服务之后调用"; | ||
| 189 | + break; | ||
| 190 | + case BTK_START_GATHER_LOCATION_SERVICE_OFF_ERROR: | ||
| 191 | + title = @"开始采集失败"; | ||
| 192 | + message = @"没有开启系统定位服务"; | ||
| 193 | + break; | ||
| 194 | + case BTK_START_GATHER_LOCATION_ALWAYS_USAGE_AUTH_ERROR: | ||
| 195 | + title = @"开始采集失败"; | ||
| 196 | + message = @"没有开启后台定位权限"; | ||
| 197 | + break; | ||
| 198 | + case BTK_START_GATHER_INTERNAL_ERROR: | ||
| 199 | + title = @"开始采集失败"; | ||
| 200 | + message = @"SDK服务内部出现错误"; | ||
| 201 | + break; | ||
| 202 | + default: | ||
| 203 | + title = @"开始采集失败"; | ||
| 204 | + message = @"开始采集轨迹的结果未知"; | ||
| 205 | + break; | ||
| 206 | + } | ||
| 207 | + NSDictionary *info = @{@"type":@(TRACK_SERVICE_OPERATION_TYPE_START_GATHER), | ||
| 208 | + @"title":title, | ||
| 209 | + @"message":message, | ||
| 210 | + }; | ||
| 211 | + // 发送广播 | ||
| 212 | + [[NSNotificationCenter defaultCenter] postNotificationName:TrackServiceOperationResultNotification object:nil userInfo:info]; | ||
| 213 | +} | ||
| 214 | + | ||
| 215 | +-(void)onStopGather:(BTKGatherErrorCode)error { | ||
| 216 | + // 维护状态标志 | ||
| 217 | + if (error == BTK_STOP_GATHER_NO_ERROR) { | ||
| 218 | + NSLog(@"停止采集成功"); | ||
| 219 | + self.isGatherStarted = FALSE; | ||
| 220 | + } else { | ||
| 221 | + NSLog(@"停止采集失败"); | ||
| 222 | + } | ||
| 223 | + // 构造广播内容 | ||
| 224 | + NSString *title = nil; | ||
| 225 | + NSString *message = nil; | ||
| 226 | + switch (error) { | ||
| 227 | + case BTK_STOP_GATHER_NO_ERROR: | ||
| 228 | + title = @"停止采集成功"; | ||
| 229 | + message = @"SDK停止采集本设备的轨迹信息"; | ||
| 230 | + break; | ||
| 231 | + case BTK_STOP_GATHER_NOT_YET_STARTED_ERROR: | ||
| 232 | + title = @"停止采集失败"; | ||
| 233 | + message = @"还没有开始采集,无法停止"; | ||
| 234 | + break; | ||
| 235 | + default: | ||
| 236 | + title = @"停止采集失败"; | ||
| 237 | + message = @"停止采集轨迹的结果未知"; | ||
| 238 | + break; | ||
| 239 | + } | ||
| 240 | + NSDictionary *info = @{@"type":@(TRACK_SERVICE_OPERATION_TYPE_STOP_GATHER), | ||
| 241 | + @"title":title, | ||
| 242 | + @"message":message, | ||
| 243 | + }; | ||
| 244 | + // 发送广播 | ||
| 245 | + [[NSNotificationCenter defaultCenter] postNotificationName:TrackServiceOperationResultNotification object:nil userInfo:info]; | ||
| 246 | +} | ||
| 247 | + | ||
| 248 | +-(void)onGetPushMessage:(BTKPushMessage *)message { | ||
| 249 | + if (self.noAcceptFenceNotify) { | ||
| 250 | + return; | ||
| 251 | + } | ||
| 252 | + NSLog(@">>>>>>>>>>>接收到BD通知<<<<<<<<<<<<<"); | ||
| 253 | + // 不是地理围栏的报警,不解析 | ||
| 254 | + if (message.type != 0x03 && message.type != 0x04) { | ||
| 255 | + return; | ||
| 256 | + } | ||
| 257 | + BTKPushMessageFenceAlarmContent *content = (BTKPushMessageFenceAlarmContent *)message.content; | ||
| 258 | + NSString *fenceID = [NSString stringWithFormat:@"%lu", (unsigned long)content.fenceID]; | ||
| 259 | + NSString *monitoredObject = [NSString stringWithFormat:@"「%@」", content.monitoredObject]; | ||
| 260 | + NSString *action = nil; | ||
| 261 | + if (content.actionType == BTK_FENCE_MONITORED_OBJECT_ACTION_TYPE_ENTER) { | ||
| 262 | + action = @"进入"; | ||
| 263 | + } else { | ||
| 264 | + action = @"离开"; | ||
| 265 | + } | ||
| 266 | + NSString *fenceType = nil; | ||
| 267 | + if (message.type == 0x03) { | ||
| 268 | + fenceType = @"服务端围栏"; | ||
| 269 | + } else { | ||
| 270 | + fenceType = @"客户端围栏"; | ||
| 271 | + } | ||
| 272 | + // 通过触发报警的轨迹点,解析出触发报警的时间 | ||
| 273 | + BTKFenceAlarmLocationPoint *currentPoint = content.currentPoint; | ||
| 274 | + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; | ||
| 275 | + [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; | ||
| 276 | + NSDate *alarmDate = [NSDate dateWithTimeIntervalSince1970:currentPoint.loctime]; | ||
| 277 | + NSString *alarmDateStr = [dateFormatter stringFromDate:alarmDate]; | ||
| 278 | + | ||
| 279 | + NSString *pushMessage = [NSString stringWithFormat:@"终端 %@ 在 %@ %@ %@%@", monitoredObject, alarmDateStr, action, fenceType, fenceID]; | ||
| 280 | + NSDictionary *dict = @{ | ||
| 281 | + @"action":action, | ||
| 282 | + @"fenceType":fenceType, | ||
| 283 | + @"fenceID":fenceID | ||
| 284 | + }; | ||
| 285 | + NSLog(@"推送消息: %@", pushMessage); | ||
| 286 | + [[NSNotificationCenter defaultCenter] postNotificationName:TrackServiceGetPushMessageNotification object:nil userInfo:@{@"message":dict}]; | ||
| 287 | +} | ||
| 288 | + | ||
| 289 | +-(void)setIsStartRecord:(BOOL)isStartRecord{ | ||
| 290 | + _isStartRecord = isStartRecord; | ||
| 291 | + if (!isStartRecord) { | ||
| 292 | + if (_pedometer) { | ||
| 293 | + [_pedometer stopPedometerUpdates]; | ||
| 294 | + _pedometer = nil; | ||
| 295 | + } | ||
| 296 | + } | ||
| 297 | +} | ||
| 298 | + | ||
| 299 | +- (void)recordStep:(NSDate *)date isUser:(BOOL)isU{ | ||
| 300 | + if (!self.isStartRecord) { | ||
| 301 | + return; | ||
| 302 | + } | ||
| 303 | + _isUser = isU; | ||
| 304 | + if (isU) { | ||
| 305 | + CNRunExitModel *tempM = [[CNTrackLoaclDataManager shareManager] getExitModel:CNUserShareModelUid]; | ||
| 306 | + if (tempM.step.length > 0 && ![tempM.step isEqualToString:@"<null>"]) { | ||
| 307 | + _lastStepCount = [tempM.step integerValue]; | ||
| 308 | + }else{ | ||
| 309 | + _lastStepCount = 0; | ||
| 310 | + } | ||
| 311 | + }else{ | ||
| 312 | + CNRunToolModel *model = [[CNTrackLoaclDataManager shareManager] getRunToolModel:CNUserShareModelUid]; | ||
| 313 | + if (model.step.length > 0 && ![model.step isEqualToString:@"<null>"]) { | ||
| 314 | + _lastStepCount = [model.step integerValue]; | ||
| 315 | + }else{ | ||
| 316 | + _lastStepCount = 0; | ||
| 317 | + } | ||
| 318 | + } | ||
| 319 | + | ||
| 320 | + | ||
| 321 | + //开始记录步数 | ||
| 322 | + if([CMPedometer isStepCountingAvailable]){ | ||
| 323 | + //开始计步 | ||
| 324 | + _pedometer = [CMPedometer new]; | ||
| 325 | + [_pedometer startPedometerUpdatesFromDate:date withHandler:^(CMPedometerData * _Nullable pedometerData, NSError * _Nullable error) { | ||
| 326 | + [self performSelectorOnMainThread:@selector(updateStepTotal:) withObject:pedometerData waitUntilDone:YES]; | ||
| 327 | + }]; | ||
| 328 | + } | ||
| 329 | +} | ||
| 330 | + | ||
| 331 | +//更新步数和公里数和配速 | ||
| 332 | +- (void)updateStepTotal:(CMPedometerData *)pedometerData{ | ||
| 333 | + if (_isUser) { | ||
| 334 | + CNRunExitModel *tempM = [[CNTrackLoaclDataManager shareManager] getExitModel:CNUserShareModelUid]; | ||
| 335 | + tempM.step = [NSString stringWithFormat:@"%ld",([pedometerData.numberOfSteps integerValue] + _lastStepCount)]; | ||
| 336 | + [[CNTrackLoaclDataManager shareManager] updateExitModel:tempM]; | ||
| 337 | + if ([self.delegate respondsToSelector:@selector(currentPedometer:)]) { | ||
| 338 | + [self.delegate currentPedometer:tempM]; | ||
| 339 | + } | ||
| 340 | + }else{ | ||
| 341 | + CNRunToolModel *model = [[CNTrackLoaclDataManager shareManager] getRunToolModel:CNUserShareModelUid]; | ||
| 342 | + NSInteger step = [pedometerData.numberOfSteps integerValue] +_lastStepCount; | ||
| 343 | + model.step = [NSString stringWithFormat:@"%ld",([pedometerData.numberOfSteps integerValue] + _lastStepCount)]; | ||
| 344 | + [[CNTrackLoaclDataManager shareManager] updateRunToolModel:model]; | ||
| 345 | + if ([self.delegate respondsToSelector:@selector(currentToolPedometer:)]) { | ||
| 346 | + [self.delegate currentToolPedometer:step]; | ||
| 347 | + } | ||
| 348 | + } | ||
| 349 | +} | ||
| 350 | +@end |
| 1 | +// | ||
| 2 | +// CNHistoryTrackParam.h | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/5. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import <Foundation/Foundation.h> | ||
| 10 | + | ||
| 11 | +NS_ASSUME_NONNULL_BEGIN | ||
| 12 | +///历史轨迹参数model | ||
| 13 | +@interface CNHistoryTrackParam : NSObject | ||
| 14 | +@property (nonatomic, copy) NSString *entityName; | ||
| 15 | +@property (nonatomic, assign) NSUInteger startTime; | ||
| 16 | +@property (nonatomic, assign) NSUInteger endTime; | ||
| 17 | +@property (nonatomic, assign) BOOL isProcessed; | ||
| 18 | +@property (nonatomic, strong) BTKQueryTrackProcessOption *processOption; | ||
| 19 | +@property (nonatomic, assign) BTKTrackProcessOptionSupplementMode supplementMode; | ||
| 20 | + | ||
| 21 | +@end | ||
| 22 | + | ||
| 23 | +NS_ASSUME_NONNULL_END |
| 1 | +// | ||
| 2 | +// CNHistoryTrackPoint.h | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/5. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import <Foundation/Foundation.h> | ||
| 10 | + | ||
| 11 | +NS_ASSUME_NONNULL_BEGIN | ||
| 12 | + | ||
| 13 | +@interface CNHistoryTrackPoint : NSObject | ||
| 14 | +@property (nonatomic, assign) CLLocationCoordinate2D coordinate; | ||
| 15 | +@property (nonatomic, assign) NSUInteger loctime; | ||
| 16 | +@property (nonatomic, assign) NSUInteger direction; | ||
| 17 | +@property (nonatomic, assign) double speed; | ||
| 18 | +@end | ||
| 19 | + | ||
| 20 | +NS_ASSUME_NONNULL_END |
| 1 | +// | ||
| 2 | +// CNHistoryViewModel.h | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/5. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import <Foundation/Foundation.h> | ||
| 10 | +#import "CNHistoryTrackParam.h" | ||
| 11 | + | ||
| 12 | +NS_ASSUME_NONNULL_BEGIN | ||
| 13 | +typedef void (^HistoryQueryCompletionHandler) (NSArray *points); | ||
| 14 | + | ||
| 15 | +@interface CNHistoryViewModel : NSObject<BTKTrackDelegate> | ||
| 16 | +@property (nonatomic, copy) HistoryQueryCompletionHandler completionHandler; | ||
| 17 | + | ||
| 18 | +- (void)queryHistoryWithParam:(CNHistoryTrackParam *)param; | ||
| 19 | + | ||
| 20 | +@end | ||
| 21 | + | ||
| 22 | +NS_ASSUME_NONNULL_END |
| 1 | +// | ||
| 2 | +// CNHistoryViewModel.m | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/5. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import "CNHistoryViewModel.h" | ||
| 10 | +#import "CNHistoryTrackPoint.h" | ||
| 11 | + | ||
| 12 | +#define GLOBAL_QUEUE dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) | ||
| 13 | + | ||
| 14 | +@interface CNHistoryViewModel() | ||
| 15 | +@property (nonatomic, strong) NSMutableArray *points; | ||
| 16 | +@property (nonatomic, strong) dispatch_group_t historyDispatchGroup; | ||
| 17 | +@property (nonatomic, assign) NSUInteger firstResponseSize; | ||
| 18 | +@property (nonatomic, assign) NSUInteger total; | ||
| 19 | +@property (nonatomic, strong) CNHistoryTrackParam *param; | ||
| 20 | +@end | ||
| 21 | + | ||
| 22 | +// 轨迹查询每页的上限为5000条,但是若请求纠偏甚至绑路后的轨迹,比较耗时。综合考虑,我们选取每页1000条 | ||
| 23 | +static NSUInteger const kHistoryTrackPageSize = 1000; | ||
| 24 | + | ||
| 25 | +@implementation CNHistoryViewModel | ||
| 26 | +-(instancetype)init { | ||
| 27 | + self = [super init]; | ||
| 28 | + if (self) { | ||
| 29 | + _points = [NSMutableArray array]; | ||
| 30 | + _historyDispatchGroup = dispatch_group_create(); | ||
| 31 | + } | ||
| 32 | + return self; | ||
| 33 | +} | ||
| 34 | + | ||
| 35 | +- (void)queryHistoryWithParam:(CNHistoryTrackParam *)param { | ||
| 36 | + // 清空已有数据 | ||
| 37 | + [self.points removeAllObjects]; | ||
| 38 | + | ||
| 39 | + self.param = param; | ||
| 40 | + // 发送第一次请求,确定size和total,以决定后续是否还需要发请求,以及发送请求的pageSize和pageIndex | ||
| 41 | + dispatch_async(dispatch_get_global_queue(0, 0), ^{ | ||
| 42 | + BTKQueryHistoryTrackRequest *request = [[BTKQueryHistoryTrackRequest alloc] initWithEntityName:param.entityName startTime:param.startTime endTime:param.endTime isProcessed:param.isProcessed processOption:param.processOption supplementMode:param.supplementMode outputCoordType:BTK_COORDTYPE_GCJ02 sortType:BTK_TRACK_SORT_TYPE_ASC pageIndex:1 pageSize:kHistoryTrackPageSize serviceID:BDMapServiceID tag:1]; | ||
| 43 | + [[BTKTrackAction sharedInstance] queryHistoryTrackWith:request delegate:self]; | ||
| 44 | + }); | ||
| 45 | +} | ||
| 46 | + | ||
| 47 | +-(void)onQueryHistoryTrack:(NSData *)response { | ||
| 48 | + | ||
| 49 | + NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingAllowFragments error:nil]; | ||
| 50 | + | ||
| 51 | + | ||
| 52 | +// NSLog(@"%@",dict); | ||
| 53 | + | ||
| 54 | + if (nil == dict) { | ||
| 55 | + NSLog(@"HISTORY TRACK查询格式转换出错"); | ||
| 56 | + if (self.completionHandler) { | ||
| 57 | + self.completionHandler(@[]); | ||
| 58 | + } | ||
| 59 | + return; | ||
| 60 | + } | ||
| 61 | + if (0 != [dict[@"status"] intValue]) { | ||
| 62 | + NSLog(@"HISTORY TRACK查询返回错误"); | ||
| 63 | + if (self.completionHandler) { | ||
| 64 | + self.completionHandler(@[]); | ||
| 65 | + } | ||
| 66 | + return; | ||
| 67 | + } | ||
| 68 | + // 每次回调得到的历史轨迹点,都加到数组中 | ||
| 69 | + for (NSDictionary *point in dict[@"points"]) { | ||
| 70 | + CNHistoryTrackPoint *p = [[CNHistoryTrackPoint alloc] init]; | ||
| 71 | + p.coordinate = CLLocationCoordinate2DMake([point[@"latitude"] doubleValue], [point[@"longitude"] doubleValue]); | ||
| 72 | + p.loctime = [point[@"loc_time"] unsignedIntValue]; | ||
| 73 | + p.direction = [point[@"direction"] unsignedIntValue]; | ||
| 74 | + p.speed = [point[@"speed"] doubleValue]; | ||
| 75 | + | ||
| 76 | + | ||
| 77 | + | ||
| 78 | + [self.points addObject:p]; | ||
| 79 | + | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + // 对于第一次回调结果,根据total和size,确认还需要发送几次请求,并行发送这些请求 | ||
| 83 | + // 使用dispatch_group同步多次请求,当所有请求均收到响应后,points属性中存储的就是所有的轨迹点了 | ||
| 84 | + // 根据请求的是否是纠偏后的结果,处理方式稍有不同: | ||
| 85 | + // 若是纠偏后的轨迹,直接使用direction字段即可,该方向是准确的; | ||
| 86 | + // 若是原始的轨迹,direction字段可能不准,我们自己根据相邻点计算出方向。 | ||
| 87 | + // 最好都是请求纠偏后的轨迹,简化客户端处理步骤 | ||
| 88 | + if ([dict[@"tag"] unsignedIntValue] == 1) { | ||
| 89 | + self.firstResponseSize = [dict[@"size"] unsignedIntValue]; | ||
| 90 | + self.total = [dict[@"total"] unsignedIntValue]; | ||
| 91 | + for (size_t i = 0; i < self.total / self.firstResponseSize; i++) { | ||
| 92 | + dispatch_group_enter(self.historyDispatchGroup); | ||
| 93 | + | ||
| 94 | + BTKQueryHistoryTrackRequest *request = [[BTKQueryHistoryTrackRequest alloc] initWithEntityName:self.param.entityName startTime:self.param.startTime endTime:self.param.endTime isProcessed:self.param.isProcessed processOption:self.param.processOption supplementMode:self.param.supplementMode outputCoordType:BTK_COORDTYPE_BD09LL sortType:BTK_TRACK_SORT_TYPE_ASC pageIndex:(2 + i) pageSize:kHistoryTrackPageSize serviceID:BDMapServiceID tag:(2 + i)]; | ||
| 95 | + [[BTKTrackAction sharedInstance] queryHistoryTrackWith:request delegate:self]; | ||
| 96 | + } | ||
| 97 | + dispatch_group_notify(self.historyDispatchGroup, GLOBAL_QUEUE, ^{ | ||
| 98 | + // 将所有查询到的轨迹点,按照loc_time升序排列,注意是稳定排序。 | ||
| 99 | + // 因为绑路时会补充道路形状点,其loc_time与原始轨迹点一样,相同的loc_time在排序后必须保持原始的顺序,否则direction不准。 | ||
| 100 | + [self.points sortWithOptions:NSSortStable usingComparator:^NSComparisonResult(CNHistoryTrackPoint * _Nonnull obj1, CNHistoryTrackPoint * _Nonnull obj2) { | ||
| 101 | + if (obj1.loctime < obj2.loctime) { | ||
| 102 | + return NSOrderedAscending; | ||
| 103 | + } else if (obj1.loctime > obj2.loctime) { | ||
| 104 | + return NSOrderedDescending; | ||
| 105 | + } else { | ||
| 106 | + return NSOrderedSame; | ||
| 107 | + } | ||
| 108 | + }]; | ||
| 109 | + // 如果我们请求的是原始轨迹,最好自己计算每个轨迹点的方向,因为此时返回的direction字段可能不准确。 | ||
| 110 | + if (FALSE == self.param.isProcessed) { | ||
| 111 | + // 根据相邻两点之间的坐标,计算方向 | ||
| 112 | + for (size_t i = 0; i < self.points.count - 1; i++) { | ||
| 113 | + CNHistoryTrackPoint *point1 = (CNHistoryTrackPoint *)self.points[i]; | ||
| 114 | + CNHistoryTrackPoint *point2 = (CNHistoryTrackPoint *)self.points[i + 1]; | ||
| 115 | + double lat1 = [self getRadianFromDegree:point1.coordinate.latitude]; | ||
| 116 | + double lon1 = [self getRadianFromDegree:point1.coordinate.longitude]; | ||
| 117 | + double lat2 = [self getRadianFromDegree:point2.coordinate.latitude]; | ||
| 118 | + double lon2 = [self getRadianFromDegree:point2.coordinate.longitude]; | ||
| 119 | + double deltaOfLon = lon2 - lon1; | ||
| 120 | + double y = sin(deltaOfLon) * cos(lat2); | ||
| 121 | + double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(deltaOfLon); | ||
| 122 | + double radianDirection = atan2(y, x); | ||
| 123 | + double degreeDirection = [self getDegreeFromRadian:radianDirection]; | ||
| 124 | + ((CNHistoryTrackPoint *)self.points[i]).direction = [self mapGeometryDirectionToGPSDirection:degreeDirection]; | ||
| 125 | + } | ||
| 126 | + } | ||
| 127 | + if (self.completionHandler) { | ||
| 128 | + self.completionHandler(self.points); | ||
| 129 | + } | ||
| 130 | + }); | ||
| 131 | + } else { | ||
| 132 | + dispatch_group_leave(self.historyDispatchGroup); | ||
| 133 | + } | ||
| 134 | +} | ||
| 135 | + | ||
| 136 | +- (double)getRadianFromDegree:(double)degree { | ||
| 137 | + return degree * M_PI / 180.0; | ||
| 138 | +} | ||
| 139 | + | ||
| 140 | +- (double)getDegreeFromRadian:(double)radian { | ||
| 141 | + return radian * 180.0 / M_PI; | ||
| 142 | +} | ||
| 143 | + | ||
| 144 | +- (double)mapGeometryDirectionToGPSDirection:(double)geometryDirection { | ||
| 145 | + double gpsDirection = geometryDirection; | ||
| 146 | + if (geometryDirection < 0) { | ||
| 147 | + gpsDirection = geometryDirection + 360.0; | ||
| 148 | + } | ||
| 149 | + return gpsDirection; | ||
| 150 | +} | ||
| 151 | +@end |
| 1 | +// | ||
| 2 | +// CNLinePointNode.h | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/15. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import <Foundation/Foundation.h> | ||
| 10 | + | ||
| 11 | +NS_ASSUME_NONNULL_BEGIN | ||
| 12 | + | ||
| 13 | +@interface CNLinePointNode : NSObject | ||
| 14 | +@property (nonatomic, assign) CLLocationCoordinate2D coordinate; | ||
| 15 | + | ||
| 16 | +@end | ||
| 17 | + | ||
| 18 | +NS_ASSUME_NONNULL_END |
| 1 | +// | ||
| 2 | +// CNMapView.h | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/4. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import <UIKit/UIKit.h> | ||
| 10 | +#import <BaiduMapAPI_Base/BMKBaseComponent.h>//引入base相关所有的头文件 | ||
| 11 | +#import <BaiduMapAPI_Map/BMKMapComponent.h>//引入地图功能所有的头文件 | ||
| 12 | +#import <BMKLocationkit/BMKLocationComponent.h>//定位功能 | ||
| 13 | + | ||
| 14 | +@protocol CNMapViewDelegate <NSObject> | ||
| 15 | + | ||
| 16 | +- (void)quiteVC; | ||
| 17 | + | ||
| 18 | +@end | ||
| 19 | +NS_ASSUME_NONNULL_BEGIN | ||
| 20 | + | ||
| 21 | +@interface CNMapView : UIView | ||
| 22 | + | ||
| 23 | +@property (nonatomic, weak) id<CNMapViewDelegate> delegate; | ||
| 24 | +@property (nonatomic, strong) BMKMapView *mapView; //当前界面的mapView | ||
| 25 | +@property (nonatomic, assign) BOOL noNeedLocation; | ||
| 26 | +@property (nonatomic, assign) BOOL hiddenSubView; | ||
| 27 | +@property (nonatomic, assign) float tempHeight; | ||
| 28 | +@property (nonatomic, copy) NSArray *dataJsonARR; | ||
| 29 | +@property (nonatomic, strong) BMKUserLocation *userLocation; //当前位置对象 | ||
| 30 | + | ||
| 31 | +//定位 | ||
| 32 | +@property (nonatomic, strong) BMKLocationManager *locationManager;//定位管理 | ||
| 33 | + | ||
| 34 | +@property (nonatomic, assign) float originH; | ||
| 35 | +- (void)drawLine:(BOOL)isStop fArr:(NSArray *)arr1 lArr:(NSArray *)arr2; | ||
| 36 | +@end | ||
| 37 | + | ||
| 38 | +NS_ASSUME_NONNULL_END |
| 1 | +// | ||
| 2 | +// CNMapView.m | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/4. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import "CNMapView.h" | ||
| 10 | +#import "CNHistoryTrackPoint.h" | ||
| 11 | +#import <BaiduMapAPI_Utils/BMKUtilsComponent.h> | ||
| 12 | + | ||
| 13 | +@interface BMKSportNode : NSObject | ||
| 14 | +@property (nonatomic, assign) CLLocationCoordinate2D coordinate; | ||
| 15 | +@property (nonatomic, assign) CGFloat angle; | ||
| 16 | +@property (nonatomic, assign) CGFloat distance; | ||
| 17 | +@property (nonatomic, assign) CGFloat speed; | ||
| 18 | +@end | ||
| 19 | +@implementation BMKSportNode | ||
| 20 | + | ||
| 21 | +@end | ||
| 22 | + | ||
| 23 | +@interface CNMapView() | ||
| 24 | +< | ||
| 25 | +BMKMapViewDelegate, | ||
| 26 | +BMKLocationManagerDelegate | ||
| 27 | +> | ||
| 28 | +@property (nonatomic, strong) NSMutableArray *sportNodes; | ||
| 29 | +@property (nonatomic, assign) NSUInteger sportNodeNum; | ||
| 30 | +@property (nonatomic, strong) BMKPolyline *pathPolyLine; //当前界面的多边形(运动轨迹) | ||
| 31 | + | ||
| 32 | +@property (nonatomic, strong) BMKPointAnnotation *startAnnotation; //当前界面的标注 | ||
| 33 | +@property (nonatomic, strong) BMKPointAnnotation *endAnnotation; //当前界面的标注 | ||
| 34 | + | ||
| 35 | +@property (nonatomic, assign) CLLocationCoordinate2D mineLocationCoordinate; | ||
| 36 | +@property (nonatomic, assign) BOOL isLocation;//定位是否成功 | ||
| 37 | + | ||
| 38 | +@property (nonatomic, strong) UIButton *resetBtn; //重新定位按钮 | ||
| 39 | +@property (nonatomic, strong) NSMutableArray *minePoints; | ||
| 40 | +@property (nonatomic, strong) BMKPolyline *fminePolyLine; | ||
| 41 | +@property (nonatomic, strong) BMKPolyline *lminePolyLine; | ||
| 42 | + | ||
| 43 | +@end | ||
| 44 | +@implementation CNMapView | ||
| 45 | + | ||
| 46 | +-(instancetype)initWithFrame:(CGRect)frame{ | ||
| 47 | + self = [super initWithFrame:frame]; | ||
| 48 | + if (self) { | ||
| 49 | + _sportNodes = [NSMutableArray array]; | ||
| 50 | + _minePoints = [NSMutableArray array]; | ||
| 51 | + [self addSubview:self.mapView]; | ||
| 52 | + CGPoint p = self.mapView.compassPosition; | ||
| 53 | + p.y += 100; | ||
| 54 | + self.mapView.compassPosition = p; | ||
| 55 | + [self.mapView addSubview:self.resetBtn]; | ||
| 56 | + [self.resetBtn mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 57 | + make.left.equalTo(self.mapView.mas_left).offset(15); | ||
| 58 | + make.bottom.equalTo(self.mapView.mas_bottom).offset(-50); | ||
| 59 | + }]; | ||
| 60 | + } | ||
| 61 | + return self; | ||
| 62 | +} | ||
| 63 | + | ||
| 64 | +-(void)setDataJsonARR:(NSArray *)dataJsonARR{ | ||
| 65 | + _dataJsonARR = dataJsonARR; | ||
| 66 | + [_sportNodes removeAllObjects]; | ||
| 67 | + for (CNHistoryTrackPoint *point in dataJsonARR) { | ||
| 68 | + BMKSportNode *sportNode = [[BMKSportNode alloc] init]; | ||
| 69 | + sportNode.coordinate = point.coordinate;//CLLocationCoordinate2DMake([dictionary[@"lat"] doubleValue], [dictionary[@"lon"] doubleValue]); | ||
| 70 | + [_sportNodes addObject:sportNode]; | ||
| 71 | + } | ||
| 72 | + _sportNodeNum = _sportNodes.count; | ||
| 73 | + [self start];//添加路线 | ||
| 74 | +} | ||
| 75 | + | ||
| 76 | +-(void)drawLine:(BOOL)isStop fArr:(NSArray *)arr1 lArr:(NSArray *)arr2{ | ||
| 77 | +// for (CNHistoryTrackPoint *point in points) { | ||
| 78 | + [_minePoints addObjectsFromArray:arr1]; | ||
| 79 | + [_minePoints addObjectsFromArray:arr2]; | ||
| 80 | + if (isStop) { | ||
| 81 | + CLLocationCoordinate2D paths1[arr1.count]; | ||
| 82 | + for (NSUInteger i = 0; i < arr1.count; i ++) { | ||
| 83 | + CNHistoryTrackPoint *point = arr1[i]; | ||
| 84 | + paths1[i] = point.coordinate; | ||
| 85 | + } | ||
| 86 | + _fminePolyLine = [BMKPolyline polylineWithCoordinates:paths1 count:arr1.count]; | ||
| 87 | + //初始化标注类BMKPointAnnotation的实例 | ||
| 88 | + _startAnnotation = [[BMKPointAnnotation alloc] init]; | ||
| 89 | + //设置标注的经纬度坐标 | ||
| 90 | + _startAnnotation.coordinate = paths1[0]; | ||
| 91 | + // [self.mapView setCenterCoordinate:paths[0] animated:YES]; | ||
| 92 | + //设置标注的标题 | ||
| 93 | + _startAnnotation.title = @"起点"; | ||
| 94 | + //初始化标注类BMKPointAnnotation的实例 | ||
| 95 | + _endAnnotation = [[BMKPointAnnotation alloc] init]; | ||
| 96 | + if (arr2.count > 0) { | ||
| 97 | + CLLocationCoordinate2D paths2[arr2.count]; | ||
| 98 | + for (NSUInteger i = 0; i < arr2.count; i ++) { | ||
| 99 | + CNHistoryTrackPoint *point = arr2[i]; | ||
| 100 | + paths2[i] = point.coordinate; | ||
| 101 | + } | ||
| 102 | + _lminePolyLine = [BMKPolyline polylineWithCoordinates:paths2 count:arr2.count]; | ||
| 103 | + //设置标注的经纬度坐标 | ||
| 104 | + _endAnnotation.coordinate = paths2[arr2.count-1]; | ||
| 105 | + //设置标注的标题 | ||
| 106 | + _endAnnotation.title = @"终点"; | ||
| 107 | + | ||
| 108 | + }else{ | ||
| 109 | + //设置标注的经纬度坐标 | ||
| 110 | + _endAnnotation.coordinate = paths1[arr1.count-1]; | ||
| 111 | + //设置标注的标题 | ||
| 112 | + _endAnnotation.title = @"终点"; | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 116 | + | ||
| 117 | + | ||
| 118 | + [self->_mapView addOverlay:self->_fminePolyLine]; | ||
| 119 | + [self->_mapView addOverlay:self->_lminePolyLine]; | ||
| 120 | + //将标注添加到当前地图View中 | ||
| 121 | + [self->_mapView addAnnotation:self->_startAnnotation]; | ||
| 122 | + //将标注添加到当前地图View中 | ||
| 123 | + [self->_mapView addAnnotation:self->_endAnnotation]; | ||
| 124 | + [self mapViewFitPoints:self.minePoints]; | ||
| 125 | + }); | ||
| 126 | + } | ||
| 127 | +} | ||
| 128 | + | ||
| 129 | +#pragma mark - private | ||
| 130 | +- (void)start{ | ||
| 131 | + CLLocationCoordinate2D paths[_sportNodeNum]; | ||
| 132 | + for (NSUInteger i = 0; i < _sportNodeNum; i ++) { | ||
| 133 | + BMKSportNode *node = _sportNodes[i]; | ||
| 134 | + paths[i] = node.coordinate; | ||
| 135 | + } | ||
| 136 | + _pathPolyLine = [BMKPolyline polylineWithCoordinates:paths count:_sportNodeNum]; | ||
| 137 | + //初始化标注类BMKPointAnnotation的实例 | ||
| 138 | + _startAnnotation = [[BMKPointAnnotation alloc] init]; | ||
| 139 | + //设置标注的经纬度坐标 | ||
| 140 | + _startAnnotation.coordinate = paths[0]; | ||
| 141 | +// [self.mapView setCenterCoordinate:paths[0] animated:YES]; | ||
| 142 | + //设置标注的标题 | ||
| 143 | + _startAnnotation.title = @"起点"; | ||
| 144 | + //初始化标注类BMKPointAnnotation的实例 | ||
| 145 | + _endAnnotation = [[BMKPointAnnotation alloc] init]; | ||
| 146 | + //设置标注的经纬度坐标 | ||
| 147 | + _endAnnotation.coordinate = paths[_sportNodeNum-1]; | ||
| 148 | + //设置标注的标题 | ||
| 149 | + _endAnnotation.title = @"终点"; | ||
| 150 | + | ||
| 151 | + dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 152 | + /** | ||
| 153 | + 向地图View添加Overlay,需要实现BMKMapViewDelegate的-mapView:viewForOverlay: | ||
| 154 | + 方法来生成标注对应的View | ||
| 155 | + | ||
| 156 | + @param overlay 要添加的overlay | ||
| 157 | + */ | ||
| 158 | + [self.mapView removeOverlays:self.mapView.overlays]; | ||
| 159 | + [self.mapView removeAnnotations:self.mapView.annotations]; | ||
| 160 | + [self->_mapView addOverlay:self->_pathPolyLine]; | ||
| 161 | + //将标注添加到当前地图View中 | ||
| 162 | + [self->_mapView addAnnotation:self->_startAnnotation]; | ||
| 163 | + //将标注添加到当前地图View中 | ||
| 164 | + [self->_mapView addAnnotation:self->_endAnnotation]; | ||
| 165 | + [self mapViewFitPolyLine:self->_pathPolyLine]; | ||
| 166 | + }); | ||
| 167 | +} | ||
| 168 | + | ||
| 169 | +- (void)mapViewFitPoints:(NSArray *) points { | ||
| 170 | + CGFloat leftTopX, leftTopY, rightBottomX, rightBottomY; | ||
| 171 | + if (points.count < 1) { | ||
| 172 | + return; | ||
| 173 | + } | ||
| 174 | + CNHistoryTrackPoint *p = points[0]; | ||
| 175 | + CLLocationCoordinate2D coor = p.coordinate; | ||
| 176 | + BMKMapPoint pt = BMKMapPointForCoordinate(coor); | ||
| 177 | + // BMKMapPoint pt = polyLine.points[0]; | ||
| 178 | + // 左上角顶点 | ||
| 179 | + leftTopX = pt.x; | ||
| 180 | + leftTopY = pt.y; | ||
| 181 | + // 右下角顶点 | ||
| 182 | + rightBottomX = pt.x; | ||
| 183 | + rightBottomY = pt.y; | ||
| 184 | + for (int i = 1; i < points.count; i++) { | ||
| 185 | + CNHistoryTrackPoint *p = points[i]; | ||
| 186 | + CLLocationCoordinate2D coor = p.coordinate; | ||
| 187 | + BMKMapPoint pt = BMKMapPointForCoordinate(coor); | ||
| 188 | + // BMKMapPoint pt = polyLine.points[i]; | ||
| 189 | + leftTopX = pt.x < leftTopX ? pt.x : leftTopX; | ||
| 190 | + leftTopY = pt.y < leftTopY ? pt.y : leftTopY; | ||
| 191 | + rightBottomX = pt.x > rightBottomX ? pt.x : rightBottomX; | ||
| 192 | + rightBottomY = pt.y > rightBottomY ? pt.y : rightBottomY; | ||
| 193 | + } | ||
| 194 | + BMKMapRect rect; | ||
| 195 | + rect.origin = BMKMapPointMake(leftTopX, leftTopY); | ||
| 196 | + rect.size = BMKMapSizeMake(rightBottomX - leftTopX, rightBottomY - leftTopY); | ||
| 197 | + UIEdgeInsets padding = UIEdgeInsetsMake(100 , 50, 200, 50); | ||
| 198 | + [_mapView fitVisibleMapRect:rect edgePadding:padding withAnimated:YES]; | ||
| 199 | +} | ||
| 200 | + | ||
| 201 | + | ||
| 202 | +//根据polyline设置地图范围 | ||
| 203 | +- (void)mapViewFitPolyLine:(BMKPolyline *) polyLine { | ||
| 204 | + CGFloat leftTopX, leftTopY, rightBottomX, rightBottomY; | ||
| 205 | + if (polyLine.pointCount < 1) { | ||
| 206 | + return; | ||
| 207 | + } | ||
| 208 | + BMKMapPoint pt = polyLine.points[0]; | ||
| 209 | + // 左上角顶点 | ||
| 210 | + leftTopX = pt.x; | ||
| 211 | + leftTopY = pt.y; | ||
| 212 | + // 右下角顶点 | ||
| 213 | + rightBottomX = pt.x; | ||
| 214 | + rightBottomY = pt.y; | ||
| 215 | + for (int i = 1; i < polyLine.pointCount; i++) { | ||
| 216 | + BMKMapPoint pt = polyLine.points[i]; | ||
| 217 | + leftTopX = pt.x < leftTopX ? pt.x : leftTopX; | ||
| 218 | + leftTopY = pt.y < leftTopY ? pt.y : leftTopY; | ||
| 219 | + rightBottomX = pt.x > rightBottomX ? pt.x : rightBottomX; | ||
| 220 | + rightBottomY = pt.y > rightBottomY ? pt.y : rightBottomY; | ||
| 221 | + } | ||
| 222 | + BMKMapRect rect; | ||
| 223 | + rect.origin = BMKMapPointMake(leftTopX, leftTopY); | ||
| 224 | + rect.size = BMKMapSizeMake(rightBottomX - leftTopX, rightBottomY - leftTopY); | ||
| 225 | + UIEdgeInsets padding = UIEdgeInsetsMake(kNavigationBarHeight+50 , 50, self.originH+50, 50); | ||
| 226 | + [_mapView fitVisibleMapRect:rect edgePadding:padding withAnimated:YES]; | ||
| 227 | + | ||
| 228 | +} | ||
| 229 | + | ||
| 230 | +-(void)setTempHeight:(float)tempHeight{ | ||
| 231 | + _tempHeight = tempHeight; | ||
| 232 | + if (self.pathPolyLine) { | ||
| 233 | +// [self mapViewFitPolyLine:self.pathPolyLine]; | ||
| 234 | + [self mapViewFitPolyLine:self.pathPolyLine height:tempHeight]; | ||
| 235 | + } | ||
| 236 | +} | ||
| 237 | + | ||
| 238 | +-(void)setHiddenSubView:(BOOL)hiddenSubView{ | ||
| 239 | + _hiddenSubView = hiddenSubView; | ||
| 240 | + if (hiddenSubView) { | ||
| 241 | + self.resetBtn.hidden = YES; | ||
| 242 | + } | ||
| 243 | +} | ||
| 244 | + | ||
| 245 | +//根据polyline设置地图范围 | ||
| 246 | +- (void)mapViewFitPolyLine:(BMKPolyline *) polyLine height:(float)height{ | ||
| 247 | + CGFloat leftTopX, leftTopY, rightBottomX, rightBottomY; | ||
| 248 | + if (polyLine.pointCount < 1) { | ||
| 249 | + return; | ||
| 250 | + } | ||
| 251 | + BMKMapPoint pt = polyLine.points[0]; | ||
| 252 | + // 左上角顶点 | ||
| 253 | + leftTopX = pt.x; | ||
| 254 | + leftTopY = pt.y; | ||
| 255 | + // 右下角顶点 | ||
| 256 | + rightBottomX = pt.x; | ||
| 257 | + rightBottomY = pt.y; | ||
| 258 | + for (int i = 1; i < polyLine.pointCount; i++) { | ||
| 259 | + BMKMapPoint pt = polyLine.points[i]; | ||
| 260 | + leftTopX = pt.x < leftTopX ? pt.x : leftTopX; | ||
| 261 | + leftTopY = pt.y < leftTopY ? pt.y : leftTopY; | ||
| 262 | + rightBottomX = pt.x > rightBottomX ? pt.x : rightBottomX; | ||
| 263 | + rightBottomY = pt.y > rightBottomY ? pt.y : rightBottomY; | ||
| 264 | + } | ||
| 265 | + BMKMapRect rect; | ||
| 266 | + rect.origin = BMKMapPointMake(leftTopX, leftTopY); | ||
| 267 | + rect.size = BMKMapSizeMake(rightBottomX - leftTopX,rightBottomY - leftTopY); | ||
| 268 | + UIEdgeInsets padding = UIEdgeInsetsMake(kNavigationBarHeight+20, 50, SCREEN_HEIGHT-height+20, 50); | ||
| 269 | + [_mapView fitVisibleMapRect:rect edgePadding:padding withAnimated:YES]; | ||
| 270 | +} | ||
| 271 | + | ||
| 272 | +-(void)setNoNeedLocation:(BOOL)noNeedLocation{ | ||
| 273 | + _noNeedLocation = noNeedLocation; | ||
| 274 | + @try { | ||
| 275 | + [self.locationManager stopUpdatingHeading]; | ||
| 276 | + [self.locationManager stopUpdatingLocation]; | ||
| 277 | + } @catch (NSException *exception) { | ||
| 278 | + NSLog(@"CNMapView.m 1111111111崩溃了"); | ||
| 279 | + } | ||
| 280 | +} | ||
| 281 | +#pragma mark -- 定位delegate | ||
| 282 | +//权限改变 | ||
| 283 | +- (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{ | ||
| 284 | + if (status == kCLAuthorizationStatusDenied) { | ||
| 285 | + MJWeakSelf | ||
| 286 | + QMUIAlertAction *action1 = [QMUIAlertAction actionWithTitle:@"确定" style:QMUIAlertActionStyleCancel handler:^(__kindof QMUIAlertController *aAlertController, QMUIAlertAction *action) { | ||
| 287 | + if ([weakSelf.delegate respondsToSelector:@selector(quiteVC)]) { | ||
| 288 | + [weakSelf.delegate quiteVC]; | ||
| 289 | + } | ||
| 290 | + }]; | ||
| 291 | + QMUIAlertController *alertController = [QMUIAlertController alertControllerWithTitle:@"" message:@"无法获取你的位置信息。\n 请到手机系统的[隐私]->[定位服务]中打开定位服务,并允许网家家使用定位服务" preferredStyle:QMUIAlertControllerStyleAlert]; | ||
| 292 | + [alertController addAction:action1]; | ||
| 293 | + [alertController showWithAnimated:YES]; | ||
| 294 | + } | ||
| 295 | +} | ||
| 296 | + | ||
| 297 | +- (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager doRequestAlwaysAuthorization:(CLLocationManager * _Nonnull)locationManager{ | ||
| 298 | + [locationManager requestAlwaysAuthorization]; | ||
| 299 | +} | ||
| 300 | + | ||
| 301 | +- (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager didFailWithError:(NSError * _Nullable)error { | ||
| 302 | + NSLog(@"定位失败"); | ||
| 303 | + self.isLocation = NO; | ||
| 304 | +} | ||
| 305 | +// 定位SDK中,方向变更的回调 | ||
| 306 | +- (void)BMKLocationManager:(BMKLocationManager *)manager didUpdateHeading:(CLHeading * _Nullable)heading{ | ||
| 307 | + if (!heading) { | ||
| 308 | + return; | ||
| 309 | + } | ||
| 310 | + self.userLocation.heading = heading; | ||
| 311 | + [self.mapView updateLocationData:self.userLocation]; | ||
| 312 | +} | ||
| 313 | + | ||
| 314 | +// 定位SDK中,位置变更的回调 | ||
| 315 | +- (void)BMKLocationManager:(BMKLocationManager *)manager didUpdateLocation:(BMKLocation *)location orError:(NSError *)error { | ||
| 316 | + if (error) { | ||
| 317 | + self.isLocation = NO; | ||
| 318 | + NSLog(@"locError:{%ld - %@};", (long)error.code, error.localizedDescription); | ||
| 319 | + // [QMUITips showInfo:@"位置更新失败" inView:self.view hideAfterDelay:0.5]; | ||
| 320 | + }else{ | ||
| 321 | + self.mineLocationCoordinate = location.location.coordinate; | ||
| 322 | + self.isLocation = YES; | ||
| 323 | + } | ||
| 324 | + if (!location) { | ||
| 325 | + return; | ||
| 326 | + } | ||
| 327 | + // [QMUITips showInfo:@"位置更新" inView:self.view hideAfterDelay:0.5]; | ||
| 328 | + if (self.noNeedLocation) { | ||
| 329 | + return; | ||
| 330 | + } | ||
| 331 | + self.userLocation.location = location.location; | ||
| 332 | + [self.mapView updateLocationData:self.userLocation];//动态更新我的位置数据 | ||
| 333 | +} | ||
| 334 | + | ||
| 335 | +#pragma mark - 地图Delegate | ||
| 336 | +- (void)mapViewDidFinishLoading:(BMKMapView *)mapView { | ||
| 337 | +// [self start];//添加路线 | ||
| 338 | + if (self.noNeedLocation) { | ||
| 339 | + return; | ||
| 340 | + } | ||
| 341 | + [self.locationManager startUpdatingLocation]; | ||
| 342 | + [self.locationManager startUpdatingHeading]; | ||
| 343 | +} | ||
| 344 | +/** | ||
| 345 | + 根据overlay生成对应的BMKOverlayView | ||
| 346 | + | ||
| 347 | + @param mapView 地图View | ||
| 348 | + @param overlay 指定的overlay | ||
| 349 | + @return 生成的覆盖物View | ||
| 350 | + */ | ||
| 351 | +- (BMKOverlayView *)mapView:(BMKMapView *)mapView viewForOverlay:(id<BMKOverlay>)overlay { | ||
| 352 | + if ([overlay isKindOfClass:[BMKPolyline class]]) { | ||
| 353 | + BMKPolylineView *polylineView = [[BMKPolylineView alloc] initWithPolyline:overlay]; | ||
| 354 | + polylineView.lineWidth = 2; | ||
| 355 | + polylineView.strokeColor = [RGBOF(0x5BC4A4) colorWithAlphaComponent:1]; | ||
| 356 | + return polylineView; | ||
| 357 | + } | ||
| 358 | + return nil; | ||
| 359 | +} | ||
| 360 | +/** | ||
| 361 | + 根据anntation生成对应的annotationView | ||
| 362 | + | ||
| 363 | + @param mapView 地图View | ||
| 364 | + @param annotation 指定的标注 | ||
| 365 | + @return 生成的标注View | ||
| 366 | + */ | ||
| 367 | + | ||
| 368 | +- (BMKAnnotationView *)mapView:(BMKMapView *)mapView viewForAnnotation:(id<BMKAnnotation>)annotation { | ||
| 369 | + if ([annotation isKindOfClass:[BMKPointAnnotation class]]) { | ||
| 370 | + | ||
| 371 | + NSString *AnnotationViewID = @"baiduAnnotation"; | ||
| 372 | + BMKAnnotationView *annotationView = nil; | ||
| 373 | + if (annotationView == nil) { | ||
| 374 | + annotationView = [[BMKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID]; | ||
| 375 | + } | ||
| 376 | + UIImageView *bgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, -38/2+5, 68, 68)]; | ||
| 377 | + bgView.image = [UIImage imageNamed:@"map-fw"]; | ||
| 378 | + UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, -38/2+5, 30, 38)]; | ||
| 379 | + if (annotation == _startAnnotation) { | ||
| 380 | + imageView.image = [UIImage imageNamed:@"map_location-start"]; | ||
| 381 | + } else if (annotation == _endAnnotation){ | ||
| 382 | + imageView.image = [UIImage imageNamed:@"map_location-finish"]; | ||
| 383 | + } | ||
| 384 | + UIView *underView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 15, 7)]; | ||
| 385 | + underView.backgroundColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:0.5]; | ||
| 386 | + underView.centerX = imageView.centerX+2; | ||
| 387 | + underView.centerY = imageView.centerY+38/2-3; | ||
| 388 | + underView.layer.cornerRadius = 6; | ||
| 389 | + underView.layer.masksToBounds = YES; | ||
| 390 | + bgView.centerX = underView.centerX; | ||
| 391 | + bgView.centerY = underView.centerY - 8; | ||
| 392 | + [annotationView addSubview:bgView]; | ||
| 393 | + [annotationView addSubview:underView]; | ||
| 394 | + [annotationView addSubview:imageView]; | ||
| 395 | + annotationView.frame = CGRectMake(0, -38/2+5, 30, 38); | ||
| 396 | + annotationView.enabled3D = YES; | ||
| 397 | + annotationView.hidePaopaoWhenSingleTapOnMap = YES; | ||
| 398 | + annotationView.hidePaopaoWhenDoubleTapOnMap = YES; | ||
| 399 | + annotationView.hidePaopaoWhenTwoFingersTapOnMap = YES; | ||
| 400 | + annotationView.hidePaopaoWhenSelectOthers = YES; | ||
| 401 | + return annotationView; | ||
| 402 | + } | ||
| 403 | + return nil; | ||
| 404 | +} | ||
| 405 | + | ||
| 406 | +#pragma mark - lazy | ||
| 407 | +-(BMKMapView *)mapView{ | ||
| 408 | + if (!_mapView) { | ||
| 409 | + _mapView = [[BMKMapView alloc] initWithFrame:self.frame]; | ||
| 410 | + _mapView.delegate = self; | ||
| 411 | + //设置地图比例尺级别 | ||
| 412 | + _mapView.zoomLevel = 17; | ||
| 413 | + _mapView.showMapScaleBar = NO;//显示比例尺 | ||
| 414 | + _mapView.showsUserLocation = YES;//显示定位图层 | ||
| 415 | + // //显示我的位置,我的位置图标和地图都不会旋转 | ||
| 416 | + _mapView.userTrackingMode = BMKUserTrackingModeHeading; | ||
| 417 | + // //更换我的位置图标 | ||
| 418 | + // // self.mapView是BMKMapView对象 | ||
| 419 | + BMKLocationViewDisplayParam *param = [[BMKLocationViewDisplayParam alloc] init]; | ||
| 420 | + // //定位图标名称,需要将该图片放到 mapapi.bundle/images 目录下 | ||
| 421 | + // // param.locationViewImgName = @"icon_nav_bus"; | ||
| 422 | + // //用户自定义定位图标,V4.2.1以后支持 | ||
| 423 | + param.locationViewImage = [UIImage imageNamed:@"map_dw"]; | ||
| 424 | + // //根据配置参数更新定位图层样式 | ||
| 425 | + //设置显示精度圈,默认YES | ||
| 426 | + param.isAccuracyCircleShow = NO; | ||
| 427 | + //精度圈 边框颜色 | ||
| 428 | +// param.accuracyCircleStrokeColor = kWhiteColor; | ||
| 429 | +// //精度圈 填充颜色 | ||
| 430 | +// param.accuracyCircleFillColor = kWhiteColor; | ||
| 431 | + [_mapView updateLocationViewWithParam:param]; | ||
| 432 | + | ||
| 433 | + } | ||
| 434 | + return _mapView; | ||
| 435 | +} | ||
| 436 | +-(BMKLocationManager *)locationManager{ | ||
| 437 | + if (!_locationManager) { | ||
| 438 | + //初始化实例 | ||
| 439 | + _locationManager = [[BMKLocationManager alloc] init]; | ||
| 440 | + //设置delegate | ||
| 441 | + _locationManager.delegate = self; | ||
| 442 | + //设置返回位置的坐标系类型 | ||
| 443 | + _locationManager.coordinateType = BMKLocationCoordinateTypeGCJ02; | ||
| 444 | + //设置距离过滤参数 | ||
| 445 | + _locationManager.distanceFilter = 1.0f; | ||
| 446 | + //设置预期精度参数 | ||
| 447 | + _locationManager.desiredAccuracy = kCLLocationAccuracyBest; | ||
| 448 | + //设置应用位置类型 | ||
| 449 | + _locationManager.activityType = CLActivityTypeFitness; | ||
| 450 | + //设置是否自动停止位置更新 | ||
| 451 | + _locationManager.pausesLocationUpdatesAutomatically = NO; | ||
| 452 | + //设置是否允许后台定位 | ||
| 453 | + _locationManager.allowsBackgroundLocationUpdates = YES; | ||
| 454 | + //设置位置获取超时时间 | ||
| 455 | +// _locationManager.locationTimeout = 10; | ||
| 456 | + //设置获取地址信息超时时间 | ||
| 457 | + // _locationManager.reGeocodeTimeout = 3; | ||
| 458 | + } | ||
| 459 | + return _locationManager; | ||
| 460 | +} | ||
| 461 | + | ||
| 462 | +-(BMKUserLocation *)userLocation{ | ||
| 463 | + if (!_userLocation) { | ||
| 464 | + _userLocation = [[BMKUserLocation alloc] init]; | ||
| 465 | + } | ||
| 466 | + return _userLocation; | ||
| 467 | +} | ||
| 468 | + | ||
| 469 | +-(UIButton *)resetBtn{ | ||
| 470 | + if (!_resetBtn) { | ||
| 471 | + _resetBtn = [[UIButton alloc] init]; | ||
| 472 | + [_resetBtn setImage:[UIImage imageNamed:@"where_select"] forState:UIControlStateNormal]; | ||
| 473 | + [_resetBtn addTarget:self action:@selector(clickRestBtn) forControlEvents:UIControlEventTouchUpInside]; | ||
| 474 | + } | ||
| 475 | + return _resetBtn; | ||
| 476 | +} | ||
| 477 | + | ||
| 478 | +- (void)clickRestBtn{ | ||
| 479 | + [self resetPosition]; | ||
| 480 | +} | ||
| 481 | +- (void)resetPosition{ | ||
| 482 | + if (self.isLocation) { | ||
| 483 | + [self.mapView setCenterCoordinate:self.userLocation.location.coordinate animated:YES]; | ||
| 484 | + }else{//没自动定位到位置,需要手动定位 | ||
| 485 | + @try { | ||
| 486 | + [self.locationManager stopUpdatingLocation]; | ||
| 487 | + } @catch (NSException *exception) { | ||
| 488 | + NSLog(@"CNMapView.m 崩溃了"); | ||
| 489 | + } | ||
| 490 | + | ||
| 491 | + [QMUITips showLoadingInView:self]; | ||
| 492 | + MJWeakSelf | ||
| 493 | + [self.locationManager requestLocationWithReGeocode:NO withNetworkState:YES completionBlock:^(BMKLocation * _Nullable location, BMKLocationNetworkState state, NSError * _Nullable error) { | ||
| 494 | + [QMUITips hideAllTips]; | ||
| 495 | + BOOL isError = false; | ||
| 496 | + if (error) | ||
| 497 | + { | ||
| 498 | + isError = YES; | ||
| 499 | + // NSLog(@"locError:{%ld - %@};", (long)error.code, error.localizedDescription); | ||
| 500 | + } | ||
| 501 | + if (location) {//得到定位信息,添加annotation | ||
| 502 | + if (location.location) { | ||
| 503 | + NSLog(@"LOC = %@",location.location); | ||
| 504 | + //把地图放到位置中心点 | ||
| 505 | + weakSelf.mineLocationCoordinate = location.location.coordinate; | ||
| 506 | + [weakSelf.mapView setCenterCoordinate:weakSelf.mineLocationCoordinate animated:YES]; | ||
| 507 | + //实现该方法,否则定位图标不出现 | ||
| 508 | + weakSelf.userLocation.location = location.location; | ||
| 509 | + [weakSelf.mapView updateLocationData:weakSelf.userLocation]; | ||
| 510 | + } | ||
| 511 | + }else{ | ||
| 512 | + isError = YES; | ||
| 513 | + } | ||
| 514 | + if ([error.localizedDescription containsString:@"网络"] && [error.localizedDescription containsString:@"失败"]) { | ||
| 515 | + [QMUITips showInfo:@"网络错误,请检查网络。" inView:self.mapView hideAfterDelay:1.5]; | ||
| 516 | + }else{ | ||
| 517 | + if (isError) { | ||
| 518 | + [QMUITips showInfo:@"无法获取您的位置信息。" inView:self.mapView hideAfterDelay:1.5]; | ||
| 519 | + } | ||
| 520 | + } | ||
| 521 | + if (self.noNeedLocation) { | ||
| 522 | + return; | ||
| 523 | + } | ||
| 524 | + [self.locationManager startUpdatingLocation]; | ||
| 525 | + [self.locationManager startUpdatingHeading]; | ||
| 526 | + }]; | ||
| 527 | + | ||
| 528 | + } | ||
| 529 | +} | ||
| 530 | +@end |
| 1 | +// | ||
| 2 | +// CNReUpLoadTableViewCell.h | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/27. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import <UIKit/UIKit.h> | ||
| 10 | +@class CNTrackUploadFailModel; | ||
| 11 | +#define kCNReUpLoadTableViewCell @"CNReUpLoadTableViewCell" | ||
| 12 | +@class CNReUpLoadTableViewCell; | ||
| 13 | +@protocol CNReUpLoadTableViewCellDelegate <NSObject> | ||
| 14 | +- (void)needToReloadTable:(CNReUpLoadTableViewCell *)cell index:(NSInteger)index; | ||
| 15 | + | ||
| 16 | +@end | ||
| 17 | +@interface CNReUpLoadTableViewCell : UITableViewCell | ||
| 18 | +@property (nonatomic, weak) id <CNReUpLoadTableViewCellDelegate> delegate; | ||
| 19 | +@property (nonatomic, assign) NSInteger index; | ||
| 20 | +@property (nonatomic, strong) CNTrackUploadFailModel *model; | ||
| 21 | +@property (nonatomic, copy) void(^deleteClickBlock)(NSInteger index); | ||
| 22 | + | ||
| 23 | +@end |
| 1 | +// | ||
| 2 | +// CNReUpLoadTableViewCell.m | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/27. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import "CNReUpLoadTableViewCell.h" | ||
| 10 | +#import "CNTrackUploadFailModel.h" | ||
| 11 | +#import "UIColor+CNLiveExtension.h" | ||
| 12 | +#import "CNLiveSportsDetailModel.h" | ||
| 13 | +#import "CNHistoryTrackParam.h" | ||
| 14 | +#import "CNHistoryViewModel.h" | ||
| 15 | +#import "CNHistoryTrackPoint.h" | ||
| 16 | +#import "CNTrackLoaclDataManager.h" | ||
| 17 | + | ||
| 18 | +@interface CNReUpLoadTableViewCell () | ||
| 19 | + | ||
| 20 | +@property (nonatomic, strong) UIView *bgView; | ||
| 21 | +@property (nonatomic, strong) UILabel *dateLabel; | ||
| 22 | +@property (nonatomic, strong) UILabel *timeLabel; | ||
| 23 | +@property (nonatomic, strong) UILabel *addressLabel; | ||
| 24 | +@property (nonatomic, strong) UILabel *distanceLabel; | ||
| 25 | + | ||
| 26 | +@property (nonatomic, strong) QMUIButton *durationBtn; | ||
| 27 | +@property (nonatomic, strong) QMUIButton *speedBtn; | ||
| 28 | +@property (nonatomic, strong) QMUIButton *stepNumberBtn; | ||
| 29 | +@property (nonatomic, strong) UIView *line; | ||
| 30 | +@property (nonatomic, strong) QMUIButton *reUploadBtn; | ||
| 31 | +@property (nonatomic, strong) QMUIButton *deleteBtn; | ||
| 32 | + | ||
| 33 | +@property (nonatomic, strong) UILabel *desLabel; | ||
| 34 | + | ||
| 35 | +@end | ||
| 36 | + | ||
| 37 | +@implementation CNReUpLoadTableViewCell | ||
| 38 | + | ||
| 39 | +static const NSInteger margin = 20; | ||
| 40 | + | ||
| 41 | +#pragma mark - Init | ||
| 42 | +- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{ | ||
| 43 | + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; | ||
| 44 | + if (self) { | ||
| 45 | + self.contentView.backgroundColor = [UIColor colorWithRed:248/255.0 green:248/255.0 blue:248/255.0 alpha:1.0]; | ||
| 46 | + [self setupUI]; | ||
| 47 | + } | ||
| 48 | + return self; | ||
| 49 | +} | ||
| 50 | + | ||
| 51 | +#pragma mark - UI | ||
| 52 | +- (void)setupUI{ | ||
| 53 | + [self.contentView addSubview:self.bgView]; | ||
| 54 | + [self.contentView addSubview:self.line]; | ||
| 55 | + | ||
| 56 | + [self.contentView addSubview:self.deleteBtn]; | ||
| 57 | + [self.contentView addSubview:self.reUploadBtn]; | ||
| 58 | + [self.contentView addSubview:self.dateLabel]; | ||
| 59 | + [self.contentView addSubview:self.timeLabel]; | ||
| 60 | + [self.contentView addSubview:self.desLabel]; | ||
| 61 | + | ||
| 62 | + [self.contentView addSubview:self.addressLabel]; | ||
| 63 | + [self.contentView addSubview:self.distanceLabel]; | ||
| 64 | + | ||
| 65 | + [self.contentView addSubview:self.durationBtn]; | ||
| 66 | + [self.contentView addSubview:self.speedBtn]; | ||
| 67 | + [self.contentView addSubview:self.stepNumberBtn]; | ||
| 68 | + | ||
| 69 | + | ||
| 70 | +} | ||
| 71 | + | ||
| 72 | +- (void)layoutSubviews{ | ||
| 73 | + [super layoutSubviews]; | ||
| 74 | + [_bgView mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 75 | + make.left.top.equalTo(self).offset(10); | ||
| 76 | + make.right.equalTo(self.mas_right).offset(-10); | ||
| 77 | + make.bottom.equalTo(self.mas_bottom).offset(-10); | ||
| 78 | + }]; | ||
| 79 | + _bgView.layer.cornerRadius = 5; | ||
| 80 | + _bgView.layer.masksToBounds = YES; | ||
| 81 | + | ||
| 82 | + | ||
| 83 | + [_deleteBtn mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 84 | + make.right.equalTo(self.mas_right).offset(-margin); | ||
| 85 | + make.bottom.equalTo(self.mas_bottom).offset(-margin); | ||
| 86 | + make.size.mas_equalTo(CGSizeMake(65, 26)); | ||
| 87 | + }]; | ||
| 88 | + _deleteBtn.layer.cornerRadius = 26/2; | ||
| 89 | + _deleteBtn.layer.masksToBounds = YES; | ||
| 90 | + _deleteBtn.layer.borderWidth = 1; | ||
| 91 | + _deleteBtn.layer.borderColor = [UIColor colorWithRed:54/255.0 green:194/255.0 blue:141/255.0 alpha:1.0].CGColor; | ||
| 92 | + | ||
| 93 | + [_reUploadBtn mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 94 | + make.right.equalTo(self.deleteBtn.mas_left).offset(-margin); | ||
| 95 | + make.bottom.equalTo(self.mas_bottom).offset(-margin); | ||
| 96 | + make.size.mas_equalTo(CGSizeMake(75, 26)); | ||
| 97 | + }]; | ||
| 98 | + _reUploadBtn.layer.cornerRadius = 26/2; | ||
| 99 | + _reUploadBtn.layer.masksToBounds = YES; | ||
| 100 | + _reUploadBtn.layer.borderWidth = 1; | ||
| 101 | + _reUploadBtn.layer.borderColor = [UIColor colorWithRed:54/255.0 green:194/255.0 blue:141/255.0 alpha:1.0].CGColor; | ||
| 102 | + | ||
| 103 | + | ||
| 104 | + | ||
| 105 | + [_line mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 106 | + make.bottom.equalTo(self.reUploadBtn.mas_top).with.offset(-margin/2); | ||
| 107 | + make.left.equalTo(self.contentView.mas_left).with.offset(margin); | ||
| 108 | + make.right.equalTo(self.contentView.mas_right).with.offset(-margin); | ||
| 109 | + make.height.offset(0.5); | ||
| 110 | + }]; | ||
| 111 | + | ||
| 112 | + //日期 | ||
| 113 | + [_dateLabel mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 114 | + make.left.equalTo(self).offset(margin); | ||
| 115 | + make.top.left.equalTo(self).offset(25); | ||
| 116 | +// make.height.offset(20); | ||
| 117 | + }]; | ||
| 118 | + | ||
| 119 | + //时间 | ||
| 120 | + [_timeLabel mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 121 | + make.top.equalTo(self.dateLabel); | ||
| 122 | + make.left.equalTo(self.dateLabel.mas_right).with.offset(margin); | ||
| 123 | +// make.height.offset(20); | ||
| 124 | + }]; | ||
| 125 | + | ||
| 126 | + //描述 | ||
| 127 | + [_desLabel mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 128 | + make.right.equalTo(self.mas_right).offset(-margin); | ||
| 129 | + make.centerY.equalTo(self.dateLabel); | ||
| 130 | + }]; | ||
| 131 | + | ||
| 132 | + //地址 | ||
| 133 | + [_addressLabel mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 134 | + make.top.equalTo(self.dateLabel.mas_bottom).with.offset(10); | ||
| 135 | + make.left.equalTo(self.dateLabel.mas_left); | ||
| 136 | + make.right.equalTo(self.mas_right).with.offset(-margin); | ||
| 137 | +// make.height.offset(25); | ||
| 138 | + }]; | ||
| 139 | + | ||
| 140 | + //距离 | ||
| 141 | + [_distanceLabel mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 142 | + make.top.equalTo(self.addressLabel.mas_bottom).with.offset(10); | ||
| 143 | + make.left.equalTo(self.addressLabel.mas_left); | ||
| 144 | + make.right.equalTo(self.contentView.mas_right).with.offset(-margin); | ||
| 145 | +// make.height.offset(40); | ||
| 146 | + }]; | ||
| 147 | + | ||
| 148 | + [_durationBtn mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 149 | + make.bottom.equalTo(self.line.mas_top).with.offset(-10); | ||
| 150 | + make.left.equalTo(self.addressLabel.mas_left); | ||
| 151 | + make.height.offset(25); | ||
| 152 | + | ||
| 153 | + }]; | ||
| 154 | + | ||
| 155 | + [_speedBtn mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 156 | + make.bottom.equalTo(self.line.mas_top).with.offset(-10); | ||
| 157 | + make.left.equalTo(self.durationBtn.mas_right).with.offset(30); | ||
| 158 | + make.height.offset(25); | ||
| 159 | + }]; | ||
| 160 | + | ||
| 161 | + //步数 | ||
| 162 | + [_stepNumberBtn mas_makeConstraints:^(MASConstraintMaker *make) { | ||
| 163 | + make.bottom.equalTo(self.line.mas_top).with.offset(-10); | ||
| 164 | + make.left.equalTo(self.speedBtn.mas_right).with.offset(30); | ||
| 165 | + make.height.offset(25); | ||
| 166 | + | ||
| 167 | + }]; | ||
| 168 | +} | ||
| 169 | +- (void)dealloc{ | ||
| 170 | + | ||
| 171 | +} | ||
| 172 | +#pragma mark - Data | ||
| 173 | +- (void)setModel:(CNTrackUploadFailModel *)model{ | ||
| 174 | + _model = model; | ||
| 175 | + _dateLabel.text = [CNLiveTimeTools getDateByTimeStamp:model.startTime formatter:@"MM月dd日"]; | ||
| 176 | + _timeLabel.text = [CNLiveTimeTools getDateByTimeStamp:model.startTime formatter:@"HH:mm"]; | ||
| 177 | + _addressLabel.text = model.eventName; | ||
| 178 | + _distanceLabel.attributedText = [self setupDistanceString:model.totalKM]; | ||
| 179 | + [_durationBtn setTitle:[CNLiveTimeTools getMMSSFromSS:model.totalTime] forState:UIControlStateNormal]; | ||
| 180 | + [_speedBtn setTitle:model.speed forState:UIControlStateNormal]; | ||
| 181 | + [_stepNumberBtn setTitle:model.totalStep forState:UIControlStateNormal]; | ||
| 182 | +} | ||
| 183 | + | ||
| 184 | +- (void)awakeFromNib { | ||
| 185 | + [super awakeFromNib]; | ||
| 186 | + // Initialization code | ||
| 187 | +} | ||
| 188 | + | ||
| 189 | +- (void)setSelected:(BOOL)selected animated:(BOOL)animated { | ||
| 190 | + [super setSelected:selected animated:animated]; | ||
| 191 | + | ||
| 192 | + // Configure the view for the selected state | ||
| 193 | +} | ||
| 194 | + | ||
| 195 | +#pragma mark - Private Methods | ||
| 196 | +//时间 地点 | ||
| 197 | +- (NSMutableAttributedString *)setupDistanceString:(NSString *)str{ | ||
| 198 | + NSString *strs = [NSString stringWithFormat:@"%@ 公里",str]; | ||
| 199 | + NSMutableAttributedString *attri = [[NSMutableAttributedString alloc] initWithString:strs]; | ||
| 200 | + | ||
| 201 | + [attri addAttribute:NSForegroundColorAttributeName value:CNLiveColorWithHexString(@"#333333") range:NSMakeRange(0, strs.length)]; | ||
| 202 | + [attri addAttribute:NSFontAttributeName value:UIFontCNMake(26) range:NSMakeRange(0, str.length)]; | ||
| 203 | + [attri addAttribute:NSFontAttributeName value:UIFontCNMake(14) range:NSMakeRange(str.length, strs.length-str.length)]; | ||
| 204 | + | ||
| 205 | + return attri; | ||
| 206 | +} | ||
| 207 | + | ||
| 208 | +- (void)deleteBtnAction{ | ||
| 209 | + if (self.deleteClickBlock) { | ||
| 210 | + self.deleteClickBlock(self.index); | ||
| 211 | + } | ||
| 212 | +} | ||
| 213 | + | ||
| 214 | +- (void)reUploadAction{ | ||
| 215 | + if (![CNLiveNetworking isNetworking]) { | ||
| 216 | + [QMUITips showInfo:@"暂无网络" inView:AppKeyWindow hideAfterDelay:1.5]; | ||
| 217 | + return; | ||
| 218 | + } | ||
| 219 | + NSDictionary *dict = [self.model.endCoordsDictStr mj_JSONObject]; | ||
| 220 | + CLLocationCoordinate2D coordinate; | ||
| 221 | + coordinate.latitude = [dict[@"lat"] doubleValue]; | ||
| 222 | + coordinate.longitude = [dict[@"long"] doubleValue]; | ||
| 223 | + //请求自己的历史轨迹 | ||
| 224 | + [self queryCurrentRunningEndPoint:^(NSArray *points) { | ||
| 225 | + __block BOOL isSuccess = NO;//是否到达了终点 | ||
| 226 | + [points enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { | ||
| 227 | + CNHistoryTrackPoint *minePoint = obj; | ||
| 228 | + CLLocation *originLocation = [[CLLocation alloc] initWithLatitude:coordinate.latitude longitude:coordinate.longitude]; | ||
| 229 | + CLLocation *currentLocation = [[CLLocation alloc] initWithLatitude:minePoint.coordinate.latitude longitude:minePoint.coordinate.longitude]; | ||
| 230 | + CLLocationDistance distance = [originLocation distanceFromLocation:currentLocation]; | ||
| 231 | + if (distance < 50) {//表示到达终点了 | ||
| 232 | + isSuccess = YES; | ||
| 233 | + *stop = YES; | ||
| 234 | + } | ||
| 235 | + }]; | ||
| 236 | + if (isSuccess) {//到达了终点 | ||
| 237 | + __block NSMutableArray *mutArr = [NSMutableArray arrayWithArray:points]; | ||
| 238 | + __block int successCount = 0; | ||
| 239 | + NSArray *arr = [self.model.pointsArrStr mj_JSONObject]; | ||
| 240 | + NSMutableArray<CNLiveSportsCoordinatesModel *> *models = [CNLiveSportsCoordinatesModel mj_objectArrayWithKeyValuesArray:arr]; | ||
| 241 | + for (CNLiveSportsCoordinatesModel *pointNode in models) { | ||
| 242 | + CLLocation *originLocation = [[CLLocation alloc] initWithLatitude:[pointNode.latitude doubleValue] longitude:[pointNode.longitude doubleValue]]; | ||
| 243 | + [mutArr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { | ||
| 244 | + CNHistoryTrackPoint *minePoint = obj; | ||
| 245 | + CLLocation *currentLocation = [[CLLocation alloc] initWithLatitude:minePoint.coordinate.latitude longitude:minePoint.coordinate.longitude]; | ||
| 246 | + CLLocationDistance distance = [originLocation distanceFromLocation:currentLocation]; | ||
| 247 | + if (distance < 50) {//表示这个点已经完成 | ||
| 248 | + [mutArr removeObjectsInRange:NSMakeRange(0, idx+1)]; | ||
| 249 | + successCount ++; | ||
| 250 | + *stop = YES; | ||
| 251 | + } | ||
| 252 | + }]; | ||
| 253 | + } | ||
| 254 | + if (successCount*1.000/models.count*1.000 > 0.70) {//大于70%则认为任务完成 | ||
| 255 | + [self uploadService:YES]; | ||
| 256 | + }else{ | ||
| 257 | + [self uploadService:NO]; | ||
| 258 | + } | ||
| 259 | + }else{//没有到达终点,直接算未完成 | ||
| 260 | + [self uploadService:NO]; | ||
| 261 | + } | ||
| 262 | + }]; | ||
| 263 | +} | ||
| 264 | + | ||
| 265 | +//请求 | ||
| 266 | +- (void)uploadService:(BOOL)isSuccessTrack{ | ||
| 267 | + NSString *strUrl = CNSportsChinaSaveRecordUrl; | ||
| 268 | + NSDictionary *dict = @{ | ||
| 269 | + @"eventId":self.model.eventId, | ||
| 270 | + @"sid":CNUserShareModelUid, | ||
| 271 | + @"employTime":self.model.totalTime, | ||
| 272 | + @"mileage":self.model.totalKM, | ||
| 273 | + @"pace":self.model.speed, | ||
| 274 | + @"step":self.model.totalStep, | ||
| 275 | + //@"roadmap":imgUrlStr, | ||
| 276 | + @"startTime":self.model.startTime, | ||
| 277 | + @"endTime":self.model.endTime, | ||
| 278 | + @"isPause":self.model.isStop.length>0?@"1":@"0", | ||
| 279 | + @"pauseTime":self.model.isStop.length>0?self.model.stopTime:@"", | ||
| 280 | + @"continueTime":self.model.isStop.length>0?self.model.reStartTime:@"", | ||
| 281 | + @"completeStatus":isSuccessTrack?@"1":@"0" | ||
| 282 | + }; | ||
| 283 | + [CNLiveNetworking requestNetworkWithMethod:CNLiveRequestMethodPOST URLString:strUrl Param:dict CacheType:CNLiveNetworkCacheTypeNetworkOnly CompletionBlock:^(NSURLSessionTask *requestTask, id responseObject, NSError *error) { | ||
| 284 | + if (error) { | ||
| 285 | + [QMUITips showInfo:@"服务异常,请重试" inView:AppKeyWindow hideAfterDelay:1.5]; | ||
| 286 | + //弹窗,是否暂存,是否重试 | ||
| 287 | +// [self alertEndSelect:isSuccessTrack img:imgUrlStr]; | ||
| 288 | + }else{ | ||
| 289 | + if ([responseObject isKindOfClass:[NSDictionary class]]) { | ||
| 290 | + NSString *resultCode = [NSString stringWithFormat:@"%@", responseObject[@"errorCode"]]; | ||
| 291 | + if ([resultCode isEqualToString:@"0"]) { | ||
| 292 | + //删除数据库中的逻辑辅助数据 | ||
| 293 | + [[CNTrackLoaclDataManager shareManager] deleteFUploadModel:self.model]; | ||
| 294 | + [QMUITips showInfo:@"重新上传成功" inView:AppKeyWindow hideAfterDelay:1.5]; | ||
| 295 | + if ([self.delegate respondsToSelector:@selector(needToReloadTable:index:)]) { | ||
| 296 | + [self.delegate needToReloadTable:self index:self.index]; | ||
| 297 | + } | ||
| 298 | + }else{ | ||
| 299 | + [QMUITips showInfo:@"服务异常,请重试" inView:AppKeyWindow hideAfterDelay:1.5]; | ||
| 300 | + } | ||
| 301 | + }else{ | ||
| 302 | + [QMUITips showInfo:@"服务异常,请重试" inView:AppKeyWindow hideAfterDelay:1.5]; | ||
| 303 | + } | ||
| 304 | + } | ||
| 305 | + }]; | ||
| 306 | +} | ||
| 307 | + | ||
| 308 | +#pragma mark -- 自己的历史轨迹 | ||
| 309 | +- (void)queryCurrentRunningEndPoint:(void(^)(NSArray *))handle{ | ||
| 310 | + NSMutableArray *tempArray = [NSMutableArray arrayWithCapacity:0]; | ||
| 311 | + if ([self.model.isStop isEqualToString:@"yes"]) { | ||
| 312 | + CNHistoryTrackParam * paramInfo =[[CNHistoryTrackParam alloc]init]; | ||
| 313 | + [paramInfo setStartTime:[self.model.startTime integerValue]]; | ||
| 314 | + [paramInfo setEndTime:[self.model.stopTime integerValue]]; | ||
| 315 | + [paramInfo setEntityName:CNUserShareModelUid]; | ||
| 316 | + [paramInfo setIsProcessed:true]; | ||
| 317 | + BTKQueryTrackProcessOption *processOption = [[BTKQueryTrackProcessOption alloc] init]; | ||
| 318 | + processOption.radiusThreshold = 100; | ||
| 319 | + processOption.denoise = true; | ||
| 320 | + processOption.vacuate = true; | ||
| 321 | + processOption.mapMatch = false; | ||
| 322 | + processOption.transportMode = BTK_TRACK_PROCESS_OPTION_TRANSPORT_MODE_WALKING; | ||
| 323 | + paramInfo.processOption = processOption; | ||
| 324 | + paramInfo.supplementMode = BTK_TRACK_PROCESS_OPTION_SUPPLEMENT_MODE_WALKING; | ||
| 325 | + CNHistoryViewModel *vm = [[CNHistoryViewModel alloc] init]; | ||
| 326 | + vm.completionHandler = ^(NSArray *points) { | ||
| 327 | + [tempArray addObjectsFromArray:points]; | ||
| 328 | + if (self.model.reStartTime.length > 0) { | ||
| 329 | + CNHistoryTrackParam * paramInfo2 =[[CNHistoryTrackParam alloc]init]; | ||
| 330 | + [paramInfo2 setStartTime:[self.model.reStartTime integerValue]]; | ||
| 331 | + [paramInfo2 setEndTime:[self.model.endTime integerValue]]; | ||
| 332 | + [paramInfo2 setEntityName:CNUserShareModelUid]; | ||
| 333 | + [paramInfo2 setIsProcessed:true]; | ||
| 334 | + BTKQueryTrackProcessOption *processOption2 = [[BTKQueryTrackProcessOption alloc] init]; | ||
| 335 | + processOption2.radiusThreshold = 100; | ||
| 336 | + processOption2.denoise = true; | ||
| 337 | + processOption2.vacuate = true; | ||
| 338 | + processOption2.mapMatch = false; | ||
| 339 | + processOption2.transportMode = BTK_TRACK_PROCESS_OPTION_TRANSPORT_MODE_WALKING; | ||
| 340 | + paramInfo2.processOption = processOption; | ||
| 341 | + paramInfo2.supplementMode = BTK_TRACK_PROCESS_OPTION_SUPPLEMENT_MODE_WALKING; | ||
| 342 | + CNHistoryViewModel *vm2 = [[CNHistoryViewModel alloc] init]; | ||
| 343 | + vm2.completionHandler = ^(NSArray *points) { | ||
| 344 | + [tempArray addObjectsFromArray:points]; | ||
| 345 | + handle(tempArray); | ||
| 346 | + }; | ||
| 347 | + [vm2 queryHistoryWithParam:paramInfo2]; | ||
| 348 | + }else{ | ||
| 349 | + handle(tempArray); | ||
| 350 | + } | ||
| 351 | + }; | ||
| 352 | + [vm queryHistoryWithParam:paramInfo]; | ||
| 353 | + }else{ | ||
| 354 | + CNHistoryTrackParam * paramInfo =[[CNHistoryTrackParam alloc]init]; | ||
| 355 | + [paramInfo setStartTime:[self.model.startTime integerValue]]; | ||
| 356 | + [paramInfo setEndTime:[self.model.endTime integerValue]]; | ||
| 357 | + [paramInfo setEntityName:CNUserShareModelUid]; | ||
| 358 | + [paramInfo setIsProcessed:true]; | ||
| 359 | + BTKQueryTrackProcessOption *processOption = [[BTKQueryTrackProcessOption alloc] init]; | ||
| 360 | + processOption.radiusThreshold = 100; | ||
| 361 | + processOption.denoise = true; | ||
| 362 | + processOption.vacuate = true; | ||
| 363 | + processOption.mapMatch = false; | ||
| 364 | + processOption.transportMode = BTK_TRACK_PROCESS_OPTION_TRANSPORT_MODE_WALKING; | ||
| 365 | + paramInfo.processOption = processOption; | ||
| 366 | + paramInfo.supplementMode = BTK_TRACK_PROCESS_OPTION_SUPPLEMENT_MODE_WALKING; | ||
| 367 | + CNHistoryViewModel *vm = [[CNHistoryViewModel alloc] init]; | ||
| 368 | + vm.completionHandler = ^(NSArray *points) { | ||
| 369 | + [tempArray addObjectsFromArray:points]; | ||
| 370 | + handle(tempArray); | ||
| 371 | + }; | ||
| 372 | + [vm queryHistoryWithParam:paramInfo]; | ||
| 373 | + } | ||
| 374 | + | ||
| 375 | +} | ||
| 376 | +#pragma mark - Lazy loading | ||
| 377 | +-(UIView *)bgView{ | ||
| 378 | + if (!_bgView) { | ||
| 379 | + _bgView = [[UIView alloc] init]; | ||
| 380 | + _bgView.backgroundColor = kWhiteColor; | ||
| 381 | + } | ||
| 382 | + return _bgView; | ||
| 383 | +} | ||
| 384 | + | ||
| 385 | +- (UILabel *)dateLabel{ | ||
| 386 | + if(_dateLabel == nil){ | ||
| 387 | + _dateLabel = [[UILabel alloc] init]; | ||
| 388 | + _dateLabel.textColor = CNLiveColorWithHexString(@"666666"); | ||
| 389 | + _dateLabel.font = UIFontCNMake(14); | ||
| 390 | + | ||
| 391 | + } | ||
| 392 | + return _dateLabel; | ||
| 393 | + | ||
| 394 | +} | ||
| 395 | + | ||
| 396 | +- (UILabel *)timeLabel{ | ||
| 397 | + if(_timeLabel == nil){ | ||
| 398 | + _timeLabel = [[UILabel alloc] init]; | ||
| 399 | + _timeLabel.textColor = CNLiveColorWithHexString(@"888888"); | ||
| 400 | + _timeLabel.font = UIFontCNMake(14); | ||
| 401 | + _timeLabel.userInteractionEnabled = YES; | ||
| 402 | + | ||
| 403 | + } | ||
| 404 | + return _timeLabel; | ||
| 405 | + | ||
| 406 | +} | ||
| 407 | + | ||
| 408 | +- (UILabel *)addressLabel{ | ||
| 409 | + if(_addressLabel == nil){ | ||
| 410 | + _addressLabel = [[UILabel alloc] init]; | ||
| 411 | + _addressLabel.textColor = CNLiveColorWithHexString(@"333333"); | ||
| 412 | + _addressLabel.font = UIFontCNMake(12); | ||
| 413 | + _addressLabel.userInteractionEnabled = YES; | ||
| 414 | + | ||
| 415 | + } | ||
| 416 | + return _addressLabel; | ||
| 417 | + | ||
| 418 | +} | ||
| 419 | + | ||
| 420 | +- (UILabel *)distanceLabel{ | ||
| 421 | + if(_distanceLabel == nil){ | ||
| 422 | + _distanceLabel = [[UILabel alloc] init]; | ||
| 423 | + _distanceLabel.textColor = CNLiveColorWithHexString(@"333333"); | ||
| 424 | + _distanceLabel.font = UIFontCNMake(30); | ||
| 425 | + _distanceLabel.userInteractionEnabled = YES; | ||
| 426 | + | ||
| 427 | + } | ||
| 428 | + return _distanceLabel; | ||
| 429 | + | ||
| 430 | +} | ||
| 431 | + | ||
| 432 | +- (QMUIButton *)durationBtn{ | ||
| 433 | + if(_durationBtn == nil){ | ||
| 434 | + _durationBtn = [QMUIButton buttonWithType:UIButtonTypeCustom]; | ||
| 435 | + _durationBtn.titleLabel.font = UIFontCNMake(13); | ||
| 436 | + [_durationBtn setTitleColor:CNLiveColorWithHexString(@"666666") forState:UIControlStateNormal]; | ||
| 437 | + [_durationBtn setTitle:@"00:00:00" forState:UIControlStateNormal]; | ||
| 438 | + [_durationBtn setImage:[UIImage imageNamed:@"sports_china_wdjl_time"] forState:UIControlStateNormal]; | ||
| 439 | + _durationBtn.adjustsImageWhenHighlighted = NO; | ||
| 440 | + _durationBtn.imagePosition = QMUIButtonImagePositionRight; | ||
| 441 | + _durationBtn.spacingBetweenImageAndTitle = 5; | ||
| 442 | + _durationBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; | ||
| 443 | + | ||
| 444 | + } | ||
| 445 | + return _durationBtn; | ||
| 446 | + | ||
| 447 | +} | ||
| 448 | + | ||
| 449 | +- (QMUIButton *)speedBtn{ | ||
| 450 | + if(_speedBtn == nil){ | ||
| 451 | + _speedBtn = [QMUIButton buttonWithType:UIButtonTypeCustom]; | ||
| 452 | + _speedBtn.titleLabel.font = UIFontCNMake(13); | ||
| 453 | + [_speedBtn setTitleColor:CNLiveColorWithHexString(@"666666") forState:UIControlStateNormal]; | ||
| 454 | + [_speedBtn setTitle:@"0" forState:UIControlStateNormal]; | ||
| 455 | + [_speedBtn setImage:[UIImage imageNamed:@"sports_china_wdjl_speed"] forState:UIControlStateNormal]; | ||
| 456 | + _speedBtn.adjustsImageWhenHighlighted = NO; | ||
| 457 | + _speedBtn.imagePosition = QMUIButtonImagePositionRight; | ||
| 458 | + _speedBtn.spacingBetweenImageAndTitle = 5; | ||
| 459 | + _speedBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; | ||
| 460 | + | ||
| 461 | + } | ||
| 462 | + return _speedBtn; | ||
| 463 | + | ||
| 464 | +} | ||
| 465 | + | ||
| 466 | +- (QMUIButton *)stepNumberBtn{ | ||
| 467 | + if(_stepNumberBtn == nil){ | ||
| 468 | + _stepNumberBtn = [QMUIButton buttonWithType:UIButtonTypeCustom]; | ||
| 469 | + _stepNumberBtn.titleLabel.font = UIFontCNMake(13); | ||
| 470 | + [_stepNumberBtn setTitleColor:CNLiveColorWithHexString(@"666666") forState:UIControlStateNormal]; | ||
| 471 | + [_stepNumberBtn setTitle:@"0" forState:UIControlStateNormal]; | ||
| 472 | + [_stepNumberBtn setImage:[UIImage imageNamed:@"sports_china_wdjl_step"] forState:UIControlStateNormal]; | ||
| 473 | + _stepNumberBtn.adjustsImageWhenHighlighted = NO; | ||
| 474 | + _stepNumberBtn.imagePosition = QMUIButtonImagePositionRight; | ||
| 475 | + _stepNumberBtn.spacingBetweenImageAndTitle = 5; | ||
| 476 | + _stepNumberBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; | ||
| 477 | + | ||
| 478 | + } | ||
| 479 | + return _stepNumberBtn; | ||
| 480 | + | ||
| 481 | +} | ||
| 482 | + | ||
| 483 | +- (UIView *)line{ | ||
| 484 | + if(_line == nil){ | ||
| 485 | + _line = [[UIView alloc] init]; | ||
| 486 | + _line.backgroundColor = CNLiveColorWithHexString(@"ebebeb"); | ||
| 487 | + | ||
| 488 | + } | ||
| 489 | + return _line; | ||
| 490 | + | ||
| 491 | +} | ||
| 492 | + | ||
| 493 | +- (QMUIButton *)deleteBtn{ | ||
| 494 | + if(_deleteBtn == nil){ | ||
| 495 | + _deleteBtn = [QMUIButton buttonWithType:UIButtonTypeCustom]; | ||
| 496 | + [_deleteBtn setTitle:@"删 除" forState:UIControlStateNormal]; | ||
| 497 | + _deleteBtn.titleLabel.font = UIFontCNMake(12); | ||
| 498 | + [_deleteBtn setTitleColor:[UIColor colorWithRed:54/255.0 green:194/255.0 blue:141/255.0 alpha:1.0] forState:UIControlStateNormal]; | ||
| 499 | + [_deleteBtn addTarget:self action:@selector(deleteBtnAction) forControlEvents:UIControlEventTouchUpInside]; | ||
| 500 | + } | ||
| 501 | + return _deleteBtn; | ||
| 502 | +} | ||
| 503 | + | ||
| 504 | +-(QMUIButton *)reUploadBtn{ | ||
| 505 | + if(_reUploadBtn == nil){ | ||
| 506 | + _reUploadBtn = [QMUIButton buttonWithType:UIButtonTypeCustom]; | ||
| 507 | + [_reUploadBtn setTitle:@"重新上传" forState:UIControlStateNormal]; | ||
| 508 | + _reUploadBtn.titleLabel.font = UIFontCNMake(12); | ||
| 509 | + [_reUploadBtn setTitleColor:[UIColor colorWithRed:54/255.0 green:194/255.0 blue:141/255.0 alpha:1.0] forState:UIControlStateNormal]; | ||
| 510 | + [_reUploadBtn addTarget:self action:@selector(reUploadAction) forControlEvents:UIControlEventTouchUpInside]; | ||
| 511 | + } | ||
| 512 | + return _reUploadBtn; | ||
| 513 | +} | ||
| 514 | + | ||
| 515 | +-(UILabel *)desLabel{ | ||
| 516 | + if(_desLabel == nil){ | ||
| 517 | + _desLabel = [[UILabel alloc] init]; | ||
| 518 | + _desLabel.textColor = [UIColor colorWithRed:254/255.0 green:78/255.0 blue:78/255.0 alpha:1.0]; | ||
| 519 | + _desLabel.font = UIFontCNMake(12); | ||
| 520 | + _desLabel.userInteractionEnabled = YES; | ||
| 521 | + _desLabel.text = @"上传失败"; | ||
| 522 | + } | ||
| 523 | + return _desLabel; | ||
| 524 | +} | ||
| 525 | +@end |
| 1 | +// | ||
| 2 | +// CNRunEndCircleProgress.h | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/14. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | + | ||
| 10 | +#import <UIKit/UIKit.h> | ||
| 11 | +#import "CNRunEndCountingLabel.h" | ||
| 12 | + | ||
| 13 | +#define CNCircleDegreeToRadian(d) ((d)*M_PI)/180.0 | ||
| 14 | +#define CNCircleRGB(r, g, b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1.0] | ||
| 15 | +#define CNCircleSelfWidth self.frame.size.width | ||
| 16 | +#define CNCircleSelfHeight self.frame.size.height | ||
| 17 | + | ||
| 18 | +@interface CNRunEndCircleProgress : UIView | ||
| 19 | + | ||
| 20 | +//图形定制 | ||
| 21 | +@property (nonatomic, strong) UIColor *pathBackColor;/**<线条背景色*/ | ||
| 22 | +@property (nonatomic, strong) UIColor *pathFillColor;/**<线条填充色*/ | ||
| 23 | +@property (nonatomic, strong) UIImageView *pointImage;/**<小圆点图片*/ | ||
| 24 | +@property (nonatomic, strong) CNRunEndCountingLabel *progressLabel; | ||
| 25 | + | ||
| 26 | +//角度相关 | ||
| 27 | +@property (nonatomic, assign) CGFloat startAngle;/**<起点角度。角度从水平右侧开始为0,顺时针为增加角度。直接传度数 如-90 */ | ||
| 28 | +@property (nonatomic, assign) CGFloat reduceAngle;/**<减少的角度 直接传度数 如30*/ | ||
| 29 | +@property (nonatomic, assign) CGFloat strokeWidth;/**<线宽*/ | ||
| 30 | + | ||
| 31 | +@property (nonatomic, assign) CGFloat duration;/**<动画时长*/ | ||
| 32 | + | ||
| 33 | +@property (nonatomic, assign) BOOL showPoint;/**<是否显示小圆点*/ | ||
| 34 | +@property (nonatomic, assign) BOOL showProgressText;/**<是否显示文字*/ | ||
| 35 | +@property (nonatomic, assign) BOOL increaseFromLast;/**<是否从上次数值开始动画,默认为NO*/ | ||
| 36 | + | ||
| 37 | +//进度 | ||
| 38 | +@property (nonatomic, assign) CGFloat progress;/**<进度 0-1 */ | ||
| 39 | + | ||
| 40 | +/** | ||
| 41 | + 初始化 | ||
| 42 | + | ||
| 43 | + @param frame 使用自动布局时传CGRectZero | ||
| 44 | + @param pathBackColor 背景线条色 | ||
| 45 | + @param pathFillColor 填充线条色 | ||
| 46 | + @param startAngle 开始角度 | ||
| 47 | + @param strokeWidth 线条宽度 | ||
| 48 | + @return CNCircleProgress | ||
| 49 | + */ | ||
| 50 | +- (instancetype)initWithFrame:(CGRect)frame | ||
| 51 | + pathBackColor:(UIColor *)pathBackColor | ||
| 52 | + pathFillColor:(UIColor *)pathFillColor | ||
| 53 | + startAngle:(CGFloat)startAngle | ||
| 54 | + strokeWidth:(CGFloat)strokeWidth; | ||
| 55 | + | ||
| 56 | +@end |
| 1 | +// | ||
| 2 | +// CNRunEndCircleProgress.m | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/14. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | + | ||
| 10 | +#import "CNRunEndCircleProgress.h" | ||
| 11 | + | ||
| 12 | +@interface CNRunEndCircleProgress ()<CAAnimationDelegate> | ||
| 13 | + | ||
| 14 | +@property (nonatomic, strong) CAShapeLayer *backLayer; | ||
| 15 | +@property (nonatomic, strong) CAShapeLayer *progressLayer; | ||
| 16 | + | ||
| 17 | +@property (nonatomic, assign) CGFloat realWidth;//实际边长 | ||
| 18 | +@property (nonatomic, assign) CGFloat radius;//半径 | ||
| 19 | +@property (nonatomic, assign) CGFloat lastProgress;/**<上次进度 0-1 */ | ||
| 20 | +@property (nonatomic, strong) CAAnimation *lastPointAnimation; | ||
| 21 | + | ||
| 22 | +@end | ||
| 23 | + | ||
| 24 | + | ||
| 25 | +@implementation CNRunEndCircleProgress | ||
| 26 | + | ||
| 27 | +- (instancetype)init { | ||
| 28 | + if (self = [super init]) { | ||
| 29 | + [self initialization]; | ||
| 30 | + } | ||
| 31 | + return self; | ||
| 32 | +} | ||
| 33 | + | ||
| 34 | +- (instancetype)initWithFrame:(CGRect)frame { | ||
| 35 | + if (self = [super initWithFrame:frame]) { | ||
| 36 | + [self initialization]; | ||
| 37 | + } | ||
| 38 | + return self; | ||
| 39 | +} | ||
| 40 | + | ||
| 41 | +- (void)awakeFromNib { | ||
| 42 | + [super awakeFromNib]; | ||
| 43 | + [self initialization]; | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +//初始化 | ||
| 47 | +- (instancetype)initWithFrame:(CGRect)frame | ||
| 48 | + pathBackColor:(UIColor *)pathBackColor | ||
| 49 | + pathFillColor:(UIColor *)pathFillColor | ||
| 50 | + startAngle:(CGFloat)startAngle | ||
| 51 | + strokeWidth:(CGFloat)strokeWidth { | ||
| 52 | + if (self = [super initWithFrame:frame]) { | ||
| 53 | + [self initialization]; | ||
| 54 | + self.pathBackColor = pathBackColor; | ||
| 55 | + self.pathFillColor = pathFillColor; | ||
| 56 | + _startAngle = CNCircleDegreeToRadian(startAngle); | ||
| 57 | + _strokeWidth = strokeWidth; | ||
| 58 | + } | ||
| 59 | + return self; | ||
| 60 | +} | ||
| 61 | + | ||
| 62 | +//初始化数据 | ||
| 63 | +- (void)initialization { | ||
| 64 | + self.backgroundColor = [UIColor greenColor];//[UIColor colorWithRed:250/255.0 green:112/255.0 blue:112/255.0 alpha:1.0]; | ||
| 65 | + _pathBackColor = [UIColor lightGrayColor]; | ||
| 66 | + _pathFillColor = [UIColor redColor]; | ||
| 67 | + | ||
| 68 | + _strokeWidth = 10;//线宽默认为10 | ||
| 69 | + _startAngle = CNCircleDegreeToRadian(0);//圆起点位置 | ||
| 70 | + _reduceAngle = CNCircleDegreeToRadian(0);//整个圆缺少的角度 | ||
| 71 | + | ||
| 72 | + _duration = 1.5;//动画时长 | ||
| 73 | + _showPoint = YES;//小圆点 | ||
| 74 | + _showProgressText = YES;//文字 | ||
| 75 | + | ||
| 76 | + //初始化layer | ||
| 77 | + [self initSubviews]; | ||
| 78 | +} | ||
| 79 | + | ||
| 80 | +#pragma Get | ||
| 81 | +- (CAShapeLayer *)backLayer { | ||
| 82 | + if (!_backLayer) { | ||
| 83 | + _backLayer = [CAShapeLayer layer]; | ||
| 84 | + _backLayer.fillColor = [UIColor clearColor].CGColor;//填充色 | ||
| 85 | + _backLayer.lineWidth = _strokeWidth; | ||
| 86 | + _backLayer.strokeColor = _pathBackColor.CGColor; | ||
| 87 | + _backLayer.lineCap = @"round"; | ||
| 88 | + } | ||
| 89 | + return _backLayer; | ||
| 90 | +} | ||
| 91 | + | ||
| 92 | +- (CAShapeLayer *)progressLayer { | ||
| 93 | + if (!_progressLayer) { | ||
| 94 | + _progressLayer = [CAShapeLayer layer]; | ||
| 95 | + _progressLayer.fillColor = [UIColor clearColor].CGColor;//填充色 | ||
| 96 | + _progressLayer.lineWidth = _strokeWidth; | ||
| 97 | + _progressLayer.strokeColor = _pathFillColor.CGColor; | ||
| 98 | + _progressLayer.lineCap = @"round"; | ||
| 99 | + } | ||
| 100 | + return _progressLayer; | ||
| 101 | +} | ||
| 102 | + | ||
| 103 | +- (UIImageView *)pointImage { | ||
| 104 | + if (!_pointImage) { | ||
| 105 | + _pointImage = [[UIImageView alloc] init]; | ||
| 106 | + NSBundle *mainBundle = [NSBundle bundleForClass:[self class]]; | ||
| 107 | + NSBundle *resourcesBundle = [NSBundle bundleWithPath:[mainBundle pathForResource:@"CNCircleProgress" ofType:@"bundle"]]; | ||
| 108 | + _pointImage.image = [UIImage imageNamed:@"circle_point1" inBundle:resourcesBundle compatibleWithTraitCollection:nil]; | ||
| 109 | + } | ||
| 110 | + return _pointImage; | ||
| 111 | +} | ||
| 112 | + | ||
| 113 | +- (CNRunEndCountingLabel *)progressLabel { | ||
| 114 | + if (!_progressLabel) { | ||
| 115 | + _progressLabel = [[CNRunEndCountingLabel alloc] init]; | ||
| 116 | + _progressLabel.textColor = [UIColor blackColor]; | ||
| 117 | + _progressLabel.textAlignment = NSTextAlignmentCenter; | ||
| 118 | + _progressLabel.font = [UIFont systemFontOfSize:22]; | ||
| 119 | + _progressLabel.text = @"0%"; | ||
| 120 | + } | ||
| 121 | + return _progressLabel; | ||
| 122 | +} | ||
| 123 | + | ||
| 124 | +- (CAAnimation *)pathAnimation { | ||
| 125 | + CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; | ||
| 126 | + pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; | ||
| 127 | + pathAnimation.duration = _duration; | ||
| 128 | + pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; | ||
| 129 | + pathAnimation.fromValue = [NSNumber numberWithFloat:_increaseFromLast==YES?_lastProgress:0]; | ||
| 130 | + pathAnimation.toValue = [NSNumber numberWithFloat:_progress]; | ||
| 131 | + pathAnimation.fillMode = kCAFillModeForwards; | ||
| 132 | + pathAnimation.removedOnCompletion = NO; | ||
| 133 | + return pathAnimation; | ||
| 134 | +} | ||
| 135 | + | ||
| 136 | +- (CAAnimation *)pointAnimation { | ||
| 137 | + CAKeyframeAnimation *pointAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; | ||
| 138 | + pointAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; | ||
| 139 | + pointAnimation.fillMode = kCAFillModeForwards; | ||
| 140 | + pointAnimation.calculationMode = @"paced"; | ||
| 141 | + pointAnimation.removedOnCompletion = NO; | ||
| 142 | + pointAnimation.duration = _duration; | ||
| 143 | + pointAnimation.delegate = self; | ||
| 144 | + | ||
| 145 | + BOOL clockwise = NO; | ||
| 146 | + if (_progress<_lastProgress && _increaseFromLast == YES) { | ||
| 147 | + clockwise = YES; | ||
| 148 | + } | ||
| 149 | + UIBezierPath *imagePath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(_realWidth/2.0, _realWidth/2.0) radius:_radius startAngle:_increaseFromLast==YES?(2*M_PI-_reduceAngle)*_lastProgress+_startAngle:_startAngle endAngle:(2*M_PI-_reduceAngle)*_progress+_startAngle clockwise:!clockwise]; | ||
| 150 | + pointAnimation.path = imagePath.CGPath; | ||
| 151 | + | ||
| 152 | + return pointAnimation; | ||
| 153 | +} | ||
| 154 | + | ||
| 155 | +#pragma Set | ||
| 156 | +- (void)setStartAngle:(CGFloat)startAngle { | ||
| 157 | + if (_startAngle != CNCircleDegreeToRadian(startAngle)) { | ||
| 158 | + _startAngle = CNCircleDegreeToRadian(startAngle); | ||
| 159 | + [self setNeedsLayout]; | ||
| 160 | + } | ||
| 161 | +} | ||
| 162 | + | ||
| 163 | +- (void)setReduceAngle:(CGFloat)reduceAngle { | ||
| 164 | + if (_reduceAngle != CNCircleDegreeToRadian(reduceAngle)) { | ||
| 165 | + if (reduceAngle>=360) { | ||
| 166 | + return; | ||
| 167 | + } | ||
| 168 | + _reduceAngle = CNCircleDegreeToRadian(reduceAngle); | ||
| 169 | + [self setNeedsLayout]; | ||
| 170 | + } | ||
| 171 | +} | ||
| 172 | + | ||
| 173 | +- (void)setStrokeWidth:(CGFloat)strokeWidth { | ||
| 174 | + if (_strokeWidth != strokeWidth) { | ||
| 175 | + _strokeWidth = strokeWidth; | ||
| 176 | + _radius = _realWidth/2.0 - _strokeWidth/2.0; | ||
| 177 | + [self setNeedsLayout]; | ||
| 178 | + } | ||
| 179 | +} | ||
| 180 | + | ||
| 181 | +- (void)setPathBackColor:(UIColor *)pathBackColor { | ||
| 182 | + if (_pathBackColor != pathBackColor) { | ||
| 183 | + _pathBackColor = pathBackColor; | ||
| 184 | + self.backLayer.strokeColor = _pathBackColor.CGColor; | ||
| 185 | + } | ||
| 186 | +} | ||
| 187 | + | ||
| 188 | +- (void)setPathFillColor:(UIColor *)pathFillColor { | ||
| 189 | + if (_pathFillColor != pathFillColor) { | ||
| 190 | + _pathFillColor = pathFillColor; | ||
| 191 | + self.progressLayer.strokeColor = _pathFillColor.CGColor; | ||
| 192 | + } | ||
| 193 | +} | ||
| 194 | + | ||
| 195 | +- (void)setShowPoint:(BOOL)showPoint { | ||
| 196 | + if (_showPoint != showPoint) { | ||
| 197 | + _showPoint = showPoint; | ||
| 198 | + if (_showPoint) { | ||
| 199 | + self.pointImage.hidden = NO; | ||
| 200 | + [self updatePointPosition]; | ||
| 201 | + } else { | ||
| 202 | + self.pointImage.hidden = YES; | ||
| 203 | + } | ||
| 204 | + } | ||
| 205 | +} | ||
| 206 | + | ||
| 207 | +-(void)setShowProgressText:(BOOL)showProgressText { | ||
| 208 | + if (_showProgressText != showProgressText) { | ||
| 209 | + _showProgressText = showProgressText; | ||
| 210 | + if (_showProgressText) { | ||
| 211 | + self.progressLabel.hidden = NO; | ||
| 212 | + } else { | ||
| 213 | + self.progressLabel.hidden = YES; | ||
| 214 | + } | ||
| 215 | + } | ||
| 216 | +} | ||
| 217 | + | ||
| 218 | +- (void)setProgress:(CGFloat)progress { | ||
| 219 | + _progress = MAX(MIN(1, progress), 0); | ||
| 220 | + __weak typeof(self) weakSelf = self; | ||
| 221 | + dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 222 | + __strong typeof(weakSelf) strongSelf = weakSelf; | ||
| 223 | + [strongSelf startAnimation]; | ||
| 224 | + }); | ||
| 225 | +} | ||
| 226 | + | ||
| 227 | +#pragma Methods | ||
| 228 | +- (void)startAnimation { | ||
| 229 | + | ||
| 230 | + [self.progressLayer addAnimation:[self pathAnimation] forKey:@"strokeEndAnimation"]; | ||
| 231 | + | ||
| 232 | + if (_showPoint) { | ||
| 233 | + CAAnimation *pointAnimation = [self pointAnimation]; | ||
| 234 | + [self.pointImage.layer addAnimation:pointAnimation forKey:@"pointAnimation"]; | ||
| 235 | + self.lastPointAnimation = pointAnimation; | ||
| 236 | + | ||
| 237 | + if (!_increaseFromLast && _progress == 0.0) { | ||
| 238 | + [self.pointImage.layer removeAllAnimations]; | ||
| 239 | + } | ||
| 240 | + } | ||
| 241 | + | ||
| 242 | + if (_showProgressText && _increaseFromLast) { | ||
| 243 | + [self.progressLabel countingFrom:_lastProgress*100 to:_progress*100 duration:_duration]; | ||
| 244 | + } else if (_showProgressText) { | ||
| 245 | + [self.progressLabel countingFrom:0 to:_progress*100 duration:_duration]; | ||
| 246 | + } | ||
| 247 | + | ||
| 248 | + _lastProgress = _progress; | ||
| 249 | +} | ||
| 250 | + | ||
| 251 | +- (UIBezierPath *)getNewBezierPath { | ||
| 252 | + return [UIBezierPath bezierPathWithArcCenter:CGPointMake(_realWidth/2.0, _realWidth/2.0) radius:_radius startAngle:_startAngle endAngle:(2*M_PI-_reduceAngle+_startAngle) clockwise:YES]; | ||
| 253 | +} | ||
| 254 | + | ||
| 255 | +- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { | ||
| 256 | + if (flag && anim == [self.pointImage.layer animationForKey:@"pointAnimation"]) { | ||
| 257 | + [self updatePointPosition]; | ||
| 258 | + } | ||
| 259 | +} | ||
| 260 | + | ||
| 261 | +- (void)updatePointPosition { | ||
| 262 | + CGFloat currentEndAngle = (2*M_PI-_reduceAngle)*_progress+_startAngle; | ||
| 263 | + [_pointImage.layer removeAllAnimations]; | ||
| 264 | + _pointImage.center = CGPointMake(_realWidth/2.0+_radius*cosf(currentEndAngle), _realWidth/2.0+_radius*sinf(currentEndAngle)); | ||
| 265 | +} | ||
| 266 | + | ||
| 267 | +#pragma initSubviews | ||
| 268 | +- (void)initSubviews { | ||
| 269 | + [self.layer addSublayer:self.backLayer]; | ||
| 270 | + [self.layer addSublayer:self.progressLayer]; | ||
| 271 | + | ||
| 272 | + [self addSubview:self.pointImage]; | ||
| 273 | + [self addSubview:self.progressLabel]; | ||
| 274 | +} | ||
| 275 | + | ||
| 276 | +#pragma layout | ||
| 277 | +- (void)layoutSubviews { | ||
| 278 | + [super layoutSubviews]; | ||
| 279 | + | ||
| 280 | + self.realWidth = MIN(CNCircleSelfWidth, CNCircleSelfHeight); | ||
| 281 | + self.radius = _realWidth/2.0 - _strokeWidth/2.0; | ||
| 282 | + | ||
| 283 | + self.backLayer.frame = CGRectMake(0, 0, _realWidth, _realWidth); | ||
| 284 | + self.backLayer.lineWidth = _strokeWidth; | ||
| 285 | + self.backLayer.path = [self getNewBezierPath].CGPath; | ||
| 286 | + | ||
| 287 | + self.progressLayer.frame = CGRectMake(0, 0, _realWidth, _realWidth); | ||
| 288 | + self.progressLayer.lineWidth = _strokeWidth; | ||
| 289 | + self.progressLayer.path = [self getNewBezierPath].CGPath; | ||
| 290 | + self.progressLayer.strokeEnd = 0.0; | ||
| 291 | + | ||
| 292 | + self.progressLabel.frame = CGRectMake(0, 0, _realWidth, _realWidth); | ||
| 293 | + | ||
| 294 | + self.pointImage.frame = CGRectMake(0, 0, _strokeWidth, _strokeWidth); | ||
| 295 | + [self updatePointPosition]; | ||
| 296 | + | ||
| 297 | +} | ||
| 298 | + | ||
| 299 | +-(void)dealloc{ | ||
| 300 | + NSLog(@""); | ||
| 301 | +} | ||
| 302 | +@end |
| 1 | +// | ||
| 2 | +// ZZCountingLabel.h | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/14. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import <UIKit/UIKit.h> | ||
| 10 | + | ||
| 11 | +@interface CNRunEndCountingLabel : UILabel | ||
| 12 | + | ||
| 13 | +@property (nonatomic, assign) CGFloat duration; | ||
| 14 | + | ||
| 15 | +- (void)countingFrom:(CGFloat)fromValue to:(CGFloat)toValue; | ||
| 16 | +- (void)countingFrom:(CGFloat)fromValue to:(CGFloat)toValue duration:(CGFloat)duration; | ||
| 17 | + | ||
| 18 | +@end |
| 1 | +// | ||
| 2 | +// ZZCountingLabel.m | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/14. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import "CNRunEndCountingLabel.h" | ||
| 10 | + | ||
| 11 | +@interface CNRunEndCountingLabel () | ||
| 12 | + | ||
| 13 | +@property (nonatomic, strong) CADisplayLink *playLink; | ||
| 14 | +@property (nonatomic, assign) NSInteger displayPerSecond; | ||
| 15 | + | ||
| 16 | +@property (nonatomic, assign) CGFloat fromValue; | ||
| 17 | +@property (nonatomic, assign) CGFloat toValue; | ||
| 18 | + | ||
| 19 | +@property (nonatomic, assign) CGFloat increaseValue; | ||
| 20 | +@property (nonatomic, assign) CGFloat perValue; | ||
| 21 | + | ||
| 22 | +@end | ||
| 23 | + | ||
| 24 | +@implementation CNRunEndCountingLabel | ||
| 25 | + | ||
| 26 | +- (instancetype)init { | ||
| 27 | + if (self = [super init]) { | ||
| 28 | + [self initValues]; | ||
| 29 | + } | ||
| 30 | + return self; | ||
| 31 | +} | ||
| 32 | + | ||
| 33 | +- (instancetype)initWithFrame:(CGRect)frame { | ||
| 34 | + if (self = [super initWithFrame:frame]) { | ||
| 35 | + [self initValues]; | ||
| 36 | + } | ||
| 37 | + return self; | ||
| 38 | +} | ||
| 39 | + | ||
| 40 | +- (void)awakeFromNib { | ||
| 41 | + [super awakeFromNib]; | ||
| 42 | + [self initValues]; | ||
| 43 | +} | ||
| 44 | + | ||
| 45 | +- (void)initValues { | ||
| 46 | + _duration = 2.0; | ||
| 47 | + _displayPerSecond = 30; | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +- (void)countingFrom:(CGFloat)fromValue to:(CGFloat)toValue { | ||
| 51 | + [self countingFrom:fromValue to:toValue duration:_duration]; | ||
| 52 | +} | ||
| 53 | + | ||
| 54 | +- (void)countingFrom:(CGFloat)fromValue to:(CGFloat)toValue duration:(CGFloat)duration { | ||
| 55 | + | ||
| 56 | + _fromValue = fromValue; | ||
| 57 | + _toValue = toValue; | ||
| 58 | + _duration = duration; | ||
| 59 | + | ||
| 60 | + _increaseValue = _fromValue; | ||
| 61 | + _perValue = (_toValue - _fromValue)/(_duration==0?1:(_displayPerSecond*_duration)); | ||
| 62 | + | ||
| 63 | + if (self.playLink) { | ||
| 64 | + [self.playLink invalidate]; | ||
| 65 | + self.playLink = nil; | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + CADisplayLink *playLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(countingAction)]; | ||
| 69 | + if (@available(iOS 10.0, *)) { | ||
| 70 | + playLink.preferredFramesPerSecond = _displayPerSecond; | ||
| 71 | + } else { | ||
| 72 | + playLink.frameInterval = 60/(_displayPerSecond==0?1:_displayPerSecond); | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + [playLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; | ||
| 76 | + [playLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:UITrackingRunLoopMode]; | ||
| 77 | + self.playLink = playLink; | ||
| 78 | + | ||
| 79 | +} | ||
| 80 | + | ||
| 81 | +- (void)countingAction { | ||
| 82 | + _increaseValue += _perValue; | ||
| 83 | + | ||
| 84 | + if (_fromValue < _toValue) { | ||
| 85 | + if (_increaseValue >= _toValue) { | ||
| 86 | + [self stopDisplayLink]; | ||
| 87 | + } | ||
| 88 | + } else { | ||
| 89 | + if (_increaseValue <= _toValue) { | ||
| 90 | + [self stopDisplayLink]; | ||
| 91 | + } | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 95 | + self.text = [NSString stringWithFormat:@"%.0f%%",_increaseValue]; | ||
| 96 | + }); | ||
| 97 | +} | ||
| 98 | + | ||
| 99 | +- (void)stopDisplayLink { | ||
| 100 | + | ||
| 101 | + [self.playLink invalidate]; | ||
| 102 | + self.playLink = nil; | ||
| 103 | + | ||
| 104 | + _increaseValue = _toValue; | ||
| 105 | +} | ||
| 106 | + | ||
| 107 | +@end |
| 1 | +// | ||
| 2 | +// CNTrackTableView.h | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/19. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import <UIKit/UIKit.h> | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | +@interface CNTrackTableView : UITableView | ||
| 14 | +@property (nonatomic, strong) UIView *view; | ||
| 15 | +@property (nonatomic, assign) CGFloat receiverHeight; | ||
| 16 | +@end | ||
| 17 | + | ||
| 18 | + |
| 1 | +// | ||
| 2 | +// CNTrackTableView.m | ||
| 3 | +// CNLiveNetAdd | ||
| 4 | +// | ||
| 5 | +// Created by open on 2019/6/19. | ||
| 6 | +// Copyright © 2019 cnlive. All rights reserved. | ||
| 7 | +// | ||
| 8 | + | ||
| 9 | +#import "CNTrackTableView.h" | ||
| 10 | + | ||
| 11 | +@implementation CNTrackTableView | ||
| 12 | +- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {//从底部往上区域手势事件不响应 | ||
| 13 | + if (![self.layer containsPoint:point]) { | ||
| 14 | + return NO; | ||
| 15 | + } | ||
| 16 | + if (self.view) { | ||
| 17 | + if ([self.view.layer containsPoint:point]) { | ||
| 18 | + return YES; | ||
| 19 | + } | ||
| 20 | + } | ||
| 21 | + if (point.y < self.receiverHeight) { | ||
| 22 | + return NO; | ||
| 23 | + } | ||
| 24 | + return YES; | ||
| 25 | +} | ||
| 26 | + | ||
| 27 | +@end |