From 15f5680b532238290d0adf095a93e5af1c5f1203 Mon Sep 17 00:00:00 2001
From: zuoxiao <470321431@qq.com>
Date: 星期五, 07 二月 2025 17:14:57 +0800
Subject: [PATCH] 1.添加显示隐藏取水口、分水房功能 2.完善图例自定义控件功能和显示 3.处理工单添加选择时间功能

---
 app/src/main/assets/js/map.js                                         |   71 ++++
 app/src/main/java/com/dayu/pipirrapp/activity/OrderDealActivity.java  |   13 
 app/src/main/res/layout/activity_order_deal.xml                       |   10 
 app/src/main/java/com/dayu/pipirrapp/MyApplication.java               |    2 
 app/src/main/java/com/dayu/pipirrapp/dao/DivideDao.java               |    4 
 app/src/main/java/com/dayu/pipirrapp/dao/MarkerDao.java               |    2 
 app/src/main/java/com/dayu/pipirrapp/utils/DateUtils.java             |   14 
 app/src/main/res/drawable/divide_home_unselected.xml                  |   25 +
 app/src/main/res/layout/fragment_map.xml                              |   17 
 expand_button/src/main/res/values/attrs.xml                           |    6 
 app/src/main/res/drawable/marker_blue.xml                             |    9 
 app/src/main/res/drawable/marker_unselected.xml                       |    9 
 expand_button/src/main/java/com/example/expand_button/ExpandButton.kt |  416 +++++++++++++++++++++++----
 app/src/main/java/com/dayu/pipirrapp/fragment/MapFragment.java        |  222 +++++++++-----
 app/src/main/res/drawable/divide_home_blue.xml                        |   25 +
 15 files changed, 672 insertions(+), 173 deletions(-)

diff --git a/app/src/main/assets/js/map.js b/app/src/main/assets/js/map.js
index 85b3113..bfd0f8d 100644
--- a/app/src/main/assets/js/map.js
+++ b/app/src/main/assets/js/map.js
@@ -27,6 +27,12 @@
     let pipeLineList = [];
     let currentPipePath = [];
 
+    // 瀛樺偍鎵�鏈夊彇姘村彛鏍囪鐨勬暟缁�
+    let waterIntakeMarkers = [];
+
+    // 瀛樺偍鎵�鏈夊垎姘存埧鏍囪鐨勬暟缁�
+    let divideMarkers = [];
+
     // 灏嗘柟娉曟寕杞藉埌 window 涓�
     function mountMethodToWindow() {
         window.locationOverLay = locationOverLay;
@@ -46,6 +52,10 @@
         window.hideAllPipeLines = hideAllPipeLines;
         window.clearAllPipeLines = clearAllPipeLines;
         window.addPipeNetwork = addPipeNetwork;
+        window.hideAllWaterIntakes = hideAllWaterIntakes;
+        window.showAllWaterIntakes = showAllWaterIntakes;
+        window.hideAllDivides = hideAllDivides;
+        window.showAllDivides = showAllDivides;
     }
 
 
@@ -242,19 +252,26 @@
         let label = new T.Label({
             text: `<div style='position:absolute;left:-50%;transform: translateX(-50%);'>${name}<div>`,
             position: marker.getLngLat(),
-            offset: new T.Point(0, 8), // 璁剧疆鏍囨敞鏂囧瓧鐨勪綅缃�
-            opacity: 1, // 璁剧疆鏂囨湰鐨勬樉绀轰笉閫忔槑搴︼紙鑼冨洿0-1锛�
+            offset: new T.Point(0, 8),
+            opacity: 1,
         });
-        label.setBorderLine(0); // 璁剧疆鏂囨湰鐨勮竟妗嗙嚎瀹�
-        label.setBackgroundColor("transparent"); // 璁剧疆鏂囨湰鐨勮儗鏅壊锛堥�忔槑鑹诧級
+        label.setBorderLine(0);
+        label.setBackgroundColor("transparent");
         label.setFontColor("#FFFFFF");
         label.setFontSize(10);
         marker.label = label;
         if (isRed) {
             lastClickedMarker = marker;
         }
+        
+        // 灏嗘爣璁板拰鏍囩瀛樺偍鍒版暟缁勪腑
+        waterIntakeMarkers.push({
+            marker: marker,
+            label: label
+        });
+        
         map.addOverLay(label);
-        map.addOverLay(marker); // 灏嗘爣娉ㄦ坊鍔犲埌鍦板浘涓�
+        map.addOverLay(marker);
         return "addMarker鍔犺浇鎴愬姛 id:" + id
     }
     //鏇存柊浣嶅潗鏍�
@@ -538,6 +555,13 @@
         if (isRed) {
             lastClickedMarker = marker;
         }
+
+        // 灏嗗垎姘存埧鏍囪鍜屾爣绛惧瓨鍌ㄥ埌鏁扮粍涓�
+        divideMarkers.push({
+            marker: marker,
+            label: label
+        });
+
         map.addOverLay(label);
         map.addOverLay(marker); // 灏嗘爣娉ㄦ坊鍔犲埌鍦板浘涓�
         return "addMarker鍔犺浇鎴愬姛 id:" + id
@@ -577,9 +601,44 @@
         window.Android.showDivideDetail(data);
     }
 
+    /**
+     * 闅愯棌鎵�鏈夊彇姘村彛鏍囪
+     */
+    function hideAllWaterIntakes() {
+        waterIntakeMarkers.forEach(item => {
+            map.removeOverLay(item.marker);
+            map.removeOverLay(item.label);
+        });
+    }
 
+    /**
+     * 鏄剧ず鎵�鏈夊彇姘村彛鏍囪
+     */
+    function showAllWaterIntakes() {
+        waterIntakeMarkers.forEach(item => {
+            map.addOverLay(item.marker);
+            map.addOverLay(item.label);
+        });
+    }
 
+    /**
+     * 闅愯棌鎵�鏈夊垎姘存埧鏍囪
+     */
+    function hideAllDivides() {
+        divideMarkers.forEach(item => {
+            map.removeOverLay(item.marker);
+            map.removeOverLay(item.label);
+        });
+    }
 
-
+    /**
+     * 鏄剧ず鎵�鏈夊垎姘存埧鏍囪
+     */
+    function showAllDivides() {
+        divideMarkers.forEach(item => {
+            map.addOverLay(item.marker);
+            map.addOverLay(item.label);
+        });
+    }
 
 })();
diff --git a/app/src/main/java/com/dayu/pipirrapp/MyApplication.java b/app/src/main/java/com/dayu/pipirrapp/MyApplication.java
index 1bb8f2f..3681ff6 100644
--- a/app/src/main/java/com/dayu/pipirrapp/MyApplication.java
+++ b/app/src/main/java/com/dayu/pipirrapp/MyApplication.java
@@ -32,7 +32,7 @@
 
 //        JPushInterface.setDebugMode(true);
 //        JPushInterface.init(this);
-        CrashReport.initCrashReport(getApplicationContext(), "3d4bcf7046", false);
+        CrashReport.initCrashReport(getApplicationContext(), "f6dea280a2", false);
 
 //        // 璁剧疆鍏ㄥ眬鐨刄ncaughtExceptionHandler
 //        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
