diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_fuel@3x.png b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_fuel@3x.png index a928c03..f7f1357 100644 Binary files a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_fuel@3x.png and b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_fuel@3x.png differ diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_mileage@3x.png b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_mileage@3x.png new file mode 100644 index 0000000..1d8cbce Binary files /dev/null and b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_mileage@3x.png differ diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_person@3x.png b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_person@3x.png new file mode 100644 index 0000000..043966d Binary files /dev/null and b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_person@3x.png differ diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_phone@3x.png b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_phone@3x.png new file mode 100644 index 0000000..27d3f81 Binary files /dev/null and b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_phone@3x.png differ diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_price@3x.png b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_price@3x.png new file mode 100644 index 0000000..d0dca61 Binary files /dev/null and b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_price@3x.png differ diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_time@3x.png b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_time@3x.png new file mode 100644 index 0000000..b5e259e Binary files /dev/null and b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_time@3x.png differ diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_toll@3x.png b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_toll@3x.png new file mode 100644 index 0000000..3b184a6 Binary files /dev/null and b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_toll@3x.png differ diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AAddHPopView.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AAddHPopView.h new file mode 100644 index 0000000..839f636 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AAddHPopView.h @@ -0,0 +1,30 @@ +// +// AAddHPopView.h +// AMapNavIOSSDK +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * 气泡弹框视图 + * + * 用法: + * AAddHPopView *pop = [[AAddHPopView alloc] init]; + * [pop showInView:self.view sourceView:addHbtn]; + * + * - 点击气泡外部自动消失 + * - 箭头在右下角45度,指向 sourceView 中心 + */ +@interface AAddHPopView : UIView + +/// 展示气泡,sourceView 为箭头指向的锚定按钮(坐标系属于 view) +- (void)showInView:(UIView *)view sourceView:(UIView *)sourceView; + +/// 手动消失(点击空白处会自动调用) +- (void)dismiss; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AAddHPopView.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AAddHPopView.m new file mode 100644 index 0000000..a624e11 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AAddHPopView.m @@ -0,0 +1,359 @@ +// +// AAddHPopView.m +// AMapNavIOSSDK +// + +#import "AAddHPopView.h" +#import +#import "UIColor+ANavMap.h" + +// ─── 尺寸常量 ──────────────────────────────────────────────────────────────── +static const CGFloat kBubbleWidth = 200.f; // 气泡宽度 +static const CGFloat kHeaderHeight = 50.f; // 顶部绿色标题区高度 +static const CGFloat kOptionHeight = 60.f; // 每行选项高度 +static const CGFloat kArrowWidth = 50.f; // 箭头底边宽(aw = ah*2 使左右45度对称) +static const CGFloat kArrowHeight = 15.f; // 箭头高度 +static const CGFloat kBubbleRadius = 15.f; // 气泡圆角半径 +static const CGFloat kBubbleGap = 5.f; // 气泡底部与 sourceView 顶部间距 +static const CGFloat kScreenPadding = 15.f; // 气泡距屏幕边缘最小距离 + + +// ─── 自定义气泡容器:自绘白色气泡 + 底部箭头 ───────────────────────────────── +@interface _ABubbleContainerView : UIView +/// 箭头中心 X(相对于本 view 坐标系),用于 showInView 精确定位 +@property (nonatomic, assign) CGFloat arrowCenterX; +@end + +@implementation _ABubbleContainerView + +- (instancetype)init { + self = [super init]; + if (self) { + self.backgroundColor = [UIColor clearColor]; + _arrowCenterX = kBubbleWidth / 2.f; + } + return self; +} + +- (void)setArrowCenterX:(CGFloat)arrowCenterX { + _arrowCenterX = arrowCenterX; + [self setNeedsDisplay]; +} + +- (void)drawRect:(CGRect)rect { + CGFloat bw = kBubbleWidth; // 160 + CGFloat bh = kHeaderHeight + kOptionHeight * 2.f; // 150 + CGFloat r = kBubbleRadius; // 10 + CGFloat aw = kArrowWidth; // 16 箭头底边宽 + CGFloat ah = kArrowHeight; // 10 箭头高度 + + // 箭头在底部偏右:指向右下45度 + // 箭头底边: 从 (arrowX-aw/2, bh) 到 (arrowX, bh) + // 箭头尖端: (arrowX + ah, bh + ah) — 相对于底边中心向右下45度 + CGFloat arrowX = bw - 15.f; // 箭头底边右端 X(偏右下) + CGFloat arrowTipX = arrowX + ah; // 箭头尖端 X(向右偏移ah = 45度) + CGFloat arrowTipY = bh + ah; // 箭头尖端 Y(向下偏移ah = 45度) + + UIBezierPath *path = [UIBezierPath bezierPath]; + + // ── 顶部左圆角 → 顶部右圆角 ── + [path moveToPoint:CGPointMake(r, 0)]; + [path addLineToPoint:CGPointMake(bw - r, 0)]; + [path addArcWithCenter:CGPointMake(bw - r, r) radius:r + startAngle:-M_PI_2 endAngle:0 clockwise:YES]; + + // ── 右边 → 右下圆角 ── + [path addLineToPoint:CGPointMake(bw, bh - r)]; + [path addArcWithCenter:CGPointMake(bw - r, bh - r) radius:r + startAngle:0 endAngle:M_PI_2 clockwise:YES]; + + // ── 底边 → 箭头底边右端 ── + [path addLineToPoint:CGPointMake(arrowX, bh)]; + // 箭头斜边(45度向右下到尖端) + [path addLineToPoint:CGPointMake(arrowTipX, arrowTipY)]; + // 箭头底边左端(垂直向上) + [path addLineToPoint:CGPointMake(arrowX - ah, bh)]; + + // ── 左下圆角 ── + [path addArcWithCenter:CGPointMake(r, bh - r) radius:r + startAngle:M_PI_2 endAngle:M_PI clockwise:YES]; + + // ── 左边 → 左上圆角 ── + [path addLineToPoint:CGPointMake(0, r)]; + [path addArcWithCenter:CGPointMake(r, r) radius:r + startAngle:M_PI endAngle:-M_PI_2 clockwise:YES]; + [path closePath]; + + // ── 阴影 + 白色填充 ── + CGContextRef ctx = UIGraphicsGetCurrentContext(); + CGContextSaveGState(ctx); + CGContextSetShadowWithColor(ctx, CGSizeMake(0, 3), 10.f, + [[UIColor blackColor] colorWithAlphaComponent:0.15f].CGColor); + [[UIColor whiteColor] setFill]; + [path fill]; + CGContextRestoreGState(ctx); + [[UIColor whiteColor] setFill]; + [path fill]; + + // 保存箭头尖端坐标用于定位 + _arrowTipX = arrowTipX; + _arrowTipY = arrowTipY; +} + +// 供外部访问的箭头尖端坐标 +static CGFloat _arrowTipX = 0; +static CGFloat _arrowTipY = 0; + +@end + + +// ─── AAddHPopView ──────────────────────────────────────────────────────────── + +@interface AAddHPopView () + +@property (nonatomic, strong) _ABubbleContainerView *bubbleContainer; +@property (nonatomic, strong) UIView *headerView; +@property (nonatomic, strong) UILabel *titleLabel; +@property (nonatomic, strong) UIView *separatorLine1; +@property (nonatomic, strong) UILabel *option1Label; +@property (nonatomic, strong) UIView *separatorLine2; +@property (nonatomic, strong) UILabel *option2Label; + +@end + +@implementation AAddHPopView + +#pragma mark - Init + +- (instancetype)init { + return [self initWithFrame:CGRectZero]; +} + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + [self p_setupUI]; + } + return self; +} + +#pragma mark - Setup UI + +- (void)p_setupUI { + self.backgroundColor = [UIColor clearColor]; + + // ── 点击空白处(self)消失 ── + UITapGestureRecognizer *bgTap = [[UITapGestureRecognizer alloc] initWithTarget:self + action:@selector(dismiss)]; + bgTap.cancelsTouchesInView = NO; + [self addGestureRecognizer:bgTap]; + + // ── 气泡容器 ── + [self addSubview:self.bubbleContainer]; + + // ── header(绿色标题区,仅裁剪上两角) ── + [self.bubbleContainer addSubview:self.headerView]; + [self.headerView addSubview:self.titleLabel]; + + // ── 分隔线 1 ── + [self.bubbleContainer addSubview:self.separatorLine1]; + + // ── 选项 1 ── + [self.bubbleContainer addSubview:self.option1Label]; + + // ── 分隔线 2 ── + [self.bubbleContainer addSubview:self.separatorLine2]; + + // ── 选项 2 ── + [self.bubbleContainer addSubview:self.option2Label]; + + // ── 阻止气泡内点击冒泡到 bgTap ── + UITapGestureRecognizer *bubbleTap = [[UITapGestureRecognizer alloc] initWithTarget:self + action:@selector(p_bubbleTapped)]; + [self.bubbleContainer addGestureRecognizer:bubbleTap]; + + // ── Masonry 内部约束(基于 bubbleContainer) ── + // 子视图宽度统一约束到 kBubbleWidth(160),气泡主体实际宽度 + [self.headerView mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.left.equalTo(self.bubbleContainer); + make.width.mas_equalTo(kBubbleWidth); + make.height.mas_equalTo(kHeaderHeight); + }]; + + [self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(self.headerView); + }]; + + [self.separatorLine1 mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.headerView.mas_bottom); + make.left.mas_equalTo(@0); + make.width.mas_equalTo(kBubbleWidth); + make.height.mas_equalTo(0.5); + }]; + + [self.option1Label mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.separatorLine1.mas_bottom); + make.left.mas_equalTo(@0); + make.width.mas_equalTo(kBubbleWidth); + make.height.mas_equalTo(kOptionHeight); + }]; + + [self.separatorLine2 mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.option1Label.mas_bottom); + make.left.mas_equalTo(@0); + make.width.mas_equalTo(kBubbleWidth); + make.height.mas_equalTo(0.5); + }]; + + [self.option2Label mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.separatorLine2.mas_bottom); + make.left.mas_equalTo(@0); + make.width.mas_equalTo(kBubbleWidth); + make.height.mas_equalTo(kOptionHeight); + }]; +} + +#pragma mark - Show / Dismiss + +- (void)showInView:(UIView *)view sourceView:(UIView *)sourceView { + self.frame = view.bounds; + [view addSubview:self]; + + // ── 计算 sourceView 在 view 坐标系中的 frame ── + CGRect srcFrame = [sourceView convertRect:sourceView.bounds toView:view]; + + // ── 容器尺寸 ── + CGFloat containerW = kBubbleWidth; // 160 + CGFloat containerH = kHeaderHeight + kOptionHeight * 2.f; // 150 + CGFloat ah = kArrowHeight; // 16 箭头高度 + + // ── 箭头尖端坐标(相对于 bubbleContainer 左下角为原点)── + // 与 drawRect 中一致:arrowX = bw - 35, arrowTipX = arrowX + ah + CGFloat arrowX_inContainer = containerW - 25.f; // 箭头底边右端 X + CGFloat arrowTipX_inContainer = arrowX_inContainer + ah; // 箭头尖端 X(右下45度) + CGFloat arrowTipY_inContainer = containerH + ah; // 箭头尖端 Y + + // ── 位置计算:气泡在按钮左上方,箭头尖端指向按钮中心 ── + CGFloat srcCenterX = CGRectGetMidX(srcFrame); + CGFloat srcCenterY = CGRectGetMidY(srcFrame); + + // 箭头尖端应指向按钮中心 + CGFloat containerX = srcCenterX - arrowTipX_inContainer; + containerX = MAX(kScreenPadding, MIN(containerX, view.bounds.size.width - containerW - kScreenPadding)); + + // 气泡顶部位置 + CGFloat containerY = srcCenterY - arrowTipY_inContainer; + containerY = MAX(kScreenPadding, containerY); + + self.bubbleContainer.bounds = CGRectMake(0, 0, containerW, containerH + ah); + + // 锚点设置在箭头尖端位置(相对于容器),实现箭头精准指向 + self.bubbleContainer.layer.anchorPoint = CGPointMake(arrowTipX_inContainer / containerW, + arrowTipY_inContainer / (containerH + ah)); + self.bubbleContainer.center = CGPointMake(srcCenterX - 25, srcCenterY - 20); + + // ── 入场动画 ── + self.alpha = 0.f; + self.bubbleContainer.transform = CGAffineTransformMakeScale(0.85f, 0.85f); + + [UIView animateWithDuration:0.25f + delay:0.f + usingSpringWithDamping:0.72f + initialSpringVelocity:0.3f + options:UIViewAnimationOptionCurveEaseOut + animations:^{ + self.alpha = 1.f; + self.bubbleContainer.transform = CGAffineTransformIdentity; + } completion:nil]; +} + +- (void)dismiss { + [UIView animateWithDuration:0.18f + delay:0.f + options:UIViewAnimationOptionCurveEaseIn + animations:^{ + self.alpha = 0.f; + self.bubbleContainer.transform = CGAffineTransformMakeScale(0.85f, 0.85f); + } completion:^(BOOL finished) { + [self removeFromSuperview]; + }]; +} + +#pragma mark - Private Actions + +- (void)p_bubbleTapped { + // 阻止冒泡,气泡内点击不消失 +} + +#pragma mark - Lazy Load + +- (_ABubbleContainerView *)bubbleContainer { + if (!_bubbleContainer) { + _bubbleContainer = [[_ABubbleContainerView alloc] init]; + } + return _bubbleContainer; +} + +- (UIView *)headerView { + if (!_headerView) { + _headerView = [[UIView alloc] init]; + _headerView.backgroundColor = [UIColor hp_colorWithRGBHex:0x1BA855]; + if (@available(iOS 11.0, *)) { + _headerView.layer.cornerRadius = kBubbleRadius; + _headerView.layer.maskedCorners = kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner; + _headerView.clipsToBounds = YES; + } + } + return _headerView; +} + +- (UILabel *)titleLabel { + if (!_titleLabel) { + _titleLabel = [[UILabel alloc] init]; + _titleLabel.text = @"加氢规划模式"; + _titleLabel.textColor = [UIColor whiteColor]; + _titleLabel.font = [UIFont boldSystemFontOfSize:15.f]; + _titleLabel.textAlignment = NSTextAlignmentCenter; + } + return _titleLabel; +} + +- (UIView *)separatorLine1 { + if (!_separatorLine1) { + _separatorLine1 = [[UIView alloc] init]; + _separatorLine1.backgroundColor = [UIColor colorWithWhite:0.88f alpha:1.f]; + } + return _separatorLine1; +} + +- (UILabel *)option1Label { + if (!_option1Label) { + _option1Label = [[UILabel alloc] init]; + _option1Label.text = @"送货规划模式"; + _option1Label.textColor = [UIColor hp_colorWithRGBHex:0xC9CDD4]; + _option1Label.font = [UIFont boldSystemFontOfSize:14.f]; + _option1Label.textAlignment = NSTextAlignmentCenter; + } + return _option1Label; +} + +- (UIView *)separatorLine2 { + if (!_separatorLine2) { + _separatorLine2 = [[UIView alloc] init]; + _separatorLine2.backgroundColor = [UIColor colorWithWhite:0.88f alpha:1.f]; + } + return _separatorLine2; +} + +- (UILabel *)option2Label { + if (!_option2Label) { + _option2Label = [[UILabel alloc] init]; + _option2Label.text = @"成本计算模式"; + _option2Label.textColor = [UIColor hp_colorWithRGBHex:0xC9CDD4]; + _option2Label.font = [UIFont boldSystemFontOfSize:14.f]; + _option2Label.textAlignment = NSTextAlignmentCenter; + } + return _option2Label; +} + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ACustomNaviDriveController.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ACustomNaviDriveController.h new file mode 100644 index 0000000..88d203a --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ACustomNaviDriveController.h @@ -0,0 +1,16 @@ +// +// ACustomNaviDriveController.h +// AMapNavIOSSDK +// +// Created by admin on 2026/4/11. +// + +#import "ABaseViewController.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ACustomNaviDriveController : ABaseViewController + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ACustomNaviDriveController.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ACustomNaviDriveController.m new file mode 100644 index 0000000..ab414ea --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ACustomNaviDriveController.m @@ -0,0 +1,22 @@ +// +// ACustomNaviDriveController.m +// AMapNavIOSSDK +// +// Created by admin on 2026/4/11. +// + +#import "ACustomNaviDriveController.h" + +@interface ACustomNaviDriveController () + +@end + +@implementation ACustomNaviDriveController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. +} + + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.h index 3a34308..e4dfb8f 100644 --- a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.h +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.h @@ -21,8 +21,8 @@ NS_ASSUME_NONNULL_BEGIN -@interface ARoutePlaneController : ABaseViewController - +@interface ARoutePlaneController : ABaseViewController +@property (nonatomic , strong) AMapNaviDriveView * driveView; @end NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.m index dde4cf1..564a930 100644 --- a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.m +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.m @@ -18,7 +18,7 @@ #import "AMapPrivacyUtility.h" -#import "AStationDetailPopupController.h" +#import "AStationDetailPopupView.h" #define kRouteIndicatorViewHeight 64.f @@ -26,8 +26,9 @@ #import "AMapNavHttpUtil.h" #import "ACustomStepView.h" #import "ABottomBarView.h" +#import "AAddHPopView.h" -@interface ARoutePlaneController () +@interface ARoutePlaneController () @property (nonatomic, strong) UITextField *textField; /// 底部搜索+规划路线栏 @@ -65,11 +66,14 @@ @property (nonatomic , strong)ACustomStepView * stepView; /// 当前弹出的站点详情弹框 -@property (nonatomic , strong)AStationDetailPopupController * stationDetailPopup; +@property (nonatomic , strong)AStationDetailPopupView * stationDetailPopup; @property (nonatomic, strong) ANavPointModel *pointModel; //当前选的目的点 @property (nonatomic, strong) ATripCalcDataModel * tjdPathInfoModel;//途经点信息 @property (nonatomic, strong) CLLocationManager * locationManager; + +/// 加氢规划按钮(用于气泡弹框定位) +@property (nonatomic, weak) UIButton *addHBtn; @end @implementation ARoutePlaneController @@ -156,6 +160,8 @@ -(void)requestRoutePathWithParms:(NSDictionary*)dic completeHandle:(void(^)(ATripCalcDataModel * tjd))blk { + ///清除上一次数据影响 + self.tjdPathInfoModel = nil; NSString * token = [[NSUserDefaults standardUserDefaults]valueForKey:@"flutter.token"]; NSString * carNo = [[NSUserDefaults standardUserDefaults]valueForKey:@"flutter.plateNumber"]; @@ -279,7 +285,7 @@ [bottomBar mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self.view); - make.bottom.equalTo(self.view); + make.bottom.equalTo(self.view).offset(-AMP_TabbarHeight - 10); }]; // ── 兼容旧逻辑:保留 startTf / dstTf 属性(隐藏,不再显示) ── @@ -319,25 +325,55 @@ [stepView addObserver:self forKeyPath:@"value" options:NSKeyValueObservingOptionNew context:nil]; self.stepView = stepView; + stepView.hidden = YES; ///当前位置按钮 UIButton * btn = [UIButton buttonWithType:UIButtonTypeCustom]; - [btn setImage:[AMapNavCommonUtil imageWithName3x:@"my_location_icon"] forState:UIControlStateNormal]; - btn.backgroundColor = [UIColor lightGrayColor]; + [btn setBackgroundImage:[AMapNavCommonUtil imageWithName3x:@"my_location_icon"] forState:UIControlStateNormal]; + + btn.backgroundColor = [UIColor whiteColor]; btn.titleLabel.font = [UIFont systemFontOfSize:14]; - btn.layer.cornerRadius = 20; + btn.layer.cornerRadius = 22; [btn addTarget:self action:@selector(updateUserLocalAction) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:btn]; [btn mas_makeConstraints:^(MASConstraintMaker *make) { make.right.equalTo(self.view).offset(-10); - make.width.height.equalTo(@40); - make.bottom.equalTo(bottomBar.mas_top).offset(-85); + make.width.height.equalTo(@44); + make.bottom.equalTo(bottomBar.mas_top).offset(-105); }]; + ///加氢规划按钮 + UIButton *addHbtn = [UIButton buttonWithType:UIButtonTypeCustom]; + addHbtn.backgroundColor = [UIColor hp_colorWithRGBHex:0x017137]; + addHbtn.titleLabel.numberOfLines = 2; + + [addHbtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [addHbtn setTitle:@"加氢规划" forState:UIControlStateNormal]; + + addHbtn.titleLabel.font = [UIFont boldSystemFontOfSize:11]; + addHbtn.titleEdgeInsets = UIEdgeInsetsMake(0, 3, 0, 3); + + addHbtn.layer.cornerRadius = 22; + [addHbtn addTarget:self action:@selector(addHbtnAction:) forControlEvents:UIControlEventTouchUpInside]; + [self.view addSubview:addHbtn]; + [addHbtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(self.view).offset(-10); + make.width.height.equalTo(@44); + make.bottom.equalTo(btn.mas_top).offset(-25); + }]; + self.addHBtn = addHbtn; + } +- (void)addHbtnAction:(UIButton *)sender { + // 显示加氢规划模式气泡弹窗,箭头指向按钮 + AAddHPopView *popView = [[AAddHPopView alloc] init]; + [popView showInView:self.view sourceView:sender]; +} + + - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqualToString:@"value"]) { self.mapView.zoomLevel = [change[NSKeyValueChangeNewKey] doubleValue]; @@ -363,6 +399,7 @@ self.mapView.userTrackingMode = MAUserTrackingModeFollowWithHeading; self.mapView.desiredAccuracy = kCLLocationAccuracyNearestTenMeters; // 定位精度 _mapView.showsScale= YES; + _mapView.showsCompass = NO; _mapView.logoCenter = CGPointMake(CGRectGetWidth(self.view.bounds)-55, 450); self.mapView.zoomLevel = 11; @@ -508,7 +545,7 @@ 0, 0, 0); - strategy = AMapNaviDrivingStrategyMultipleDefault;//使用默认策略 + strategy = AMapNaviDrivingStrategyMultipleDefault;//使用默认策略,DRIVING_MULTIPLE_ROUTES_DEFAULT id delegate = [AMapNaviDriveManager sharedInstance].delegate; if (!delegate) { @@ -780,7 +817,8 @@ [config setNeedCalculateRouteWhenPresent:NO];//不在算路 [config setMultipleRouteNaviMode:NO];//直接单线路径导航 // [config setNeedDestoryDriveManagerInstanceWhenDismiss:NO]; - + [config setShowDrivingStrategyPreferenceView:NO]; + [self.compositeManager presentRoutePlanViewControllerWithOptions:config]; } @@ -797,6 +835,8 @@ // [config setMultipleRouteNaviMode:NO];//直接单线路径导航 // [config setNeedDestoryDriveManagerInstanceWhenDismiss:NO]; +// [config setShowDrivingStrategyPreferenceView:NO]; + [self.compositeManager presentRoutePlanViewControllerWithOptions:config]; } @@ -995,9 +1035,12 @@ [self updateUIWithData:aoi textField:self.dstTf]; + ///地图选点加氢站,直接弹出开始导航弹窗(显示时间、费用、里程、路费等),不用再回填名称 + //详情弹框 + [self willRequestTJDInfo]; // 同步更新底部栏目的地文字 - self.bottomBarView.destinationText = aoi.name; +// self.bottomBarView.destinationText = aoi.name; } } @@ -1056,6 +1099,7 @@ AMapPOI *_dstPoi = self.dstPoi ? self.dstPoi : self.defaultDstPoi; if (!_dstPoi) { + [AMapNavCommonUtil showMsg:@"请先选择目的地"]; return; } @@ -1066,9 +1110,19 @@ navPoint.stationID = _dstPoi.uid; self.pointModel = navPoint; + if (self.stationDetailPopup) { + [self.stationDetailPopup resetUI]; + } + ///有_stationID 请求接口;无:不走接口,直接调整高德规划路线; if (!navPoint.stationID) { - [self gd_calPathWithNoStationId:navPoint]; +// [self gd_calPathWithNoStationId:navPoint]; + ANavPointModel * model = [ANavPointModel new]; + model.name = navPoint.name; + model.address = navPoint.address; + + [self showDstInfoPop:model]; + return; }else { __weak typeof(self) weakSelf = self; @@ -1084,7 +1138,7 @@ // --- 弹出站点详情弹框 --- if (!self.stationDetailPopup) { - AStationDetailPopupController *popup = [[AStationDetailPopupController alloc] init]; + AStationDetailPopupView *popup = [[AStationDetailPopupView alloc] init]; popup.delegate = self; self.stationDetailPopup = popup; } @@ -1100,14 +1154,26 @@ self.stationDetailPopup.driveDistance = [NSString stringWithFormat:@"%.1f" , self.tjdPathInfoModel.pathDto.distance / 1000.0] ; ///油费 self.stationDetailPopup.tollFee = self.tjdPathInfoModel.pathDto.tolls; + + ///新增字段信息 + self.stationDetailPopup.contactName = self.tjdPathInfoModel.destinationSite.liaisonName; + self.stationDetailPopup.contactPhone = self.tjdPathInfoModel.destinationSite.liaisonPhone; + self.stationDetailPopup.businessHours = [NSString stringWithFormat:@"%@-%@" , [AMapNavCommonUtil stringValueFromStr:self.tjdPathInfoModel.destinationSite.startBusiness] , [AMapNavCommonUtil stringValueFromStr:self.tjdPathInfoModel.destinationSite.endBusiness]]; + self.stationDetailPopup.hydrogenPrice = [AMapNavCommonUtil stringValueFromStr:self.tjdPathInfoModel.destinationSite.hydrogenPrice]; - [self.stationDetailPopup presentInViewController:self]; + [self.stationDetailPopup showInView:self.view]; +// [self addChildViewController:self.stationDetailPopup]; +// +// CGRect rect = CGRectMake(CGRectGetMinX(self.view.frame), CGRectGetMinY(self.view.frame), CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame) - (AMP_TabbarHeight + 20) * 2); +// self.stationDetailPopup.view.frame = rect; +// +// [self.view addSubview:self.stationDetailPopup.view]; } -#pragma mark - AStationDetailPopupDelegate +#pragma mark - AStationDetailPopupViewDelegate -- (void)stationDetailPopupDidTapStartNavi:(AStationDetailPopupController *)popup { +- (void)stationDetailPopupViewDidTapStartNavi:(AStationDetailPopupView *)popup { self.stationDetailPopup = nil; ///点击开始导航: ///1、有途经点,计算路线,然后再直接导航 @@ -1126,7 +1192,7 @@ } } -- (void)stationDetailPopupDidTapClose:(AStationDetailPopupController *)popup { +- (void)stationDetailPopupViewDidTapClose:(AStationDetailPopupView *)popup { self.stationDetailPopup = nil; } @@ -1140,6 +1206,9 @@ } - (void)bottomBarViewDidTapSearchField:(ABottomBarView *)barView { + ///清除上一次数据影响 + self.tjdPathInfoModel = nil; + // 弹出地址搜索页,选中后更新目的地输入框 ASearchAddressController *vc = [[ASearchAddressController alloc] init]; UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc]; @@ -1160,7 +1229,8 @@ -(void)updateUIWithData: (AMapPOI*)poi textField: (UITextField*)tf { BOOL isStart = tf.tag == 100; - tf.text = poi.name; + ///不显示内容 +// tf.text = poi.name; if (isStart) { self.startPoi = poi; diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ASearchAddressController.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ASearchAddressController.m index c0ce3a8..ef28b82 100644 --- a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ASearchAddressController.m +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ASearchAddressController.m @@ -18,10 +18,12 @@ @property (nonatomic , strong) UIBarButtonItem *rightItem; @property (nonatomic ,strong)UIButton * backBtn; -@property (nonatomic , strong) NSArray *dataArr; +@property (nonatomic , strong) NSMutableArray *dataArr; @property (nonatomic, strong) UITextField *inputAddressTf; @property (nonatomic, strong) AMapSearchAPI *search; +@property (nonatomic,assign)NSInteger currPage; + @end @implementation ASearchAddressController @@ -30,6 +32,9 @@ [super viewDidLoad]; // Do any additional setup after loading the view. self.title = @"选择地点"; + self.currPage = 1; + _dataArr = [NSMutableArray array]; + [self initSubview]; @@ -80,7 +85,8 @@ btn.layer.borderWidth = 1; btn.layer.cornerRadius = 5; btn.titleLabel.font = [UIFont systemFontOfSize:12]; - + btn.hidden = YES; + [btn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; [btn addTarget:self action:@selector(searchBtnAction) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:btn]; @@ -134,6 +140,14 @@ // [self.navigationController popViewControllerAnimated:YES]; } +- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { + if (indexPath.row == self.dataArr.count - 1 && (self.dataArr.count % 20 == 0)) { + self.currPage = self.currPage + 1; + [self requestAddressWithAddress:self.inputAddressTf.text atPage:self.currPage]; + } + +} + #pragma mark - - (UITableView *)tableView { if (!_tableView) { @@ -189,6 +203,7 @@ // request.types = @"高等院校"; // request.requireExtension = YES; request.offset =20; + request.page = 1; /* 搜索SDK 3.2.0 中新增加的功能,只搜索本城市的POI。*/ request.cityLimit = YES; @@ -199,6 +214,27 @@ } +-(void)requestAddressWithAddress:(NSString *)addr atPage:(NSInteger)page { + AMapPOIKeywordsSearchRequest *request = [[AMapPOIKeywordsSearchRequest alloc] init]; + + request.keywords = addr; + + AMapNavSDKManager * sdk = [AMapNavSDKManager sharedManager]; + request.city = sdk.localCity; + + +// request.types = @"高等院校"; +// request.requireExtension = YES; + request.offset =20; + request.page = page; + + /* 搜索SDK 3.2.0 中新增加的功能,只搜索本城市的POI。*/ + request.cityLimit = YES; +// request.requireSubPOIs = YES; + + + [self.search AMapPOIKeywordsSearch:request]; +} #pragma mark - /* POI 搜索回调. */ @@ -212,7 +248,8 @@ //解析response获取POI信息,具体解析见 Demo - self.dataArr = [NSArray arrayWithArray:pois]; + [self.dataArr addObjectsFromArray:pois]; + [self.tableView reloadData]; } @@ -221,6 +258,8 @@ - (BOOL)textFieldShouldReturn:(UITextField *)textField { [textField resignFirstResponder]; + [self.dataArr removeAllObjects]; + self.currPage = 1; [self startSearchWithAddress:textField.text]; diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AStationDetailPopupController.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AStationDetailPopupController.h index ce2a216..9cd5358 100644 --- a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AStationDetailPopupController.h +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AStationDetailPopupController.h @@ -39,6 +39,19 @@ NS_ASSUME_NONNULL_BEGIN /// 过路费,如 @"30元";若 nil 则隐藏 @property (nonatomic, copy, nullable) NSString *tollFee; +/// 营业时间,如 @"00:00-24:00";有值显示,无值显示 - +@property (nonatomic, copy, nullable) NSString *businessHours; + +/// 站点联系人,如 @"陈凯";有值显示,无值显示 - +@property (nonatomic, copy, nullable) NSString *contactName; + +/// 联系方式,如 @"18019187371";有值显示,无值显示 - +@property (nonatomic, copy, nullable) NSString *contactPhone; + +/// 加氢价格,如 @"32元/L";有值显示,无值显示 - +@property (nonatomic, copy, nullable) NSString *hydrogenPrice; + + @property (nonatomic, weak, nullable) id delegate; /// 以半透明蒙层方式弹出在目标控制器上 @@ -50,6 +63,9 @@ NS_ASSUME_NONNULL_BEGIN /// 关闭弹框,动画结束后执行 completion(用于关闭后再 present 其他页面) - (void)dismissWithCompletion:(nullable void(^)(void))completion; + +-(void)resetUI; + @end NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AStationDetailPopupController.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AStationDetailPopupController.m index 9ba560a..6cfe370 100644 --- a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AStationDetailPopupController.m +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AStationDetailPopupController.m @@ -57,6 +57,21 @@ static inline UIColor *AStationThemeGreen(void) { /// 卡片 bottom constraint(动画用) @property (nonatomic, strong) MASConstraint *cardBottomConstraint; +// ── 营业时间 ── +@property (nonatomic, strong) UILabel *businessHoursLabel; + +// ── 站点联系人 ── +@property (nonatomic, strong) UIImageView *contactPersonIconView; +@property (nonatomic, strong) UILabel *contactPersonLabel; + +// ── 加氢价格 ── +@property (nonatomic, strong) UIImageView *priceIconView; +@property (nonatomic, strong) UILabel *priceLabel; + +// ── 联系方式 ── +@property (nonatomic, strong) UIImageView *phoneIconView; +@property (nonatomic, strong) UILabel *phoneLabel; + @end @implementation AStationDetailPopupController @@ -121,6 +136,26 @@ static inline UIColor *AStationThemeGreen(void) { if (self.isViewLoaded) [self _updateUI]; } +- (void)setBusinessHours:(NSString *)businessHours { + _businessHours = [businessHours copy]; + if (self.isViewLoaded) [self _updateUI]; +} + +- (void)setContactName:(NSString *)contactName { + _contactName = [contactName copy]; + if (self.isViewLoaded) [self _updateUI]; +} + +- (void)setContactPhone:(NSString *)contactPhone { + _contactPhone = [contactPhone copy]; + if (self.isViewLoaded) [self _updateUI]; +} + +- (void)setHydrogenPrice:(NSString *)hydrogenPrice { + _hydrogenPrice = [hydrogenPrice copy]; + if (self.isViewLoaded) [self _updateUI]; +} + #pragma mark - Build UI /** @@ -168,10 +203,13 @@ static inline UIColor *AStationThemeGreen(void) { [card addSubview:closeBtn]; self.closeButton = closeBtn; + UIColor * headTextColor = [UIColor hp_colorWithRGBHex:0x1D2129]; + UIFont * headTextFont = [UIFont hp_pingFangMedium:14]; + // ── 站点名称 ── UILabel *nameLabel = [[UILabel alloc] init]; - nameLabel.font = [UIFont boldSystemFontOfSize:18]; - nameLabel.textColor = [UIColor colorWithWhite:0.1 alpha:1]; + nameLabel.font = [UIFont hp_pingFangMedium:18]; + nameLabel.textColor = headTextColor; nameLabel.numberOfLines = 2; // nameLabel.adjustsFontSizeToFitWidth = YES; nameLabel.minimumScaleFactor = 0.8; @@ -180,8 +218,8 @@ static inline UIColor *AStationThemeGreen(void) { // ── 预计加氢费用(名称右侧,间距20pt) ── UILabel *costLabel = [[UILabel alloc] init]; - costLabel.font = [UIFont systemFontOfSize:14]; - costLabel.textColor = [UIColor colorWithWhite:0.2 alpha:1]; + costLabel.font = headTextFont; + costLabel.textColor = headTextColor; costLabel.numberOfLines = 1; costLabel.textAlignment = NSTextAlignmentLeft; // [costLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal]; @@ -189,10 +227,18 @@ static inline UIColor *AStationThemeGreen(void) { [card addSubview:costLabel]; self.costLabel = costLabel; + // ── 营业时间(站点名称下方,4pt间距,浅灰色小字) ── + UILabel *bizHoursLabel = [[UILabel alloc] init]; + bizHoursLabel.font = [UIFont hp_pingFangRegular:14]; + bizHoursLabel.textColor = [UIColor hp_colorWithRGBHex:0x1D2129]; + bizHoursLabel.numberOfLines = 1; + [card addSubview:bizHoursLabel]; + self.businessHoursLabel = bizHoursLabel; + // ── 地址 ── UILabel *addrLabel = [[UILabel alloc] init]; - addrLabel.font = [UIFont systemFontOfSize:13]; - addrLabel.textColor = [UIColor colorWithWhite:0.5 alpha:1]; + addrLabel.font = [UIFont hp_pingFangRegular:14]; + addrLabel.textColor = [UIColor hp_colorWithRGBHex:0x86909C]; addrLabel.numberOfLines = 2; [card addSubview:addrLabel]; self.addressLabel = addrLabel; @@ -212,45 +258,84 @@ static inline UIColor *AStationThemeGreen(void) { // ── 预计时间图标 ── UIImageView *timeIcon = [[UIImageView alloc] init]; timeIcon.contentMode = UIViewContentModeScaleAspectFit; - timeIcon.image = [AMapNavCommonUtil imageWithName3x:@"pre_time_icon"]; + timeIcon.image = [AMapNavCommonUtil imageWithName3x:@"ic_time"]; [card addSubview:timeIcon]; self.timeIconView = timeIcon; // ── 预计时间文字 ── UILabel *timeLabel = [[UILabel alloc] init]; - timeLabel.font = [UIFont systemFontOfSize:14]; - timeLabel.textColor = [UIColor colorWithWhite:0.2 alpha:1]; + timeLabel.font = headTextFont; + timeLabel.textColor = headTextColor; [card addSubview:timeLabel]; self.timeLabel = timeLabel; // ── 行驶里程图标 ── UIImageView *distIcon = [[UIImageView alloc] init]; distIcon.contentMode = UIViewContentModeScaleAspectFit; - distIcon.image = [AMapNavCommonUtil imageWithName3x:@"pre_distance_icon"]; + distIcon.image = [AMapNavCommonUtil imageWithName3x:@"ic_mileage"]; [card addSubview:distIcon]; self.distanceIconView = distIcon; // ── 行驶里程文字 ── UILabel *distLabel = [[UILabel alloc] init]; - distLabel.font = [UIFont systemFontOfSize:14]; - distLabel.textColor = [UIColor colorWithWhite:0.2 alpha:1]; + distLabel.font = headTextFont; + distLabel.textColor = headTextColor; [card addSubview:distLabel]; self.distanceLabel = distLabel; // ── 过路费图标 ── UIImageView *tollIcon = [[UIImageView alloc] init]; tollIcon.contentMode = UIViewContentModeScaleAspectFit; - tollIcon.image = [AMapNavCommonUtil imageWithName3x:@"pre_cost_icon"]; + tollIcon.image = [AMapNavCommonUtil imageWithName3x:@"ic_toll"]; [card addSubview:tollIcon]; self.tollIconView = tollIcon; // ── 过路费文字 ── UILabel *tollLabel = [[UILabel alloc] init]; - tollLabel.font = [UIFont systemFontOfSize:14]; - tollLabel.textColor = [UIColor colorWithWhite:0.2 alpha:1]; + tollLabel.font = headTextFont; + tollLabel.textColor = headTextColor; [card addSubview:tollLabel]; self.tollLabel = tollLabel; + // ── 站点联系人图标 & 文字 ── + UIImageView *personIcon = [[UIImageView alloc] init]; + personIcon.contentMode = UIViewContentModeScaleAspectFit; + personIcon.image = [AMapNavCommonUtil imageWithName3x:@"ic_person"]; + [card addSubview:personIcon]; + self.contactPersonIconView = personIcon; + + UILabel *personLabel = [[UILabel alloc] init]; + personLabel.font = headTextFont; + personLabel.textColor = headTextColor; + [card addSubview:personLabel]; + self.contactPersonLabel = personLabel; + + // ── 加氢价格图标 & 文字 ── + UIImageView *priceIcon = [[UIImageView alloc] init]; + priceIcon.contentMode = UIViewContentModeScaleAspectFit; + priceIcon.image = [AMapNavCommonUtil imageWithName3x:@"ic_price"]; + [card addSubview:priceIcon]; + self.priceIconView = priceIcon; + + UILabel *priceLabel = [[UILabel alloc] init]; + priceLabel.font = headTextFont; + priceLabel.textColor = headTextColor; + [card addSubview:priceLabel]; + self.priceLabel = priceLabel; + + // ── 联系方式图标 & 文字 ── + UIImageView *phoneIcon = [[UIImageView alloc] init]; + phoneIcon.contentMode = UIViewContentModeScaleAspectFit; + phoneIcon.image = [AMapNavCommonUtil imageWithName3x:@"ic_phone"]; + [card addSubview:phoneIcon]; + self.phoneIconView = phoneIcon; + + UILabel *phoneLabel = [[UILabel alloc] init]; + phoneLabel.font = headTextFont; + phoneLabel.textColor = headTextColor; + [card addSubview:phoneLabel]; + self.phoneLabel = phoneLabel; + // ── 开始导航按钮 ── UIButton *naviBtn = [UIButton buttonWithType:UIButtonTypeCustom]; [naviBtn setTitle:@"开始导航" forState:UIControlStateNormal]; @@ -301,24 +386,34 @@ static inline UIColor *AStationThemeGreen(void) { make.right.equalTo(self.closeButton.mas_left).offset(-12); }]; - // ── 地址(名称下方,6pt间距) ── - [self.addressLabel mas_makeConstraints:^(MASConstraintMaker *make) { + // ── 营业时间(站点名称下方,6pt间距) ── + [self.businessHoursLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self.stationNameLabel.mas_bottom).offset(10); make.left.equalTo(card).offset(16); make.right.equalTo(card).offset(-16); }]; + // ── 地址(营业时间下方,6pt间距) ── + [self.addressLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.businessHoursLabel.mas_bottom).offset(10); + make.left.equalTo(card).offset(16); + make.right.equalTo(card).offset(-16); + }]; + self.separator.hidden = YES; + // ── 分割线(地址下方,12pt间距) ── [self.separator mas_makeConstraints:^(MASConstraintMaker *make) { - make.top.equalTo(self.addressLabel.mas_bottom).offset(15); + make.top.equalTo(self.addressLabel.mas_bottom).offset(10); make.left.equalTo(card).offset(16); make.right.equalTo(card).offset(-16); make.height.mas_equalTo(0.5); }]; + CGFloat _offset_y = 18; + // ── 预计时间行(分割线下方,14pt) ── [self.timeIconView mas_makeConstraints:^(MASConstraintMaker *make) { - make.top.equalTo(self.separator.mas_bottom).offset(15); + make.top.equalTo(self.separator.mas_bottom).offset(12); make.left.equalTo(card).offset(16); make.width.height.mas_equalTo(iconSize); }]; @@ -333,7 +428,7 @@ static inline UIColor *AStationThemeGreen(void) { ///cost [self.costIconView mas_makeConstraints:^(MASConstraintMaker *make) { make.centerY.equalTo(self.timeIconView); - make.left.equalTo(self.timeLabel.mas_right).offset(30); + make.left.equalTo(self.timeLabel.mas_right).offset(40); make.width.height.mas_equalTo(iconSize); }]; @@ -346,7 +441,7 @@ static inline UIColor *AStationThemeGreen(void) { // ── 行驶里程 + 过路费行(时间行下方,12pt) ── [self.distanceIconView mas_makeConstraints:^(MASConstraintMaker *make) { - make.top.equalTo(self.timeIconView.mas_bottom).offset(15); + make.top.equalTo(self.timeIconView.mas_bottom).offset(_offset_y); make.left.equalTo(card).offset(16); make.width.height.mas_equalTo(iconSize); }]; @@ -372,9 +467,49 @@ static inline UIColor *AStationThemeGreen(void) { make.height.mas_equalTo(24); }]; - // ── 开始导航按钮(里程行下方18pt,距卡片底部30pt) ── + // ── 站点联系人行(过路费行下方,14pt) ── + [self.contactPersonIconView mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.distanceIconView.mas_bottom).offset(_offset_y); + make.left.equalTo(card).offset(16); + make.width.height.mas_equalTo(iconSize); + }]; + + [self.contactPersonLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.contactPersonIconView); + make.left.equalTo(self.contactPersonIconView.mas_right).offset(6); + make.height.mas_equalTo(24); + }]; + + // ── 加氢价格(与站点联系人同行,右侧对齐 costIconView) ── + [self.priceIconView mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.contactPersonIconView); + make.left.equalTo(self.costIconView.mas_left); + make.width.height.mas_equalTo(iconSize); + }]; + + [self.priceLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.contactPersonIconView); + make.left.equalTo(self.priceIconView.mas_right).offset(6); + make.right.lessThanOrEqualTo(card).offset(-10); + make.height.mas_equalTo(24); + }]; + + // ── 联系方式行(站点联系人行下方,12pt) ── + [self.phoneIconView mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.contactPersonIconView.mas_bottom).offset(_offset_y); + make.left.equalTo(card).offset(16); + make.width.height.mas_equalTo(iconSize); + }]; + + [self.phoneLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.phoneIconView); + make.left.equalTo(self.phoneIconView.mas_right).offset(6); + make.height.mas_equalTo(24); + }]; + + // ── 开始导航按钮(联系方式行下方18pt,距卡片底部 safeArea) ── [self.startNaviButton mas_makeConstraints:^(MASConstraintMaker *make) { - make.top.equalTo(self.distanceIconView.mas_bottom).offset(50); + make.top.equalTo(self.phoneIconView.mas_bottom).offset(40); make.left.equalTo(card).offset(16); make.right.equalTo(card).offset(-16); make.height.mas_equalTo(48); @@ -386,29 +521,63 @@ static inline UIColor *AStationThemeGreen(void) { - (void)_updateUI { self.stationNameLabel.text = (self.pointModel.name.length > 0) - ? self.pointModel.name : @"--"; + ? self.pointModel.name : @"-"; + + // ── 营业时间 ── + self.businessHoursLabel.text = (self.businessHours.length > 0) + ? [NSString stringWithFormat:@"营业时间:%@", self.businessHours] + : @"营业时间:-"; self.costLabel.text = (self.estimatedCost.length > 0) ? [NSString stringWithFormat:@"预计加氢费用:%@元", self.estimatedCost] - : @"预计加氢费用:--元"; + : @"预计加氢费用:-"; self.addressLabel.text = (self.pointModel.address.length > 0) - ? self.pointModel.address : @"--"; + ? self.pointModel.address : @"-"; // ── 预计时间(始终显示,无值显示"-- 分钟") ── self.timeLabel.text = (self.estimatedTime.length > 0) ? [NSString stringWithFormat:@"预计时间:%@分钟", self.estimatedTime] - : @"预计时间:--分钟"; + : @"预计时间:-"; // ── 行驶里程(始终显示,无值显示"-- 公里") ── self.distanceLabel.text = (self.driveDistance.length > 0) ? [NSString stringWithFormat:@"行驶里程:%@公里", self.driveDistance] - : @"行驶里程:--公里"; + : @"行驶里程:-"; // ── 过路费(始终显示,无值显示"-- 元") ── self.tollLabel.text = (self.tollFee.length > 0) ? [NSString stringWithFormat:@"过路费:%@元", self.tollFee] - : @"过路费:--元"; + : @"过路费:-"; + + // ── 站点联系人(有值显示值,无值显示 -) ── + self.contactPersonLabel.text = (self.contactName.length > 0) + ? [NSString stringWithFormat:@"站联系人:%@", self.contactName] + : @"站联系人:-"; + + // ── 加氢价格(有值显示值,无值显示 -) ── + self.priceLabel.text = (self.hydrogenPrice.length > 0) + ? [NSString stringWithFormat:@"加氢价格:%@/L", self.hydrogenPrice] + : @"加氢价格:-"; + + // ── 联系方式(有值显示值,无值显示 -) ── + self.phoneLabel.text = (self.contactPhone.length > 0) + ? [NSString stringWithFormat:@"联系方式:%@", self.contactPhone] + : @"联系方式:-"; +} + +// 重置 UI 状态 +-(void)resetUI { + self.stationNameLabel.text = @"-"; + self.businessHoursLabel.text = @"营业时间:-"; + self.costLabel.text = @"预计加氢费用:-"; + self.addressLabel.text = @"地址:-"; + self.timeLabel.text = @"预计时间:-"; + self.distanceLabel.text = @"行驶里程:-"; + self.tollLabel.text = @"过路费:-"; + self.contactPersonLabel.text = @"站联系人:-"; + self.priceLabel.text = @"加氢价格:-"; + self.phoneLabel.text = @"联系方式:-"; } #pragma mark - Animation diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ASiteModel.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ASiteModel.h index 942ec0f..8be5fb0 100644 --- a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ASiteModel.h +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ASiteModel.h @@ -59,6 +59,11 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, copy, nullable) NSString *latitude; @property (nonatomic, copy, nullable) NSString *distance; +///新增弹框参数4.13 +@property (nonatomic, copy, nullable) NSString *hydrogenPrice; +@property (nonatomic, copy, nullable) NSString *liaisonName; +@property (nonatomic, copy, nullable) NSString *liaisonPhone; + @end NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.h index e1f7894..6b70d32 100644 --- a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.h +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.h @@ -7,6 +7,8 @@ #import #import +#import "UIColor+ANavMap.h" +#import "UIFont+HP.h" NS_ASSUME_NONNULL_BEGIN @@ -34,6 +36,8 @@ BOOL stringIsEmpty(NSString *str); /// 判断字符串是否非空 BOOL stringIsNotEmpty(NSString *str); ++(NSString *)stringValueFromStr:(NSString *)str; + @end NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.m index 2d34da4..54243db 100644 --- a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.m +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.m @@ -117,6 +117,15 @@ BOOL stringIsNotEmpty (NSString *str) return ! stringIsEmpty(str); } +/// 字符串转数值 ++(NSString *)stringValueFromStr:(NSString *)str { + if (stringIsEmpty(str)) { + return @""; + } + return str; +} + + #pragma mark - 获取图片 +(UIImage *)imageWithName:(NSString *)name { diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/UIColor+ANavMap.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/UIColor+ANavMap.h new file mode 100644 index 0000000..d7b50e5 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/UIColor+ANavMap.h @@ -0,0 +1,20 @@ +// +// UIColor+ANavMap.h +// AMapNavIOSSDK +// +// Created by admin on 2026/4/11. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface UIColor (ANavMap) ++ (UIColor *)hp_colorWithRGBHex:(UInt32)hex; ++ (UIColor *)hp_colorWithRGBHex:(UInt32)hex alpha:(CGFloat)alpha; + +//格式:AHEX ++ (UIColor *)hp_colorWithRGBAHEX:(UInt32)hex; +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/UIColor+ANavMap.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/UIColor+ANavMap.m new file mode 100644 index 0000000..099e436 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/UIColor+ANavMap.m @@ -0,0 +1,53 @@ +// +// UIColor+ANavMap.m +// AMapNavIOSSDK +// +// Created by admin on 2026/4/11. +// + +#import "UIColor+ANavMap.h" + +@implementation UIColor (ANavMap) + + +//格式:HEX ++ (UIColor *)hp_colorWithRGBHex:(UInt32)hex +{ + CGFloat r = (hex >> 16) & 0xFF; + CGFloat g = (hex >> 8) & 0xFF; + CGFloat b = (hex) & 0xFF; + CGFloat a = 1.0f; + return [UIColor colorWithRed:r / 255.0f + green:g / 255.0f + blue:b / 255.0f + alpha:a]; +} + ++ (UIColor *)hp_colorWithRGBHex:(UInt32)hex alpha:(CGFloat)alpha +{ + CGFloat r = (hex >> 16) & 0xFF; + CGFloat g = (hex >> 8) & 0xFF; + CGFloat b = (hex) & 0xFF; + CGFloat a = alpha; + return [UIColor colorWithRed:r / 255.0f + green:g / 255.0f + blue:b / 255.0f + alpha:a]; +} + + +//格式:AHEX ++ (UIColor *)hp_colorWithRGBAHEX:(UInt32)hex +{ + CGFloat r = (hex >> 24) & 0xFF; + CGFloat g = (hex >> 16) & 0xFF; + CGFloat b = (hex >> 8) & 0xFF; + CGFloat a = (hex) & 0xFF; + return [UIColor colorWithRed:r / 255.0f + green:g / 255.0f + blue:b / 255.0f + alpha:a / 255.0f]; +} + + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/UIFont+HP.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/UIFont+HP.h new file mode 100644 index 0000000..50d7c0d --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/UIFont+HP.h @@ -0,0 +1,36 @@ +// +// UIFont+HP.h +// Hippo +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * UIFont 快捷分类 + * 统一使用 PingFang SC 字族,覆盖 Light / Regular / Medium / Semibold 四个字重。 + * + * 使用示例: + * label.font = [UIFont hp_pingFangLight:14]; + * label.font = [UIFont hp_pingFangRegular:16]; + * label.font = [UIFont hp_pingFangMedium:15]; + * label.font = [UIFont hp_pingFangSemibold:18]; + */ +@interface UIFont (HP) + +#pragma mark - PingFang SC Light(细体) ++ (UIFont *)hp_pingFangLight:(CGFloat)size; + +#pragma mark - PingFang SC Regular(常规) ++ (UIFont *)hp_pingFangRegular:(CGFloat)size; + +#pragma mark - PingFang SC Medium(中等) ++ (UIFont *)hp_pingFangMedium:(CGFloat)size; + +#pragma mark - PingFang SC Semibold(半粗) ++ (UIFont *)hp_pingFangSemibold:(CGFloat)size; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/UIFont+HP.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/UIFont+HP.m new file mode 100644 index 0000000..b1458cc --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/UIFont+HP.m @@ -0,0 +1,45 @@ +// +// UIFont+HP.m +// Hippo +// + +#import "UIFont+HP.h" + +// PingFang SC 字族名称常量 +static NSString * const kHPFontPingFangLight = @"PingFangSC-Light"; +static NSString * const kHPFontPingFangRegular = @"PingFangSC-Regular"; +static NSString * const kHPFontPingFangMedium = @"PingFangSC-Medium"; +static NSString * const kHPFontPingFangSemibold = @"PingFangSC-Semibold"; + +@implementation UIFont (HP) + +#pragma mark - PingFang SC Light(细体) + ++ (UIFont *)hp_pingFangLight:(CGFloat)size { + UIFont *font = [UIFont fontWithName:kHPFontPingFangLight size:size]; + // 若系统不支持该字体,回退到系统字体对应字重 + return font ?: [UIFont systemFontOfSize:size weight:UIFontWeightLight]; +} + +#pragma mark - PingFang SC Regular(常规) + ++ (UIFont *)hp_pingFangRegular:(CGFloat)size { + UIFont *font = [UIFont fontWithName:kHPFontPingFangRegular size:size]; + return font ?: [UIFont systemFontOfSize:size weight:UIFontWeightRegular]; +} + +#pragma mark - PingFang SC Medium(中等) + ++ (UIFont *)hp_pingFangMedium:(CGFloat)size { + UIFont *font = [UIFont fontWithName:kHPFontPingFangMedium size:size]; + return font ?: [UIFont systemFontOfSize:size weight:UIFontWeightMedium]; +} + +#pragma mark - PingFang SC Semibold(半粗) + ++ (UIFont *)hp_pingFangSemibold:(CGFloat)size { + UIFont *font = [UIFont fontWithName:kHPFontPingFangSemibold size:size]; + return font ?: [UIFont systemFontOfSize:size weight:UIFontWeightSemibold]; +} + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/ABottomBarView.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/ABottomBarView.m index 047e079..728f4fa 100644 --- a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/ABottomBarView.m +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/ABottomBarView.m @@ -163,6 +163,7 @@ static inline UIColor *ABottomBarThemeGreen(void) { self.calRouteButton = btn; CGFloat off_y = AMP_TabbarHeight; + off_y = 0; #ifdef kAMapSDKDebugFlag off_y = 0; #endif @@ -172,7 +173,7 @@ static inline UIColor *ABottomBarThemeGreen(void) { make.left.equalTo(card).offset(16); make.right.equalTo(card).offset(-16); make.height.mas_equalTo(48); - make.bottom.equalTo(card).offset(-40 - off_y); + make.bottom.equalTo(card).offset(-40); }]; } diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/AStationDetailPopupView.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/AStationDetailPopupView.h new file mode 100644 index 0000000..81d55e7 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/AStationDetailPopupView.h @@ -0,0 +1,70 @@ +// +// AStationDetailPopupView.h +// AMapNavIOSSDK +// +// Created by admin on 2026/3/22. +// + +#import +#import "ANavPointModel.h" +#import "AMapNavSDKHeader.h" + +NS_ASSUME_NONNULL_BEGIN + +@class AStationDetailPopupView; + +@protocol AStationDetailPopupViewDelegate + +@optional +/// 点击"开始导航" +- (void)stationDetailPopupViewDidTapStartNavi:(AStationDetailPopupView *)popup; +/// 点击关闭 +- (void)stationDetailPopupViewDidTapClose:(AStationDetailPopupView *)popup; + +@end + +@interface AStationDetailPopupView : UIView + +@property (nonatomic, strong, nullable) ANavPointModel *pointModel; + +/// 预计加氢费用(元),可由外部传入;若 nil 则隐藏 +@property (nonatomic, copy, nullable) NSString *estimatedCost; + +/// 预计时间,如 @"15分钟";若 nil 则隐藏 +@property (nonatomic, copy, nullable) NSString *estimatedTime; + +/// 行驶里程,如 @"23.5公里";若 nil 则隐藏 +@property (nonatomic, copy, nullable) NSString *driveDistance; + +/// 过路费,如 @"30元";若 nil 则隐藏 +@property (nonatomic, copy, nullable) NSString *tollFee; + +/// 营业时间,如 @"00:00-24:00";有值显示,无值显示 - +@property (nonatomic, copy, nullable) NSString *businessHours; + +/// 站点联系人,如 @"陈凯";有值显示,无值显示 - +@property (nonatomic, copy, nullable) NSString *contactName; + +/// 联系方式,如 @"18019187371";有值显示,无值显示 - +@property (nonatomic, copy, nullable) NSString *contactPhone; + +/// 加氢价格,如 @"32元/L";有值显示,无值显示 - +@property (nonatomic, copy, nullable) NSString *hydrogenPrice; + +@property (nonatomic, weak, nullable) id delegate; + +/// 显示弹框动画 +- (void)showInView:(UIView *)parentView; + +/// 隐藏弹框动画 +- (void)hideWithCompletion:(nullable void(^)(void))completion; + +/// 隐藏弹框动画(无 completion) +- (void)hide; + +/// 重置 UI 状态 +- (void)resetUI; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/AStationDetailPopupView.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/AStationDetailPopupView.m new file mode 100644 index 0000000..8d4ca8c --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/AStationDetailPopupView.m @@ -0,0 +1,655 @@ +// +// AStationDetailPopupView.m +// AMapNavIOSSDK +// +// Created by admin on 2026/3/22. +// + +#import "AStationDetailPopupView.h" +#import "AMapNavCommonUtil.h" +#import + +// 主题绿色(开始导航按钮背景) +static inline UIColor *AStationThemeGreen(void) { + return [UIColor colorWithRed:0x1A/255.0 green:0x7C/255.0 blue:0x43/255.0 alpha:1.0]; +} + +@interface AStationDetailPopupView () + +/// 背景蒙层 +@property (nonatomic, strong) UIControl *maskControl; + +/// 弹框卡片容器 +@property (nonatomic, strong) UIView *cardView; + +/// 站点名称 +@property (nonatomic, strong) UILabel *stationNameLabel; + +/// 预计加氢费用(名称右侧) +@property (nonatomic, strong) UIImageView *costIconView; +@property (nonatomic, strong) UILabel *costLabel; + +/// 地址 +@property (nonatomic, strong) UILabel *addressLabel; + +/// 分割线 +@property (nonatomic, strong) UIView *separator; + +/// 预计时间行 +@property (nonatomic, strong) UIImageView *timeIconView; +@property (nonatomic, strong) UILabel *timeLabel; + +/// 行驶里程 +@property (nonatomic, strong) UIImageView *distanceIconView; +@property (nonatomic, strong) UILabel *distanceLabel; + +/// 过路费 +@property (nonatomic, strong) UIImageView *tollIconView; +@property (nonatomic, strong) UILabel *tollLabel; + +/// 关闭按钮 +@property (nonatomic, strong) UIButton *closeButton; + +/// 开始导航按钮 +@property (nonatomic, strong) UIButton *startNaviButton; + +// ── 营业时间 ── +@property (nonatomic, strong) UILabel *businessHoursLabel; + +// ── 站点联系人 ── +@property (nonatomic, strong) UIImageView *contactPersonIconView; +@property (nonatomic, strong) UILabel *contactPersonLabel; + +// ── 加氢价格 ── +@property (nonatomic, strong) UIImageView *priceIconView; +@property (nonatomic, strong) UILabel *priceLabel; + +// ── 联系方式 ── +@property (nonatomic, strong) UIImageView *phoneIconView; +@property (nonatomic, strong) UILabel *phoneLabel; + +/// 卡片 bottom constraint(动画用) +@property (nonatomic, strong) MASConstraint *cardBottomConstraint; + +@end + +@implementation AStationDetailPopupView + +#pragma mark - Init + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + self.backgroundColor = [UIColor clearColor]; + [self _buildUI]; + [self _setupMasonryConstraints]; + [self _updateUI]; + } + return self; +} + +#pragma mark - Public + +- (void)showInView:(UIView *)parentView { + self.alpha = 0; + self.maskControl.alpha = 0; + [parentView addSubview:self]; + [self mas_remakeConstraints:^(MASConstraintMaker *make) { +// make.edges.equalTo(parentView); + make.top.left.right.equalTo(parentView); + make.bottom.equalTo(parentView).offset((-AMP_TabbarSafeBottomMargin - 35)); + }]; + [self _playShowAnimation]; +} + +- (void)hide { + [self hideWithCompletion:nil]; +} + +- (void)hideWithCompletion:(void(^)(void))completion { + [self _playDismissAnimationWithCompletion:^{ + [self removeFromSuperview]; + if (completion) { + completion(); + } + }]; +} + +#pragma mark - Setter Override(弹出前赋值 或 弹出后动态更新) + +- (void)setPointModel:(ANavPointModel *)pointModel { + _pointModel = pointModel; + [self _updateUI]; +} + +- (void)setEstimatedCost:(NSString *)estimatedCost { + _estimatedCost = [estimatedCost copy]; + [self _updateUI]; +} + +- (void)setEstimatedTime:(NSString *)estimatedTime { + _estimatedTime = [estimatedTime copy]; + [self _updateUI]; +} + +- (void)setDriveDistance:(NSString *)driveDistance { + _driveDistance = [driveDistance copy]; + [self _updateUI]; +} + +- (void)setTollFee:(NSString *)tollFee { + _tollFee = [tollFee copy]; + [self _updateUI]; +} + +- (void)setBusinessHours:(NSString *)businessHours { + _businessHours = [businessHours copy]; + [self _updateUI]; +} + +- (void)setContactName:(NSString *)contactName { + _contactName = [contactName copy]; + [self _updateUI]; +} + +- (void)setContactPhone:(NSString *)contactPhone { + _contactPhone = [contactPhone copy]; + [self _updateUI]; +} + +- (void)setHydrogenPrice:(NSString *)hydrogenPrice { + _hydrogenPrice = [hydrogenPrice copy]; + [self _updateUI]; +} + +#pragma mark - Build UI + +/** + 卡片结构: + ┌──────────────────────────────────── [✕] ┐ + │ 站点名称(加粗) 预计加氢费用:--元 │ ← 同行,间距20pt + │ 地址(灰色小字,多行) │ + │ ──────────────────────────────────────── │ + │ [icon] 预计时间:-- 分钟 │ + │ [icon] 行驶里程:-- 公里 [icon] 过路费:-- 元 │ + │ ╔════════════════════════════════════╗ │ + │ ║ 开始导航 ║ │ + │ ╚════════════════════════════════════╝ │ + │ (距底部30pt) │ + └─────────────────────────────────────────┘ +*/ +- (void)_buildUI { + // ── 蒙层 ── + UIControl *mask = [[UIControl alloc] init]; + mask.backgroundColor = [UIColor colorWithWhite:0 alpha:0.35]; + [mask addTarget:self action:@selector(_onMaskTapped) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:mask]; + self.maskControl = mask; + + // ── 卡片 ── + UIView *card = [[UIView alloc] init]; + card.backgroundColor = [UIColor whiteColor]; + card.layer.cornerRadius = 16; + card.layer.masksToBounds = NO; + card.layer.shadowColor = [UIColor blackColor].CGColor; + card.layer.shadowOpacity = 0.15; + card.layer.shadowRadius = 12; + card.layer.shadowOffset = CGSizeMake(0, -4); + [self addSubview:card]; + self.cardView = card; + + // ── 关闭按钮 ── + UIButton *closeBtn = [UIButton buttonWithType:UIButtonTypeCustom]; + [closeBtn setImage:[AMapNavCommonUtil imageWithName:@"icon_close"] forState:UIControlStateNormal]; + [closeBtn setTitleColor:[UIColor colorWithWhite:0.5 alpha:1] forState:UIControlStateNormal]; + closeBtn.titleLabel.font = [UIFont systemFontOfSize:16]; + [closeBtn addTarget:self action:@selector(_onCloseTapped) forControlEvents:UIControlEventTouchUpInside]; + [card addSubview:closeBtn]; + self.closeButton = closeBtn; + + UIColor *headTextColor = [UIColor hp_colorWithRGBHex:0x1D2129]; + UIFont *headTextFont = [UIFont hp_pingFangMedium:14]; + + // ── 站点名称 ── + UILabel *nameLabel = [[UILabel alloc] init]; + nameLabel.font = [UIFont hp_pingFangMedium:18]; + nameLabel.textColor = headTextColor; + nameLabel.numberOfLines = 2; + nameLabel.minimumScaleFactor = 0.8; + [card addSubview:nameLabel]; + self.stationNameLabel = nameLabel; + + // ── 预计加氢费用(名称右侧,间距20pt) ── + UILabel *costLabel = [[UILabel alloc] init]; + costLabel.font = headTextFont; + costLabel.textColor = headTextColor; + costLabel.numberOfLines = 1; + costLabel.textAlignment = NSTextAlignmentLeft; + [card addSubview:costLabel]; + self.costLabel = costLabel; + + // ── 营业时间(站点名称下方,4pt间距,浅灰色小字) ── + UILabel *bizHoursLabel = [[UILabel alloc] init]; + bizHoursLabel.font = [UIFont hp_pingFangRegular:14]; + bizHoursLabel.textColor = [UIColor hp_colorWithRGBHex:0x1D2129]; + bizHoursLabel.numberOfLines = 1; + [card addSubview:bizHoursLabel]; + self.businessHoursLabel = bizHoursLabel; + + // ── 地址 ── + UILabel *addrLabel = [[UILabel alloc] init]; + addrLabel.font = [UIFont hp_pingFangRegular:14]; + addrLabel.textColor = [UIColor hp_colorWithRGBHex:0x86909C]; + addrLabel.numberOfLines = 2; + [card addSubview:addrLabel]; + self.addressLabel = addrLabel; + + UIImageView *costIcon = [[UIImageView alloc] init]; + costIcon.contentMode = UIViewContentModeScaleAspectFit; + costIcon.image = [AMapNavCommonUtil imageWithName3x:@"ic_fuel"]; + [card addSubview:costIcon]; + self.costIconView = costIcon; + + // ── 分割线 ── + UIView *sep = [[UIView alloc] init]; + sep.backgroundColor = [UIColor colorWithWhite:0.88 alpha:1]; + [card addSubview:sep]; + self.separator = sep; + + // ── 预计时间图标 ── + UIImageView *timeIcon = [[UIImageView alloc] init]; + timeIcon.contentMode = UIViewContentModeScaleAspectFit; + timeIcon.image = [AMapNavCommonUtil imageWithName3x:@"ic_time"]; + [card addSubview:timeIcon]; + self.timeIconView = timeIcon; + + // ── 预计时间文字 ── + UILabel *timeLabel = [[UILabel alloc] init]; + timeLabel.font = headTextFont; + timeLabel.textColor = headTextColor; + [card addSubview:timeLabel]; + self.timeLabel = timeLabel; + + // ── 行驶里程图标 ── + UIImageView *distIcon = [[UIImageView alloc] init]; + distIcon.contentMode = UIViewContentModeScaleAspectFit; + distIcon.image = [AMapNavCommonUtil imageWithName3x:@"ic_mileage"]; + [card addSubview:distIcon]; + self.distanceIconView = distIcon; + + // ── 行驶里程文字 ── + UILabel *distLabel = [[UILabel alloc] init]; + distLabel.font = headTextFont; + distLabel.textColor = headTextColor; + [card addSubview:distLabel]; + self.distanceLabel = distLabel; + + // ── 过路费图标 ── + UIImageView *tollIcon = [[UIImageView alloc] init]; + tollIcon.contentMode = UIViewContentModeScaleAspectFit; + tollIcon.image = [AMapNavCommonUtil imageWithName3x:@"ic_toll"]; + [card addSubview:tollIcon]; + self.tollIconView = tollIcon; + + // ── 过路费文字 ── + UILabel *tollLabel = [[UILabel alloc] init]; + tollLabel.font = headTextFont; + tollLabel.textColor = headTextColor; + [card addSubview:tollLabel]; + self.tollLabel = tollLabel; + + // ── 站点联系人图标 & 文字 ── + UIImageView *personIcon = [[UIImageView alloc] init]; + personIcon.contentMode = UIViewContentModeScaleAspectFit; + personIcon.image = [AMapNavCommonUtil imageWithName3x:@"ic_person"]; + [card addSubview:personIcon]; + self.contactPersonIconView = personIcon; + + UILabel *personLabel = [[UILabel alloc] init]; + personLabel.font = headTextFont; + personLabel.textColor = headTextColor; + [card addSubview:personLabel]; + self.contactPersonLabel = personLabel; + + // ── 加氢价格图标 & 文字 ── + UIImageView *priceIcon = [[UIImageView alloc] init]; + priceIcon.contentMode = UIViewContentModeScaleAspectFit; + priceIcon.image = [AMapNavCommonUtil imageWithName3x:@"ic_price"]; + [card addSubview:priceIcon]; + self.priceIconView = priceIcon; + + UILabel *priceLabel = [[UILabel alloc] init]; + priceLabel.font = headTextFont; + priceLabel.textColor = headTextColor; + [card addSubview:priceLabel]; + self.priceLabel = priceLabel; + + // ── 联系方式图标 & 文字 ── + UIImageView *phoneIcon = [[UIImageView alloc] init]; + phoneIcon.contentMode = UIViewContentModeScaleAspectFit; + phoneIcon.image = [AMapNavCommonUtil imageWithName3x:@"ic_phone"]; + [card addSubview:phoneIcon]; + self.phoneIconView = phoneIcon; + + UILabel *phoneLabel = [[UILabel alloc] init]; + phoneLabel.font = headTextFont; + phoneLabel.textColor = headTextColor; + [card addSubview:phoneLabel]; + self.phoneLabel = phoneLabel; + + // ── 开始导航按钮 ── + UIButton *naviBtn = [UIButton buttonWithType:UIButtonTypeCustom]; + [naviBtn setTitle:@"开始导航" forState:UIControlStateNormal]; + [naviBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + naviBtn.titleLabel.font = [UIFont boldSystemFontOfSize:17]; + naviBtn.backgroundColor = AStationThemeGreen(); + naviBtn.layer.cornerRadius = 24; + [naviBtn addTarget:self action:@selector(_onStartNaviTapped) forControlEvents:UIControlEventTouchUpInside]; + [card addSubview:naviBtn]; + self.startNaviButton = naviBtn; +} + +#pragma mark - Masonry Constraints + +- (void)_setupMasonryConstraints { + UIView *card = self.cardView; + CGFloat iconSize = 16; + + // ── 蒙层:铺满父视图 ── + [self.maskControl mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(self); + }]; + + // ── 卡片:左右各16 ── + [card mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self).offset(0); + make.right.equalTo(self).offset(-0); + make.bottom.equalTo(self).offset(-0); + }]; + + // ── 关闭按钮:右上角 ── + [self.closeButton mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(card).offset(8); + make.right.equalTo(card).offset(-15); + make.width.height.mas_equalTo(40); + }]; + + // ── 站点名称 ── + [self.stationNameLabel setContentHuggingPriority:UILayoutPriorityDefaultLow + forAxis:UILayoutConstraintAxisHorizontal]; + [self.stationNameLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(card).offset(25); + make.left.equalTo(card).offset(16); + make.right.equalTo(self.closeButton.mas_left).offset(-12); + }]; + + // ── 营业时间(站点名称下方,10pt间距) ── + [self.businessHoursLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.stationNameLabel.mas_bottom).offset(10); + make.left.equalTo(card).offset(16); + make.right.equalTo(card).offset(-16); + }]; + + // ── 地址(营业时间下方,10pt间距) ── + [self.addressLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.businessHoursLabel.mas_bottom).offset(10); + make.left.equalTo(card).offset(16); + make.right.equalTo(card).offset(-16); + }]; + self.separator.hidden = YES; + + // ── 分割线(地址下方,10pt间距) ── + [self.separator mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.addressLabel.mas_bottom).offset(10); + make.left.equalTo(card).offset(16); + make.right.equalTo(card).offset(-16); + make.height.mas_equalTo(0.5); + }]; + + CGFloat _offset_y = 18; + + // ── 预计时间行(分割线下方,12pt) ── + [self.timeIconView mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.separator.mas_bottom).offset(12); + make.left.equalTo(card).offset(16); + make.width.height.mas_equalTo(iconSize); + }]; + + [self.timeLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.timeIconView); + make.left.equalTo(self.timeIconView.mas_right).offset(6); + make.height.mas_equalTo(24); + }]; + + /// cost + [self.costIconView mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.timeIconView); + make.left.equalTo(self.timeLabel.mas_right).offset(40); + make.width.height.mas_equalTo(iconSize); + }]; + + [self.costLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.costIconView); + make.left.equalTo(self.costIconView.mas_right).offset(6); + make.right.lessThanOrEqualTo(card).offset(-10); + }]; + + // ── 行驶里程 + 过路费行(时间行下方,12pt) ── + [self.distanceIconView mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.timeIconView.mas_bottom).offset(_offset_y); + make.left.equalTo(card).offset(16); + make.width.height.mas_equalTo(iconSize); + }]; + + [self.distanceLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.distanceIconView); + make.left.equalTo(self.distanceIconView.mas_right).offset(6); + make.width.mas_lessThanOrEqualTo(130); + make.height.mas_equalTo(24); + }]; + + [self.tollIconView mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.distanceIconView); + make.left.equalTo(self.costIconView.mas_left); + make.width.height.mas_equalTo(iconSize); + }]; + + [self.tollLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.distanceIconView); + make.left.equalTo(self.tollIconView.mas_right).offset(6); + make.height.mas_equalTo(24); + }]; + + // ── 站点联系人行(过路费行下方,14pt) ── + [self.contactPersonIconView mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.distanceIconView.mas_bottom).offset(_offset_y); + make.left.equalTo(card).offset(16); + make.width.height.mas_equalTo(iconSize); + }]; + + [self.contactPersonLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.contactPersonIconView); + make.left.equalTo(self.contactPersonIconView.mas_right).offset(6); +// make.height.mas_equalTo(24); + make.width.lessThanOrEqualTo(self).multipliedBy(0.4); + }]; + + // ── 加氢价格(与站点联系人同行,右侧对齐 costIconView) ── + [self.priceIconView mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.contactPersonIconView); + make.left.equalTo(self.costIconView.mas_left); + make.width.height.mas_equalTo(iconSize); + }]; + + [self.priceLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.contactPersonIconView); + make.left.equalTo(self.priceIconView.mas_right).offset(6); + make.right.lessThanOrEqualTo(card).offset(-10); + make.height.mas_equalTo(24); + }]; + + // ── 联系方式行(站点联系人行下方,12pt) ── + [self.phoneIconView mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.contactPersonIconView.mas_bottom).offset(_offset_y); + make.left.equalTo(card).offset(16); + make.width.height.mas_equalTo(iconSize); + }]; + + [self.phoneLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.phoneIconView); + make.left.equalTo(self.phoneIconView.mas_right).offset(6); + make.height.mas_equalTo(24); + }]; + + // ── 开始导航按钮(联系方式行下方18pt,距卡片底部 safeArea) ── + [self.startNaviButton mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.phoneIconView.mas_bottom).offset(40); + make.left.equalTo(card).offset(16); + make.right.equalTo(card).offset(-16); + make.height.mas_equalTo(48); + make.bottom.equalTo(card).offset(-AMP_TabbarSafeBottomMargin); + }]; +} + +#pragma mark - Data Update + +- (void)_updateUI { + self.stationNameLabel.text = (self.pointModel.name.length > 0) + ? self.pointModel.name : @"-"; + + // ── 营业时间 ── + self.businessHoursLabel.text = (self.businessHours.length > 0) + ? [NSString stringWithFormat:@"营业时间:%@", self.businessHours] + : @"营业时间:-"; + + self.costLabel.text = (self.estimatedCost.length > 0) + ? [NSString stringWithFormat:@"预计加氢费用:%@元", self.estimatedCost] + : @"预计加氢费用:-"; + + self.addressLabel.text = (self.pointModel.address.length > 0) + ? self.pointModel.address : @"-"; + + // ── 预计时间(始终显示,无值显示"-- 分钟") ── + self.timeLabel.text = (self.estimatedTime.length > 0) + ? [NSString stringWithFormat:@"预计时间:%@分钟", self.estimatedTime] + : @"预计时间:-"; + + // ── 行驶里程(始终显示,无值显示"-- 公里") ── + self.distanceLabel.text = (self.driveDistance.length > 0) + ? [NSString stringWithFormat:@"行驶里程:%@公里", self.driveDistance] + : @"行驶里程:-"; + + // ── 过路费(始终显示,无值显示"-- 元") ── + self.tollLabel.text = (self.tollFee.length > 0) + ? [NSString stringWithFormat:@"过路费:%@元", self.tollFee] + : @"过路费:-"; + + // ── 站点联系人(有值显示值,无值显示 -) ── + self.contactPersonLabel.text = (self.contactName.length > 0) + ? [NSString stringWithFormat:@"站联系人:%@", self.contactName] + : @"站联系人:-"; + + // ── 加氢价格(有值显示值,无值显示 -) ── + self.priceLabel.text = (self.hydrogenPrice.length > 0) + ? [NSString stringWithFormat:@"加氢价格:%@/L", self.hydrogenPrice] + : @"加氢价格:-"; + + // ── 联系方式(有值显示值,无值显示 -) ── + self.phoneLabel.text = (self.contactPhone.length > 0) + ? [NSString stringWithFormat:@"联系方式:%@", self.contactPhone] + : @"联系方式:-"; +} + +// 重置 UI 状态 +- (void)resetUI { + self.stationNameLabel.text = @"-"; + self.businessHoursLabel.text = @"营业时间:-"; + self.costLabel.text = @"预计加氢费用:-"; + self.addressLabel.text = @"地址:-"; + self.timeLabel.text = @"预计时间:-"; + self.distanceLabel.text = @"行驶里程:-"; + self.tollLabel.text = @"过路费:-"; + self.contactPersonLabel.text = @"站联系人:-"; + self.priceLabel.text = @"加氢价格:-"; + self.phoneLabel.text = @"联系方式:-"; +} + +#pragma mark - Animation + +/** + 弹入动画 +*/ +- (void)_playShowAnimation { + // 初始状态:卡片在屏幕下方(完全隐藏在屏幕外) + [self.cardView mas_remakeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self).offset(0); + make.right.equalTo(self).offset(-0); + make.top.equalTo(self.mas_bottom).offset(0); + }]; + + [self layoutIfNeeded]; + + // 目标状态:卡片正常显示 + [self.cardView mas_remakeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self).offset(0); + make.right.equalTo(self).offset(-0); + make.bottom.equalTo(self).offset(-AMP_TabbarSafeBottomMargin); + }]; + + [UIView animateWithDuration:0.36 + delay:0 + usingSpringWithDamping:0.82 + initialSpringVelocity:0.5 + options:UIViewAnimationOptionCurveEaseOut + animations:^{ + self.alpha = 1; + self.maskControl.alpha = 1; + [self layoutIfNeeded]; + } completion:nil]; +} + +- (void)_playDismissAnimationWithCompletion:(void(^)(void))completion { + [self.cardView mas_remakeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self).offset(0); + make.right.equalTo(self).offset(-0); + make.top.equalTo(self.mas_bottom).offset(20); + }]; + + [UIView animateWithDuration:0.25 + delay:0 + options:UIViewAnimationOptionCurveEaseIn + animations:^{ + self.maskControl.alpha = 0; + [self layoutIfNeeded]; + } completion:^(BOOL finished) { + if (completion) completion(); + }]; +} + +#pragma mark - Actions + +- (void)_onMaskTapped { + if ([self.delegate respondsToSelector:@selector(stationDetailPopupViewDidTapClose:)]) { + [self.delegate stationDetailPopupViewDidTapClose:self]; + } + [self hide]; +} + +- (void)_onCloseTapped { + if ([self.delegate respondsToSelector:@selector(stationDetailPopupViewDidTapClose:)]) { + [self.delegate stationDetailPopupViewDidTapClose:self]; + } + [self hide]; +} + +- (void)_onStartNaviTapped { + __weak typeof(self) weakSelf = self; + [self hideWithCompletion:^{ + __strong typeof(weakSelf) strongSelf = weakSelf; + if ([strongSelf.delegate respondsToSelector:@selector(stationDetailPopupViewDidTapStartNavi:)]) { + [strongSelf.delegate stationDetailPopupViewDidTapStartNavi:strongSelf]; + } + }]; +} + +@end