Compare commits
13 Commits
ef60b8ed62
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| b462312c2e | |||
| ec96a96be2 | |||
|
|
0ba9547992 | ||
| c6e7616be2 | |||
| eae654c47e | |||
| f01875abb9 | |||
| 881da166d1 | |||
| 14b2e6b35c | |||
| 20c39a4a12 | |||
|
|
5c74c7ccc0 | ||
| 23fc0da5c8 | |||
| 7efd933416 | |||
| 2b33dac384 |
65
ln_jq_app/CLAUDE.md
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
Behavioral guidelines to reduce common LLM coding mistakes. Merge with project-specific instructions as needed.
|
||||||
|
|
||||||
|
**Tradeoff:** These guidelines bias toward caution over speed. For trivial tasks, use judgment.
|
||||||
|
|
||||||
|
## 1. Think Before Coding
|
||||||
|
|
||||||
|
**Don't assume. Don't hide confusion. Surface tradeoffs.**
|
||||||
|
|
||||||
|
Before implementing:
|
||||||
|
- State your assumptions explicitly. If uncertain, ask.
|
||||||
|
- If multiple interpretations exist, present them - don't pick silently.
|
||||||
|
- If a simpler approach exists, say so. Push back when warranted.
|
||||||
|
- If something is unclear, stop. Name what's confusing. Ask.
|
||||||
|
|
||||||
|
## 2. Simplicity First
|
||||||
|
|
||||||
|
**Minimum code that solves the problem. Nothing speculative.**
|
||||||
|
|
||||||
|
- No features beyond what was asked.
|
||||||
|
- No abstractions for single-use code.
|
||||||
|
- No "flexibility" or "configurability" that wasn't requested.
|
||||||
|
- No error handling for impossible scenarios.
|
||||||
|
- If you write 200 lines and it could be 50, rewrite it.
|
||||||
|
|
||||||
|
Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
|
||||||
|
|
||||||
|
## 3. Surgical Changes
|
||||||
|
|
||||||
|
**Touch only what you must. Clean up only your own mess.**
|
||||||
|
|
||||||
|
When editing existing code:
|
||||||
|
- Don't "improve" adjacent code, comments, or formatting.
|
||||||
|
- Don't refactor things that aren't broken.
|
||||||
|
- Match existing style, even if you'd do it differently.
|
||||||
|
- If you notice unrelated dead code, mention it - don't delete it.
|
||||||
|
|
||||||
|
When your changes create orphans:
|
||||||
|
- Remove imports/variables/functions that YOUR changes made unused.
|
||||||
|
- Don't remove pre-existing dead code unless asked.
|
||||||
|
|
||||||
|
The test: Every changed line should trace directly to the user's request.
|
||||||
|
|
||||||
|
## 4. Goal-Driven Execution
|
||||||
|
|
||||||
|
**Define success criteria. Loop until verified.**
|
||||||
|
|
||||||
|
Transform tasks into verifiable goals:
|
||||||
|
- "Add validation" → "Write tests for invalid inputs, then make them pass"
|
||||||
|
- "Fix the bug" → "Write a test that reproduces it, then make it pass"
|
||||||
|
- "Refactor X" → "Ensure tests pass before and after"
|
||||||
|
|
||||||
|
For multi-step tasks, state a brief plan:
|
||||||
|
```
|
||||||
|
1. [Step] → verify: [check]
|
||||||
|
2. [Step] → verify: [check]
|
||||||
|
3. [Step] → verify: [check]
|
||||||
|
```
|
||||||
|
|
||||||
|
Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**These guidelines are working if:** fewer unnecessary changes in diffs, fewer rewrites due to overcomplication, and clarifying questions come before implementation rather than after mistakes.
|
||||||
@@ -1,19 +1,49 @@
|
|||||||
# ln_jq_app
|
# 加氢预约app
|
||||||
|
### 主要功能介绍
|
||||||
|
1. 主要给本公司的合作司机提供加氢预约和路线规划的功能 方便日常预约加氢能源量
|
||||||
|
2. 主要给本公司的加氢站点提供预约查看功能,根据预约量准备和实际消耗数量
|
||||||
|
3. 主要核心流程
|
||||||
|
司机登录->无绑定记录需绑定车牌->绑定后即可提交预约(可选择修改预约时间、加氢量、站点)
|
||||||
|
站点登录->操作司机预约工单->确认或者拒绝->新预约单会有广播提醒->站点状态更改会广播提醒司机用户
|
||||||
|
4. 当前版本号:1.2.5+8
|
||||||
|
sdk配置:dart 3.9.0+
|
||||||
|
|
||||||
加氢预约app
|
# 代码仓库说明
|
||||||
|
地址:http://gitea.lnh2e.com/guyongliang/ln-ios.git
|
||||||
|
git tag 可查看所有已推送版本历史,都已做好标签
|
||||||
|
>生产测试分别对应不同的域名,build的时候切换对应分支即可
|
||||||
|
origin/main 生产环境
|
||||||
|
origin/dev 测试环境
|
||||||
|
origin/dev_map 联调高德相关
|
||||||
|
|
||||||
|
# 项目结构介绍
|
||||||
|
1、登录页面分为司机端和站点端,具体可以查看HomeController类中的getHomePage()函数,根据登录渠道的不同进入不同的菜单栏
|
||||||
|
2、全局搜索HttpService.to. 可以看到http相关设置、get post请求等
|
||||||
|
>lib/
|
||||||
|
├── common/ # 公共模块、项目配置
|
||||||
|
│ ├── styles/ # 样式配置
|
||||||
|
│ └── model/ # 数据模型
|
||||||
|
│ └──styles/theme.dart #域名切换功能配置、域名地址、相关key、主题色等
|
||||||
|
├── pages/ # 页面模块
|
||||||
|
│ ├── home/ # 跳转页面,区分跳转逻辑
|
||||||
|
│ ├── b_page/ # 站点端页面
|
||||||
|
│ ├── c_page/ # 司机端页面
|
||||||
|
│ └──base_widgets/NativePageIOS.dart #该类由原生android、ios 实现了高德相关功能
|
||||||
|
│ ├── login/ # 登录页面
|
||||||
|
│ ├── common/ # 公共页面
|
||||||
|
│ └── url_host/ # 域名切换功能页面
|
||||||
|
├── main.dart # 启动类
|
||||||
|
└── storage_service.dart # 缓存类,存储枚举key
|
||||||
|
|
||||||
|
|
||||||
android jks
|
|
||||||
小羚羚
|
|
||||||
Ln123456.
|
|
||||||
|
|
||||||
|
|
||||||
高德key
|
|
||||||
安卓 92495660f7bc990cb475426c47c03b65
|
|
||||||
苹果:3ac08e5e14df9d7a52e98d40e21a0189
|
|
||||||
|
|
||||||
key:2cc1d822e313307fe311c3127a1deeb5
|
|
||||||
秘钥:0529b72df6bf0c577ff2182cb8b1d970
|
|
||||||
|
|
||||||
|
# 基本配置如下
|
||||||
安卓包名:com.lingniu.driver
|
安卓包名:com.lingniu.driver
|
||||||
iOS包名:com.lnkj.ln_jq_app
|
iOS包名:com.lnkj.lnJqApp
|
||||||
|
>android jks,别名密码
|
||||||
|
>小羚羚
|
||||||
|
>Ln123456.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
7
ln_jq_app/android/.claude/settings.local.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(./gradlew assembleDebug --stacktrace)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,8 +37,8 @@ android {
|
|||||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
||||||
minSdk = flutter.minSdkVersion
|
minSdk = flutter.minSdkVersion
|
||||||
targetSdk = flutter.targetSdkVersion
|
targetSdk = flutter.targetSdkVersion
|
||||||
versionCode = 7
|
versionCode = 8
|
||||||
versionName = "1.2.4"
|
versionName = "1.2.5"
|
||||||
}
|
}
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
@@ -72,4 +72,5 @@ flutter {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation("com.amap.api:navi-3dmap-location-search:10.0.700_3dmap10.0.700_loc6.4.5_sea9.7.2")
|
implementation("com.amap.api:navi-3dmap-location-search:10.0.700_3dmap10.0.700_loc6.4.5_sea9.7.2")
|
||||||
implementation("com.squareup.okhttp3:okhttp:4.12.0")
|
implementation("com.squareup.okhttp3:okhttp:4.12.0")
|
||||||
|
implementation("androidx.appcompat:appcompat:1.7.1")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,13 @@
|
|||||||
android:theme="@android:style/Theme.NoTitleBar"
|
android:theme="@android:style/Theme.NoTitleBar"
|
||||||
android:configChanges="orientation|keyboardHidden|screenSize|navigation"
|
android:configChanges="orientation|keyboardHidden|screenSize|navigation"
|
||||||
android:screenOrientation="portrait" />
|
android:screenOrientation="portrait" />
|
||||||
|
<!--搜索目的地 Activity-->
|
||||||
|
<activity
|
||||||
|
android:name="com.lnkj.ln_jq_app.SearchDestinationActivity"
|
||||||
|
android:theme="@android:style/Theme.NoTitleBar"
|
||||||
|
android:configChanges="orientation|keyboardHidden|screenSize|navigation"
|
||||||
|
android:screenOrientation="portrait"
|
||||||
|
android:windowSoftInputMode="adjustResize" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.lnkj.ln_jq_app;
|
package com.lnkj.ln_jq_app;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -37,6 +38,9 @@ public class MainActivity extends FlutterActivity {
|
|||||||
"NativeFirstPage",
|
"NativeFirstPage",
|
||||||
new NativeMapFactory(this)
|
new NativeMapFactory(this)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 设置 Activity 实例到地图
|
||||||
|
NativeMapFactory.setActivity(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -108,6 +112,27 @@ public class MainActivity extends FlutterActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
|
// 处理从搜索目的地页面返回的结果
|
||||||
|
if (requestCode == 1000 && resultCode == RESULT_OK && data != null) {
|
||||||
|
String name = data.getStringExtra(SearchDestinationActivity.EXTRA_RESULT_NAME);
|
||||||
|
String address = data.getStringExtra(SearchDestinationActivity.EXTRA_RESULT_ADDRESS);
|
||||||
|
double lat = data.getDoubleExtra(SearchDestinationActivity.EXTRA_RESULT_LAT, 0);
|
||||||
|
double lon = data.getDoubleExtra(SearchDestinationActivity.EXTRA_RESULT_LON, 0);
|
||||||
|
String district = data.getStringExtra(SearchDestinationActivity.EXTRA_RESULT_DISTRICT);
|
||||||
|
|
||||||
|
if (name != null && lat != 0 && lon != 0) {
|
||||||
|
// 获取地图实例并设置目的地
|
||||||
|
NativeMapView mapView = NativeMapFactory.getMapView();
|
||||||
|
if (mapView != null) {
|
||||||
|
mapView.setDestination(name, address, lat, lon, district);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.lnkj.ln_jq_app;
|
package com.lnkj.ln_jq_app;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import io.flutter.plugin.common.MessageCodec;
|
import io.flutter.plugin.common.MessageCodec;
|
||||||
@@ -34,4 +35,13 @@ public class NativeMapFactory extends PlatformViewFactory {
|
|||||||
public static NativeMapView getMapView() {
|
public static NativeMapView getMapView() {
|
||||||
return mapViewInstance;
|
return mapViewInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 Activity 实例
|
||||||
|
*/
|
||||||
|
public static void setActivity(Activity activity) {
|
||||||
|
if (mapViewInstance != null) {
|
||||||
|
mapViewInstance.setActivity(activity);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,34 +8,23 @@ import android.graphics.BitmapFactory;
|
|||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.PorterDuff;
|
import android.graphics.PorterDuff;
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.graphics.drawable.ColorDrawable;
|
|
||||||
import android.graphics.drawable.GradientDrawable;
|
import android.graphics.drawable.GradientDrawable;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.text.Editable;
|
|
||||||
import android.text.InputType;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.TextWatcher;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.inputmethod.EditorInfo;
|
|
||||||
import android.view.inputmethod.InputMethodManager;
|
|
||||||
import android.widget.ArrayAdapter;
|
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ListView;
|
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
@@ -71,11 +60,7 @@ import com.amap.api.services.geocoder.GeocodeSearch;
|
|||||||
import com.amap.api.services.geocoder.RegeocodeAddress;
|
import com.amap.api.services.geocoder.RegeocodeAddress;
|
||||||
import com.amap.api.services.geocoder.RegeocodeQuery;
|
import com.amap.api.services.geocoder.RegeocodeQuery;
|
||||||
import com.amap.api.services.geocoder.RegeocodeResult;
|
import com.amap.api.services.geocoder.RegeocodeResult;
|
||||||
import com.amap.api.services.help.Inputtips;
|
|
||||||
import com.amap.api.services.help.InputtipsQuery;
|
|
||||||
import com.amap.api.services.help.Tip;
|
|
||||||
import com.amap.api.services.route.BusRouteResult;
|
import com.amap.api.services.route.BusRouteResult;
|
||||||
import com.amap.api.services.route.DrivePath;
|
|
||||||
import com.amap.api.services.route.DriveRouteResult;
|
import com.amap.api.services.route.DriveRouteResult;
|
||||||
import com.amap.api.services.route.RideRouteResult;
|
import com.amap.api.services.route.RideRouteResult;
|
||||||
import com.amap.api.services.route.RouteSearch;
|
import com.amap.api.services.route.RouteSearch;
|
||||||
@@ -91,7 +76,6 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import io.flutter.plugin.platform.PlatformView;
|
import io.flutter.plugin.platform.PlatformView;
|
||||||
import okhttp3.Call;
|
import okhttp3.Call;
|
||||||
import okhttp3.Callback;
|
import okhttp3.Callback;
|
||||||
@@ -104,7 +88,7 @@ import okhttp3.Response;
|
|||||||
/**
|
/**
|
||||||
* 高德地图导航
|
* 高德地图导航
|
||||||
*/
|
*/
|
||||||
public class NativeMapView implements PlatformView, LocationSource, AMapLocationListener, GeocodeSearch.OnGeocodeSearchListener, RouteSearch.OnRouteSearchListener, AMap.OnMarkerClickListener, Inputtips.InputtipsListener {
|
public class NativeMapView implements PlatformView, LocationSource, AMapLocationListener, GeocodeSearch.OnGeocodeSearchListener, RouteSearch.OnRouteSearchListener, AMap.OnMarkerClickListener {
|
||||||
|
|
||||||
private static final String TAG = "NativeMapView";
|
private static final String TAG = "NativeMapView";
|
||||||
private final FrameLayout container;
|
private final FrameLayout container;
|
||||||
@@ -120,17 +104,14 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
private final OkHttpClient httpClient = new OkHttpClient();
|
private final OkHttpClient httpClient = new OkHttpClient();
|
||||||
|
|
||||||
// UI组件
|
// UI组件
|
||||||
private EditText endInput;
|
private TextView endInput;
|
||||||
private LinearLayout searchArea; // 规划路线面板
|
private LinearLayout searchArea; // 规划路线面板
|
||||||
private LinearLayout detailPanel; // 详情面板
|
private LinearLayout detailPanel; // 详情面板
|
||||||
|
|
||||||
private View modeMenu; //模式选择
|
private View modeMenu; //模式选择
|
||||||
private TextView tvStationName, tvStationAddr, planToggleBtn;
|
private TextView tvStationName, tvStationAddr, planToggleBtn, tvBusinessHours;
|
||||||
private ListView suggestionList; // 输入提示列表
|
|
||||||
private ArrayAdapter<String> suggestionAdapter; // 提示列表适配器
|
|
||||||
private List<Tip> currentTipList; // 当前提示列表
|
|
||||||
//时间 费用 里程 路费
|
//时间 费用 里程 路费
|
||||||
private TextView tvDuration, tvDistance, tvTolls, tvTollsFuel;
|
private TextView tvDuration, tvDistance, tvTolls, tvTollsFuel, tvPerson, tvPrice, tvPhone;
|
||||||
|
|
||||||
private LatLng currentLatLng;
|
private LatLng currentLatLng;
|
||||||
private String startName = "我的位置";
|
private String startName = "我的位置";
|
||||||
@@ -140,7 +121,6 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
private LatLng endPoint;
|
private LatLng endPoint;
|
||||||
private boolean isFirstLocation = true;
|
private boolean isFirstLocation = true;
|
||||||
private boolean isUserSelectedDestination = false; // 标识用户是否手动选择了目的地
|
private boolean isUserSelectedDestination = false; // 标识用户是否手动选择了目的地
|
||||||
private boolean isProgrammaticTextChange = false; // 标识是否是程序自动设置文本
|
|
||||||
private final List<Marker> stationMarkers = new ArrayList<>();
|
private final List<Marker> stationMarkers = new ArrayList<>();
|
||||||
|
|
||||||
// 存储token和车牌号
|
// 存储token和车牌号
|
||||||
@@ -154,14 +134,18 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
private TruckRouteData truckRouteData;
|
private TruckRouteData truckRouteData;
|
||||||
//当前定位信息
|
//当前定位信息
|
||||||
private AMapLocation mLoc;
|
private AMapLocation mLoc;
|
||||||
|
private ImageButton mLocBtn;
|
||||||
|
|
||||||
|
|
||||||
public NativeMapView(Context context, int id, Object args) {
|
public NativeMapView(Context context, int id, Object args) {
|
||||||
this.mContext = context;
|
this.mContext = context;
|
||||||
mActivity = getActivityFromContext(context);
|
mActivity = getActivityFromContext(context);
|
||||||
|
|
||||||
MapsInitializer.updatePrivacyShow(mActivity, true, true);
|
// 确保 mActivity 不为 null,如果为 null 则使用 context
|
||||||
MapsInitializer.updatePrivacyAgree(mActivity, true);
|
Activity activity = mActivity != null ? mActivity : (context instanceof Activity ? (Activity) context : null);
|
||||||
|
|
||||||
|
MapsInitializer.updatePrivacyShow(activity, true, true);
|
||||||
|
MapsInitializer.updatePrivacyAgree(activity, true);
|
||||||
|
|
||||||
mapView = new MapView(context);
|
mapView = new MapView(context);
|
||||||
mapView.onCreate(null);
|
mapView.onCreate(null);
|
||||||
@@ -203,7 +187,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
bottomContainer = new LinearLayout(context);
|
bottomContainer = new LinearLayout(context);
|
||||||
bottomContainer.setOrientation(LinearLayout.VERTICAL);
|
bottomContainer.setOrientation(LinearLayout.VERTICAL);
|
||||||
bottomContainer.setGravity(Gravity.BOTTOM);
|
bottomContainer.setGravity(Gravity.BOTTOM);
|
||||||
|
bottomContainer.setBackgroundResource(R.drawable.rounded_top_bg);
|
||||||
// 1. 详情面板 (用于显示加氢站详细信息,初始隐藏)
|
// 1. 详情面板 (用于显示加氢站详细信息,初始隐藏)
|
||||||
detailPanel = createDetailPanel(context);
|
detailPanel = createDetailPanel(context);
|
||||||
detailPanel.setVisibility(View.GONE);
|
detailPanel.setVisibility(View.GONE);
|
||||||
@@ -218,141 +202,89 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
searchArea.setFocusable(true);
|
searchArea.setFocusable(true);
|
||||||
searchArea.setFocusableInTouchMode(true);
|
searchArea.setFocusableInTouchMode(true);
|
||||||
|
|
||||||
endInput = new EditText(context);
|
endInput = new TextView(context);
|
||||||
endInput.setHint("请输入目的地,不输入则自动匹配推荐加氢站");
|
endInput.setHint("请输入目的地,不输入则自动匹配推荐加氢站");
|
||||||
endInput.setTextSize(13);
|
endInput.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_search, 0, 0, 0);
|
||||||
|
endInput.setCompoundDrawablePadding(dp2px(8));
|
||||||
|
endInput.setTextSize(12);
|
||||||
|
endInput.setTextColor(Color.parseColor("#333333"));
|
||||||
endInput.setHintTextColor(Color.GRAY);
|
endInput.setHintTextColor(Color.GRAY);
|
||||||
endInput.setPadding(dp2px(12), dp2px(12), dp2px(12), dp2px(12));
|
endInput.setPadding(dp2px(12), dp2px(12), dp2px(12), dp2px(12));
|
||||||
endInput.setBackground(getRoundedDrawable(Color.parseColor("#F8F8F8"), 8));
|
endInput.setBackground(getRoundedDrawable(Color.parseColor("#F8F8F8"), 8));
|
||||||
endInput.setSingleLine(true);
|
endInput.setSingleLine(true);
|
||||||
endInput.setInputType(InputType.TYPE_CLASS_TEXT); // 明确输入类型
|
endInput.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
endInput.setImeOptions(EditorInfo.IME_ACTION_SEARCH);
|
endInput.setOnClickListener(v -> {
|
||||||
endInput.setFocusable(true);
|
try {
|
||||||
endInput.setFocusableInTouchMode(true);
|
Log.d(TAG, "endInput clicked, mActivity=" + (mActivity != null ? "not null" : "null"));
|
||||||
endInput.setClickable(true);
|
|
||||||
endInput.setCursorVisible(true);
|
|
||||||
|
|
||||||
// 针对 EditText 的特殊处理
|
// 设置回调
|
||||||
endInput.setOnTouchListener((v, event) -> {
|
SearchDestinationActivity.setCallback((name, address, lat, lon, district) -> {
|
||||||
if (event.getAction() == MotionEvent.ACTION_UP) {
|
Log.d(TAG, "Callback received: " + name + ", lat=" + lat + ", lon=" + lon);
|
||||||
v.requestFocus();
|
// 直接设置,不依赖 mActivity.runOnUiThread
|
||||||
v.postDelayed(() -> {
|
setDestination(name, address, lat, lon, district);
|
||||||
InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
||||||
if (imm != null) {
|
|
||||||
// 使用 SHOW_FORCED 或确保结果成功
|
|
||||||
imm.showSoftInput(v, InputMethodManager.SHOW_FORCED);
|
|
||||||
}
|
|
||||||
}, 100);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 处理搜索键按下
|
// 跳转到搜索目的地页面 - 使用更安全的方式
|
||||||
endInput.setOnEditorActionListener((v, actionId, event) -> {
|
Intent intent = new Intent(mContext, SearchDestinationActivity.class);
|
||||||
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
suggestionList.setVisibility(View.GONE);
|
|
||||||
// 可以在这里直接触发路线规划,但保持原来的按钮点击逻辑
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 初始化提示列表
|
Log.d(TAG, "Starting SearchDestinationActivity with intent");
|
||||||
currentTipList = new ArrayList<>();
|
mContext.startActivity(intent);
|
||||||
suggestionList = new ListView(context);
|
|
||||||
suggestionList.setBackgroundColor(Color.WHITE);
|
|
||||||
suggestionList.setDividerHeight(1);
|
|
||||||
suggestionList.setDivider(new ColorDrawable(Color.LTGRAY));
|
|
||||||
suggestionList.setPadding(dp2px(5), dp2px(5), dp2px(5), dp2px(5));
|
|
||||||
suggestionAdapter = new ArrayAdapter<String>(context, android.R.layout.simple_list_item_1, new ArrayList<>()) {
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
|
|
||||||
// 获取默认的 View
|
|
||||||
View view = super.getView(position, convertView, parent);
|
|
||||||
TextView text = view.findViewById(android.R.id.text1);
|
|
||||||
text.setTextColor(Color.parseColor("#333333"));
|
|
||||||
text.setTextSize(14);
|
|
||||||
view.setBackgroundColor(Color.TRANSPARENT);
|
|
||||||
|
|
||||||
return view;
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Failed to start SearchDestinationActivity", e);
|
||||||
|
e.printStackTrace();
|
||||||
|
// 显示错误提示
|
||||||
|
try {
|
||||||
|
if (mContext != null) {
|
||||||
|
Toast.makeText(mContext, "无法打开搜索页面: " + e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
};
|
} catch (Exception toastException) {
|
||||||
suggestionList.setAdapter(suggestionAdapter);
|
Log.e(TAG, "Failed to show toast", toastException);
|
||||||
suggestionList.setVisibility(View.GONE);
|
|
||||||
suggestionList.setOnItemClickListener((parent, view, position, id) -> {
|
|
||||||
Tip tip = currentTipList.get(position);
|
|
||||||
if (tip.getPoint() != null) {
|
|
||||||
endPoint = new LatLng(tip.getPoint().getLatitude(), tip.getPoint().getLongitude());
|
|
||||||
String name = tip.getName();
|
|
||||||
String district = tip.getDistrict();
|
|
||||||
endName = name;
|
|
||||||
endAddress = tip.getAddress();
|
|
||||||
isGetInputtips = true;
|
|
||||||
isUserSelectedDestination = true; // 标识用户手动选择了目的地
|
|
||||||
isProgrammaticTextChange = true; // 标识是程序自动设置文本
|
|
||||||
endInput.setText(district != null && !district.isEmpty() ? name + " " + district : name);
|
|
||||||
isProgrammaticTextChange = false; // 恢复标志
|
|
||||||
suggestionList.setVisibility(View.GONE);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
endInput.addTextChangedListener(new TextWatcher() {
|
|
||||||
@Override
|
|
||||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
|
||||||
// 如果是程序自动设置文本,不触发搜索
|
|
||||||
if (isProgrammaticTextChange) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s.length() > 1) {
|
|
||||||
// 使用当前位置的城市进行搜索
|
|
||||||
String city = currentLatLng != null ? "" : "";
|
|
||||||
InputtipsQuery query = new InputtipsQuery(s.toString(), "");
|
|
||||||
query.setCityLimit(false);
|
|
||||||
Inputtips inputtips = new Inputtips(mContext, query);
|
|
||||||
inputtips.setInputtipsListener(NativeMapView.this);
|
|
||||||
inputtips.requestInputtipsAsyn();
|
|
||||||
} else {
|
|
||||||
suggestionList.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterTextChanged(Editable s) {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
endInput.setOnFocusChangeListener((v, hasFocus) -> {
|
|
||||||
if (!hasFocus) {
|
|
||||||
suggestionList.setVisibility(View.GONE);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
searchArea.addView(endInput);
|
searchArea.addView(endInput);
|
||||||
searchArea.addView(suggestionList);
|
|
||||||
|
|
||||||
View vSpace = new View(context);
|
View vSpace = new View(context);
|
||||||
searchArea.addView(vSpace, new LinearLayout.LayoutParams(1, dp2px(12)));
|
searchArea.addView(vSpace, new LinearLayout.LayoutParams(1, dp2px(12)));
|
||||||
|
|
||||||
Button planBtn = new Button(context);
|
// 创建自定义按钮布局
|
||||||
planBtn.setText("规划路线");
|
LinearLayout planBtnContainer = new LinearLayout(context);
|
||||||
planBtn.setTextColor(Color.WHITE);
|
planBtnContainer.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
planBtn.setTypeface(Typeface.DEFAULT_BOLD);
|
planBtnContainer.setGravity(Gravity.CENTER);
|
||||||
planBtn.setBackground(getRoundedDrawable(Color.parseColor("#017143"), 99));
|
planBtnContainer.setBackground(getRoundedDrawable(Color.parseColor("#017143"), 99));
|
||||||
planBtn.setOnClickListener(v -> calculateRouteBeforeNavi());
|
planBtnContainer.setPadding(0, 0, 0, 0);
|
||||||
searchArea.addView(planBtn, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp2px(48)));
|
|
||||||
|
// 添加图标
|
||||||
|
ImageView pathIcon = new ImageView(context);
|
||||||
|
pathIcon.setImageResource(R.drawable.ic_path);
|
||||||
|
pathIcon.setColorFilter(Color.WHITE);
|
||||||
|
LinearLayout.LayoutParams iconParams = new LinearLayout.LayoutParams(dp2px(20), dp2px(20));
|
||||||
|
iconParams.rightMargin = dp2px(6); // 图标和文字之间的间距
|
||||||
|
planBtnContainer.addView(pathIcon, iconParams);
|
||||||
|
|
||||||
|
// 添加文字
|
||||||
|
TextView planText = new TextView(context);
|
||||||
|
planText.setText("规划路线");
|
||||||
|
planText.setTextColor(Color.WHITE);
|
||||||
|
planText.setTextSize(14);
|
||||||
|
planText.setTypeface(Typeface.DEFAULT_BOLD);
|
||||||
|
planText.setGravity(Gravity.CENTER);
|
||||||
|
planBtnContainer.addView(planText);
|
||||||
|
|
||||||
|
// 设置点击事件
|
||||||
|
planBtnContainer.setOnClickListener(v -> calculateRouteBeforeNavi());
|
||||||
|
searchArea.addView(planBtnContainer, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp2px(40)));
|
||||||
|
|
||||||
bottomContainer.addView(searchArea);
|
bottomContainer.addView(searchArea);
|
||||||
|
|
||||||
// 设置统一的底部间距
|
// 设置统一的底部间距
|
||||||
FrameLayout.LayoutParams bottomParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
FrameLayout.LayoutParams bottomParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
bottomParams.gravity = Gravity.BOTTOM;
|
bottomParams.gravity = Gravity.BOTTOM;
|
||||||
bottomParams.setMargins(dp2px(12), 0, dp2px(12), dp2px(65));
|
|
||||||
container.addView(bottomContainer, bottomParams);
|
container.addView(bottomContainer, bottomParams);
|
||||||
|
container.setPadding(0, 0, 0, dp2px(65));
|
||||||
|
|
||||||
|
|
||||||
// --- 模式选择菜单 ---
|
// --- 模式选择菜单 ---
|
||||||
@@ -361,9 +293,10 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
// 布局参数:位于规划按钮上方
|
// 布局参数:位于规划按钮上方
|
||||||
FrameLayout.LayoutParams menuParams = new FrameLayout.LayoutParams(dp2px(130), ViewGroup.LayoutParams.WRAP_CONTENT);
|
FrameLayout.LayoutParams menuParams = new FrameLayout.LayoutParams(dp2px(130), ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
menuParams.gravity = Gravity.BOTTOM | Gravity.END;
|
menuParams.gravity = Gravity.BOTTOM | Gravity.END;
|
||||||
menuParams.setMargins(0, 0, dp2px(15), dp2px(330)); // 高度根据按钮位置调整
|
menuParams.setMargins(0, 0, dp2px(15), dp2px(230)); // 高度根据按钮位置调整
|
||||||
container.addView(modeMenu, menuParams);
|
container.addView(modeMenu, menuParams);
|
||||||
|
|
||||||
|
|
||||||
// 加氢规划圆形按钮
|
// 加氢规划圆形按钮
|
||||||
planToggleBtn = new TextView(context);
|
planToggleBtn = new TextView(context);
|
||||||
planToggleBtn.setText("加氢\n规划");
|
planToggleBtn.setText("加氢\n规划");
|
||||||
@@ -384,71 +317,37 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
int layoutSize = dp2px(44);
|
int layoutSize = dp2px(44);
|
||||||
FrameLayout.LayoutParams toggleParams = new FrameLayout.LayoutParams(layoutSize, layoutSize);
|
FrameLayout.LayoutParams toggleParams = new FrameLayout.LayoutParams(layoutSize, layoutSize);
|
||||||
toggleParams.gravity = Gravity.BOTTOM | Gravity.END;
|
toggleParams.gravity = Gravity.BOTTOM | Gravity.END;
|
||||||
toggleParams.setMargins(0, 0, dp2px(12), dp2px(340)); // 位于定位按钮上方
|
toggleParams.setMargins(0, 0, dp2px(12), dp2px(210)); // 位于定位按钮上方
|
||||||
container.addView(planToggleBtn, toggleParams);
|
container.addView(planToggleBtn, toggleParams);
|
||||||
|
|
||||||
// --- 右下角定位按钮 ---
|
// --- 右下角定位按钮 ---
|
||||||
ImageButton locBtn = new ImageButton(context);
|
mLocBtn = new ImageButton(context);
|
||||||
locBtn.setImageResource(R.drawable.ic_location);
|
mLocBtn.setImageResource(R.drawable.ic_location);
|
||||||
// 设置自定义的白色圆形背景
|
// 设置自定义的白色圆形背景
|
||||||
locBtn.setBackgroundColor(Color.TRANSPARENT);
|
mLocBtn.setBackgroundColor(Color.TRANSPARENT);
|
||||||
// 设置投影(仅在 API 21+ 有效,能产生干净的阴影而非黑块)
|
// 设置投影(仅在 API 21+ 有效,能产生干净的阴影而非黑块)
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
locBtn.setElevation(dp2px(4));
|
mLocBtn.setElevation(dp2px(4));
|
||||||
}
|
}
|
||||||
locBtn.setScaleType(ImageView.ScaleType.FIT_CENTER);
|
mLocBtn.setScaleType(ImageView.ScaleType.FIT_CENTER);
|
||||||
int padding = dp2px(2);
|
int padding = dp2px(2);
|
||||||
locBtn.setPadding(padding, padding, padding, padding);
|
mLocBtn.setPadding(padding, padding, padding, padding);
|
||||||
locBtn.setOnClickListener(v -> {
|
mLocBtn.setOnClickListener(v -> {
|
||||||
if (currentLatLng != null)
|
if (currentLatLng != null)
|
||||||
aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 15f));
|
aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 15f));
|
||||||
});
|
});
|
||||||
FrameLayout.LayoutParams locParams = new FrameLayout.LayoutParams(layoutSize, layoutSize);
|
FrameLayout.LayoutParams locParams = new FrameLayout.LayoutParams(layoutSize, layoutSize);
|
||||||
locParams.setMargins(0, 0, dp2px(15), dp2px(285)); // 调高一点,避开底部的面板
|
locParams.setMargins(0, 0, dp2px(15), dp2px(150)); // 调高一点,避开底部的面板
|
||||||
locParams.gravity = Gravity.BOTTOM | Gravity.END;
|
locParams.gravity = Gravity.BOTTOM | Gravity.END;
|
||||||
container.addView(locBtn, locParams);
|
container.addView(mLocBtn, locParams);
|
||||||
|
|
||||||
//最后调用监听函数
|
|
||||||
addKeyboardListener();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addKeyboardListener() {
|
|
||||||
container.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
|
|
||||||
Rect r = new Rect();
|
|
||||||
// 获取当前窗口可视区域
|
|
||||||
container.getWindowVisibleDisplayFrame(r);
|
|
||||||
|
|
||||||
// screenHeight - 可视区域高度 = 键盘高度
|
|
||||||
int screenHeight = container.getRootView().getHeight();
|
|
||||||
int keypadHeight = screenHeight - r.bottom;
|
|
||||||
|
|
||||||
// 如果键盘高度大于屏幕的 15%,说明键盘弹出了
|
|
||||||
if (keypadHeight > screenHeight * 0.15) {
|
|
||||||
// 键盘弹出:增加底部 Margin
|
|
||||||
updateBottomMargin(keypadHeight);
|
|
||||||
} else {
|
|
||||||
// 键盘收起:恢复原有 Margin (你代码中设置的是 dp2px(65))
|
|
||||||
updateBottomMargin(dp2px(65));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateBottomMargin(int bottomPx) {
|
|
||||||
if (bottomContainer != null) {
|
|
||||||
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) bottomContainer.getLayoutParams();
|
|
||||||
if (params != null) {
|
|
||||||
// 动态设置底部间距
|
|
||||||
params.setMargins(dp2px(12), 0, dp2px(12), bottomPx);
|
|
||||||
bottomContainer.setLayoutParams(params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private LinearLayout createDetailPanel(Context context) {
|
private LinearLayout createDetailPanel(Context context) {
|
||||||
LinearLayout panel = new LinearLayout(context);
|
LinearLayout panel = new LinearLayout(context);
|
||||||
panel.setOrientation(LinearLayout.VERTICAL);
|
panel.setOrientation(LinearLayout.VERTICAL);
|
||||||
panel.setBackground(getRoundedDrawable(Color.WHITE, 16));
|
int padding = dp2px(15);
|
||||||
panel.setPadding(dp2px(20), dp2px(20), dp2px(20), dp2px(20));
|
panel.setPadding(padding, padding, padding, padding);
|
||||||
|
|
||||||
// --- (包含标题和关闭按钮) ---
|
// --- (包含标题和关闭按钮) ---
|
||||||
LinearLayout titleLayout = new LinearLayout(context);
|
LinearLayout titleLayout = new LinearLayout(context);
|
||||||
@@ -469,10 +368,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
ivClose.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
|
ivClose.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
|
||||||
ivClose.setPadding(dp2px(5), dp2px(5), dp2px(5), dp2px(5));
|
ivClose.setPadding(dp2px(5), dp2px(5), dp2px(5), dp2px(5));
|
||||||
ivClose.setOnClickListener(v -> {
|
ivClose.setOnClickListener(v -> {
|
||||||
if (detailPanel != null)
|
resetView();
|
||||||
detailPanel.setVisibility(View.GONE);
|
|
||||||
searchArea.setVisibility(View.VISIBLE);
|
|
||||||
planToggleBtn.setVisibility(View.VISIBLE);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
LinearLayout.LayoutParams closeParams = new LinearLayout.LayoutParams(dp2px(28), dp2px(28));
|
LinearLayout.LayoutParams closeParams = new LinearLayout.LayoutParams(dp2px(28), dp2px(28));
|
||||||
@@ -480,6 +376,13 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
|
|
||||||
panel.addView(titleLayout);
|
panel.addView(titleLayout);
|
||||||
|
|
||||||
|
//营业时间和地址
|
||||||
|
tvBusinessHours = new TextView(context);
|
||||||
|
tvBusinessHours.setTextSize(13);
|
||||||
|
tvBusinessHours.setPadding(0, dp2px(4), 0, 0);
|
||||||
|
tvBusinessHours.setTextColor(Color.GRAY);
|
||||||
|
panel.addView(tvBusinessHours);
|
||||||
|
|
||||||
tvStationAddr = new TextView(context);
|
tvStationAddr = new TextView(context);
|
||||||
tvStationAddr.setTextSize(13);
|
tvStationAddr.setTextSize(13);
|
||||||
tvStationAddr.setPadding(0, dp2px(4), 0, 0);
|
tvStationAddr.setPadding(0, dp2px(4), 0, 0);
|
||||||
@@ -496,8 +399,8 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
row1.setOrientation(LinearLayout.HORIZONTAL);
|
row1.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
row1.setGravity(Gravity.CENTER_VERTICAL);
|
row1.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
row1.setPadding(0, dp2px(8), 0, 0); // 增加行间距
|
row1.setPadding(0, dp2px(8), 0, 0); // 增加行间距
|
||||||
tvDuration = createInfoItem(row1, R.drawable.ic_time, "预计时间:", "", 1.0f);
|
tvDuration = createInfoItem(row1, R.drawable.ic_time, "预计时间:", "-", 1.0f);
|
||||||
tvTollsFuel = createInfoItem(row1, R.drawable.ic_fuel, "加氢费用:", "", 1.0f);
|
tvTollsFuel = createInfoItem(row1, R.drawable.ic_fuel, "加氢费用:", "-", 1.0f);
|
||||||
routeInfoLayout.addView(row1);
|
routeInfoLayout.addView(row1);
|
||||||
|
|
||||||
// 第二行:里程 + 过路费
|
// 第二行:里程 + 过路费
|
||||||
@@ -507,17 +410,34 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
row2.setPadding(0, dp2px(10), 0, 0); // 增加行间距
|
row2.setPadding(0, dp2px(10), 0, 0); // 增加行间距
|
||||||
|
|
||||||
// 里程
|
// 里程
|
||||||
tvDistance = createInfoItem(row2, R.drawable.ic_mileage, "行驶里程:", "", 1.0f);
|
tvDistance = createInfoItem(row2, R.drawable.ic_mileage, "行驶里程:", "-", 1.0f);
|
||||||
// 过路费
|
// 过路费
|
||||||
tvTolls = createInfoItem(row2, R.drawable.ic_toll, "过路费:", "", 1.0f);
|
tvTolls = createInfoItem(row2, R.drawable.ic_toll, "过路费:", "-", 1.0f);
|
||||||
|
|
||||||
routeInfoLayout.addView(row2);
|
routeInfoLayout.addView(row2);
|
||||||
|
|
||||||
|
//第三行
|
||||||
|
LinearLayout row3 = new LinearLayout(context);
|
||||||
|
row3.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
row3.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
|
row3.setPadding(0, dp2px(8), 0, 0); // 增加行间距
|
||||||
|
tvPerson = createInfoItem(row3, R.drawable.ic_person, "站联系人:", "-", 1.0f);
|
||||||
|
tvPrice = createInfoItem(row3, R.drawable.ic_price, "加氢价格:", "-", 1.0f);
|
||||||
|
routeInfoLayout.addView(row3);
|
||||||
|
|
||||||
|
LinearLayout row4 = new LinearLayout(context);
|
||||||
|
row4.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
row4.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
|
row4.setPadding(0, dp2px(8), 0, 0); // 增加行间距
|
||||||
|
tvPhone = createInfoItem(row4, R.drawable.ic_phone, "联系方式:", "-", 1.0f);
|
||||||
|
routeInfoLayout.addView(row4);
|
||||||
|
|
||||||
|
|
||||||
panel.addView(routeInfoLayout);
|
panel.addView(routeInfoLayout);
|
||||||
|
|
||||||
Button startNaviBtn = new Button(context);
|
Button startNaviBtn = new Button(context);
|
||||||
startNaviBtn.setText("开始导航");
|
startNaviBtn.setText("开始导航");
|
||||||
startNaviBtn.setTextColor(Color.WHITE);
|
startNaviBtn.setTextColor(Color.WHITE);
|
||||||
startNaviBtn.setBackground(getRoundedDrawable(Color.parseColor("#017143"), 10));
|
startNaviBtn.setBackground(getRoundedDrawable(Color.parseColor("#017143"), 99));
|
||||||
startNaviBtn.setOnClickListener(v -> startRouteSearch());
|
startNaviBtn.setOnClickListener(v -> startRouteSearch());
|
||||||
|
|
||||||
LinearLayout.LayoutParams btnParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp2px(48));
|
LinearLayout.LayoutParams btnParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp2px(48));
|
||||||
@@ -527,6 +447,15 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
return panel;
|
return panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void resetView() {
|
||||||
|
if (detailPanel != null)
|
||||||
|
detailPanel.setVisibility(View.GONE);
|
||||||
|
searchArea.setVisibility(View.VISIBLE);
|
||||||
|
planToggleBtn.setVisibility(View.VISIBLE);
|
||||||
|
mLocBtn.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isGetInputtips = false;
|
private boolean isGetInputtips = false;
|
||||||
|
|
||||||
private void calculateRouteBeforeNavi() {
|
private void calculateRouteBeforeNavi() {
|
||||||
@@ -543,107 +472,113 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
//如果是输入地址提示内容
|
//如果是输入地址提示内容
|
||||||
|
|
||||||
if (isGetInputtips) {
|
if (isGetInputtips) {
|
||||||
// 开始规划前隐藏输入框面板
|
truckRouteData = null;
|
||||||
searchArea.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
RouteSearch.FromAndTo fromAndTo = new RouteSearch.FromAndTo(new LatLonPoint(startPoint.latitude, startPoint.longitude), new LatLonPoint(endPoint.latitude, endPoint.longitude));
|
RouteSearch.FromAndTo fromAndTo = new RouteSearch.FromAndTo(new LatLonPoint(startPoint.latitude, startPoint.longitude), new LatLonPoint(endPoint.latitude, endPoint.longitude));
|
||||||
RouteSearch.DriveRouteQuery query = new RouteSearch.DriveRouteQuery(fromAndTo, RouteSearch.DRIVING_SINGLE_DEFAULT, null, null, "");
|
RouteSearch.DriveRouteQuery query = new RouteSearch.DriveRouteQuery(fromAndTo, RouteSearch.DRIVING_SINGLE_DEFAULT, null, null, "");
|
||||||
routeSearch.calculateDriveRouteAsyn(query);
|
routeSearch.calculateDriveRouteAsyn(query);
|
||||||
|
|
||||||
|
|
||||||
|
// 开始规划前隐藏输入框面板
|
||||||
|
searchArea.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
fetchTruckRouteAlgorithm(mLoc);
|
fetchTruckRouteAlgorithm(mLoc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onGetInputtips(List<Tip> tipList, int rCode) {
|
|
||||||
if (rCode == 1000 && tipList != null && !tipList.isEmpty()) {
|
|
||||||
currentTipList.clear();
|
|
||||||
currentTipList.addAll(tipList);
|
|
||||||
|
|
||||||
List<String> suggestionNames = new ArrayList<>();
|
|
||||||
for (Tip tip : tipList) {
|
|
||||||
String name = tip.getName();
|
|
||||||
String district = tip.getDistrict();
|
|
||||||
// 在提示中显示名称和区域
|
|
||||||
String displayText = district != null && !district.isEmpty() ? name + " " + district : name;
|
|
||||||
suggestionNames.add(displayText);
|
|
||||||
}
|
|
||||||
|
|
||||||
suggestionAdapter.clear();
|
|
||||||
suggestionAdapter.addAll(suggestionNames);
|
|
||||||
suggestionAdapter.notifyDataSetChanged();
|
|
||||||
|
|
||||||
// 显示提示列表
|
|
||||||
new Handler(Looper.getMainLooper()).post(() -> {
|
|
||||||
if (suggestionNames.size() > 0) {
|
|
||||||
suggestionList.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
suggestionList.setBackgroundColor(Color.WHITE);
|
|
||||||
|
|
||||||
// 限制显示的高度
|
|
||||||
int height = Math.min(suggestionNames.size() * dp2px(45), dp2px(200));
|
|
||||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
||||||
height
|
|
||||||
);
|
|
||||||
suggestionList.setLayoutParams(params);
|
|
||||||
} else {
|
|
||||||
suggestionList.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// 请求失败或无结果,隐藏提示列表
|
|
||||||
new Handler(Looper.getMainLooper()).post(() -> suggestionList.setVisibility(View.GONE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDriveRouteSearched(DriveRouteResult result, int rCode) {
|
public void onDriveRouteSearched(DriveRouteResult result, int rCode) {
|
||||||
|
if (mActivity == null) {
|
||||||
|
Log.e(TAG, "mActivity is null in onDriveRouteSearched");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mActivity.runOnUiThread(new Runnable() {
|
mActivity.runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
||||||
|
String hydrogenCost = "-"; // 默认显示横线
|
||||||
|
String hydrogenPrice = "-"; // 默认显示横线
|
||||||
|
String liaisonName = "-";
|
||||||
|
String liaisonPhone = "-";
|
||||||
|
String startBusiness = "-";
|
||||||
|
String endBusiness = "-";
|
||||||
|
double distanceKm = 0;
|
||||||
|
String distanceKmStr = "-";
|
||||||
|
long durationMin = 0;
|
||||||
|
String durationMinStr = "-";
|
||||||
|
String tolls = "-";
|
||||||
|
|
||||||
if (rCode == AMapException.CODE_AMAP_SUCCESS && result != null && !result.getPaths().isEmpty()) {
|
if (rCode == AMapException.CODE_AMAP_SUCCESS && result != null && !result.getPaths().isEmpty()) {
|
||||||
DrivePath path = result.getPaths().get(0);
|
|
||||||
|
|
||||||
// 规划成功,显示详情面板,隐藏模式选择
|
// 规划成功,显示详情面板,隐藏模式选择
|
||||||
if (detailPanel != null)
|
if (detailPanel != null)
|
||||||
detailPanel.setVisibility(View.VISIBLE);
|
detailPanel.setVisibility(View.VISIBLE);
|
||||||
if (planToggleBtn != null)
|
if (planToggleBtn != null)
|
||||||
planToggleBtn.setVisibility(View.GONE);
|
planToggleBtn.setVisibility(View.GONE);
|
||||||
|
if (mLocBtn != null)
|
||||||
|
mLocBtn.setVisibility(View.GONE);
|
||||||
if (modeMenu != null)
|
if (modeMenu != null)
|
||||||
modeMenu.setVisibility(View.GONE);
|
modeMenu.setVisibility(View.GONE);
|
||||||
|
|
||||||
tvStationName.setText(endName);
|
tvStationName.setText(endName);
|
||||||
tvStationAddr.setText(endAddress);
|
tvStationAddr.setText(endAddress);
|
||||||
|
|
||||||
double distanceKm = truckRouteData.pathDto.distance / 1000f;
|
|
||||||
long durationMin = truckRouteData.pathDto.duration / 60;
|
|
||||||
String tolls = truckRouteData.pathDto.tolls;
|
|
||||||
|
|
||||||
String hydrogenCost = "--"; // 默认显示横线
|
if (truckRouteData != null) {
|
||||||
try {
|
PathDto pathDto = truckRouteData.pathDto;
|
||||||
|
if (pathDto != null) {
|
||||||
|
distanceKm = pathDto.distance / 1000f;
|
||||||
|
durationMin = pathDto.duration / 60;
|
||||||
|
tolls = pathDto.tolls + "元";
|
||||||
|
|
||||||
|
distanceKmStr = String.format("%.1f", distanceKm) + "公里";
|
||||||
|
durationMinStr = durationMin + "分钟";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 增加多级非空校验,防止点击搜索条目时崩溃
|
// 增加多级非空校验,防止点击搜索条目时崩溃
|
||||||
if (truckRouteData != null &&
|
if (truckRouteData != null &&
|
||||||
truckRouteData.algorithmPath != null &&
|
truckRouteData.algorithmPath != null &&
|
||||||
truckRouteData.algorithmPath.hydrogenCost != null &&
|
truckRouteData.algorithmPath.hydrogenCost != null &&
|
||||||
!truckRouteData.algorithmPath.hydrogenCost.isEmpty()) {
|
!truckRouteData.algorithmPath.hydrogenCost.isEmpty()) {
|
||||||
hydrogenCost = truckRouteData.algorithmPath.hydrogenCost;
|
hydrogenCost = truckRouteData.algorithmPath.hydrogenCost;
|
||||||
|
hydrogenCost = (isGetInputtips ? "--" : hydrogenCost) + "元";
|
||||||
}
|
}
|
||||||
|
|
||||||
tvDuration.setText("预计时间:" + durationMin + "分钟");
|
tvDuration.setText("预计时间:" + durationMinStr);
|
||||||
tvDistance.setText("行驶里程:" + String.format("%.1f", distanceKm) + "公里");
|
tvDistance.setText("行驶里程:" + distanceKmStr);
|
||||||
tvTolls.setText("过路费:" + tolls + "元");
|
tvTolls.setText("过路费:" + tolls);
|
||||||
tvTollsFuel.setText("加氢费用:" + (isGetInputtips ? "--" : hydrogenCost) + "元");
|
tvTollsFuel.setText("预计加氢费用:" + hydrogenCost);
|
||||||
|
|
||||||
|
|
||||||
|
if (truckRouteData != null) {
|
||||||
|
DestinationSite destinationSite = truckRouteData.destinationSite;
|
||||||
|
if (destinationSite != null) {
|
||||||
|
startBusiness = destinationSite.startBusiness;
|
||||||
|
endBusiness = destinationSite.endBusiness;
|
||||||
|
hydrogenPrice = destinationSite.hydrogenPrice + "/L";
|
||||||
|
liaisonName = destinationSite.liaisonName;
|
||||||
|
liaisonPhone = destinationSite.liaisonPhone;
|
||||||
|
//开始结束时间
|
||||||
|
startBusiness = startBusiness + "-" + endBusiness;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tvBusinessHours.setText("营业时间:" + startBusiness);
|
||||||
|
if (liaisonName != null && liaisonName.length() > 5) {
|
||||||
|
liaisonName = liaisonName.substring(0, 5) + "...";
|
||||||
|
}
|
||||||
|
tvPerson.setText("站联系人:" + liaisonName);
|
||||||
|
tvPrice.setText("加氢价格:" + hydrogenPrice);
|
||||||
|
tvPhone.setText("联系方式:" + liaisonPhone);
|
||||||
|
|
||||||
|
|
||||||
isGetInputtips = false;
|
|
||||||
|
|
||||||
aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(endPoint, 13f));
|
aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(endPoint, 13f));
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "获取加氢费用失败", e);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// 规划失败回退面板
|
// 规划失败回退面板
|
||||||
searchArea.setVisibility(View.VISIBLE);
|
searchArea.setVisibility(View.VISIBLE);
|
||||||
@@ -736,6 +671,11 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
// 检查途径点数量,决定使用哪种导航方式
|
// 检查途径点数量,决定使用哪种导航方式
|
||||||
int wayPointsCount = waysPoiIds.size();
|
int wayPointsCount = waysPoiIds.size();
|
||||||
Log.d(TAG, "途经点数量: " + wayPointsCount);
|
Log.d(TAG, "途经点数量: " + wayPointsCount);
|
||||||
|
|
||||||
|
//如果是输入地址提示内容,不判断途经点
|
||||||
|
if (isGetInputtips) {
|
||||||
|
wayPointsCount = 0;
|
||||||
|
}
|
||||||
if (wayPointsCount > 3) {
|
if (wayPointsCount > 3) {
|
||||||
// 途经点超过3个,跳转到 NavigationActivity
|
// 途经点超过3个,跳转到 NavigationActivity
|
||||||
Intent intent = new Intent(mContext, NavigationActivity.class);
|
Intent intent = new Intent(mContext, NavigationActivity.class);
|
||||||
@@ -802,13 +742,11 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
* 获取货车路线算法信息
|
* 获取货车路线算法信息
|
||||||
*/
|
*/
|
||||||
private void fetchTruckRouteAlgorithm(AMapLocation loc) {
|
private void fetchTruckRouteAlgorithm(AMapLocation loc) {
|
||||||
|
|
||||||
showLoading();
|
|
||||||
|
|
||||||
if (plateNumber == null || plateNumber.isEmpty()) {
|
if (plateNumber == null || plateNumber.isEmpty()) {
|
||||||
|
Toast.makeText(mActivity,"请先绑定车辆后进行导航",Toast.LENGTH_SHORT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
showLoading();
|
||||||
try {
|
try {
|
||||||
JSONObject json = new JSONObject();
|
JSONObject json = new JSONObject();
|
||||||
json.put("longitude", String.valueOf(loc.getLongitude()));
|
json.put("longitude", String.valueOf(loc.getLongitude()));
|
||||||
@@ -923,11 +861,18 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
aMap.setMyLocationEnabled(true);
|
aMap.setMyLocationEnabled(true);
|
||||||
aMap.setOnMarkerClickListener(this);
|
aMap.setOnMarkerClickListener(this);
|
||||||
|
|
||||||
// 添加地图触摸监听器,点击地图时隐藏提示列表
|
// 添加地图点击监听,当 detailPanel 显示时点击地图就执行 resetView
|
||||||
aMap.setOnMapClickListener(latLng -> {
|
aMap.setOnMapClickListener(latLng -> {
|
||||||
if (suggestionList != null && suggestionList.getVisibility() == View.VISIBLE) {
|
if (detailPanel != null && detailPanel.getVisibility() == View.VISIBLE) {
|
||||||
suggestionList.setVisibility(View.GONE);
|
resetView();
|
||||||
}
|
}
|
||||||
|
modeMenu.setVisibility(View.GONE);
|
||||||
|
});
|
||||||
|
aMap.setOnPOIClickListener(poi -> {
|
||||||
|
if (detailPanel != null && detailPanel.getVisibility() == View.VISIBLE) {
|
||||||
|
resetView();
|
||||||
|
}
|
||||||
|
modeMenu.setVisibility(View.GONE);
|
||||||
});
|
});
|
||||||
|
|
||||||
MyLocationStyle myLocationStyle = new MyLocationStyle();
|
MyLocationStyle myLocationStyle = new MyLocationStyle();
|
||||||
@@ -942,7 +887,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
}
|
}
|
||||||
|
|
||||||
myLocationStyle.anchor(0.5f, 0.5f);
|
myLocationStyle.anchor(0.5f, 0.5f);
|
||||||
myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER);
|
myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_SHOW);
|
||||||
aMap.setMyLocationStyle(myLocationStyle);
|
aMap.setMyLocationStyle(myLocationStyle);
|
||||||
aMap.getUiSettings().setZoomControlsEnabled(false);
|
aMap.getUiSettings().setZoomControlsEnabled(false);
|
||||||
aMap.getUiSettings().setLogoPosition(AMapOptions.LOGO_POSITION_BOTTOM_LEFT);
|
aMap.getUiSettings().setLogoPosition(AMapOptions.LOGO_POSITION_BOTTOM_LEFT);
|
||||||
@@ -973,6 +918,33 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
mlocationClient.stopLocation();
|
mlocationClient.stopLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDestination(String name, String address, double lat, double lon, String district) {
|
||||||
|
endName = name;
|
||||||
|
endAddress = address;
|
||||||
|
endPoint = new LatLng(lat, lon);
|
||||||
|
isUserSelectedDestination = true;
|
||||||
|
isGetInputtips = true;
|
||||||
|
|
||||||
|
Log.d(TAG, "setDestination called with name=" + name);
|
||||||
|
|
||||||
|
// 简化逻辑,直接设置文本
|
||||||
|
endInput.post(() -> {
|
||||||
|
try {
|
||||||
|
endInput.setText(district != null && !district.isEmpty() ? (name + " " + district ): name);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Failed to set text to endInput", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 Activity 实例
|
||||||
|
*/
|
||||||
|
public void setActivity(Activity activity) {
|
||||||
|
this.mActivity = activity;
|
||||||
|
}
|
||||||
|
|
||||||
public void startLocation() {
|
public void startLocation() {
|
||||||
if (mlocationClient == null) {
|
if (mlocationClient == null) {
|
||||||
try {
|
try {
|
||||||
@@ -1127,6 +1099,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
dataMap.put("latLng", latLng);
|
dataMap.put("latLng", latLng);
|
||||||
dataMap.put("stationId", stationId);
|
dataMap.put("stationId", stationId);
|
||||||
dataMap.put("address", address);
|
dataMap.put("address", address);
|
||||||
|
dataMap.put("name", name);
|
||||||
m.setObject(dataMap);
|
m.setObject(dataMap);
|
||||||
|
|
||||||
stationMarkers.add(m);
|
stationMarkers.add(m);
|
||||||
@@ -1137,7 +1110,27 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
|
|
||||||
//地图选点
|
//地图选点
|
||||||
for (Marker m : stationMarkers) {
|
for (Marker m : stationMarkers) {
|
||||||
m.setIcon(BitmapDescriptorFactory.fromResource(m.equals(marker) ? R.drawable.ic_marker : R.drawable.ic_un_marker));
|
Object obj = m.getObject();
|
||||||
|
if (obj instanceof Map) {
|
||||||
|
Map<String, Object> dataMap = (Map<String, Object>) obj;
|
||||||
|
String name = (String) dataMap.get("name");
|
||||||
|
|
||||||
|
if (name != null) {
|
||||||
|
// 截取显示名称(最多7个字符)
|
||||||
|
String displayName = name.length() > 7 ? name.substring(0, 7) + "..." :
|
||||||
|
name;
|
||||||
|
boolean isSelected = m.equals(marker);
|
||||||
|
|
||||||
|
// 使用 getMarkerIconWithText 创建带文字的图标
|
||||||
|
BitmapDescriptor icon = getMarkerIconWithText(mContext, displayName,
|
||||||
|
isSelected);
|
||||||
|
m.setIcon(icon);
|
||||||
|
} else {
|
||||||
|
// 如果没有 name,降级到直接设置图标
|
||||||
|
m.setIcon(BitmapDescriptorFactory.fromResource(m.equals(marker) ?
|
||||||
|
R.drawable.ic_marker : R.drawable.ic_un_marker));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1162,6 +1155,9 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
// 更新 UI 和 业务逻辑
|
// 更新 UI 和 业务逻辑
|
||||||
endName = marker.getTitle();
|
endName = marker.getTitle();
|
||||||
isUserSelectedDestination = true; // 标识用户手动选择了目的地
|
isUserSelectedDestination = true; // 标识用户手动选择了目的地
|
||||||
|
isGetInputtips = false;
|
||||||
|
|
||||||
|
endInput.setText("");
|
||||||
|
|
||||||
// 需要传入当前位置以便接口计算路线
|
// 需要传入当前位置以便接口计算路线
|
||||||
if (mlocationClient != null && mlocationClient.getLastKnownLocation() != null) {
|
if (mlocationClient != null && mlocationClient.getLastKnownLocation() != null) {
|
||||||
@@ -1306,9 +1302,12 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
|
|
||||||
// 文本内容
|
// 文本内容
|
||||||
TextView tv = new TextView(mContext);
|
TextView tv = new TextView(mContext);
|
||||||
|
|
||||||
|
|
||||||
tv.setText(label + value);
|
tv.setText(label + value);
|
||||||
tv.setTextSize(14);
|
|
||||||
tv.setTextColor(Color.parseColor("#333333"));
|
tv.setTextSize(12);
|
||||||
|
tv.setTextColor(Color.parseColor("#ff1d2129"));
|
||||||
tv.setPadding(dp2px(6), 0, 0, 0);
|
tv.setPadding(dp2px(6), 0, 0, 0);
|
||||||
|
|
||||||
LinearLayout.LayoutParams tvParams = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f);
|
LinearLayout.LayoutParams tvParams = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f);
|
||||||
@@ -1321,23 +1320,6 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
return tv; // 返回TextView以便后续更新内容
|
return tv; // 返回TextView以便后续更新内容
|
||||||
}
|
}
|
||||||
|
|
||||||
// 过载一个不需要weight的方法给第一行使用
|
|
||||||
private TextView createInfoItem(LinearLayout parent, int iconRes, String label, String value) {
|
|
||||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
|
||||||
|
|
||||||
ImageView iv = new ImageView(mContext);
|
|
||||||
iv.setImageResource(iconRes);
|
|
||||||
iv.setColorFilter(Color.parseColor("#017143"));
|
|
||||||
parent.addView(iv, new LinearLayout.LayoutParams(dp2px(18), dp2px(18)));
|
|
||||||
|
|
||||||
TextView tv = new TextView(mContext);
|
|
||||||
tv.setTextSize(14);
|
|
||||||
tv.setTextColor(Color.parseColor("#333333"));
|
|
||||||
tv.setPadding(dp2px(6), 0, 0, 0);
|
|
||||||
parent.addView(tv, params);
|
|
||||||
|
|
||||||
return tv;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建模式菜单视图
|
// 创建模式菜单视图
|
||||||
private View createModeMenu(Context context) {
|
private View createModeMenu(Context context) {
|
||||||
@@ -1360,9 +1342,9 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
TextView item3 = createMenuItem(context, "加氢规划模式", true);
|
TextView item3 = createMenuItem(context, "加氢规划模式", true);
|
||||||
item3.setOnClickListener(v -> switchMode("加氢规划"));
|
item3.setOnClickListener(v -> switchMode("加氢规划"));
|
||||||
|
|
||||||
menu.addView(item1);
|
|
||||||
menu.addView(item2);
|
|
||||||
menu.addView(item3);
|
menu.addView(item3);
|
||||||
|
menu.addView(item2);
|
||||||
|
menu.addView(item1);
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1373,13 +1355,12 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
tv.setPadding(dp2px(15), dp2px(12), dp2px(15), dp2px(12));
|
tv.setPadding(dp2px(15), dp2px(12), dp2px(15), dp2px(12));
|
||||||
tv.setGravity(Gravity.CENTER);
|
tv.setGravity(Gravity.CENTER);
|
||||||
if (isHighlight) {
|
if (isHighlight) {
|
||||||
tv.setTextColor(Color.WHITE);
|
|
||||||
// 顶部圆角绿色背景
|
// 顶部圆角绿色背景
|
||||||
tv.setBackground(getTopRoundedDrawable(Color.parseColor("#27AE60"), 12));
|
tv.setBackground(getTopRoundedDrawable(Color.parseColor("#27AE60"), 12));
|
||||||
} else {
|
} else {
|
||||||
tv.setTextColor(Color.parseColor("#666666"));
|
|
||||||
tv.setBackgroundColor(Color.TRANSPARENT);
|
tv.setBackgroundColor(Color.TRANSPARENT);
|
||||||
}
|
}
|
||||||
|
tv.setTextColor(Color.parseColor(isHighlight ? "#ffffffff" : "#ffc9cdd4"));
|
||||||
return tv;
|
return tv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1463,6 +1444,9 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
destinationSite.longitude = siteJson.optString("longitude", "");
|
destinationSite.longitude = siteJson.optString("longitude", "");
|
||||||
destinationSite.latitude = siteJson.optString("latitude", "");
|
destinationSite.latitude = siteJson.optString("latitude", "");
|
||||||
destinationSite.distance = siteJson.optString("distance", "");
|
destinationSite.distance = siteJson.optString("distance", "");
|
||||||
|
destinationSite.hydrogenPrice = siteJson.optString("hydrogenPrice", "");
|
||||||
|
destinationSite.liaisonName = siteJson.optString("liaisonName", "");
|
||||||
|
destinationSite.liaisonPhone = siteJson.optString("liaisonPhone", "");
|
||||||
truckRouteData.destinationSite = destinationSite;
|
truckRouteData.destinationSite = destinationSite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1660,5 +1644,9 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
|
|||||||
public String longitude;
|
public String longitude;
|
||||||
public String latitude;
|
public String latitude;
|
||||||
public String distance;
|
public String distance;
|
||||||
|
|
||||||
|
public String hydrogenPrice;
|
||||||
|
public String liaisonName;
|
||||||
|
public String liaisonPhone;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -187,6 +187,7 @@ public class NavigationActivity extends ComponentActivity implements AMapNaviLis
|
|||||||
mAMapNavi.setCarInfo(carInfo);
|
mAMapNavi.setCarInfo(carInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mAMapNavi.setUseInnerVoice(true);
|
||||||
// 计算并启动导航
|
// 计算并启动导航
|
||||||
mAMapNavi.calculateDriveRoute(startNaviPoi, endNaviPoi, wayPoints, PathPlanningStrategy.DRIVING_MULTIPLE_ROUTES_DEFAULT);
|
mAMapNavi.calculateDriveRoute(startNaviPoi, endNaviPoi, wayPoints, PathPlanningStrategy.DRIVING_MULTIPLE_ROUTES_DEFAULT);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,261 @@
|
|||||||
|
package com.lnkj.ln_jq_app;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.drawable.ColorDrawable;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.Editable;
|
||||||
|
import android.text.TextWatcher;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.ListView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.amap.api.services.help.Inputtips;
|
||||||
|
import com.amap.api.services.help.InputtipsQuery;
|
||||||
|
import com.amap.api.services.help.Tip;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import androidx.activity.ComponentActivity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索目的地页面
|
||||||
|
*/
|
||||||
|
public class SearchDestinationActivity extends ComponentActivity implements Inputtips.InputtipsListener {
|
||||||
|
private static final String TAG = "SearchDestinationActivity";
|
||||||
|
|
||||||
|
public static final String EXTRA_RESULT_NAME = "result_name";
|
||||||
|
public static final String EXTRA_RESULT_ADDRESS = "result_address";
|
||||||
|
public static final String EXTRA_RESULT_LAT = "result_lat";
|
||||||
|
public static final String EXTRA_RESULT_LON = "result_lon";
|
||||||
|
public static final String EXTRA_RESULT_DISTRICT = "result_district";
|
||||||
|
|
||||||
|
// 静态回调接口
|
||||||
|
public interface DestinationCallback {
|
||||||
|
void onDestinationSelected(String name, String address, double lat, double lon, String district);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DestinationCallback callback;
|
||||||
|
|
||||||
|
public static void setCallback(DestinationCallback callback) {
|
||||||
|
SearchDestinationActivity.callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
private EditText searchInput;
|
||||||
|
private ListView suggestionList;
|
||||||
|
private ImageView backBtn;
|
||||||
|
|
||||||
|
private ArrayAdapter<String> suggestionAdapter;
|
||||||
|
private List<Tip> currentTipList;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
try {
|
||||||
|
setContentView(R.layout.activity_search_destination);
|
||||||
|
|
||||||
|
initViews();
|
||||||
|
setupListeners();
|
||||||
|
|
||||||
|
// 自动显示键盘
|
||||||
|
showKeyboard();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error in onCreate", e);
|
||||||
|
e.printStackTrace();
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initViews() {
|
||||||
|
try {
|
||||||
|
Log.d(TAG, "initViews started");
|
||||||
|
searchInput = findViewById(R.id.search_input);
|
||||||
|
suggestionList = findViewById(R.id.suggestion_list);
|
||||||
|
backBtn = findViewById(R.id.back_btn);
|
||||||
|
|
||||||
|
currentTipList = new ArrayList<>();
|
||||||
|
|
||||||
|
Log.d(TAG, "initViews completed: searchInput=" + (searchInput != null ? "ok" : "null") + ", suggestionList=" + (suggestionList != null ? "ok" : "null") + ", backBtn=" + (backBtn != null ? "ok" : "null"));
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error in initViews", e);
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
suggestionAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, new ArrayList<>()) {
|
||||||
|
@Override
|
||||||
|
public View getView(int position, android.view.View convertView, android.view.ViewGroup parent) {
|
||||||
|
View view = super.getView(position, convertView, parent);
|
||||||
|
TextView text = view.findViewById(android.R.id.text1);
|
||||||
|
text.setTextColor(Color.parseColor("#333333"));
|
||||||
|
text.setTextSize(14);
|
||||||
|
view.setBackgroundColor(Color.TRANSPARENT);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
suggestionList.setAdapter(suggestionAdapter);
|
||||||
|
suggestionList.setDivider(new ColorDrawable(Color.LTGRAY));
|
||||||
|
suggestionList.setDividerHeight(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void setupListeners() {
|
||||||
|
try {
|
||||||
|
Log.d(TAG, "setupListeners started");
|
||||||
|
|
||||||
|
// 返回按钮
|
||||||
|
backBtn.setOnClickListener(v -> {
|
||||||
|
Log.d(TAG, "Back button clicked");
|
||||||
|
hideKeyboard();
|
||||||
|
finish();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 文本变化监听
|
||||||
|
searchInput.addTextChangedListener(new TextWatcher() {
|
||||||
|
@Override
|
||||||
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||||
|
Log.d(TAG, "Text changed: " + (s != null ? s.toString() : "null") + ", length=" + (s != null ? s.length() : 0));
|
||||||
|
if (s.length() > 1) {
|
||||||
|
searchLocation(s.toString());
|
||||||
|
} else {
|
||||||
|
suggestionList.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable s) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 列表点击
|
||||||
|
suggestionList.setOnItemClickListener((parent, view, position, id) -> {
|
||||||
|
Log.d(TAG, "Suggestion clicked at position: " + position);
|
||||||
|
try {
|
||||||
|
Tip tip = currentTipList.get(position);
|
||||||
|
if (tip.getPoint() != null) {
|
||||||
|
String name = tip.getName();
|
||||||
|
String address = tip.getAddress();
|
||||||
|
String district = tip.getDistrict();
|
||||||
|
double lat = tip.getPoint().getLatitude();
|
||||||
|
double lon = tip.getPoint().getLongitude();
|
||||||
|
|
||||||
|
Log.d(TAG, "Selected destination: " + name + ", lat=" + lat + ", lon=" + lon);
|
||||||
|
|
||||||
|
// 优先使用静态回调
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onDestinationSelected(name, address, lat, lon, district);
|
||||||
|
} else {
|
||||||
|
// 降级使用 Intent 回调
|
||||||
|
Intent result = new Intent();
|
||||||
|
result.putExtra(EXTRA_RESULT_NAME, name);
|
||||||
|
result.putExtra(EXTRA_RESULT_ADDRESS, address);
|
||||||
|
result.putExtra(EXTRA_RESULT_LAT, lat);
|
||||||
|
result.putExtra(EXTRA_RESULT_LON, lon);
|
||||||
|
result.putExtra(EXTRA_RESULT_DISTRICT, district);
|
||||||
|
setResult(RESULT_OK, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
hideKeyboard();
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error handling suggestion click", e);
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Log.d(TAG, "setupListeners completed");
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error in setupListeners", e);
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void searchLocation(String keyword) {
|
||||||
|
try {
|
||||||
|
Log.d(TAG, "Searching for: " + keyword);
|
||||||
|
InputtipsQuery query = new InputtipsQuery(keyword, "");
|
||||||
|
query.setCityLimit(false);
|
||||||
|
Inputtips inputtips = new Inputtips(this, query);
|
||||||
|
inputtips.setInputtipsListener(this);
|
||||||
|
inputtips.requestInputtipsAsyn();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error in searchLocation", e);
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onGetInputtips(List<Tip> tipList, int rCode) {
|
||||||
|
Log.d(TAG, "onGetInputtips called, rCode=" + rCode + ", tipList size=" + (tipList != null ? tipList.size() : "null"));
|
||||||
|
if (rCode == 1000 && tipList != null && !tipList.isEmpty()) {
|
||||||
|
currentTipList.clear();
|
||||||
|
currentTipList.addAll(tipList);
|
||||||
|
|
||||||
|
List<String> suggestionNames = new ArrayList<>();
|
||||||
|
for (Tip tip : tipList) {
|
||||||
|
String name = tip.getName();
|
||||||
|
String district = tip.getDistrict();
|
||||||
|
String displayText = district != null && !district.isEmpty() ? name + " " + district : name;
|
||||||
|
suggestionNames.add(displayText);
|
||||||
|
}
|
||||||
|
|
||||||
|
runOnUiThread(() -> {
|
||||||
|
suggestionAdapter.clear();
|
||||||
|
suggestionAdapter.addAll(suggestionNames);
|
||||||
|
suggestionAdapter.notifyDataSetChanged();
|
||||||
|
|
||||||
|
if (suggestionNames.size() > 0) {
|
||||||
|
suggestionList.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
suggestionList.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
runOnUiThread(() -> {
|
||||||
|
suggestionList.setVisibility(View.GONE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void showKeyboard() {
|
||||||
|
searchInput.requestFocus();
|
||||||
|
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||||
|
if (imm != null) {
|
||||||
|
imm.showSoftInput(searchInput, InputMethodManager.SHOW_IMPLICIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hideKeyboard() {
|
||||||
|
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||||
|
if (imm != null) {
|
||||||
|
imm.hideSoftInputFromWindow(searchInput.getWindowToken(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPointerCaptureChanged(boolean hasCapture) {
|
||||||
|
super.onPointerCaptureChanged(hasCapture);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
// 清理回调,避免内存泄漏
|
||||||
|
callback = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
ln_jq_app/android/app/src/main/res/drawable/back.png
Normal file
|
After Width: | Height: | Size: 705 B |
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- 背景颜色:使用浅灰色 -->
|
||||||
|
<solid android:color="#ffffffff" />
|
||||||
|
<!-- 圆角:8dp左右 -->
|
||||||
|
<corners android:radius="8dp" />
|
||||||
|
<!-- 边框:可选,如果需要更清晰的边缘可以加上 -->
|
||||||
|
<stroke android:width="1dp" android:color="#EAEAEA" />
|
||||||
|
</shape>
|
||||||
|
Before Width: | Height: | Size: 1.1 KiB |
40
ln_jq_app/android/app/src/main/res/drawable/ic_fuel.xml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="16dp"
|
||||||
|
android:height="16dp"
|
||||||
|
android:viewportWidth="16"
|
||||||
|
android:viewportHeight="16">
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M8,14.667C10.946,14.667 13.333,12.496 13.333,9.818C13.333,7.192 11.556,4.364 8,1.333C4.444,4.364 2.667,7.192 2.667,9.818C2.667,12.496 5.054,14.667 8,14.667Z"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M6.286,6.333L8,8.123L9.714,6.333"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M6,8.719H10"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M6,10.509H10"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M8,8.719V12"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
</vector>
|
||||||
|
Before Width: | Height: | Size: 1.1 KiB |
41
ln_jq_app/android/app/src/main/res/drawable/ic_mileage.xml
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="16dp"
|
||||||
|
android:height="16dp"
|
||||||
|
android:viewportWidth="16"
|
||||||
|
android:viewportHeight="16">
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M3.667,1.375L2,13.375"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M12.333,1.375L13.988,13.36"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M8,1.375V3.375"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M8,11.042V13.375"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M8,6.042V8.375"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
</vector>
|
||||||
13
ln_jq_app/android/app/src/main/res/drawable/ic_path.xml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<group>
|
||||||
|
<clip-path
|
||||||
|
android:pathData="M0,0h24v24h-24z"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M6.518,10.241C4.181,10.241 2.29,12.135 2.29,14.469C2.29,16.804 6.518,21.684 6.518,21.684C6.518,21.684 10.746,16.806 10.746,14.469C10.746,12.133 8.853,10.241 6.518,10.241ZM6.518,15.616C5.853,15.616 5.313,15.077 5.313,14.411C5.313,13.745 5.853,13.206 6.518,13.206C7.184,13.206 7.723,13.745 7.723,14.411C7.723,15.077 7.181,15.616 6.518,15.616ZM19.676,2.301C18.567,2.301 17.67,3.198 17.67,4.307C17.67,5.416 19.676,7.729 19.676,7.729C19.676,7.729 21.682,5.416 21.682,4.307C21.682,3.198 20.785,2.301 19.676,2.301ZM19.676,4.851C19.36,4.851 19.104,4.595 19.104,4.279C19.104,3.963 19.36,3.707 19.676,3.707C19.992,3.707 20.248,3.963 20.248,4.279C20.246,4.595 19.99,4.851 19.676,4.851ZM18.026,13.185C17.386,12.813 16.629,12.674 15.898,12.538C14.845,12.344 14.196,12.191 14.074,11.72C14.051,11.627 14.037,11.493 14.156,11.291C14.325,11.005 14.855,10.422 16.519,9.735C16.993,9.539 17.449,9.382 17.801,9.27C18.168,9.153 18.393,8.768 18.296,8.395C18.199,8.019 17.812,7.792 17.442,7.909C17.056,8.03 16.543,8.205 15.999,8.43C14.431,9.074 13.404,9.798 12.945,10.579C12.663,11.057 12.584,11.575 12.713,12.077C12.877,12.709 13.303,13.185 13.978,13.485C14.482,13.71 15.073,13.818 15.642,13.923C16.256,14.036 16.889,14.153 17.318,14.402C17.597,14.563 17.888,14.819 17.916,15.487C17.958,16.427 16.88,17.448 14.881,18.367C13.833,18.848 12.764,19.192 12.099,19.385C11.729,19.493 11.5,19.869 11.589,20.244C11.68,20.625 12.064,20.86 12.441,20.752C13.144,20.55 14.295,20.183 15.45,19.654C16.547,19.152 17.424,18.606 18.054,18.032C18.938,17.228 19.364,16.349 19.322,15.426C19.278,14.413 18.842,13.661 18.026,13.185Z"
|
||||||
|
android:fillColor="#ffffff"/>
|
||||||
|
</group>
|
||||||
|
</vector>
|
||||||
20
ln_jq_app/android/app/src/main/res/drawable/ic_person.xml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="16dp"
|
||||||
|
android:height="16dp"
|
||||||
|
android:viewportWidth="16"
|
||||||
|
android:viewportHeight="16">
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M8,6.042C9.289,6.042 10.333,4.997 10.333,3.708C10.333,2.42 9.289,1.375 8,1.375C6.711,1.375 5.667,2.42 5.667,3.708C5.667,4.997 6.711,6.042 8,6.042Z"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M2,12.975V13.375H14V12.975C14,11.481 14,10.735 13.709,10.164C13.454,9.663 13.046,9.255 12.544,8.999C11.974,8.708 11.227,8.708 9.733,8.708H6.267C4.773,8.708 4.026,8.708 3.456,8.999C2.954,9.255 2.546,9.663 2.291,10.164C2,10.735 2,11.481 2,12.975Z"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
</vector>
|
||||||
12
ln_jq_app/android/app/src/main/res/drawable/ic_phone.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="16dp"
|
||||||
|
android:height="16dp"
|
||||||
|
android:viewportWidth="16"
|
||||||
|
android:viewportHeight="16">
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M5.665,1.937C5.908,1.937 6.131,2.068 6.248,2.28L7.064,3.749C7.171,3.941 7.176,4.174 7.077,4.371L6.292,5.942C6.292,5.942 6.519,7.112 7.472,8.065C8.425,9.018 9.591,9.242 9.591,9.242L11.162,8.456C11.359,8.358 11.592,8.363 11.785,8.47L13.258,9.289C13.469,9.407 13.6,9.63 13.6,9.872V11.563C13.6,12.424 12.8,13.046 11.984,12.771C10.308,12.205 7.707,11.128 6.058,9.479C4.409,7.831 3.332,5.229 2.767,3.553C2.491,2.737 3.113,1.937 3.975,1.937H5.665Z"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"/>
|
||||||
|
</vector>
|
||||||
40
ln_jq_app/android/app/src/main/res/drawable/ic_price.xml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="16dp"
|
||||||
|
android:height="16dp"
|
||||||
|
android:viewportWidth="16"
|
||||||
|
android:viewportHeight="16">
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M8,14.042C11.682,14.042 14.667,11.057 14.667,7.375C14.667,3.693 11.682,0.708 8,0.708C4.318,0.708 1.333,3.693 1.333,7.375C1.333,11.057 4.318,14.042 8,14.042Z"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M6,6.708H10"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M6,8.708H10"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M8.003,6.708V10.708"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M10,4.375L8,6.375L6,4.375"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
</vector>
|
||||||
26
ln_jq_app/android/app/src/main/res/drawable/ic_search.xml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="18dp"
|
||||||
|
android:height="18dp"
|
||||||
|
android:viewportWidth="18"
|
||||||
|
android:viewportHeight="18">
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M7.875,14.5C11.396,14.5 14.25,11.646 14.25,8.125C14.25,4.604 11.396,1.75 7.875,1.75C4.354,1.75 1.5,4.604 1.5,8.125C1.5,11.646 4.354,14.5 7.875,14.5Z"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#4E5969"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M9.997,5.629C9.454,5.086 8.704,4.75 7.875,4.75C7.047,4.75 6.297,5.086 5.754,5.629"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#4E5969"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M12.458,12.707L15.64,15.889"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#4E5969"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
</vector>
|
||||||
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 810 B |
19
ln_jq_app/android/app/src/main/res/drawable/ic_time.xml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="16dp"
|
||||||
|
android:height="16dp"
|
||||||
|
android:viewportWidth="16"
|
||||||
|
android:viewportHeight="16">
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M8,14.042C11.682,14.042 14.667,11.057 14.667,7.375C14.667,3.693 11.682,0.708 8,0.708C4.318,0.708 1.333,3.693 1.333,7.375C1.333,11.057 4.318,14.042 8,14.042Z"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M8.003,3.375L8.003,7.378L10.829,10.204"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
</vector>
|
||||||
|
Before Width: | Height: | Size: 924 B |
37
ln_jq_app/android/app/src/main/res/drawable/ic_toll.xml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="16dp"
|
||||||
|
android:height="16dp"
|
||||||
|
android:viewportWidth="16"
|
||||||
|
android:viewportHeight="16">
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M1.333,2.042H3.667C3.667,2.042 4,3.708 5.667,3.708C7.333,3.708 7.667,2.042 7.667,2.042H14.667V12.708H7.667C7.667,12.708 7.333,11.042 5.667,11.042C4,11.042 3.667,12.708 3.667,12.708H1.333V2.042Z"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M5.667,5.708V6.375"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M5.667,8.375V9.042"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M8.333,6.375H12"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M8.333,8.375H12"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#017137"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="#FFFFFF" />
|
||||||
|
<corners
|
||||||
|
android:topLeftRadius="24dp"
|
||||||
|
android:topRightRadius="24dp"
|
||||||
|
android:bottomLeftRadius="0dp"
|
||||||
|
android:bottomRightRadius="0dp" />
|
||||||
|
</shape>
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="#FFFFFF"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="55dp"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/back_btn"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:src="@drawable/back" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="15dp"
|
||||||
|
android:text="选择地点"
|
||||||
|
android:textColor="#000000"
|
||||||
|
android:textSize="18sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/search_input"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_margin="12dp"
|
||||||
|
android:background="@drawable/bg_search_input"
|
||||||
|
android:hint="输入地址"
|
||||||
|
android:imeOptions="actionDone"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textColor="#333333"
|
||||||
|
android:textColorHint="#999999"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<ListView
|
||||||
|
android:id="@+id/suggestion_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 844 B |
|
After Width: | Height: | Size: 792 B |
|
After Width: | Height: | Size: 909 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 864 B |
@@ -0,0 +1,30 @@
|
|||||||
|
//
|
||||||
|
// AAddHPopView.h
|
||||||
|
// AMapNavIOSSDK
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
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
|
||||||
@@ -0,0 +1,359 @@
|
|||||||
|
//
|
||||||
|
// AAddHPopView.m
|
||||||
|
// AMapNavIOSSDK
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "AAddHPopView.h"
|
||||||
|
#import <Masonry/Masonry.h>
|
||||||
|
#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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -21,8 +21,8 @@
|
|||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@interface ARoutePlaneController : ABaseViewController
|
@interface ARoutePlaneController : ABaseViewController<AMapNaviDriveDataRepresentable>
|
||||||
|
@property (nonatomic , strong) AMapNaviDriveView * driveView;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#import "AMapPrivacyUtility.h"
|
#import "AMapPrivacyUtility.h"
|
||||||
|
|
||||||
#import "AStationDetailPopupController.h"
|
#import "AStationDetailPopupView.h"
|
||||||
|
|
||||||
#define kRouteIndicatorViewHeight 64.f
|
#define kRouteIndicatorViewHeight 64.f
|
||||||
|
|
||||||
@@ -26,8 +26,9 @@
|
|||||||
#import "AMapNavHttpUtil.h"
|
#import "AMapNavHttpUtil.h"
|
||||||
#import "ACustomStepView.h"
|
#import "ACustomStepView.h"
|
||||||
#import "ABottomBarView.h"
|
#import "ABottomBarView.h"
|
||||||
|
#import "AAddHPopView.h"
|
||||||
|
|
||||||
@interface ARoutePlaneController ()<MAMapViewDelegate, AMapNaviDriveManagerDelegate,AMapNaviCompositeManagerDelegate , AMapLocationManagerDelegate , UITextFieldDelegate , AStationDetailPopupDelegate, ABottomBarViewDelegate>
|
@interface ARoutePlaneController ()<MAMapViewDelegate, AMapNaviDriveManagerDelegate,AMapNaviCompositeManagerDelegate , AMapLocationManagerDelegate , UITextFieldDelegate , AStationDetailPopupViewDelegate, ABottomBarViewDelegate>
|
||||||
@property (nonatomic, strong) UITextField *textField;
|
@property (nonatomic, strong) UITextField *textField;
|
||||||
|
|
||||||
/// 底部搜索+规划路线栏
|
/// 底部搜索+规划路线栏
|
||||||
@@ -65,11 +66,16 @@
|
|||||||
@property (nonatomic , strong)ACustomStepView * stepView;
|
@property (nonatomic , strong)ACustomStepView * stepView;
|
||||||
|
|
||||||
/// 当前弹出的站点详情弹框
|
/// 当前弹出的站点详情弹框
|
||||||
@property (nonatomic , strong)AStationDetailPopupController * stationDetailPopup;
|
@property (nonatomic , strong)AStationDetailPopupView * stationDetailPopup;
|
||||||
@property (nonatomic, strong) ANavPointModel *pointModel; //当前选的目的点
|
@property (nonatomic, strong) ANavPointModel *pointModel; //当前选的目的点
|
||||||
@property (nonatomic, strong) ATripCalcDataModel * tjdPathInfoModel;//途经点信息
|
@property (nonatomic, strong) ATripCalcDataModel * tjdPathInfoModel;//途经点信息
|
||||||
|
|
||||||
@property (nonatomic, strong) CLLocationManager * locationManager;
|
@property (nonatomic, strong) CLLocationManager * locationManager;
|
||||||
|
|
||||||
|
/// 加氢规划按钮(用于气泡弹框定位)
|
||||||
|
@property (nonatomic, weak) UIButton *addHBtn;
|
||||||
|
|
||||||
|
@property (nonatomic ,strong)MAAnnotationView * currAnnotionView;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation ARoutePlaneController
|
@implementation ARoutePlaneController
|
||||||
@@ -156,6 +162,8 @@
|
|||||||
|
|
||||||
|
|
||||||
-(void)requestRoutePathWithParms:(NSDictionary*)dic completeHandle:(void(^)(ATripCalcDataModel * tjd))blk {
|
-(void)requestRoutePathWithParms:(NSDictionary*)dic completeHandle:(void(^)(ATripCalcDataModel * tjd))blk {
|
||||||
|
///清除上一次数据影响
|
||||||
|
self.tjdPathInfoModel = nil;
|
||||||
|
|
||||||
NSString * token = [[NSUserDefaults standardUserDefaults]valueForKey:@"flutter.token"];
|
NSString * token = [[NSUserDefaults standardUserDefaults]valueForKey:@"flutter.token"];
|
||||||
NSString * carNo = [[NSUserDefaults standardUserDefaults]valueForKey:@"flutter.plateNumber"];
|
NSString * carNo = [[NSUserDefaults standardUserDefaults]valueForKey:@"flutter.plateNumber"];
|
||||||
@@ -279,7 +287,8 @@
|
|||||||
|
|
||||||
[bottomBar mas_makeConstraints:^(MASConstraintMaker *make) {
|
[bottomBar mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
make.left.right.equalTo(self.view);
|
make.left.right.equalTo(self.view);
|
||||||
make.bottom.equalTo(self.view);
|
// make.bottom.equalTo(self.view).offset(-AMP_TabbarHeight - 13);
|
||||||
|
make.bottom.equalTo(self.view).offset(0);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
// ── 兼容旧逻辑:保留 startTf / dstTf 属性(隐藏,不再显示) ──
|
// ── 兼容旧逻辑:保留 startTf / dstTf 属性(隐藏,不再显示) ──
|
||||||
@@ -319,25 +328,55 @@
|
|||||||
[stepView addObserver:self forKeyPath:@"value" options:NSKeyValueObservingOptionNew context:nil];
|
[stepView addObserver:self forKeyPath:@"value" options:NSKeyValueObservingOptionNew context:nil];
|
||||||
self.stepView = stepView;
|
self.stepView = stepView;
|
||||||
|
|
||||||
|
stepView.hidden = YES;
|
||||||
|
|
||||||
///当前位置按钮
|
///当前位置按钮
|
||||||
UIButton * btn = [UIButton buttonWithType:UIButtonTypeCustom];
|
UIButton * btn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||||
[btn setImage:[AMapNavCommonUtil imageWithName3x:@"my_location_icon"] forState:UIControlStateNormal];
|
[btn setBackgroundImage:[AMapNavCommonUtil imageWithName3x:@"my_location_icon"] forState:UIControlStateNormal];
|
||||||
btn.backgroundColor = [UIColor lightGrayColor];
|
|
||||||
|
btn.backgroundColor = [UIColor whiteColor];
|
||||||
btn.titleLabel.font = [UIFont systemFontOfSize:14];
|
btn.titleLabel.font = [UIFont systemFontOfSize:14];
|
||||||
btn.layer.cornerRadius = 20;
|
btn.layer.cornerRadius = 22;
|
||||||
|
|
||||||
[btn addTarget:self action:@selector(updateUserLocalAction) forControlEvents:UIControlEventTouchUpInside];
|
[btn addTarget:self action:@selector(updateUserLocalAction) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
|
||||||
[self.view addSubview:btn];
|
[self.view addSubview:btn];
|
||||||
[btn mas_makeConstraints:^(MASConstraintMaker *make) {
|
[btn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
make.right.equalTo(self.view).offset(-10);
|
make.right.equalTo(self.view).offset(-10);
|
||||||
make.width.height.equalTo(@40);
|
make.width.height.equalTo(@44);
|
||||||
make.bottom.equalTo(bottomBar.mas_top).offset(-85);
|
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<NSKeyValueChangeKey,id> *)change context:(void *)context {
|
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
|
||||||
if ([keyPath isEqualToString:@"value"]) {
|
if ([keyPath isEqualToString:@"value"]) {
|
||||||
self.mapView.zoomLevel = [change[NSKeyValueChangeNewKey] doubleValue];
|
self.mapView.zoomLevel = [change[NSKeyValueChangeNewKey] doubleValue];
|
||||||
@@ -363,6 +402,7 @@
|
|||||||
self.mapView.userTrackingMode = MAUserTrackingModeFollowWithHeading;
|
self.mapView.userTrackingMode = MAUserTrackingModeFollowWithHeading;
|
||||||
self.mapView.desiredAccuracy = kCLLocationAccuracyNearestTenMeters; // 定位精度
|
self.mapView.desiredAccuracy = kCLLocationAccuracyNearestTenMeters; // 定位精度
|
||||||
_mapView.showsScale= YES;
|
_mapView.showsScale= YES;
|
||||||
|
_mapView.showsCompass = NO;
|
||||||
|
|
||||||
_mapView.logoCenter = CGPointMake(CGRectGetWidth(self.view.bounds)-55, 450);
|
_mapView.logoCenter = CGPointMake(CGRectGetWidth(self.view.bounds)-55, 450);
|
||||||
self.mapView.zoomLevel = 11;
|
self.mapView.zoomLevel = 11;
|
||||||
@@ -389,7 +429,7 @@
|
|||||||
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(self.latitude, self.longitude);
|
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(self.latitude, self.longitude);
|
||||||
|
|
||||||
[_mapView setCenterCoordinate:coord animated:YES];
|
[_mapView setCenterCoordinate:coord animated:YES];
|
||||||
// [_mapView setZoomLevel:10 animated:YES];
|
[_mapView setZoomLevel:15.0 animated:YES];
|
||||||
} else {
|
} else {
|
||||||
// 如果尚未获取到位置,进入跟踪模式等待回调
|
// 如果尚未获取到位置,进入跟踪模式等待回调
|
||||||
[_mapView setUserTrackingMode:MAUserTrackingModeFollow animated:YES];
|
[_mapView setUserTrackingMode:MAUserTrackingModeFollow animated:YES];
|
||||||
@@ -508,7 +548,7 @@
|
|||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0);
|
0);
|
||||||
strategy = AMapNaviDrivingStrategyMultipleDefault;//使用默认策略
|
strategy = AMapNaviDrivingStrategyMultipleDefault;//使用默认策略,DRIVING_MULTIPLE_ROUTES_DEFAULT
|
||||||
|
|
||||||
id delegate = [AMapNaviDriveManager sharedInstance].delegate;
|
id delegate = [AMapNaviDriveManager sharedInstance].delegate;
|
||||||
if (!delegate) {
|
if (!delegate) {
|
||||||
@@ -780,6 +820,7 @@
|
|||||||
[config setNeedCalculateRouteWhenPresent:NO];//不在算路
|
[config setNeedCalculateRouteWhenPresent:NO];//不在算路
|
||||||
[config setMultipleRouteNaviMode:NO];//直接单线路径导航
|
[config setMultipleRouteNaviMode:NO];//直接单线路径导航
|
||||||
// [config setNeedDestoryDriveManagerInstanceWhenDismiss:NO];
|
// [config setNeedDestoryDriveManagerInstanceWhenDismiss:NO];
|
||||||
|
[config setShowDrivingStrategyPreferenceView:NO];
|
||||||
|
|
||||||
[self.compositeManager presentRoutePlanViewControllerWithOptions:config];
|
[self.compositeManager presentRoutePlanViewControllerWithOptions:config];
|
||||||
}
|
}
|
||||||
@@ -797,6 +838,8 @@
|
|||||||
// [config setMultipleRouteNaviMode:NO];//直接单线路径导航
|
// [config setMultipleRouteNaviMode:NO];//直接单线路径导航
|
||||||
// [config setNeedDestoryDriveManagerInstanceWhenDismiss:NO];
|
// [config setNeedDestoryDriveManagerInstanceWhenDismiss:NO];
|
||||||
|
|
||||||
|
// [config setShowDrivingStrategyPreferenceView:NO];
|
||||||
|
|
||||||
[self.compositeManager presentRoutePlanViewControllerWithOptions:config];
|
[self.compositeManager presentRoutePlanViewControllerWithOptions:config];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -978,6 +1021,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)mapView:(MAMapView *)mapView didSelectAnnotationView:(MAAnnotationView *)view {
|
- (void)mapView:(MAMapView *)mapView didSelectAnnotationView:(MAAnnotationView *)view {
|
||||||
|
self.currAnnotionView = view;
|
||||||
|
|
||||||
id pointAnnotation = view.annotation;
|
id pointAnnotation = view.annotation;
|
||||||
if ([pointAnnotation isMemberOfClass:ACustomPointAnnotation.class]) {
|
if ([pointAnnotation isMemberOfClass:ACustomPointAnnotation.class]) {
|
||||||
@@ -995,9 +1039,13 @@
|
|||||||
|
|
||||||
[self updateUIWithData:aoi textField:self.dstTf];
|
[self updateUIWithData:aoi textField:self.dstTf];
|
||||||
|
|
||||||
|
///地图选点加氢站,直接弹出开始导航弹窗(显示时间、费用、里程、路费等),不用再回填名称
|
||||||
|
//详情弹框
|
||||||
|
[self willRequestTJDInfo];
|
||||||
|
|
||||||
// 同步更新底部栏目的地文字
|
// 同步更新底部栏目的地文字
|
||||||
self.bottomBarView.destinationText = aoi.name;
|
// self.bottomBarView.destinationText = aoi.name;
|
||||||
|
self.bottomBarView.destinationText = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1009,6 +1057,7 @@
|
|||||||
self.dstPoi = nil;
|
self.dstPoi = nil;
|
||||||
self.dstTf.text = nil;
|
self.dstTf.text = nil;
|
||||||
self.bottomBarView.destinationText = nil;
|
self.bottomBarView.destinationText = nil;
|
||||||
|
self.currAnnotionView = nil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1056,6 +1105,7 @@
|
|||||||
|
|
||||||
AMapPOI *_dstPoi = self.dstPoi ? self.dstPoi : self.defaultDstPoi;
|
AMapPOI *_dstPoi = self.dstPoi ? self.dstPoi : self.defaultDstPoi;
|
||||||
if (!_dstPoi) {
|
if (!_dstPoi) {
|
||||||
|
[AMapNavCommonUtil showMsg:@"请先选择目的地"];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1066,9 +1116,19 @@
|
|||||||
navPoint.stationID = _dstPoi.uid;
|
navPoint.stationID = _dstPoi.uid;
|
||||||
self.pointModel = navPoint;
|
self.pointModel = navPoint;
|
||||||
|
|
||||||
|
if (self.stationDetailPopup) {
|
||||||
|
[self.stationDetailPopup resetUI];
|
||||||
|
}
|
||||||
|
|
||||||
///有_stationID 请求接口;无:不走接口,直接调整高德规划路线;
|
///有_stationID 请求接口;无:不走接口,直接调整高德规划路线;
|
||||||
if (!navPoint.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;
|
return;
|
||||||
}else {
|
}else {
|
||||||
__weak typeof(self) weakSelf = self;
|
__weak typeof(self) weakSelf = self;
|
||||||
@@ -1084,7 +1144,7 @@
|
|||||||
|
|
||||||
// --- 弹出站点详情弹框 ---
|
// --- 弹出站点详情弹框 ---
|
||||||
if (!self.stationDetailPopup) {
|
if (!self.stationDetailPopup) {
|
||||||
AStationDetailPopupController *popup = [[AStationDetailPopupController alloc] init];
|
AStationDetailPopupView *popup = [[AStationDetailPopupView alloc] init];
|
||||||
popup.delegate = self;
|
popup.delegate = self;
|
||||||
self.stationDetailPopup = popup;
|
self.stationDetailPopup = popup;
|
||||||
}
|
}
|
||||||
@@ -1101,13 +1161,25 @@
|
|||||||
///油费
|
///油费
|
||||||
self.stationDetailPopup.tollFee = self.tjdPathInfoModel.pathDto.tolls;
|
self.stationDetailPopup.tollFee = self.tjdPathInfoModel.pathDto.tolls;
|
||||||
|
|
||||||
[self.stationDetailPopup presentInViewController:self];
|
///新增字段信息
|
||||||
|
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 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;
|
self.stationDetailPopup = nil;
|
||||||
///点击开始导航:
|
///点击开始导航:
|
||||||
///1、有途经点,计算路线,然后再直接导航
|
///1、有途经点,计算路线,然后再直接导航
|
||||||
@@ -1126,13 +1198,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)stationDetailPopupDidTapClose:(AStationDetailPopupController *)popup {
|
- (void)stationDetailPopupViewDidTapClose:(AStationDetailPopupView *)popup {
|
||||||
self.stationDetailPopup = nil;
|
self.stationDetailPopup = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - ABottomBarViewDelegate
|
#pragma mark - ABottomBarViewDelegate
|
||||||
|
|
||||||
- (void)bottomBarViewDidTapCalRoute:(ABottomBarView *)barView {
|
- (void)bottomBarViewDidTapCalRoute:(ABottomBarView *)barView {
|
||||||
|
if (self.currAnnotionView) {
|
||||||
|
[self.mapView deselectAnnotation:self.currAnnotionView.annotation animated:NO];
|
||||||
|
self.currAnnotionView = nil;
|
||||||
|
}
|
||||||
|
|
||||||
//详情弹框
|
//详情弹框
|
||||||
[self willRequestTJDInfo];
|
[self willRequestTJDInfo];
|
||||||
@@ -1140,6 +1216,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)bottomBarViewDidTapSearchField:(ABottomBarView *)barView {
|
- (void)bottomBarViewDidTapSearchField:(ABottomBarView *)barView {
|
||||||
|
///清除上一次数据影响
|
||||||
|
self.tjdPathInfoModel = nil;
|
||||||
|
|
||||||
|
if (self.currAnnotionView) {
|
||||||
|
[self.mapView deselectAnnotation:self.currAnnotionView.annotation animated:NO];
|
||||||
|
self.currAnnotionView = nil;
|
||||||
|
}
|
||||||
|
|
||||||
// 弹出地址搜索页,选中后更新目的地输入框
|
// 弹出地址搜索页,选中后更新目的地输入框
|
||||||
ASearchAddressController *vc = [[ASearchAddressController alloc] init];
|
ASearchAddressController *vc = [[ASearchAddressController alloc] init];
|
||||||
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
|
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
|
||||||
@@ -1160,7 +1244,8 @@
|
|||||||
|
|
||||||
-(void)updateUIWithData: (AMapPOI*)poi textField: (UITextField*)tf {
|
-(void)updateUIWithData: (AMapPOI*)poi textField: (UITextField*)tf {
|
||||||
BOOL isStart = tf.tag == 100;
|
BOOL isStart = tf.tag == 100;
|
||||||
tf.text = poi.name;
|
///不显示内容
|
||||||
|
// tf.text = poi.name;
|
||||||
|
|
||||||
if (isStart) {
|
if (isStart) {
|
||||||
self.startPoi = poi;
|
self.startPoi = poi;
|
||||||
|
|||||||
@@ -18,10 +18,12 @@
|
|||||||
@property (nonatomic , strong) UIBarButtonItem *rightItem;
|
@property (nonatomic , strong) UIBarButtonItem *rightItem;
|
||||||
@property (nonatomic ,strong)UIButton * backBtn;
|
@property (nonatomic ,strong)UIButton * backBtn;
|
||||||
|
|
||||||
@property (nonatomic , strong) NSArray *dataArr;
|
@property (nonatomic , strong) NSMutableArray *dataArr;
|
||||||
|
|
||||||
@property (nonatomic, strong) UITextField *inputAddressTf;
|
@property (nonatomic, strong) UITextField *inputAddressTf;
|
||||||
@property (nonatomic, strong) AMapSearchAPI *search;
|
@property (nonatomic, strong) AMapSearchAPI *search;
|
||||||
|
@property (nonatomic,assign)NSInteger currPage;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation ASearchAddressController
|
@implementation ASearchAddressController
|
||||||
@@ -30,6 +32,9 @@
|
|||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
// Do any additional setup after loading the view.
|
// Do any additional setup after loading the view.
|
||||||
self.title = @"选择地点";
|
self.title = @"选择地点";
|
||||||
|
self.currPage = 1;
|
||||||
|
_dataArr = [NSMutableArray array];
|
||||||
|
|
||||||
|
|
||||||
[self initSubview];
|
[self initSubview];
|
||||||
|
|
||||||
@@ -65,8 +70,9 @@
|
|||||||
|
|
||||||
[inputAddressTf mas_makeConstraints:^(MASConstraintMaker *make) {
|
[inputAddressTf mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
make.left.mas_equalTo(self.view).offset(10);
|
make.left.mas_equalTo(self.view).offset(10);
|
||||||
|
make.right.mas_equalTo(self.view).offset(-10);
|
||||||
make.top.mas_equalTo(self.view).offset(kRoutePlanBarHeight + 10);
|
make.top.mas_equalTo(self.view).offset(kRoutePlanBarHeight + 10);
|
||||||
make.height.mas_equalTo(@30);
|
make.height.mas_equalTo(@35);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
self.inputAddressTf = inputAddressTf;
|
self.inputAddressTf = inputAddressTf;
|
||||||
@@ -80,6 +86,7 @@
|
|||||||
btn.layer.borderWidth = 1;
|
btn.layer.borderWidth = 1;
|
||||||
btn.layer.cornerRadius = 5;
|
btn.layer.cornerRadius = 5;
|
||||||
btn.titleLabel.font = [UIFont systemFontOfSize:12];
|
btn.titleLabel.font = [UIFont systemFontOfSize:12];
|
||||||
|
btn.hidden = YES;
|
||||||
|
|
||||||
[btn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
|
[btn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
|
||||||
[btn addTarget:self action:@selector(searchBtnAction) forControlEvents:UIControlEventTouchUpInside];
|
[btn addTarget:self action:@selector(searchBtnAction) forControlEvents:UIControlEventTouchUpInside];
|
||||||
@@ -134,6 +141,14 @@
|
|||||||
// [self.navigationController popViewControllerAnimated:YES];
|
// [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 -
|
#pragma mark -
|
||||||
- (UITableView *)tableView {
|
- (UITableView *)tableView {
|
||||||
if (!_tableView) {
|
if (!_tableView) {
|
||||||
@@ -178,28 +193,32 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[self requestAddressWithAddress:addr atPage:1];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void)requestAddressWithAddress:(NSString *)addr atPage:(NSInteger)page {
|
||||||
AMapPOIKeywordsSearchRequest *request = [[AMapPOIKeywordsSearchRequest alloc] init];
|
AMapPOIKeywordsSearchRequest *request = [[AMapPOIKeywordsSearchRequest alloc] init];
|
||||||
|
|
||||||
request.keywords = addr;
|
request.keywords = addr;
|
||||||
|
|
||||||
AMapNavSDKManager * sdk = [AMapNavSDKManager sharedManager];
|
AMapNavSDKManager * sdk = [AMapNavSDKManager sharedManager];
|
||||||
request.city = sdk.localCity;
|
// request.city = sdk.localCity;
|
||||||
|
|
||||||
|
|
||||||
// request.types = @"高等院校";
|
// request.types = @"高等院校";
|
||||||
// request.requireExtension = YES;
|
// request.requireExtension = YES;
|
||||||
request.offset =20;
|
request.offset =20;
|
||||||
|
request.page = page;
|
||||||
|
|
||||||
/* 搜索SDK 3.2.0 中新增加的功能,只搜索本城市的POI。*/
|
/* 搜索SDK 3.2.0 中新增加的功能,只搜索本城市的POI。*/
|
||||||
request.cityLimit = YES;
|
// request.cityLimit = YES;
|
||||||
// request.requireSubPOIs = YES;
|
// request.requireSubPOIs = YES;
|
||||||
|
|
||||||
|
|
||||||
[self.search AMapPOIKeywordsSearch:request];
|
[self.search AMapPOIKeywordsSearch:request];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
/* POI 搜索回调. */
|
/* POI 搜索回调. */
|
||||||
- (void)onPOISearchDone:(AMapPOISearchBaseRequest *)request response:(AMapPOISearchResponse *)response
|
- (void)onPOISearchDone:(AMapPOISearchBaseRequest *)request response:(AMapPOISearchResponse *)response
|
||||||
@@ -212,7 +231,8 @@
|
|||||||
|
|
||||||
//解析response获取POI信息,具体解析见 Demo
|
//解析response获取POI信息,具体解析见 Demo
|
||||||
|
|
||||||
self.dataArr = [NSArray arrayWithArray:pois];
|
[self.dataArr addObjectsFromArray:pois];
|
||||||
|
|
||||||
[self.tableView reloadData];
|
[self.tableView reloadData];
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -221,6 +241,8 @@
|
|||||||
|
|
||||||
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
|
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
|
||||||
[textField resignFirstResponder];
|
[textField resignFirstResponder];
|
||||||
|
[self.dataArr removeAllObjects];
|
||||||
|
self.currPage = 1;
|
||||||
|
|
||||||
[self startSearchWithAddress:textField.text];
|
[self startSearchWithAddress:textField.text];
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,19 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
/// 过路费,如 @"30元";若 nil 则隐藏
|
/// 过路费,如 @"30元";若 nil 则隐藏
|
||||||
@property (nonatomic, copy, nullable) NSString *tollFee;
|
@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<AStationDetailPopupDelegate> delegate;
|
@property (nonatomic, weak, nullable) id<AStationDetailPopupDelegate> delegate;
|
||||||
|
|
||||||
/// 以半透明蒙层方式弹出在目标控制器上
|
/// 以半透明蒙层方式弹出在目标控制器上
|
||||||
@@ -50,6 +63,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
/// 关闭弹框,动画结束后执行 completion(用于关闭后再 present 其他页面)
|
/// 关闭弹框,动画结束后执行 completion(用于关闭后再 present 其他页面)
|
||||||
- (void)dismissWithCompletion:(nullable void(^)(void))completion;
|
- (void)dismissWithCompletion:(nullable void(^)(void))completion;
|
||||||
|
|
||||||
|
|
||||||
|
-(void)resetUI;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|||||||
@@ -57,6 +57,21 @@ static inline UIColor *AStationThemeGreen(void) {
|
|||||||
/// 卡片 bottom constraint(动画用)
|
/// 卡片 bottom constraint(动画用)
|
||||||
@property (nonatomic, strong) MASConstraint *cardBottomConstraint;
|
@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
|
@end
|
||||||
|
|
||||||
@implementation AStationDetailPopupController
|
@implementation AStationDetailPopupController
|
||||||
@@ -121,6 +136,26 @@ static inline UIColor *AStationThemeGreen(void) {
|
|||||||
if (self.isViewLoaded) [self _updateUI];
|
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
|
#pragma mark - Build UI
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -168,10 +203,13 @@ static inline UIColor *AStationThemeGreen(void) {
|
|||||||
[card addSubview:closeBtn];
|
[card addSubview:closeBtn];
|
||||||
self.closeButton = closeBtn;
|
self.closeButton = closeBtn;
|
||||||
|
|
||||||
|
UIColor * headTextColor = [UIColor hp_colorWithRGBHex:0x1D2129];
|
||||||
|
UIFont * headTextFont = [UIFont hp_pingFangMedium:14];
|
||||||
|
|
||||||
// ── 站点名称 ──
|
// ── 站点名称 ──
|
||||||
UILabel *nameLabel = [[UILabel alloc] init];
|
UILabel *nameLabel = [[UILabel alloc] init];
|
||||||
nameLabel.font = [UIFont boldSystemFontOfSize:18];
|
nameLabel.font = [UIFont hp_pingFangMedium:18];
|
||||||
nameLabel.textColor = [UIColor colorWithWhite:0.1 alpha:1];
|
nameLabel.textColor = headTextColor;
|
||||||
nameLabel.numberOfLines = 2;
|
nameLabel.numberOfLines = 2;
|
||||||
// nameLabel.adjustsFontSizeToFitWidth = YES;
|
// nameLabel.adjustsFontSizeToFitWidth = YES;
|
||||||
nameLabel.minimumScaleFactor = 0.8;
|
nameLabel.minimumScaleFactor = 0.8;
|
||||||
@@ -180,8 +218,8 @@ static inline UIColor *AStationThemeGreen(void) {
|
|||||||
|
|
||||||
// ── 预计加氢费用(名称右侧,间距20pt) ──
|
// ── 预计加氢费用(名称右侧,间距20pt) ──
|
||||||
UILabel *costLabel = [[UILabel alloc] init];
|
UILabel *costLabel = [[UILabel alloc] init];
|
||||||
costLabel.font = [UIFont systemFontOfSize:14];
|
costLabel.font = headTextFont;
|
||||||
costLabel.textColor = [UIColor colorWithWhite:0.2 alpha:1];
|
costLabel.textColor = headTextColor;
|
||||||
costLabel.numberOfLines = 1;
|
costLabel.numberOfLines = 1;
|
||||||
costLabel.textAlignment = NSTextAlignmentLeft;
|
costLabel.textAlignment = NSTextAlignmentLeft;
|
||||||
// [costLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
|
// [costLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
|
||||||
@@ -189,10 +227,18 @@ static inline UIColor *AStationThemeGreen(void) {
|
|||||||
[card addSubview:costLabel];
|
[card addSubview:costLabel];
|
||||||
self.costLabel = 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];
|
UILabel *addrLabel = [[UILabel alloc] init];
|
||||||
addrLabel.font = [UIFont systemFontOfSize:13];
|
addrLabel.font = [UIFont hp_pingFangRegular:14];
|
||||||
addrLabel.textColor = [UIColor colorWithWhite:0.5 alpha:1];
|
addrLabel.textColor = [UIColor hp_colorWithRGBHex:0x86909C];
|
||||||
addrLabel.numberOfLines = 2;
|
addrLabel.numberOfLines = 2;
|
||||||
[card addSubview:addrLabel];
|
[card addSubview:addrLabel];
|
||||||
self.addressLabel = addrLabel;
|
self.addressLabel = addrLabel;
|
||||||
@@ -212,45 +258,84 @@ static inline UIColor *AStationThemeGreen(void) {
|
|||||||
// ── 预计时间图标 ──
|
// ── 预计时间图标 ──
|
||||||
UIImageView *timeIcon = [[UIImageView alloc] init];
|
UIImageView *timeIcon = [[UIImageView alloc] init];
|
||||||
timeIcon.contentMode = UIViewContentModeScaleAspectFit;
|
timeIcon.contentMode = UIViewContentModeScaleAspectFit;
|
||||||
timeIcon.image = [AMapNavCommonUtil imageWithName3x:@"pre_time_icon"];
|
timeIcon.image = [AMapNavCommonUtil imageWithName3x:@"ic_time"];
|
||||||
[card addSubview:timeIcon];
|
[card addSubview:timeIcon];
|
||||||
self.timeIconView = timeIcon;
|
self.timeIconView = timeIcon;
|
||||||
|
|
||||||
// ── 预计时间文字 ──
|
// ── 预计时间文字 ──
|
||||||
UILabel *timeLabel = [[UILabel alloc] init];
|
UILabel *timeLabel = [[UILabel alloc] init];
|
||||||
timeLabel.font = [UIFont systemFontOfSize:14];
|
timeLabel.font = headTextFont;
|
||||||
timeLabel.textColor = [UIColor colorWithWhite:0.2 alpha:1];
|
timeLabel.textColor = headTextColor;
|
||||||
[card addSubview:timeLabel];
|
[card addSubview:timeLabel];
|
||||||
self.timeLabel = timeLabel;
|
self.timeLabel = timeLabel;
|
||||||
|
|
||||||
// ── 行驶里程图标 ──
|
// ── 行驶里程图标 ──
|
||||||
UIImageView *distIcon = [[UIImageView alloc] init];
|
UIImageView *distIcon = [[UIImageView alloc] init];
|
||||||
distIcon.contentMode = UIViewContentModeScaleAspectFit;
|
distIcon.contentMode = UIViewContentModeScaleAspectFit;
|
||||||
distIcon.image = [AMapNavCommonUtil imageWithName3x:@"pre_distance_icon"];
|
distIcon.image = [AMapNavCommonUtil imageWithName3x:@"ic_mileage"];
|
||||||
[card addSubview:distIcon];
|
[card addSubview:distIcon];
|
||||||
self.distanceIconView = distIcon;
|
self.distanceIconView = distIcon;
|
||||||
|
|
||||||
// ── 行驶里程文字 ──
|
// ── 行驶里程文字 ──
|
||||||
UILabel *distLabel = [[UILabel alloc] init];
|
UILabel *distLabel = [[UILabel alloc] init];
|
||||||
distLabel.font = [UIFont systemFontOfSize:14];
|
distLabel.font = headTextFont;
|
||||||
distLabel.textColor = [UIColor colorWithWhite:0.2 alpha:1];
|
distLabel.textColor = headTextColor;
|
||||||
[card addSubview:distLabel];
|
[card addSubview:distLabel];
|
||||||
self.distanceLabel = distLabel;
|
self.distanceLabel = distLabel;
|
||||||
|
|
||||||
// ── 过路费图标 ──
|
// ── 过路费图标 ──
|
||||||
UIImageView *tollIcon = [[UIImageView alloc] init];
|
UIImageView *tollIcon = [[UIImageView alloc] init];
|
||||||
tollIcon.contentMode = UIViewContentModeScaleAspectFit;
|
tollIcon.contentMode = UIViewContentModeScaleAspectFit;
|
||||||
tollIcon.image = [AMapNavCommonUtil imageWithName3x:@"pre_cost_icon"];
|
tollIcon.image = [AMapNavCommonUtil imageWithName3x:@"ic_toll"];
|
||||||
[card addSubview:tollIcon];
|
[card addSubview:tollIcon];
|
||||||
self.tollIconView = tollIcon;
|
self.tollIconView = tollIcon;
|
||||||
|
|
||||||
// ── 过路费文字 ──
|
// ── 过路费文字 ──
|
||||||
UILabel *tollLabel = [[UILabel alloc] init];
|
UILabel *tollLabel = [[UILabel alloc] init];
|
||||||
tollLabel.font = [UIFont systemFontOfSize:14];
|
tollLabel.font = headTextFont;
|
||||||
tollLabel.textColor = [UIColor colorWithWhite:0.2 alpha:1];
|
tollLabel.textColor = headTextColor;
|
||||||
[card addSubview:tollLabel];
|
[card addSubview:tollLabel];
|
||||||
self.tollLabel = 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];
|
UIButton *naviBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||||
[naviBtn setTitle:@"开始导航" forState:UIControlStateNormal];
|
[naviBtn setTitle:@"开始导航" forState:UIControlStateNormal];
|
||||||
@@ -301,24 +386,34 @@ static inline UIColor *AStationThemeGreen(void) {
|
|||||||
make.right.equalTo(self.closeButton.mas_left).offset(-12);
|
make.right.equalTo(self.closeButton.mas_left).offset(-12);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
// ── 地址(名称下方,6pt间距) ──
|
// ── 营业时间(站点名称下方,6pt间距) ──
|
||||||
[self.addressLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
[self.businessHoursLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
make.top.equalTo(self.stationNameLabel.mas_bottom).offset(10);
|
make.top.equalTo(self.stationNameLabel.mas_bottom).offset(10);
|
||||||
make.left.equalTo(card).offset(16);
|
make.left.equalTo(card).offset(16);
|
||||||
make.right.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间距) ──
|
// ── 分割线(地址下方,12pt间距) ──
|
||||||
[self.separator mas_makeConstraints:^(MASConstraintMaker *make) {
|
[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.left.equalTo(card).offset(16);
|
||||||
make.right.equalTo(card).offset(-16);
|
make.right.equalTo(card).offset(-16);
|
||||||
make.height.mas_equalTo(0.5);
|
make.height.mas_equalTo(0.5);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
CGFloat _offset_y = 18;
|
||||||
|
|
||||||
// ── 预计时间行(分割线下方,14pt) ──
|
// ── 预计时间行(分割线下方,14pt) ──
|
||||||
[self.timeIconView mas_makeConstraints:^(MASConstraintMaker *make) {
|
[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.left.equalTo(card).offset(16);
|
||||||
make.width.height.mas_equalTo(iconSize);
|
make.width.height.mas_equalTo(iconSize);
|
||||||
}];
|
}];
|
||||||
@@ -333,7 +428,7 @@ static inline UIColor *AStationThemeGreen(void) {
|
|||||||
///cost
|
///cost
|
||||||
[self.costIconView mas_makeConstraints:^(MASConstraintMaker *make) {
|
[self.costIconView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
make.centerY.equalTo(self.timeIconView);
|
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);
|
make.width.height.mas_equalTo(iconSize);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
@@ -346,7 +441,7 @@ static inline UIColor *AStationThemeGreen(void) {
|
|||||||
|
|
||||||
// ── 行驶里程 + 过路费行(时间行下方,12pt) ──
|
// ── 行驶里程 + 过路费行(时间行下方,12pt) ──
|
||||||
[self.distanceIconView mas_makeConstraints:^(MASConstraintMaker *make) {
|
[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.left.equalTo(card).offset(16);
|
||||||
make.width.height.mas_equalTo(iconSize);
|
make.width.height.mas_equalTo(iconSize);
|
||||||
}];
|
}];
|
||||||
@@ -372,9 +467,49 @@ static inline UIColor *AStationThemeGreen(void) {
|
|||||||
make.height.mas_equalTo(24);
|
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) {
|
[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.left.equalTo(card).offset(16);
|
||||||
make.right.equalTo(card).offset(-16);
|
make.right.equalTo(card).offset(-16);
|
||||||
make.height.mas_equalTo(48);
|
make.height.mas_equalTo(48);
|
||||||
@@ -386,29 +521,63 @@ static inline UIColor *AStationThemeGreen(void) {
|
|||||||
|
|
||||||
- (void)_updateUI {
|
- (void)_updateUI {
|
||||||
self.stationNameLabel.text = (self.pointModel.name.length > 0)
|
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)
|
self.costLabel.text = (self.estimatedCost.length > 0)
|
||||||
? [NSString stringWithFormat:@"预计加氢费用:%@元", self.estimatedCost]
|
? [NSString stringWithFormat:@"预计加氢费用:%@元", self.estimatedCost]
|
||||||
: @"预计加氢费用:--元";
|
: @"预计加氢费用:-";
|
||||||
|
|
||||||
self.addressLabel.text = (self.pointModel.address.length > 0)
|
self.addressLabel.text = (self.pointModel.address.length > 0)
|
||||||
? self.pointModel.address : @"--";
|
? self.pointModel.address : @"-";
|
||||||
|
|
||||||
// ── 预计时间(始终显示,无值显示"-- 分钟") ──
|
// ── 预计时间(始终显示,无值显示"-- 分钟") ──
|
||||||
self.timeLabel.text = (self.estimatedTime.length > 0)
|
self.timeLabel.text = (self.estimatedTime.length > 0)
|
||||||
? [NSString stringWithFormat:@"预计时间:%@分钟", self.estimatedTime]
|
? [NSString stringWithFormat:@"预计时间:%@分钟", self.estimatedTime]
|
||||||
: @"预计时间:--分钟";
|
: @"预计时间:-";
|
||||||
|
|
||||||
// ── 行驶里程(始终显示,无值显示"-- 公里") ──
|
// ── 行驶里程(始终显示,无值显示"-- 公里") ──
|
||||||
self.distanceLabel.text = (self.driveDistance.length > 0)
|
self.distanceLabel.text = (self.driveDistance.length > 0)
|
||||||
? [NSString stringWithFormat:@"行驶里程:%@公里", self.driveDistance]
|
? [NSString stringWithFormat:@"行驶里程:%@公里", self.driveDistance]
|
||||||
: @"行驶里程:--公里";
|
: @"行驶里程:-";
|
||||||
|
|
||||||
// ── 过路费(始终显示,无值显示"-- 元") ──
|
// ── 过路费(始终显示,无值显示"-- 元") ──
|
||||||
self.tollLabel.text = (self.tollFee.length > 0)
|
self.tollLabel.text = (self.tollFee.length > 0)
|
||||||
? [NSString stringWithFormat:@"过路费:%@元", self.tollFee]
|
? [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
|
#pragma mark - Animation
|
||||||
|
|||||||
@@ -59,6 +59,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
@property (nonatomic, copy, nullable) NSString *latitude;
|
@property (nonatomic, copy, nullable) NSString *latitude;
|
||||||
@property (nonatomic, copy, nullable) NSString *distance;
|
@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
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
#import "UIColor+ANavMap.h"
|
||||||
|
#import "UIFont+HP.h"
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@@ -34,6 +36,8 @@ BOOL stringIsEmpty(NSString *str);
|
|||||||
/// 判断字符串是否非空
|
/// 判断字符串是否非空
|
||||||
BOOL stringIsNotEmpty(NSString *str);
|
BOOL stringIsNotEmpty(NSString *str);
|
||||||
|
|
||||||
|
+(NSString *)stringValueFromStr:(NSString *)str;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|||||||
@@ -117,6 +117,15 @@ BOOL stringIsNotEmpty (NSString *str)
|
|||||||
return ! stringIsEmpty(str);
|
return ! stringIsEmpty(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 字符串转数值
|
||||||
|
+(NSString *)stringValueFromStr:(NSString *)str {
|
||||||
|
if (stringIsEmpty(str)) {
|
||||||
|
return @"";
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - 获取图片
|
#pragma mark - 获取图片
|
||||||
+(UIImage *)imageWithName:(NSString *)name {
|
+(UIImage *)imageWithName:(NSString *)name {
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
//
|
||||||
|
// UIColor+ANavMap.h
|
||||||
|
// AMapNavIOSSDK
|
||||||
|
//
|
||||||
|
// Created by admin on 2026/4/11.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
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
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
//
|
||||||
|
// UIFont+HP.h
|
||||||
|
// Hippo
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
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
|
||||||
@@ -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
|
||||||
@@ -163,6 +163,7 @@ static inline UIColor *ABottomBarThemeGreen(void) {
|
|||||||
self.calRouteButton = btn;
|
self.calRouteButton = btn;
|
||||||
|
|
||||||
CGFloat off_y = AMP_TabbarHeight;
|
CGFloat off_y = AMP_TabbarHeight;
|
||||||
|
off_y = 0;
|
||||||
#ifdef kAMapSDKDebugFlag
|
#ifdef kAMapSDKDebugFlag
|
||||||
off_y = 0;
|
off_y = 0;
|
||||||
#endif
|
#endif
|
||||||
@@ -172,7 +173,7 @@ static inline UIColor *ABottomBarThemeGreen(void) {
|
|||||||
make.left.equalTo(card).offset(16);
|
make.left.equalTo(card).offset(16);
|
||||||
make.right.equalTo(card).offset(-16);
|
make.right.equalTo(card).offset(-16);
|
||||||
make.height.mas_equalTo(48);
|
make.height.mas_equalTo(48);
|
||||||
make.bottom.equalTo(card).offset(-40 - off_y);
|
make.bottom.equalTo(card).offset(-40 + (-AMP_TabbarHeight - 13));
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
//
|
||||||
|
// AStationDetailPopupView.h
|
||||||
|
// AMapNavIOSSDK
|
||||||
|
//
|
||||||
|
// Created by admin on 2026/3/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import "ANavPointModel.h"
|
||||||
|
#import "AMapNavSDKHeader.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@class AStationDetailPopupView;
|
||||||
|
|
||||||
|
@protocol AStationDetailPopupViewDelegate <NSObject>
|
||||||
|
|
||||||
|
@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<AStationDetailPopupViewDelegate> delegate;
|
||||||
|
|
||||||
|
/// 显示弹框动画
|
||||||
|
- (void)showInView:(UIView *)parentView;
|
||||||
|
|
||||||
|
/// 隐藏弹框动画
|
||||||
|
- (void)hideWithCompletion:(nullable void(^)(void))completion;
|
||||||
|
|
||||||
|
/// 隐藏弹框动画(无 completion)
|
||||||
|
- (void)hide;
|
||||||
|
|
||||||
|
/// 重置 UI 状态
|
||||||
|
- (void)resetUI;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,707 @@
|
|||||||
|
//
|
||||||
|
// AStationDetailPopupView.m
|
||||||
|
// AMapNavIOSSDK
|
||||||
|
//
|
||||||
|
// Created by admin on 2026/3/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "AStationDetailPopupView.h"
|
||||||
|
#import "AMapNavCommonUtil.h"
|
||||||
|
#import <Masonry/Masonry.h>
|
||||||
|
|
||||||
|
// 主题绿色(开始导航按钮背景)
|
||||||
|
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;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation AStationDetailPopupView
|
||||||
|
|
||||||
|
#pragma mark - Init
|
||||||
|
|
||||||
|
- (instancetype)initWithFrame:(CGRect)frame {
|
||||||
|
self = [super initWithFrame:frame];
|
||||||
|
if (self) {
|
||||||
|
self.backgroundColor = [UIColor clearColor];
|
||||||
|
[self setupUI];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Setup UI
|
||||||
|
|
||||||
|
- (void)setupUI {
|
||||||
|
[self addSubview:self.maskControl];
|
||||||
|
[self.cardView addSubview:self.closeButton];
|
||||||
|
[self.cardView addSubview:self.stationNameLabel];
|
||||||
|
[self.cardView addSubview:self.costLabel];
|
||||||
|
[self.cardView addSubview:self.businessHoursLabel];
|
||||||
|
[self.cardView addSubview:self.addressLabel];
|
||||||
|
[self.cardView addSubview:self.costIconView];
|
||||||
|
[self.cardView addSubview:self.separator];
|
||||||
|
[self.cardView addSubview:self.timeIconView];
|
||||||
|
[self.cardView addSubview:self.timeLabel];
|
||||||
|
[self.cardView addSubview:self.distanceIconView];
|
||||||
|
[self.cardView addSubview:self.distanceLabel];
|
||||||
|
[self.cardView addSubview:self.tollIconView];
|
||||||
|
[self.cardView addSubview:self.tollLabel];
|
||||||
|
[self.cardView addSubview:self.contactPersonIconView];
|
||||||
|
[self.cardView addSubview:self.contactPersonLabel];
|
||||||
|
[self.cardView addSubview:self.priceIconView];
|
||||||
|
[self.cardView addSubview:self.priceLabel];
|
||||||
|
[self.cardView addSubview:self.phoneIconView];
|
||||||
|
[self.cardView addSubview:self.phoneLabel];
|
||||||
|
[self.cardView addSubview:self.startNaviButton];
|
||||||
|
|
||||||
|
[self setupConstraints];
|
||||||
|
[self updateUI];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Masonry Constraints
|
||||||
|
|
||||||
|
- (void)setupConstraints {
|
||||||
|
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 + (-AMP_TabbarHeight - 13));
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}];
|
||||||
|
[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 - 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) && [self.estimatedCost doubleValue])
|
||||||
|
? [NSString stringWithFormat:@"预计加氢费用:%@元", self.estimatedCost]
|
||||||
|
: @"预计加氢费用:-";
|
||||||
|
|
||||||
|
self.addressLabel.text = (self.pointModel.address.length > 0)
|
||||||
|
? self.pointModel.address : @"-";
|
||||||
|
|
||||||
|
// ── 预计时间(始终显示,无值显示"-- 分钟") ──
|
||||||
|
self.timeLabel.text = ((self.estimatedTime.length > 0) && [self.estimatedTime doubleValue] > 0)
|
||||||
|
? [NSString stringWithFormat:@"预计时间:%@分钟", self.estimatedTime]
|
||||||
|
: @"预计时间:-";
|
||||||
|
|
||||||
|
// ── 行驶里程(始终显示,无值显示"-- 公里") ──
|
||||||
|
self.distanceLabel.text = ((self.driveDistance.length > 0) && [self.driveDistance doubleValue] > 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]
|
||||||
|
: @"联系方式:-";
|
||||||
|
}
|
||||||
|
|
||||||
|
- (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(0);
|
||||||
|
}];
|
||||||
|
|
||||||
|
[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];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Lazy Load
|
||||||
|
|
||||||
|
- (UIControl *)maskControl {
|
||||||
|
if (!_maskControl) {
|
||||||
|
_maskControl = [[UIControl alloc] init];
|
||||||
|
_maskControl.backgroundColor = [UIColor colorWithWhite:0 alpha:0];
|
||||||
|
[_maskControl addTarget:self action:@selector(onMaskTapped) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
}
|
||||||
|
return _maskControl;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIView *)cardView {
|
||||||
|
if (!_cardView) {
|
||||||
|
_cardView = [[UIView alloc] init];
|
||||||
|
_cardView.backgroundColor = [UIColor whiteColor];
|
||||||
|
_cardView.layer.cornerRadius = 16;
|
||||||
|
_cardView.layer.masksToBounds = NO;
|
||||||
|
_cardView.layer.shadowColor = [UIColor blackColor].CGColor;
|
||||||
|
_cardView.layer.shadowOpacity = 0.15;
|
||||||
|
_cardView.layer.shadowRadius = 12;
|
||||||
|
_cardView.layer.shadowOffset = CGSizeMake(0, -4);
|
||||||
|
[self addSubview:_cardView];
|
||||||
|
}
|
||||||
|
return _cardView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIButton *)closeButton {
|
||||||
|
if (!_closeButton) {
|
||||||
|
_closeButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||||
|
[_closeButton setImage:[AMapNavCommonUtil imageWithName:@"icon_close"] forState:UIControlStateNormal];
|
||||||
|
[_closeButton setTitleColor:[UIColor colorWithWhite:0.5 alpha:1] forState:UIControlStateNormal];
|
||||||
|
_closeButton.titleLabel.font = [UIFont systemFontOfSize:16];
|
||||||
|
[_closeButton addTarget:self action:@selector(onCloseTapped) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
}
|
||||||
|
return _closeButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UILabel *)stationNameLabel {
|
||||||
|
if (!_stationNameLabel) {
|
||||||
|
_stationNameLabel = [[UILabel alloc] init];
|
||||||
|
_stationNameLabel.font = [UIFont hp_pingFangMedium:18];
|
||||||
|
_stationNameLabel.textColor = [UIColor hp_colorWithRGBHex:0x1D2129];
|
||||||
|
_stationNameLabel.numberOfLines = 2;
|
||||||
|
_stationNameLabel.minimumScaleFactor = 0.8;
|
||||||
|
}
|
||||||
|
return _stationNameLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UILabel *)costLabel {
|
||||||
|
if (!_costLabel) {
|
||||||
|
_costLabel = [[UILabel alloc] init];
|
||||||
|
_costLabel.font = [UIFont hp_pingFangMedium:14];
|
||||||
|
_costLabel.textColor = [UIColor hp_colorWithRGBHex:0x1D2129];
|
||||||
|
_costLabel.numberOfLines = 1;
|
||||||
|
_costLabel.textAlignment = NSTextAlignmentLeft;
|
||||||
|
}
|
||||||
|
return _costLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UILabel *)businessHoursLabel {
|
||||||
|
if (!_businessHoursLabel) {
|
||||||
|
_businessHoursLabel = [[UILabel alloc] init];
|
||||||
|
_businessHoursLabel.font = [UIFont hp_pingFangRegular:14];
|
||||||
|
_businessHoursLabel.textColor = [UIColor hp_colorWithRGBHex:0x1D2129];
|
||||||
|
_businessHoursLabel.numberOfLines = 1;
|
||||||
|
}
|
||||||
|
return _businessHoursLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UILabel *)addressLabel {
|
||||||
|
if (!_addressLabel) {
|
||||||
|
_addressLabel = [[UILabel alloc] init];
|
||||||
|
_addressLabel.font = [UIFont hp_pingFangRegular:14];
|
||||||
|
_addressLabel.textColor = [UIColor hp_colorWithRGBHex:0x86909C];
|
||||||
|
_addressLabel.numberOfLines = 2;
|
||||||
|
}
|
||||||
|
return _addressLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIImageView *)costIconView {
|
||||||
|
if (!_costIconView) {
|
||||||
|
_costIconView = [[UIImageView alloc] init];
|
||||||
|
_costIconView.contentMode = UIViewContentModeScaleAspectFit;
|
||||||
|
_costIconView.image = [AMapNavCommonUtil imageWithName3x:@"ic_fuel"];
|
||||||
|
}
|
||||||
|
return _costIconView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIView *)separator {
|
||||||
|
if (!_separator) {
|
||||||
|
_separator = [[UIView alloc] init];
|
||||||
|
_separator.backgroundColor = [UIColor colorWithWhite:0.88 alpha:1];
|
||||||
|
_separator.hidden = YES;
|
||||||
|
}
|
||||||
|
return _separator;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIImageView *)timeIconView {
|
||||||
|
if (!_timeIconView) {
|
||||||
|
_timeIconView = [[UIImageView alloc] init];
|
||||||
|
_timeIconView.contentMode = UIViewContentModeScaleAspectFit;
|
||||||
|
_timeIconView.image = [AMapNavCommonUtil imageWithName3x:@"ic_time"];
|
||||||
|
}
|
||||||
|
return _timeIconView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UILabel *)timeLabel {
|
||||||
|
if (!_timeLabel) {
|
||||||
|
_timeLabel = [[UILabel alloc] init];
|
||||||
|
_timeLabel.font = [UIFont hp_pingFangMedium:14];
|
||||||
|
_timeLabel.textColor = [UIColor hp_colorWithRGBHex:0x1D2129];
|
||||||
|
}
|
||||||
|
return _timeLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIImageView *)distanceIconView {
|
||||||
|
if (!_distanceIconView) {
|
||||||
|
_distanceIconView = [[UIImageView alloc] init];
|
||||||
|
_distanceIconView.contentMode = UIViewContentModeScaleAspectFit;
|
||||||
|
_distanceIconView.image = [AMapNavCommonUtil imageWithName3x:@"ic_mileage"];
|
||||||
|
}
|
||||||
|
return _distanceIconView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UILabel *)distanceLabel {
|
||||||
|
if (!_distanceLabel) {
|
||||||
|
_distanceLabel = [[UILabel alloc] init];
|
||||||
|
_distanceLabel.font = [UIFont hp_pingFangMedium:14];
|
||||||
|
_distanceLabel.textColor = [UIColor hp_colorWithRGBHex:0x1D2129];
|
||||||
|
}
|
||||||
|
return _distanceLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIImageView *)tollIconView {
|
||||||
|
if (!_tollIconView) {
|
||||||
|
_tollIconView = [[UIImageView alloc] init];
|
||||||
|
_tollIconView.contentMode = UIViewContentModeScaleAspectFit;
|
||||||
|
_tollIconView.image = [AMapNavCommonUtil imageWithName3x:@"ic_toll"];
|
||||||
|
}
|
||||||
|
return _tollIconView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UILabel *)tollLabel {
|
||||||
|
if (!_tollLabel) {
|
||||||
|
_tollLabel = [[UILabel alloc] init];
|
||||||
|
_tollLabel.font = [UIFont hp_pingFangMedium:14];
|
||||||
|
_tollLabel.textColor = [UIColor hp_colorWithRGBHex:0x1D2129];
|
||||||
|
}
|
||||||
|
return _tollLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIImageView *)contactPersonIconView {
|
||||||
|
if (!_contactPersonIconView) {
|
||||||
|
_contactPersonIconView = [[UIImageView alloc] init];
|
||||||
|
_contactPersonIconView.contentMode = UIViewContentModeScaleAspectFit;
|
||||||
|
_contactPersonIconView.image = [AMapNavCommonUtil imageWithName3x:@"ic_person"];
|
||||||
|
}
|
||||||
|
return _contactPersonIconView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UILabel *)contactPersonLabel {
|
||||||
|
if (!_contactPersonLabel) {
|
||||||
|
_contactPersonLabel = [[UILabel alloc] init];
|
||||||
|
_contactPersonLabel.font = [UIFont hp_pingFangMedium:14];
|
||||||
|
_contactPersonLabel.textColor = [UIColor hp_colorWithRGBHex:0x1D2129];
|
||||||
|
}
|
||||||
|
return _contactPersonLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIImageView *)priceIconView {
|
||||||
|
if (!_priceIconView) {
|
||||||
|
_priceIconView = [[UIImageView alloc] init];
|
||||||
|
_priceIconView.contentMode = UIViewContentModeScaleAspectFit;
|
||||||
|
_priceIconView.image = [AMapNavCommonUtil imageWithName3x:@"ic_price"];
|
||||||
|
}
|
||||||
|
return _priceIconView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UILabel *)priceLabel {
|
||||||
|
if (!_priceLabel) {
|
||||||
|
_priceLabel = [[UILabel alloc] init];
|
||||||
|
_priceLabel.font = [UIFont hp_pingFangMedium:14];
|
||||||
|
_priceLabel.textColor = [UIColor hp_colorWithRGBHex:0x1D2129];
|
||||||
|
}
|
||||||
|
return _priceLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIImageView *)phoneIconView {
|
||||||
|
if (!_phoneIconView) {
|
||||||
|
_phoneIconView = [[UIImageView alloc] init];
|
||||||
|
_phoneIconView.contentMode = UIViewContentModeScaleAspectFit;
|
||||||
|
_phoneIconView.image = [AMapNavCommonUtil imageWithName3x:@"ic_phone"];
|
||||||
|
}
|
||||||
|
return _phoneIconView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UILabel *)phoneLabel {
|
||||||
|
if (!_phoneLabel) {
|
||||||
|
_phoneLabel = [[UILabel alloc] init];
|
||||||
|
_phoneLabel.font = [UIFont hp_pingFangMedium:14];
|
||||||
|
_phoneLabel.textColor = [UIColor hp_colorWithRGBHex:0x1D2129];
|
||||||
|
}
|
||||||
|
return _phoneLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIButton *)startNaviButton {
|
||||||
|
if (!_startNaviButton) {
|
||||||
|
_startNaviButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||||
|
[_startNaviButton setTitle:@"开始导航" forState:UIControlStateNormal];
|
||||||
|
[_startNaviButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
||||||
|
_startNaviButton.titleLabel.font = [UIFont boldSystemFontOfSize:17];
|
||||||
|
_startNaviButton.backgroundColor = AStationThemeGreen();
|
||||||
|
_startNaviButton.layer.cornerRadius = 24;
|
||||||
|
[_startNaviButton addTarget:self action:@selector(onStartNaviTapped) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
}
|
||||||
|
return _startNaviButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -7,6 +7,7 @@ import 'package:ln_jq_app/pages/c_page/car_info/view.dart';
|
|||||||
import 'package:ln_jq_app/pages/c_page/mine/view.dart';
|
import 'package:ln_jq_app/pages/c_page/mine/view.dart';
|
||||||
import 'package:ln_jq_app/pages/c_page/reservation/view.dart';
|
import 'package:ln_jq_app/pages/c_page/reservation/view.dart';
|
||||||
|
|
||||||
|
import '../mall/mall_view.dart';
|
||||||
import 'index.dart';
|
import 'index.dart';
|
||||||
|
|
||||||
class BaseWidgetsPage extends GetView<BaseWidgetsController> {
|
class BaseWidgetsPage extends GetView<BaseWidgetsController> {
|
||||||
@@ -33,7 +34,7 @@ class BaseWidgetsPage extends GetView<BaseWidgetsController> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _buildPages() {
|
List<Widget> _buildPages() {
|
||||||
return [ReservationPage(), NativePageIOS(), CarInfoPage(), MinePage()];
|
return [ReservationPage(), NativePageIOS(), MallPage(), CarInfoPage(), MinePage()];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 自定义导航栏 (悬浮胶囊样式)
|
// 自定义导航栏 (悬浮胶囊样式)
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 1.2.4+7
|
version: 1.2.5+8
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.9.0
|
sdk: ^3.9.0
|
||||||
|
|||||||