diff --git a/app/src/main/java/com/dayu/pipirrapp/activity/OrderDealActivity.java b/app/src/main/java/com/dayu/pipirrapp/activity/OrderDealActivity.java
index 0d707c0..411a8e2 100644
--- a/app/src/main/java/com/dayu/pipirrapp/activity/OrderDealActivity.java
+++ b/app/src/main/java/com/dayu/pipirrapp/activity/OrderDealActivity.java
@@ -23,13 +23,11 @@
 import com.dayu.pipirrapp.bean.net.AddProcessingRequest;
 import com.dayu.pipirrapp.bean.net.InsectionResult;
 import com.dayu.pipirrapp.bean.net.UplodFileState;
-import com.dayu.pipirrapp.dao.DaoSingleton;
 import com.dayu.pipirrapp.databinding.ActivityOrderDealBinding;
 import com.dayu.pipirrapp.fragment.OrderFragment;
 import com.dayu.pipirrapp.net.ApiManager;
 import com.dayu.pipirrapp.net.BaseResponse;
 import com.dayu.pipirrapp.net.subscribers.SubscriberListener;
-import com.dayu.pipirrapp.net.upload.UploadFileListener;
 import com.dayu.pipirrapp.tool.FileUploadUtils;
 import com.dayu.pipirrapp.tool.FullyGridLayoutManager;
 import com.dayu.pipirrapp.tool.GlideEngine;
@@ -58,10 +56,8 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 import retrofit2.Call;
 
@@ -87,6 +83,7 @@
     Map<String, UplodFileState> uplodFileStates = new HashMap<>();
     String workOrderId;
     LatLonBean latLonBean;
+    String strCompleteTime;
 
     /**
      * 瀹氫綅鐩戝惉
@@ -124,13 +121,15 @@
             new CardDatePickerDialog.Builder(this)
                     .setTitle("閫夋嫨澶勭悊鏃堕棿")
                     .setOnChoose("纭畾", aLong -> {
-                        //aLong  = millisecond
-
+                        //aLong = millisecond
+                        strCompleteTime = com.dayu.pipirrapp.utils.DateUtils.formatTimestamp(aLong);
+                        binding.timeData.setText(strCompleteTime);
                         return null;
                     })
                     .showBackNow(true)
                     .setDefaultTime(time)
                     .setMaxTime(time)
+                    .setMinTime(time - 365L * 24 * 60 * 60 * 1000) // 璁剧疆鏈�灏忔椂闂翠负涓�骞村墠
                     .setDisplayType(list)
                     .build().show();
         });
@@ -306,7 +305,7 @@
         result.setContent(binding.contentET.getText().toString());
         result.setInspectorId(MyApplication.myApplication.userId);
         result.setWorkOrderId(workOrderId);
-        result.setCompleteTime(com.dayu.pipirrapp.utils.DateUtils.getNowDateToMMStr());
+        result.setCompleteTime(strCompleteTime);
         if (latLonBean != null) {
             result.setLat(String.valueOf(latLonBean.getLatitude()));
             result.setLng(String.valueOf(latLonBean.getLongitude()));
diff --git a/app/src/main/java/com/dayu/pipirrapp/dao/DivideDao.java b/app/src/main/java/com/dayu/pipirrapp/dao/DivideDao.java
index aa9295a..a574aa0 100644
--- a/app/src/main/java/com/dayu/pipirrapp/dao/DivideDao.java
+++ b/app/src/main/java/com/dayu/pipirrapp/dao/DivideDao.java
@@ -17,7 +17,7 @@
 import io.reactivex.rxjava3.core.Maybe;
 
 /**
- * DivideDao -
+ * DivideDao -鍒嗘按鎴�
  *
  * @author zuoxiao
  * @version 1.0
@@ -52,6 +52,6 @@
     @Query("select  * from DivideBean")
     Single<List<DivideBean>> findAllToSingle();
 
-    @Query("SELECT * FROM divide")
+    @Query("SELECT * FROM DivideBean")
     Maybe<List<DivideBean>> getAll();  // 鏀逛负杩斿洖Maybe<List<DivideBean>>
 }
diff --git a/app/src/main/java/com/dayu/pipirrapp/dao/MarkerDao.java b/app/src/main/java/com/dayu/pipirrapp/dao/MarkerDao.java
index 0323b6d..4bd9344 100644
--- a/app/src/main/java/com/dayu/pipirrapp/dao/MarkerDao.java
+++ b/app/src/main/java/com/dayu/pipirrapp/dao/MarkerDao.java
@@ -19,7 +19,7 @@
  * author: zuo
  * Date: 2024-09-30
  * Time: 14:39
- * 澶囨敞锛�
+ * 澶囨敞锛氬彇姘村彛
  */
 @Dao
 public interface MarkerDao {
diff --git a/app/src/main/java/com/dayu/pipirrapp/fragment/MapFragment.java b/app/src/main/java/com/dayu/pipirrapp/fragment/MapFragment.java
index ddfb4c4..7229bca 100644
--- a/app/src/main/java/com/dayu/pipirrapp/fragment/MapFragment.java
+++ b/app/src/main/java/com/dayu/pipirrapp/fragment/MapFragment.java
@@ -5,9 +5,11 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Pair;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -20,6 +22,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
 import androidx.lifecycle.Observer;
 
 import com.dayu.pipirrapp.MyApplication;
@@ -62,6 +65,7 @@
 import com.dayu.pipirrapp.utils.WebViewUtils;
 import com.dayu.pipirrapp.view.ConfirmDialog;
 import com.dayu.pipirrapp.view.TipUtil;
+import com.example.expand_button.ExpandButton;
 import com.hjq.permissions.OnPermissionCallback;
 import com.hjq.permissions.Permission;
 import com.hjq.permissions.XXPermissions;
@@ -80,6 +84,7 @@
 import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
 import io.reactivex.rxjava3.disposables.CompositeDisposable;
 import io.reactivex.rxjava3.schedulers.Schedulers;
+import kotlin.Triple;
 
 /**
  * author: zuo
@@ -178,69 +183,69 @@
     private void loadLocalData() {
         // 寮傛鍔犺浇涓績鐐规暟鎹�
         compositeDisposable.add(
-            DaoSingleton.getAsynchInstance(this.getContext()).centerPointDao().findFirst()
-                .subscribeOn(Schedulers.io())
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe(result -> {
-                    centerPointBean = result;
-                    if (centerPointBean == null) {
-                        getCenterPoint();
-                    } else {
-                        jumpCenterPoint();
-                    }
-                }, throwable -> {
-                    Log.e(TAG, "Load centerPoint error: " + throwable);
-                    getCenterPoint();
-                }, () -> {
-                    // 褰揗aybe涓虹┖鏃惰皟鐢�
-                    getCenterPoint();
-                })
+                DaoSingleton.getAsynchInstance(this.getContext()).centerPointDao().findFirst()
+                        .subscribeOn(Schedulers.io())
+                        .observeOn(AndroidSchedulers.mainThread())
+                        .subscribe(result -> {
+                            centerPointBean = result;
+                            if (centerPointBean == null) {
+                                getCenterPoint();
+                            } else {
+                                jumpCenterPoint();
+                            }
+                        }, throwable -> {
+                            Log.e(TAG, "Load centerPoint error: " + throwable);
+                            getCenterPoint();
+                        }, () -> {
+                            // 褰揗aybe涓虹┖鏃惰皟鐢�
+                            getCenterPoint();
+                        })
         );
 
         // 寮傛鍔犺浇鍙栨按鍙f暟鎹�
         compositeDisposable.add(
-            DaoSingleton.getAsynchInstance(this.getContext()).markerDao().getAll()
-                .subscribeOn(Schedulers.io())
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe(markers -> {
-                    if (markers == null || markers.isEmpty()) {
-                        getMarkerData();
-                    } else {
-                        for (MarkerBean marker : markers) {
-                            markerBeanSet.put(marker.getId(), marker);
-                            setMapMarker(marker);
-                        }
-                    }
-                }, throwable -> {
-                    Log.e(TAG, "Load markers error: " + throwable.getMessage());
-                    getMarkerData();
-                }, () -> {
-                    // 褰揗aybe涓虹┖鏃惰皟鐢�
-                    getMarkerData();
-                })
+                DaoSingleton.getAsynchInstance(this.getContext()).markerDao().getAll()
+                        .subscribeOn(Schedulers.io())
+                        .observeOn(AndroidSchedulers.mainThread())
+                        .subscribe(markers -> {
+                            if (markers == null || markers.isEmpty()) {
+                                getMarkerData();
+                            } else {
+                                for (MarkerBean marker : markers) {
+                                    markerBeanSet.put(marker.getId(), marker);
+                                    setMapMarker(marker);
+                                }
+                            }
+                        }, throwable -> {
+                            Log.e(TAG, "Load markers error: " + throwable.getMessage());
+                            getMarkerData();
+                        }, () -> {
+                            // 褰揗aybe涓虹┖鏃惰皟鐢�
+                            getMarkerData();
+                        })
         );
 
         // 寮傛鍔犺浇鍒嗘按鎴挎暟鎹�
         compositeDisposable.add(
-            DaoSingleton.getAsynchInstance(this.getContext()).divideDao().getAll()
-                .subscribeOn(Schedulers.io())
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe(divides -> {
-                    if (divides == null || divides.isEmpty()) {
-                        getDivideList();
-                    } else {
-                        for (DivideBean divide : divides) {
-                            divideBeanMap.put(divide.getId(), divide);
-                            setMapDivide(divide);
-                        }
-                    }
-                }, throwable -> {
-                    Log.e(TAG, "Load divides error: " + throwable.getMessage());
-                    getDivideList();
-                }, () -> {
-                    // 褰揗aybe涓虹┖鏃惰皟鐢�
-                    getDivideList();
-                })
+                DaoSingleton.getAsynchInstance(this.getContext()).divideDao().getAll()
+                        .subscribeOn(Schedulers.io())
+                        .observeOn(AndroidSchedulers.mainThread())
+                        .subscribe(divides -> {
+                            if (divides == null || divides.isEmpty()) {
+                                getDivideList();
+                            } else {
+                                for (DivideBean divide : divides) {
+                                    divideBeanMap.put(divide.getId(), divide);
+                                    setMapDivide(divide);
+                                }
+                            }
+                        }, throwable -> {
+                            Log.e(TAG, "Load divides error: " + throwable.getMessage());
+                            getDivideList();
+                        }, () -> {
+                            // 褰揗aybe涓虹┖鏃惰皟鐢�
+                            getDivideList();
+                        })
         );
     }
 
@@ -370,19 +375,19 @@
 
                         // 浣跨敤 CompositeDisposable 绠$悊鏁版嵁搴撴彃鍏ユ搷浣�
                         compositeDisposable.add(
-                            DaoSingleton.getAsynchInstance(MapFragment.this.getContext()).markerDao().insertAll(markerBeans)
-                                .subscribeOn(Schedulers.io())
-                                .observeOn(AndroidSchedulers.mainThread())
-                                .subscribe(
-                                    () -> {
-                                        // 鎻掑叆鎴愬姛
-                                        Log.i("mWebView", "鏁版嵁鎻掑叆鎴愬姛");
-                                    },
-                                    throwable -> {
-                                        // 鎻掑叆澶辫触
-                                        Log.e("mWebView", "鏁版嵁鎻掑叆澶辫触: " + throwable.getMessage());
-                                    }
-                                )
+                                DaoSingleton.getAsynchInstance(MapFragment.this.getContext()).markerDao().insertAll(markerBeans)
+                                        .subscribeOn(Schedulers.io())
+                                        .observeOn(AndroidSchedulers.mainThread())
+                                        .subscribe(
+                                                () -> {
+                                                    // 鎻掑叆鎴愬姛
+                                                    Log.i("mWebView", "鏁版嵁鎻掑叆鎴愬姛");
+                                                },
+                                                throwable -> {
+                                                    // 鎻掑叆澶辫触
+                                                    Log.e("mWebView", "鏁版嵁鎻掑叆澶辫触: " + throwable.getMessage());
+                                                }
+                                        )
                         );
                     }
 
@@ -432,8 +437,27 @@
             Intent issue = new Intent(MapFragment.this.getActivity(), AddIssueActivity.class);
             MapFragment.this.getActivity().startActivity(issue);
         });
+        binding.expandButton.setLegendsArray(new Triple<>(
+                        ContextCompat.getDrawable(requireContext(), R.drawable.marker_blue),
+                        ContextCompat.getDrawable(requireContext(), R.drawable.marker_unselected),
+                        "鍙栨按鍙�"
+                ),
+                new Triple<>(
+                        ContextCompat.getDrawable(requireContext(), R.drawable.divide_home_blue),
+                        ContextCompat.getDrawable(requireContext(), R.drawable.divide_home_unselected),
+                        "鍒嗘按鎴�"
+                ));
+        binding.expandButton.setOnLegendItemClickListener((position, isSelected) -> {
+            switch (position) {
+                case 0:
+                    showMarkers(isSelected);
+                    break;
+                case 1:
+                    showDivideMarkers(isSelected);
+                    break;
 
-
+            }
+        });
     }
 
     /**
@@ -1010,22 +1034,22 @@
                                 setMapDivide(divideBean);
                                 divideBeans.add(divideBean);
                             }
-                            
+
                             // 浣跨敤 CompositeDisposable 绠$悊鏁版嵁搴撴彃鍏ユ搷浣�
                             compositeDisposable.add(
-                                DaoSingleton.getAsynchInstance(MapFragment.this.getContext()).divideDao().insertAll(divideBeans)
-                                    .subscribeOn(Schedulers.io())
-                                    .observeOn(AndroidSchedulers.mainThread())
-                                    .subscribe(
-                                        () -> {
-                                            // 鎻掑叆鎴愬姛
-                                            Log.i("mWebView", "鏁版嵁鎻掑叆鎴愬姛");
-                                        },
-                                        throwable -> {
-                                            // 鎻掑叆澶辫触
-                                            Log.e("mWebView", "鏁版嵁鎻掑叆澶辫触: " + throwable.getMessage());
-                                        }
-                                    )
+                                    DaoSingleton.getAsynchInstance(MapFragment.this.getContext()).divideDao().insertAll(divideBeans)
+                                            .subscribeOn(Schedulers.io())
+                                            .observeOn(AndroidSchedulers.mainThread())
+                                            .subscribe(
+                                                    () -> {
+                                                        // 鎻掑叆鎴愬姛
+                                                        Log.i("mWebView", "鏁版嵁鎻掑叆鎴愬姛");
+                                                    },
+                                                    throwable -> {
+                                                        // 鎻掑叆澶辫触
+                                                        Log.e("mWebView", "鏁版嵁鎻掑叆澶辫触: " + throwable.getMessage());
+                                                    }
+                                            )
                             );
                         }
                     } else {
@@ -1157,4 +1181,36 @@
             mWebView.restoreState(savedInstanceState);
         }
     }
+
+    /**
+     * 鏄剧ず鎴栭殣钘忓湴鍥句笂鐨勫彇姘村彛
+     *
+     * @param isShow
+     */
+    private void showMarkers(boolean isShow) {
+        if (isShow) {
+            mWebView.evaluateJavascript("javascript:showAllWaterIntakes()", value -> {
+            });
+        } else {
+            mWebView.evaluateJavascript("javascript:hideAllWaterIntakes()", value -> {
+            });
+        }
+
+    }
+
+    /**
+     * 鏄剧ず鎴栭殣钘忓湴鍥句笂鐨勫垎姘存埧
+     *
+     * @param isShow
+     */
+    private void showDivideMarkers(boolean isShow) {
+        if (isShow) {
+            mWebView.evaluateJavascript("javascript:showAllDivides()", value -> {
+            });
+        } else {
+            mWebView.evaluateJavascript("javascript:hideAllDivides()", value -> {
+            });
+        }
+    }
+
 }
diff --git a/app/src/main/java/com/dayu/pipirrapp/utils/DateUtils.java b/app/src/main/java/com/dayu/pipirrapp/utils/DateUtils.java
index 1d25d66..1cdc3c5 100644
--- a/app/src/main/java/com/dayu/pipirrapp/utils/DateUtils.java
+++ b/app/src/main/java/com/dayu/pipirrapp/utils/DateUtils.java
@@ -31,15 +31,25 @@
     /**
      * 杩斿洖缁熶竴鏍煎紡鐨勫綋鍓嶆椂闂存埅姝㈠埌鍒嗛挓
      *
-     * @return yyyy-MM-dd HH:mm:ss
+     * @return yyyy-MM-dd HH:mm
      */
     public static String getNowDateToMMStr() {
         // 褰撳墠鏃堕棿
         Date date = new Date();
         // 鍒涘缓 SimpleDateFormat 瀵硅薄锛岃缃棩鏈熸牸寮�
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault());
         // 鏍煎紡鍖栧綋鍓嶆椂闂翠负瀛楃涓�
         return sdf.format(date);
     }
 
+    /**
+     * 灏嗘椂闂存埑杞崲涓烘寚瀹氭牸寮忕殑瀛楃涓�
+     * @param timestamp 鏃堕棿鎴�
+     * @return 鏍煎紡鍖栧悗鐨勬椂闂村瓧绗︿覆 (yyyy-MM-dd HH:mm)
+     */
+    public static String formatTimestamp(long timestamp) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault());
+        return sdf.format(new Date(timestamp));
+    }
+
 }
diff --git a/app/src/main/res/drawable/divide_home_blue.xml b/app/src/main/res/drawable/divide_home_blue.xml
new file mode 100644
index 0000000..30680be
--- /dev/null
+++ b/app/src/main/res/drawable/divide_home_blue.xml
@@ -0,0 +1,25 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M9,18V42H39V18L24,6L9,18Z"
+      android:strokeLineJoin="round"
+      android:strokeWidth="4"
+      android:fillColor="#00000000"
+      android:strokeColor="#1890FF"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M19,29V42H29V29H19Z"
+      android:strokeLineJoin="round"
+      android:strokeWidth="4"
+      android:fillColor="#00000000"
+      android:strokeColor="#1890FF"/>
+  <path
+      android:pathData="M9,42H39"
+      android:strokeWidth="4"
+      android:fillColor="#00000000"
+      android:strokeColor="#1890FF"
+      android:strokeLineCap="round"/>
+</vector>
diff --git a/app/src/main/res/drawable/divide_home_unselected.xml b/app/src/main/res/drawable/divide_home_unselected.xml
new file mode 100644
index 0000000..a37f1fe
--- /dev/null
+++ b/app/src/main/res/drawable/divide_home_unselected.xml
@@ -0,0 +1,25 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M9,18V42H39V18L24,6L9,18Z"
+      android:strokeLineJoin="round"
+      android:strokeWidth="4"
+      android:fillColor="#00000000"
+      android:strokeColor="#757575"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M19,29V42H29V29H19Z"
+      android:strokeLineJoin="round"
+      android:strokeWidth="4"
+      android:fillColor="#00000000"
+      android:strokeColor="#757575"/>
+  <path
+      android:pathData="M9,42H39"
+      android:strokeWidth="4"
+      android:fillColor="#00000000"
+      android:strokeColor="#757575"
+      android:strokeLineCap="round"/>
+</vector>
diff --git a/app/src/main/res/drawable/marker_blue.xml b/app/src/main/res/drawable/marker_blue.xml
new file mode 100644
index 0000000..e3e70bf
--- /dev/null
+++ b/app/src/main/res/drawable/marker_blue.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,2L12,2C8.13,2 5,5.13 5,9c0,1.74 0.5,3.37 1.41,4.84c0.95,1.54 2.2,2.86 3.16,4.4c0.47,0.75 0.81,1.45 1.17,2.26C11,21.05 11.21,22 12,22h0c0.79,0 1,-0.95 1.25,-1.5c0.37,-0.81 0.7,-1.51 1.17,-2.26c0.96,-1.53 2.21,-2.85 3.16,-4.4C18.5,12.37 19,10.74 19,9C19,5.13 15.87,2 12,2zM12,11.75c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5S13.38,11.75 12,11.75z"
+      android:fillColor="#1890FF"/>
+</vector>
diff --git a/app/src/main/res/drawable/marker_unselected.xml b/app/src/main/res/drawable/marker_unselected.xml
new file mode 100644
index 0000000..24a8afd
--- /dev/null
+++ b/app/src/main/res/drawable/marker_unselected.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,2L12,2C8.13,2 5,5.13 5,9c0,1.74 0.5,3.37 1.41,4.84c0.95,1.54 2.2,2.86 3.16,4.4c0.47,0.75 0.81,1.45 1.17,2.26C11,21.05 11.21,22 12,22h0c0.79,0 1,-0.95 1.25,-1.5c0.37,-0.81 0.7,-1.51 1.17,-2.26c0.96,-1.53 2.21,-2.85 3.16,-4.4C18.5,12.37 19,10.74 19,9C19,5.13 15.87,2 12,2zM12,11.75c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5S13.38,11.75 12,11.75z"
+      android:fillColor="#757575"/>
+</vector>
diff --git a/app/src/main/res/layout/activity_order_deal.xml b/app/src/main/res/layout/activity_order_deal.xml
index 3bc03cb..8481bf9 100644
--- a/app/src/main/res/layout/activity_order_deal.xml
+++ b/app/src/main/res/layout/activity_order_deal.xml
@@ -62,7 +62,15 @@
                     android:text="鍙嶉鏃堕棿锛�"
                     android:textColor="@color/black"
                     android:textSize="@dimen/order_detail_button_size" />
-
+                <TextView
+                    android:id="@+id/timeData"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_centerVertical="true"
+                    android:layout_toEndOf="@+id/timeTV"
+                    android:layout_marginLeft="10dp"
+                    android:textColor="@color/black"
+                    android:textSize="@dimen/order_detail_button_size" />
                 <ImageView
                     android:layout_width="25dp"
                     android:layout_height="25dp"
diff --git a/app/src/main/res/layout/fragment_map.xml b/app/src/main/res/layout/fragment_map.xml
index e0de4e9..9a71ebc 100644
--- a/app/src/main/res/layout/fragment_map.xml
+++ b/app/src/main/res/layout/fragment_map.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    xmlns:app="http://schemas.android.com/apk/res-auto">
+    android:layout_height="match_parent">
 
     <!--    <com.github.lzyzsd.jsbridge.BridgeWebView-->
     <!--        android:id="@+id/webView"-->
@@ -110,17 +110,18 @@
         android:id="@+id/expandButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:padding="10dp"
-        android:background="@drawable/ic_green_bg"
         android:layout_alignParentRight="true"
         android:layout_marginTop="180dp"
-        android:textSize="18sp"
         android:layout_marginRight="15dp"
+        android:background="@drawable/ic_green_bg"
+        android:padding="10dp"
         android:textColor="@color/white"
+        android:textSize="18sp"
+        app:animDuration="300"
+        app:collapsedText="渚�"
         app:letterSpacing="10dp"
-        app:expandedText="鐐瑰嚮灞曞紑"
-        app:collapsedText="鐐�"
-        app:animDuration="300" />
+        app:expandedTextSize="12sp"/>
+
     <RelativeLayout
         android:id="@+id/pointRL"
         android:layout_width="match_parent"
diff --git a/expand_button/src/main/java/com/example/expand_button/ExpandButton.kt b/expand_button/src/main/java/com/example/expand_button/ExpandButton.kt
index c024329..1ac7b29 100644
--- a/expand_button/src/main/java/com/example/expand_button/ExpandButton.kt
+++ b/expand_button/src/main/java/com/example/expand_button/ExpandButton.kt
@@ -25,10 +25,23 @@
     defStyleAttr: Int = 0
 ) : AppCompatTextView(context, attrs, defStyleAttr) {
 
+    // 淇敼灞炴��
+    private data class LegendItem(
+        val selectedIcon: Drawable,
+        val unselectedIcon: Drawable,
+        val description: String,
+        var isSelected: Boolean = true
+    )
+    
+    private var legendItems: List<LegendItem> = listOf()
+    private var itemSpacing: Float = context.resources.displayMetrics.density * 16 // 鍥句緥椤逛箣闂寸殑姘村钩闂磋窛
+    private var iconSize: Int = (24 * context.resources.displayMetrics.density).toInt() // 鍥炬爣澶у皬
+    private var iconTextSpacing: Float = context.resources.displayMetrics.density * 4 // 鍥炬爣鍜屾枃瀛椾箣闂寸殑鍨傜洿闂磋窛
+
     // 灞曞紑鏃舵樉绀虹殑瀹屾暣鏂囧瓧
-    private var expandedText: String = ""
+    private var expandedText: String = "鏍囨敞鐐�: 褰撳墠浣嶇疆\n鍖哄煙: 閰嶉�佽寖鍥�"
     // 鏀惰捣鏃舵樉绀虹殑鍗曚釜瀛楃
-    private var collapsedText: String = ""
+    private var collapsedText: String = "鍥句緥"
     // 褰撳墠鏄惁澶勪簬灞曞紑鐘舵��
     private var isExpanded: Boolean = false
     // 鍔ㄧ敾鎸佺画鏃堕棿锛岄粯璁�300姣
@@ -50,7 +63,33 @@
     // 涓夎褰㈠浘鏍囦笌鏂囧瓧鐨勯棿璺濓紝榛樿涓�8dp
     private var triangleMargin: Float = 3 * context.resources.displayMetrics.density
 
+    // 娣诲姞鏂板睘鎬�
+    private var textLines: List<String> = listOf()
+
+    // 娣诲姞鐐瑰嚮鍥炶皟鎺ュ彛
+    interface OnLegendItemClickListener {
+        fun onLegendItemClick(position: Int, isSelected: Boolean)
+    }
+    
+    private var legendItemClickListener: OnLegendItemClickListener? = null
+
+    // 淇敼鍥句緥椤圭殑鎬婚珮搴﹁绠�
+    private val legendItemHeight: Int
+        get() = iconSize + iconTextSpacing.toInt() + paint.textSize.toInt() + paint.descent().toInt() - paint.ascent().toInt()
+
+    // 娣诲姞灞曞紑鍚庣殑瀛椾綋澶у皬灞炴��
+    private var expandedTextSize: Float = textSize
+
+    // 娣诲姞涓�涓彉閲忎繚瀛橀粯璁ゅ瓧浣撳ぇ灏�
+    private var defaultTextSize: Float = 0f
+
+    // 娣诲姞涓�涓睘鎬у畾涔変笁瑙掑舰鍥炬爣鐨勭偣鍑诲尯鍩熸墿灞曡寖鍥�
+    private val triangleClickPadding: Float = 15f * context.resources.displayMetrics.density // 20dp
+
     init {
+        // 淇濆瓨 XML 涓缃殑榛樿瀛椾綋澶у皬
+        defaultTextSize = textSize
+
         // 璇诲彇鑷畾涔夊睘鎬�
         context.theme.obtainStyledAttributes(
             attrs,
@@ -60,10 +99,14 @@
         ).apply {
             try {
                 customLetterSpacing = getDimension(R.styleable.ExpandButton_letterSpacing, customLetterSpacing)
-                expandedText = getString(R.styleable.ExpandButton_expandedText) ?: ""
-                collapsedText = getString(R.styleable.ExpandButton_collapsedText) ?: ""
+                expandedText = getString(R.styleable.ExpandButton_expandedText) ?: "鏍囨敞鐐�: 褰撳墠浣嶇疆\n鍖哄煙: 閰嶉�佽寖鍥�"
+                collapsedText = getString(R.styleable.ExpandButton_collapsedText) ?: "鍥句緥"
                 animationDuration = getInteger(R.styleable.ExpandButton_animDuration, 300).toLong()
                 triangleMargin = getDimension(R.styleable.ExpandButton_triangleMargin, triangleMargin)
+                itemSpacing = getDimension(R.styleable.ExpandButton_itemSpacing, itemSpacing)
+                iconSize = getDimension(R.styleable.ExpandButton_iconSize, iconSize.toFloat()).toInt()
+                iconTextSpacing = getDimension(R.styleable.ExpandButton_iconTextSpacing, iconTextSpacing)
+                expandedTextSize = getDimension(R.styleable.ExpandButton_expandedTextSize, defaultTextSize)
             } finally {
                 recycle()
             }
@@ -80,26 +123,11 @@
             }
         }
 
-        // 璁剧疆鏂囨湰鍙偣鍑伙紝浠呭湪鏀惰捣鐘舵�佹椂鍝嶅簲鐐瑰嚮灞曞紑
-        setOnClickListener {
-            if (!isExpanded) {
-                toggleExpand()
-            }
-        }
-
-        // 娣诲姞瑙︽懜浜嬩欢澶勭悊
-        setOnTouchListener { _, event ->
-            when (event.action) {
-                MotionEvent.ACTION_DOWN -> {
-                    // 妫�鏌ョ偣鍑绘槸鍚﹀湪涓夎褰㈠浘鏍囧尯鍩熷唴
-                    if (isClickOnTriangle(event.x)) {
-                        toggleExpand()
-                        return@setOnTouchListener true
-                    }
-                }
-            }
-            false
-        }
+        // 淇敼瑙︽懜浜嬩欢澶勭悊
+        setOnTouchListener(null) // 绉婚櫎鍘熸湁鐨勮Е鎽哥洃鍚櫒
+        
+        // 绉婚櫎鍘熸湁鐨勭偣鍑荤洃鍚櫒
+        setOnClickListener(null)
 
         // 璁剧疆宸﹁竟璺濓紝涓哄浘鏍囩暀鍑虹┖闂�
         compoundDrawablePadding = triangleMargin.toInt()
@@ -111,23 +139,107 @@
         )
 
         // 璁剧疆鍗曡鏄剧ず锛岄槻姝㈤珮搴﹀彉鍖�
-        maxLines = 1
-        isSingleLine = true
+        maxLines = if (isExpanded) Int.MAX_VALUE else 1
+        isSingleLine = !isExpanded
         
         // 璁剧疆鏂囧瓧鍨傜洿灞呬腑
         gravity = Gravity.CENTER_VERTICAL
+
+        // 璁剧疆榛樿鐨勫唴杈硅窛
+        val defaultPadding = (8 * context.resources.displayMetrics.density).toInt()
+        setPadding(
+            (16 * context.resources.displayMetrics.density + triangleMargin).toInt(), // 宸﹁竟璺濆鍔狅紝涓哄浘鏍囩暀绌洪棿
+            defaultPadding, // 涓婅竟璺�
+            defaultPadding, // 鍙宠竟璺�
+            defaultPadding  // 涓嬭竟璺�
+        )
+    }
+
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+        
+        if (isExpanded) {
+            // 灞曞紑鐘舵�佷笅鐨勯珮搴﹁绠�
+            val desiredHeight = legendItemHeight + paddingTop + paddingBottom
+            setMeasuredDimension(measuredWidth, desiredHeight)
+        }
     }
 
     override fun onDraw(canvas: Canvas) {
-        // 淇濆瓨鐢诲竷鐘舵��
+        // 缁樺埗灞曞紑/鏀惰捣鍥炬爣
+        drawTriangle(canvas)
+        
+        if (!isExpanded) {
+            // 鏀惰捣鐘舵�佷娇鐢ㄩ粯璁ゅ瓧浣撳ぇ灏�
+            paint.textSize = defaultTextSize
+            super.onDraw(canvas)
+            return
+        }
+        
+        // 灞曞紑鐘舵�佷娇鐢ㄥ睍寮�鍚庣殑瀛椾綋澶у皬
+        paint.textSize = expandedTextSize
+        
+        // 璁$畻鎵�鏈夊浘渚嬮」涓渶瀹界殑瀹藉害
+        val maxWidth = legendItems.maxOf { item ->
+            maxOf(paint.measureText(item.description), iconSize.toFloat())
+        }
+        
+        // 璁$畻鎬诲搴︼紙娣诲姞棣栧熬鐨勮竟璺濓級
+        val totalWidth = legendItems.size * maxWidth + 
+            (legendItems.size + 1) * itemSpacing  // 淇敼杩欓噷锛屾坊鍔犱竴涓澶栫殑闂磋窛
+        
+        // 璁$畻璧峰x鍧愭爣锛屼娇鏁翠綋姘村钩灞呬腑
+        var x = (width - totalWidth) / 2 + itemSpacing  // 娣诲姞璧峰杈硅窛
+        
+        // 璁$畻鍨傜洿灞呬腑鐨剏鍧愭爣锛岃�冭檻涓婁笅杈硅窛
+        val centerY = height / 2f
+        
+        legendItems.forEachIndexed { index, item ->
+            // 璁$畻褰撳墠鍥句緥椤圭殑璧峰浣嶇疆锛堢Щ闄ndex > 0鐨勫垽鏂級
+            val itemStartX = x
+            
+            // 璁$畻鍥炬爣鐨勬按骞充綅缃紙灞呬腑浜庡浘渚嬮」锛�
+            val iconLeft = itemStartX + (maxWidth - iconSize) / 2
+            
+            // 璁$畻鏂囧瓧鐨勪綅缃�
+            val textWidth = paint.measureText(item.description)
+            val textX = itemStartX + (maxWidth - textWidth) / 2
+            
+            // 缁樺埗鍥炬爣锛屾牴鎹�変腑鐘舵�侀�夋嫨涓嶅悓鐨勫浘鏍�
+            val iconTop = paddingTop + (height - legendItemHeight) / 2
+            val currentIcon = if (item.isSelected) item.selectedIcon else item.unselectedIcon
+            currentIcon.setBounds(
+                iconLeft.toInt(),
+                iconTop.toInt(),
+                (iconLeft + iconSize).toInt(),
+                (iconTop + iconSize).toInt()
+            )
+            currentIcon.draw(canvas)
+            
+            // 缁樺埗鏂囧瓧锛屾牴鎹�変腑鐘舵�佷娇鐢ㄤ笉鍚岀殑棰滆壊
+            paint.color = if (item.isSelected) 
+                currentTextColor 
+            else 
+                0xFF999999.toInt() // 鐏拌壊
+            val textY = iconTop + iconSize + iconTextSpacing - paint.ascent()
+            canvas.drawText(item.description, textX, textY, paint)
+            
+            // 鏇存柊涓嬩竴涓浘渚嬮」鐨勮捣濮嬩綅缃�
+            x = itemStartX + maxWidth + itemSpacing
+        }
+        
+        // 鎭㈠鐢荤瑪棰滆壊
+        paint.color = currentTextColor
+    }
+
+    // 灏嗗師鏉ョ殑onDraw涓殑涓夎褰㈢粯鍒堕�昏緫鎻愬彇鍑烘潵
+    private fun drawTriangle(canvas: Canvas) {
         canvas.save()
         
-        // 璁$畻鍥炬爣浣嶇疆
         val iconSize = triangleDrawable.intrinsicWidth
         val iconLeft = paddingLeft - iconSize - compoundDrawablePadding
         val iconTop = (height - iconSize) / 2
         
-        // 璁剧疆鍥炬爣杈圭晫
         triangleDrawable.setBounds(
             iconLeft,
             iconTop,
@@ -135,20 +247,15 @@
             iconTop + iconSize
         )
         
-        // 鏃嬭浆鐢诲竷
         canvas.rotate(
             triangleRotation,
             (iconLeft + iconSize / 2).toFloat(),
             (iconTop + iconSize / 2).toFloat()
         )
         
-        // 缁樺埗鍥炬爣
         triangleDrawable.draw(canvas)
         
-        // 鎭㈠鐢诲竷鐘舵��
         canvas.restore()
-        
-        super.onDraw(canvas)
     }
 
     /**
@@ -193,13 +300,18 @@
 
     /**
      * 鍒囨崲灞曞紑/鏀惰捣鐘舵��
-     * 浣跨敤ValueAnimator瀹炵幇瀹藉害鍔ㄧ敾鍜屽浘鏍囨棆杞�
      */
     private fun toggleExpand() {
         isExpanded = !isExpanded
 
         // 璁$畻鏀惰捣鍜屽睍寮�鐘舵�佺殑瀹藉害
-        val collapsedWidth = paint.measureText(collapsedText).toInt() + paddingLeft + paddingRight
+        val collapsedWidth = run {
+            paint.textSize = defaultTextSize
+            val width = paint.measureText(collapsedText).toInt() + paddingLeft + paddingRight
+            paint.textSize = if (isExpanded) expandedTextSize else defaultTextSize
+            width
+        }
+        
         val expandedWidth = calculateExpandedWidth()
 
         // 鍒涘缓瀹藉害鍔ㄧ敾
@@ -225,31 +337,46 @@
             duration = animationDuration
             addUpdateListener { animator ->
                 triangleRotation = animator.animatedValue as Float
-                invalidate() // 閲嶇粯浠ユ洿鏂板浘鏍囨棆杞�
+                invalidate()
             }
             start()
         }
 
-        // 鏇存柊鏂囨湰
+        // 鏇存柊鏂囨湰鍜屽瓧浣撳ぇ灏�
         if (isExpanded) {
-            setExpandedClickableText()
+            paint.textSize = expandedTextSize
         } else {
             text = collapsedText
+            paint.textSize = defaultTextSize
+            setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, defaultTextSize)
         }
+
+        invalidate()
     }
 
     /**
      * 璁$畻灞曞紑鍚庣殑鎬诲搴�
      */
     private fun calculateExpandedWidth(): Int {
-        val spaceWidth = paint.measureText(" ") * (customLetterSpacing / 10)
-        // 璁$畻鎵�鏈夊瓧绗︾殑鎬诲搴�
-        val textWidth = expandedText.fold(0f) { acc, char ->
-            acc + paint.measureText(char.toString())
+        // 涓存椂淇濆瓨褰撳墠瀛椾綋澶у皬
+        val currentTextSize = paint.textSize
+        // 璁剧疆涓哄睍寮�鐘舵�佺殑瀛椾綋澶у皬
+        paint.textSize = expandedTextSize
+        
+        try {
+            // 璁$畻鎵�鏈夊浘渚嬮」涓渶瀹界殑瀹藉害
+            val maxWidth = legendItems.maxOf { item ->
+                maxOf(paint.measureText(item.description), iconSize.toFloat())
+            }
+            
+            // 璁$畻鎬诲搴� = 鎵�鏈夊浘渚嬮」鐨勫搴� + 鎵�鏈夐棿璺濓紙鍖呮嫭棣栧熬锛� + 宸﹀彸鍐呰竟璺�
+            return (legendItems.size * maxWidth + 
+                (legendItems.size + 1) * itemSpacing +  
+                paddingLeft + paddingRight).toInt()
+        } finally {
+            // 鎭㈠鍘熸潵鐨勫瓧浣撳ぇ灏�
+            paint.textSize = currentTextSize
         }
-        // 璁$畻闂磋窛鐨勬�诲搴︼紙瀛楃鏁伴噺鍑�1涓棿璺濓級
-        val spacesWidth = spaceWidth * (expandedText.length - 1)
-        return (textWidth + spacesWidth).toInt() + paddingLeft + paddingRight
     }
 
     /**
@@ -257,39 +384,76 @@
      */
     private fun setExpandedClickableText() {
         val builder = SpannableStringBuilder()
-        expandedText.forEachIndexed { index, char ->
-            // 娣诲姞瀛楃
-            builder.append(char)
+        
+        // 璁$畻鎵�鏈夊浘渚嬮」涓渶瀹界殑瀹藉害
+        val maxWidth = legendItems.maxOf { item ->
+            maxOf(paint.measureText(item.description), iconSize.toFloat())
+        }
+        
+        // 璁$畻鎬诲搴�
+        val totalWidth = legendItems.size * maxWidth + 
+            (legendItems.size - 1) * itemSpacing
+        
+        // 璁$畻鏁翠綋姘村钩灞呬腑闇�瑕佺殑璧峰绌烘牸
+        val startPadding = ((width - totalWidth) / 2 / paint.measureText(" ")).toInt()
+        if (startPadding > 0) {
+            builder.append(" ".repeat(startPadding))
+        }
+        
+        // 娣诲姞鍨傜洿绌洪棿锛屼负鍥炬爣棰勭暀浣嶇疆
+        val verticalSpaces = ((iconSize + iconTextSpacing) / paint.textSize).toInt()
+        builder.append("\n".repeat(verticalSpaces))
+        
+        legendItems.forEachIndexed { index, item ->
+            if (index > 0) {
+                // 鍦ㄥ浘渚嬮」涔嬮棿娣诲姞姘村钩闂磋窛
+                builder.append(" ".repeat((itemSpacing / paint.measureText(" ")).toInt()))
+            }
             
-            // 涓哄瓧绗﹁缃偣鍑讳簨浠�
+            // 璁$畻姘村钩灞呬腑鎵�闇�鐨勭┖鏍兼暟
+            val textWidth = paint.measureText(item.description)
+            val paddingSpaces = ((maxWidth - textWidth) / 2 / paint.measureText(" ")).toInt()
+            
+            // 娣诲姞宸︿晶绌烘牸瀹炵幇灞呬腑
+            if (paddingSpaces > 0) {
+                builder.append(" ".repeat(paddingSpaces))
+            }
+            
+            // 娣诲姞鎻忚堪鏂囨湰
+            val startPosition = builder.length
+            builder.append(item.description)
+            
+            // 娣诲姞鍙充晶绌烘牸浠ョ‘淇濆搴︿竴鑷�
+            val remainingSpaces = ((maxWidth - textWidth) / paint.measureText(" ")).toInt() - paddingSpaces
+            if (remainingSpaces > 0) {
+                builder.append(" ".repeat(remainingSpaces))
+            }
+            
+            // 涓烘枃瀛楄缃偣鍑讳簨浠�
             val clickableSpan = object : ClickableSpan() {
                 override fun onClick(view: View) {
-                    onCharClickListener?.invoke(char, index)
+                    onCharClickListener?.invoke(item.description[0], index)
                 }
 
                 override fun updateDrawState(ds: android.text.TextPaint) {
                     super.updateDrawState(ds)
-                    // 绉婚櫎涓嬪垝绾�
                     ds.isUnderlineText = false
-                    // 淇濇寔鍘熷鏂囧瓧棰滆壊
                     ds.color = currentTextColor
                 }
             }
+            
             builder.setSpan(
                 clickableSpan,
-                builder.length - 1,
-                builder.length,
+                startPosition,
+                startPosition + item.description.length,
                 Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
             )
-            
-            // 鍙湪闈炴渶鍚庝竴涓瓧绗﹀悗娣诲姞绌烘牸浣滀负闂磋窛
-            if (index < expandedText.length - 1) {
-                builder.append(" ".repeat((customLetterSpacing / 10).toInt()))
-            }
         }
         
+        // 璁剧疆鏂囨湰瀵归綈鏂瑰紡涓哄眳涓�
+        gravity = Gravity.CENTER
+        
         text = builder
-        // 鍚敤LinkMovementMethod浠ュ搷搴擟lickableSpan鐨勭偣鍑讳簨浠�
         movementMethod = android.text.method.LinkMovementMethod.getInstance()
     }
 
@@ -299,7 +463,10 @@
     private fun isClickOnTriangle(x: Float): Boolean {
         val iconSize = triangleDrawable.intrinsicWidth
         val iconLeft = paddingLeft - iconSize - compoundDrawablePadding
-        return x <= paddingLeft && x >= iconLeft
+        
+        // 鎵╁ぇ鐐瑰嚮鍖哄煙锛氬乏鍙冲悇澧炲姞 triangleClickPadding
+        return x <= (paddingLeft + triangleClickPadding) && 
+               x >= (iconLeft - triangleClickPadding)
     }
 
     /**
@@ -316,4 +483,129 @@
             paddingBottom
         )
     }
+
+    /**
+     * 璁剧疆鍥句緥鍐呭
+     */
+    @JvmName("setLegendsList")
+    fun setLegends(items: List<Triple<Drawable, Drawable, String>>) {
+        legendItems = items.map { (selectedIcon, unselectedIcon, description) ->
+            selectedIcon.setBounds(0, 0, iconSize, iconSize)
+            unselectedIcon.setBounds(0, 0, iconSize, iconSize)
+            LegendItem(selectedIcon, unselectedIcon, description)
+        }
+        
+        if (!isExpanded) {
+            text = collapsedText
+        } else {
+            invalidate()
+        }
+        requestLayout()
+    }
+
+    // 娣诲姞涓�涓� Java 鍙嬪ソ鐨勬柟娉�
+    @JvmName("setLegendsArray")
+    fun setLegends(vararg items: Triple<Drawable, Drawable, String>) {
+        setLegends(items.toList())
+    }
+
+    /**
+     * 娣诲姞璁剧疆鐩戝惉鍣ㄧ殑鏂规硶
+     */
+    fun setOnLegendItemClickListener(listener: OnLegendItemClickListener) {
+        legendItemClickListener = listener
+    }
+
+    /**
+     * 澶勭悊瑙︽懜浜嬩欢
+     */
+    override fun onTouchEvent(event: MotionEvent): Boolean {
+        when (event.action) {
+            MotionEvent.ACTION_DOWN -> {
+                // 妫�鏌ョ偣鍑绘槸鍚﹀湪涓夎褰㈠浘鏍囧尯鍩熷唴
+                if (isClickOnTriangle(event.x)) {
+                    toggleExpand()
+                    return true
+                }
+                
+                // 濡傛灉鏄睍寮�鐘舵�侊紝妫�鏌ユ槸鍚︾偣鍑讳簡鍥句緥椤�
+                if (isExpanded) {
+                    val clickedIndex = getClickedItemIndex(event.x, event.y)
+                    if (clickedIndex != -1) {
+                        toggleItemSelection(clickedIndex)
+                        return true
+                    }
+                } else if (!isExpanded && event.x > paddingLeft) {
+                    // 鍦ㄦ敹璧风姸鎬佷笅锛岀偣鍑婚潪涓夎褰㈠尯鍩熶篃灞曞紑
+                    toggleExpand()
+                    return true
+                }
+            }
+        }
+        return super.onTouchEvent(event)
+    }
+
+    /**
+     * 鑾峰彇鐐瑰嚮浣嶇疆瀵瑰簲鐨勫浘渚嬮」绱㈠紩
+     */
+    private fun getClickedItemIndex(x: Float, y: Float): Int {
+        if (!isExpanded) return -1
+
+        val maxWidth = legendItems.maxOf { item ->
+            maxOf(paint.measureText(item.description), iconSize.toFloat())
+        }
+        
+        val totalWidth = legendItems.size * maxWidth + 
+            (legendItems.size - 1) * itemSpacing
+        
+        val startX = (width - totalWidth) / 2
+        val iconTop = paddingTop + (height - legendItemHeight) / 2
+        val iconBottom = iconTop + legendItemHeight
+
+        // 妫�鏌ュ瀭鐩存柟鍚戞槸鍚﹀湪鍥句緥椤硅寖鍥村唴
+        if (y < iconTop || y > iconBottom) return -1
+
+        // 妫�鏌ユ按骞虫柟鍚戠偣鍑荤殑鏄摢涓浘渚嬮」
+        legendItems.forEachIndexed { index, _ ->
+            val itemStartX = startX + index * (maxWidth + itemSpacing)
+            val itemEndX = itemStartX + maxWidth
+            if (x >= itemStartX && x <= itemEndX) {
+                return index
+            }
+        }
+        return -1
+    }
+
+    /**
+     * 鍒囨崲鍥句緥椤圭殑閫変腑鐘舵��
+     */
+    private fun toggleItemSelection(index: Int) {
+        if (index < 0 || index >= legendItems.size) return
+        
+        legendItems[index].isSelected = !legendItems[index].isSelected
+        legendItemClickListener?.onLegendItemClick(
+            index, 
+            legendItems[index].isSelected
+        )
+        invalidate()
+    }
+
+    /**
+     * 璁剧疆灞曞紑鍚庣殑瀛椾綋澶у皬
+     * @param size 瀛椾綋澶у皬锛堝儚绱狅級
+     */
+    fun setExpandedTextSize(size: Float) {
+        this.expandedTextSize = size
+        if (isExpanded) {
+            invalidate()
+        }
+    }
+
+    /**
+     * 璁剧疆灞曞紑鍚庣殑瀛椾綋澶у皬锛圫P锛�
+     * @param sp 瀛椾綋澶у皬锛圫P锛�
+     */
+    fun setExpandedTextSizeSp(sp: Float) {
+        setExpandedTextSize(sp * context.resources.displayMetrics.scaledDensity)
+    }
 }
\ No newline at end of file
diff --git a/expand_button/src/main/res/values/attrs.xml b/expand_button/src/main/res/values/attrs.xml
index 1d34c70..aca0c25 100644
--- a/expand_button/src/main/res/values/attrs.xml
+++ b/expand_button/src/main/res/values/attrs.xml
@@ -11,5 +11,11 @@
         <attr name="animDuration" format="integer"/>
         <!-- 涓夎褰㈠浘鏍囦笌鏂囧瓧鐨勯棿璺� -->
         <attr name="triangleMargin" format="dimension"/>
+        <!-- 鏂板灞炴�� -->
+        <attr name="itemSpacing" format="dimension"/>
+        <attr name="iconSize" format="dimension"/>
+        <attr name="iconTextSpacing" format="dimension"/>
+        <!-- 鏂板灞曞紑鍚庣殑瀛椾綋澶у皬灞炴�� -->
+        <attr name="expandedTextSize" format="dimension"/>
     </declare-styleable>
 </resources> 
\ No newline at end of file

--
Gitblit v1.8.0