From e5a090685df3d5e96a37b141d9a1d002d36f16f2 Mon Sep 17 00:00:00 2001
From: zuoxiao <470321431@qq.com>
Date: 星期五, 14 二月 2025 16:53:43 +0800
Subject: [PATCH] 1.web地图添加管网显示。 2.安卓原生添加管网信息的获取。 3.安卓原生添加管网信息的本地持久化(SQLite数据库)。 4.实现图例用户的选择状态按钮的持久化。 5.实现自定义搜索按钮的实现。 6.实现搜索后弹出界面的相关功能开发。

---
 app/src/main/res/drawable/location_marker_bg.xml                                |   28 +
 expand_button/src/main/res/drawable/bg_search_bar.xml                           |    6 
 app/src/main/java/com/dayu/pipirrapp/view/SearchResultDialog.java               |  129 ++++
 app/src/main/res/drawable/ic_pipenetwork_line_unselected.xml                    |   12 
 app/src/main/res/values/styles.xml                                              |   10 
 app/src/main/assets/js/map.js                                                   |  172 ++---
 app/src/main/java/com/dayu/pipirrapp/dao/PipeNetDao.java                        |    2 
 expand_button/src/main/java/com/example/expand_button/CustomSearchBar.kt        |  178 ++++++
 app/src/main/res/layout/dialog_search_result.xml                                |   21 
 expand_button/src/main/res/drawable/ic_search.xml                               |    9 
 app/src/main/res/layout/item_search_result.xml                                  |   36 +
 app/src/main/java/com/dayu/pipirrapp/dao/DivideDao.java                         |   11 
 app/src/main/java/com/dayu/pipirrapp/dao/CenterPointDao.java                    |    3 
 expand_button/src/main/res/values/attrs.xml                                     |   13 
 app/src/main/assets/img/location_blue.svg                                       |   13 
 app/src/main/java/com/dayu/pipirrapp/bean/db/PipeNetworkBean.java               |   60 -
 app/src/main/java/com/dayu/pipirrapp/db/converter/PipeNetworkConverter.java     |   26 
 expand_button/src/main/res/layout/layout_search_bar.xml                         |   42 +
 app/src/main/java/com/dayu/pipirrapp/bean/db/PipeNetWorkDataBean.java           |   34 +
 app/src/main/java/com/dayu/pipirrapp/utils/CommonKeyName.java                   |   11 
 app/src/main/res/drawable/walking_worker_animation.xml                          |   10 
 app/src/main/res/drawable/worker_frame1.xml                                     |   15 
 expand_button/src/main/java/com/example/expand_button/ExpandSearchView.kt       |  449 ++++++++++++++++
 app/src/main/java/com/dayu/pipirrapp/dao/MarkerDao.java                         |    2 
 /dev/null                                                                       |   12 
 app/src/main/res/layout/fragment_map.xml                                        |   35 
 app/src/main/java/com/dayu/pipirrapp/bean/net/PipeNetworkResult.java            |   22 
 app/src/main/res/drawable/ic_pipenetwork_line.xml                               |   12 
 expand_button/src/main/java/com/example/expand_button/ExpandButton.kt           |   57 -
 app/src/main/java/com/dayu/pipirrapp/fragment/MapFragment.java                  |  205 +++++-
 app/src/main/java/com/dayu/pipirrapp/bean/db/PipeNetworkDataCoordinateBean.java |   29 +
 app/src/main/res/drawable/worker_frame2.xml                                     |   15 
 32 files changed, 1,402 insertions(+), 277 deletions(-)

diff --git a/app/src/main/assets/img/location_blue.svg b/app/src/main/assets/img/location_blue.svg
new file mode 100644
index 0000000..135e3e9
--- /dev/null
+++ b/app/src/main/assets/img/location_blue.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="160" height="160" viewBox="0 0 160 160">
+    <!-- 澶栧彂鍏� (Outer Glow) -->
+    <defs>
+        <radialGradient id="outerGlow" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
+            <stop offset="0%" style="stop-color:#803D8BFF; stop-opacity:0.5" />
+            <stop offset="100%" style="stop-color:#003D8BFF; stop-opacity:0" />
+        </radialGradient>
+    </defs>
+    <circle cx="80" cy="80" r="40" fill="url(#outerGlow)" />
+
+    <!-- 鍐呭渾鐜� (Inner Circle Ring) -->
+    <circle cx="80" cy="80" r="30" fill="white" stroke="#3D8BFF" stroke-width="4" />
+</svg>
diff --git a/app/src/main/assets/js/map.js b/app/src/main/assets/js/map.js
index bfd0f8d..af17e60 100644
--- a/app/src/main/assets/js/map.js
+++ b/app/src/main/assets/js/map.js
@@ -143,7 +143,7 @@
 
     // 鎵嬫満鑾峰彇鍒板畾浣嶅悗鏄剧ず瀹氫綅
     function locationOverLay(lng, lag) {
-        console.log("function銆嬨�嬨�嬨�嬨�媗ocationOverLay");
+//        console.log("function銆嬨�嬨�嬨�嬨�媗ocationOverLay");
         map.centerAndZoom(new T.LngLat(lng, lag), map.getZoom());
         let icon = new T.Icon({
             iconUrl: CONFIG.IMAGES.LOCATION,
@@ -161,7 +161,7 @@
     //璁剧疆鍦板浘涓績鐐�
     function setCenterAndZoom(lng, lat, thiszoom) {
         zoom = thiszoom;
-        console.log("function銆嬨�嬨�嬨�嬨�媠etCenterAndZoom>>>>lng:" + lng + ",lat:" + lat);
+//        console.log("function銆嬨�嬨�嬨�嬨�媠etCenterAndZoom>>>>lng:" + lng + ",lat:" + lat);
         map.centerAndZoom(new T.LngLat(lng, lat), zoom);
     }
 
@@ -180,10 +180,9 @@
             if (lastClickedMarker !== null) {
                 lastClickedMarker.setIcon(createIcon(CONFIG.IMAGES.MARKER_BLUE));
             }
-            if(lastClickedDivide!==null)
-           {
-           lastClickedDivide.setIcon(createIcon(CONFIG.IMAGES.DIVIDE_BLUE));
-           }
+            if (lastClickedDivide !== null) {
+                lastClickedDivide.setIcon(createIcon(CONFIG.IMAGES.DIVIDE_BLUE));
+            }
             if (isShowWaterIntakeDetail || isShowDivideDetail) {
                 // 鍋囧鏄剧ず浜嗗彇姘村彛璇︽儏鍒欓殣钘忓彇姘村彛璇︽儏
                 isShowWaterIntakeDetail = false;
@@ -232,13 +231,11 @@
     function isEqualsLngLat(data1, data2) {
         return data1.lat === data2.lat && data1.lng === data2.lng;
     }
-    function addMarker(id, lng, lat, name) {
-        addMarker(id, lng, lat, name, false)
+    function addMarker(id, lng, lat, name, isShow) {
+        addMyMarker(id, lng, lat, name, false, isShow)
     }
     //娣诲姞浠庡師鐢熶紶杩囨潵鐨勫潗鏍囧苟鏄剧ず鍦ㄥ湴鍥句笂
-    function addMarker(id, lng, lat, name, isRed) {
-        console.log("function銆嬨�嬨�嬨�嬨�媋ddMarker>>>id:" + id);
-
+    function addMyMarker(id, lng, lat, name, isRed, isShow) {
         const iconUrl = isRed ? CONFIG.IMAGES.MARKER_RED : CONFIG.IMAGES.MARKER_BLUE;
         let marker = new T.Marker(
             new T.LngLat(lng, lat),
@@ -263,15 +260,16 @@
         if (isRed) {
             lastClickedMarker = marker;
         }
-        
+
         // 灏嗘爣璁板拰鏍囩瀛樺偍鍒版暟缁勪腑
         waterIntakeMarkers.push({
             marker: marker,
             label: label
         });
-        
-        map.addOverLay(label);
-        map.addOverLay(marker);
+        if (isShow === "true" || isShow === true) {
+            map.addOverLay(label);
+            map.addOverLay(marker);
+        }
         return "addMarker鍔犺浇鎴愬姛 id:" + id
     }
     //鏇存柊浣嶅潗鏍�
@@ -311,96 +309,67 @@
 
     // 绠$綉绾胯矾绠$悊
     const PipelineManager = {
-        lines: [],  // 瀛樺偍鎵�鏈夊畬鎴愮殑绾胯矾
+        lines: [],
         currentLine: {
-            points: [],  // 褰撳墠绾胯矾鐨勭偣
-            overlay: null  // 褰撳墠绾胯矾鐨勫浘灞傚璞�
+            points: [],
+            overlay: null
         },
-        
-        // 绾胯矾鏍峰紡閰嶇疆
+
         style: {
             color: '#1890FF',
             weight: 3,
             opacity: 0.8
         },
-        
-        /**
-         * 娣诲姞鐐瑰埌绠$綉绾胯矾
-         * @param {number} lng 缁忓害
-         * @param {number} lat 绾害
-         * @param {boolean} isNewLine 鏄惁寮�濮嬫柊鐨勭嚎璺�
-         */
-        addPoint(lng, lat, isNewLine) {
-            if (isNewLine) {
-                this.finishCurrentLine();
-            }
-            
+
+        addPoint(lng, lat, isNewLine, isShow) {
+//            console.log(`Adding point: ${lng}, ${lat}, isNewLine: ${isNewLine}`); // 娣诲姞鏃ュ織
+
             const point = new T.LngLat(lng, lat);
-            this.currentLine.points.push(point);
-            
-            if (this.currentLine.points.length > 1) {
-                this.updateCurrentLineDisplay();
-            }
-        },
-        
-        /**
-         * 鏇存柊褰撳墠绾胯矾鐨勬樉绀�
-         */
-        updateCurrentLineDisplay() {
-            if (!this.currentLine.overlay) {
-                // 鍒涘缓鏂扮殑绾胯矾鍥惧眰
-                this.currentLine.overlay = new T.Polyline(this.currentLine.points, this.style);
-                map.addOverLay(this.currentLine.overlay);
-            } else {
-                // 鏇存柊鐜版湁绾胯矾鐨勭偣
-                this.currentLine.overlay.setLngLats(this.currentLine.points);
-            }
-        },
-        
-        /**
-         * 瀹屾垚褰撳墠绾胯矾
-         */
-        finishCurrentLine() {
-            if (this.currentLine.points.length > 1) {
-                if (this.currentLine.overlay) {
-                    // 灏嗗綋鍓嶇嚎璺坊鍔犲埌瀹屾垚鍒楄〃
-                    this.lines.push(this.currentLine.overlay);
+
+            // 淇敼鍒ゆ柇閫昏緫锛岀‘淇濆瓧绗︿覆"false"琚纭鐞�
+            const shouldCreateNewLine = isNewLine === true || isNewLine === "true" || !this.currentLine.overlay;
+
+            if (shouldCreateNewLine) {
+                // 鍒涘缓鏂扮嚎璺�
+                this.currentLine.points = [point];
+                this.currentLine.overlay = new T.Polyline([point], this.style);
+                if (isShow === true || isShow === "true") {
+                    map.addOverLay(this.currentLine.overlay);
                 }
-            } else if (this.currentLine.overlay) {
-                // 濡傛灉鐐规暟涓嶈冻锛屾竻闄ゅ浘灞�
-                map.removeOverLay(this.currentLine.overlay);
+            } else {
+                // 娣诲姞鐐瑰埌鐜版湁绾胯矾
+                this.currentLine.points.push(point);
+                this.currentLine.overlay.setLngLats(this.currentLine.points);
+
             }
-            
-            // 閲嶇疆褰撳墠绾胯矾
-            this.currentLine = {
-                points: [],
-                overlay: null
-            };
+            // 濡傛灉鏄柊绾胯矾锛屽皢涔嬪墠鐨勭嚎璺繚瀛樺埌 lines 鏁扮粍
+            if (isNewLine === true || isNewLine === "true") {
+                this.lines.push({
+                    points: [...this.currentLine.points],
+                    overlay: this.currentLine.overlay
+                });
+            }
         },
-        
-        /**
-         * 鏄剧ず鎵�鏈夌嚎璺�
-         */
+
         showAll() {
-            this.lines.forEach(line => map.addOverLay(line));
-            if (this.currentLine.overlay) {
-                map.addOverLay(this.currentLine.overlay);
-            }
+//            console.log("showAllpipe" + this.lines.length);
+            this.lines.forEach(line => {
+                if (line.overlay) {
+                    map.addOverLay(line.overlay);
+                }
+            });
+
         },
-        
-        /**
-         * 闅愯棌鎵�鏈夌嚎璺�
-         */
+
         hideAll() {
-            this.lines.forEach(line => map.removeOverLay(line));
-            if (this.currentLine.overlay) {
-                map.removeOverLay(this.currentLine.overlay);
-            }
+//            console.log("hideAllpipe" + this.lines.length);
+            this.lines.forEach(line => {
+                if (line.overlay) {
+                    map.removeOverLay(line.overlay);
+                }
+            });
         },
-        
-        /**
-         * 娓呴櫎鎵�鏈夌嚎璺�
-         */
+
         clearAll() {
             this.hideAll();
             this.lines = [];
@@ -414,8 +383,8 @@
     /**
      * 娣诲姞绠$綉绾胯矾鐐�
      */
-    function addPipeNetwork(lng, lat, isNewLine) {
-        PipelineManager.addPoint(lng, lat, isNewLine);
+    function addPipeNetwork(lng, lat, isNewLine, isShow) {
+        PipelineManager.addPoint(lng, lat, isNewLine, isShow);
     }
 
     /**
@@ -491,14 +460,14 @@
     function refreshMarker(id, lng, lat, name) {
         map.removeOverLay(lastClickedMarker.label);
         map.removeOverLay(lastClickedMarker);
-        addMarker(id, lng, lat, name, true);
+        addMarker(id, lng, lat, name, true, true);
     }
 
 
     function mapMoveEnd(e) {
 
-            const center = e.target.getCenter();
-            window.Android.refreshCenter(center.getLng(), center.getLat());
+        const center = e.target.getCenter();
+        window.Android.refreshCenter(center.getLng(), center.getLat());
 
     }
 
@@ -524,11 +493,11 @@
         });
     }
     //娣诲姞鍒嗘按鎴�
-    function addDivide(id, lng, lat, name) {
-        addDivide(id, lng, lat, name, false)
+    function addDivide(id, lng, lat, name, isShow) {
+        addMyDivide(id, lng, lat, name, false, isShow)
     }
     //娣诲姞鍒嗘按鎴�
-    function addDivide(id, lng, lat, name, isRed) {
+    function addMyDivide(id, lng, lat, name, isRed, isShow) {
         console.log("function銆嬨�嬨�嬨�嬨�媋ddMarker>>>id:" + id);
 
         const iconUrl = isRed ? CONFIG.IMAGES.DIVIDE_RED : CONFIG.IMAGES.DIVIDE_BLUE;
@@ -561,9 +530,10 @@
             marker: marker,
             label: label
         });
-
-        map.addOverLay(label);
-        map.addOverLay(marker); // 灏嗘爣娉ㄦ坊鍔犲埌鍦板浘涓�
+        if (isShow === true || isShow === "true") {
+            map.addOverLay(label);
+            map.addOverLay(marker); // 灏嗘爣娉ㄦ坊鍔犲埌鍦板浘涓�
+        }
         return "addMarker鍔犺浇鎴愬姛 id:" + id
     }
     // 淇敼鐐瑰嚮鏍囨敞鐨勫浘鏍�
diff --git a/app/src/main/java/com/dayu/pipirrapp/bean/db/PipeNetWorkDataBean.java b/app/src/main/java/com/dayu/pipirrapp/bean/db/PipeNetWorkDataBean.java
new file mode 100644
index 0000000..e0a9f54
--- /dev/null
+++ b/app/src/main/java/com/dayu/pipirrapp/bean/db/PipeNetWorkDataBean.java
@@ -0,0 +1,34 @@
+package com.dayu.pipirrapp.bean.db;
+
+import java.util.List;
+
+/**
+ * PipNetWorkDataBean -
+ *
+ * @author zuoxiao
+ * @version 1.0
+ * @since 2025-02-11
+ */
+public class PipeNetWorkDataBean {
+    List<PipeNetworkDataCoordinateBean> coordinates;
+    String type;
+
+
+
+
+    public List<PipeNetworkDataCoordinateBean> getCoordinates() {
+        return coordinates;
+    }
+
+    public void setCoordinates(List<PipeNetworkDataCoordinateBean> coordinates) {
+        this.coordinates = coordinates;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+}
diff --git a/app/src/main/java/com/dayu/pipirrapp/bean/db/PipeNetworkBean.java b/app/src/main/java/com/dayu/pipirrapp/bean/db/PipeNetworkBean.java
index 8dbcf2b..fe15ece 100644
--- a/app/src/main/java/com/dayu/pipirrapp/bean/db/PipeNetworkBean.java
+++ b/app/src/main/java/com/dayu/pipirrapp/bean/db/PipeNetworkBean.java
@@ -2,8 +2,10 @@
 
 import androidx.room.Entity;
 import androidx.room.PrimaryKey;
+import androidx.room.TypeConverters;
 
 import com.dayu.pipirrapp.bean.net.PipeNetworkResult;
+import com.dayu.pipirrapp.db.converter.PipeNetworkConverter;
 
 import java.util.List;
 
@@ -15,65 +17,17 @@
  * @since 2025-01-17
  */
 @Entity
+@TypeConverters(PipeNetworkConverter.class)
 public class PipeNetworkBean {
     @PrimaryKey(autoGenerate = true)
     public long id;
 
     String type;
     String networkId;
-    List<PipeNetworkResult.Data> data;
+    @TypeConverters(PipeNetworkConverter.class)
+    PipeNetWorkDataBean data;
 
 
-    public class Data {
-        public class Coordinate {
-            String lat;
-            String lng;
-
-            public String getLat() {
-                return lat;
-            }
-
-            public void setLat(String lat) {
-                this.lat = lat;
-            }
-
-            public String getLng() {
-                return lng;
-            }
-
-            public void setLng(String lng) {
-                this.lng = lng;
-            }
-        }
-
-        List<PipeNetworkResult.Data.Coordinate> coordinates;
-        String type;
-        String networkId;
-
-        public List<PipeNetworkResult.Data.Coordinate> getCoordinates() {
-            return coordinates;
-        }
-
-        public void setCoordinates(List<PipeNetworkResult.Data.Coordinate> coordinates) {
-            this.coordinates = coordinates;
-        }
-
-        public String getType() {
-            return type;
-        }
-
-        public void setType(String type) {
-            this.type = type;
-        }
-
-        public String getNetworkId() {
-            return networkId;
-        }
-
-        public void setNetworkId(String networkId) {
-            this.networkId = networkId;
-        }
-    }
 
     public String getType() {
         return type;
@@ -91,11 +45,11 @@
         this.networkId = networkId;
     }
 
-    public List<PipeNetworkResult.Data> getData() {
+    public PipeNetWorkDataBean getData() {
         return data;
     }
 
-    public void setData(List<PipeNetworkResult.Data> data) {
+    public void setData(PipeNetWorkDataBean data) {
         this.data = data;
     }
 
diff --git a/app/src/main/java/com/dayu/pipirrapp/bean/db/PipeNetworkDataCoordinateBean.java b/app/src/main/java/com/dayu/pipirrapp/bean/db/PipeNetworkDataCoordinateBean.java
new file mode 100644
index 0000000..b8de500
--- /dev/null
+++ b/app/src/main/java/com/dayu/pipirrapp/bean/db/PipeNetworkDataCoordinateBean.java
@@ -0,0 +1,29 @@
+package com.dayu.pipirrapp.bean.db;
+
+/**
+ * PipeNetworkDataCoordinateBean -
+ *
+ * @author zuoxiao
+ * @version 1.0
+ * @since 2025-02-11
+ */
+public class PipeNetworkDataCoordinateBean {
+    String lat;
+    String lng;
+
+    public String getLat() {
+        return lat;
+    }
+
+    public void setLat(String lat) {
+        this.lat = lat;
+    }
+
+    public String getLng() {
+        return lng;
+    }
+
+    public void setLng(String lng) {
+        this.lng = lng;
+    }
+}
diff --git a/app/src/main/java/com/dayu/pipirrapp/bean/net/PipeNetworkResult.java b/app/src/main/java/com/dayu/pipirrapp/bean/net/PipeNetworkResult.java
index 01105ef..bbcb2aa 100644
--- a/app/src/main/java/com/dayu/pipirrapp/bean/net/PipeNetworkResult.java
+++ b/app/src/main/java/com/dayu/pipirrapp/bean/net/PipeNetworkResult.java
@@ -12,10 +12,12 @@
 public class PipeNetworkResult {
     String type;
     String networkId;
-    List<Data> data;
+    Data data;
 
 
-    public class Data {
+    public static class Data {
+        List<Coordinate> coordinates;
+        String type;
         public class Coordinate {
             String lat;
             String lng;
@@ -37,9 +39,8 @@
             }
         }
 
-        List<Coordinate> coordinates;
-        String type;
-        String networkId;
+
+
 
         public List<Coordinate> getCoordinates() {
             return coordinates;
@@ -57,13 +58,6 @@
             this.type = type;
         }
 
-        public String getNetworkId() {
-            return networkId;
-        }
-
-        public void setNetworkId(String networkId) {
-            this.networkId = networkId;
-        }
     }
 
     public String getType() {
@@ -82,11 +76,11 @@
         this.networkId = networkId;
     }
 
-    public List<Data> getData() {
+    public Data getData() {
         return data;
     }
 
-    public void setData(List<Data> data) {
+    public void setData(Data data) {
         this.data = data;
     }
 }
diff --git a/app/src/main/java/com/dayu/pipirrapp/dao/CenterPointDao.java b/app/src/main/java/com/dayu/pipirrapp/dao/CenterPointDao.java
index 05cb87e..ddc6372 100644
--- a/app/src/main/java/com/dayu/pipirrapp/dao/CenterPointDao.java
+++ b/app/src/main/java/com/dayu/pipirrapp/dao/CenterPointDao.java
@@ -32,4 +32,7 @@
     @Delete
     void delete(CenterPointBean adminData);
 
+    @Query("DELETE FROM CenterPointBean")
+    void deleteAll();
+
 }
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 a574aa0..464f24b 100644
--- a/app/src/main/java/com/dayu/pipirrapp/dao/DivideDao.java
+++ b/app/src/main/java/com/dayu/pipirrapp/dao/DivideDao.java
@@ -9,6 +9,7 @@
 
 import com.dayu.pipirrapp.bean.db.DivideBean;
 import com.dayu.pipirrapp.bean.db.MarkerBean;
+import com.dayu.pipirrapp.bean.db.SearchResultBean;
 
 import java.util.List;
 
@@ -54,4 +55,14 @@
 
     @Query("SELECT * FROM DivideBean")
     Maybe<List<DivideBean>> getAll();  // 鏀逛负杩斿洖Maybe<List<DivideBean>>
+
+    @Query("SELECT * FROM DivideBean WHERE divideName LIKE '%' || :name || '%'")
+    Single<List<DivideBean>> findByDivideNameLike(String name);
+
+    @Query("SELECT divideName as name, 'divide' as type, lat, lng, address, divideId as id FROM DivideBean " +
+           "WHERE divideName LIKE '%' || :keyword || '%' " +
+           "UNION " +
+           "SELECT name, 'marker' as type, lat, lng, address, id FROM MarkerBean " +
+           "WHERE name LIKE '%' || :keyword || '%'")
+    Single<List<SearchResultBean>> searchAllByKeyword(String keyword);
 }
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 4bd9344..c34cb55 100644
--- a/app/src/main/java/com/dayu/pipirrapp/dao/MarkerDao.java
+++ b/app/src/main/java/com/dayu/pipirrapp/dao/MarkerDao.java
@@ -53,4 +53,6 @@
     @Query("SELECT * FROM MarkerBean")
     Maybe<List<MarkerBean>> getAll();
 
+    @Query("SELECT * FROM MarkerBean WHERE name LIKE '%' || :name || '%'")
+    Single<List<MarkerBean>> findByNameLike(String name);
 }
diff --git a/app/src/main/java/com/dayu/pipirrapp/dao/PipeNetDao.java b/app/src/main/java/com/dayu/pipirrapp/dao/PipeNetDao.java
index 2c2fa9f..e4cf130 100644
--- a/app/src/main/java/com/dayu/pipirrapp/dao/PipeNetDao.java
+++ b/app/src/main/java/com/dayu/pipirrapp/dao/PipeNetDao.java
@@ -1,5 +1,6 @@
 package com.dayu.pipirrapp.dao;
 
+import androidx.room.Dao;
 import androidx.room.Delete;
 import androidx.room.Insert;
 import androidx.room.OnConflictStrategy;
@@ -17,6 +18,7 @@
 /**
  * 绠$綉鐩稿叧dao
  */
+@Dao
 public interface PipeNetDao {
     @Insert(onConflict = OnConflictStrategy.REPLACE)
     void insert(PipeNetworkBean pipeNetworkBean);
diff --git a/app/src/main/java/com/dayu/pipirrapp/db/converter/PipeNetworkConverter.java b/app/src/main/java/com/dayu/pipirrapp/db/converter/PipeNetworkConverter.java
new file mode 100644
index 0000000..55d4641
--- /dev/null
+++ b/app/src/main/java/com/dayu/pipirrapp/db/converter/PipeNetworkConverter.java
@@ -0,0 +1,26 @@
+package com.dayu.pipirrapp.db.converter;
+
+import androidx.room.TypeConverter;
+import com.dayu.pipirrapp.bean.db.PipeNetWorkDataBean;
+import com.google.gson.Gson;
+
+public class PipeNetworkConverter {
+    
+    @TypeConverter
+    public static String fromPipeNetWorkDataBean(PipeNetWorkDataBean data) {
+        if (data == null) {
+            return null;
+        }
+        Gson gson = new Gson();
+        return gson.toJson(data);
+    }
+
+    @TypeConverter
+    public static PipeNetWorkDataBean toPipeNetWorkDataBean(String dataString) {
+        if (dataString == null) {
+            return null;
+        }
+        Gson gson = new Gson();
+        return gson.fromJson(dataString, PipeNetWorkDataBean.class);
+    }
+} 
\ No newline at end of file
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 27486c3..e01d39b 100644
--- a/app/src/main/java/com/dayu/pipirrapp/fragment/MapFragment.java
+++ b/app/src/main/java/com/dayu/pipirrapp/fragment/MapFragment.java
@@ -32,7 +32,9 @@
 import com.dayu.pipirrapp.bean.db.InspectionLocationBean;
 import com.dayu.pipirrapp.bean.db.LatLonBean;
 import com.dayu.pipirrapp.bean.db.MarkerBean;
+import com.dayu.pipirrapp.bean.db.PipeNetWorkDataBean;
 import com.dayu.pipirrapp.bean.db.PipeNetworkBean;
+import com.dayu.pipirrapp.bean.db.PipeNetworkDataCoordinateBean;
 import com.dayu.pipirrapp.bean.net.CenterPointResult;
 import com.dayu.pipirrapp.bean.net.DivideListResult;
 import com.dayu.pipirrapp.bean.net.DivideResult;
@@ -61,7 +63,9 @@
 import com.dayu.pipirrapp.utils.ToastUtil;
 import com.dayu.pipirrapp.utils.WebViewUtils;
 import com.dayu.pipirrapp.view.ConfirmDialog;
+import com.dayu.pipirrapp.view.SearchResultDialog;
 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;
@@ -81,6 +85,8 @@
 import io.reactivex.rxjava3.disposables.CompositeDisposable;
 import io.reactivex.rxjava3.schedulers.Schedulers;
 import kotlin.Triple;
+import kotlin.Unit;
+import kotlin.jvm.functions.Function1;
 
 /**
  * author: zuo
@@ -108,6 +114,7 @@
     //web鍔犺浇鏃剁綉椤佃繕娌″姞杞藉畬鏃剁殑鏁版嵁
     List<MarkerBean> webNoFinishMarkerData = new ArrayList<>();
     List<DivideBean> webNoFinishDivideData = new ArrayList<>();
+    List<PipeNetworkBean> webNoFinishPipeNetworkData = new ArrayList<>();
     //鎵�鏈夌殑Marker鏁版嵁閿负marker鐨処d
     Map<String, MarkerBean> markerBeanSet = new HashMap<>();
     //鎵�鏈夊垎姘存埧
@@ -117,6 +124,9 @@
     public double centerLat;
 
     MarkerBean mMarkerBean;
+
+    //鏄惁鏄剧ずMarker
+    boolean isShowMarker, isShowPipeNetwork, isShowDivide;
 
     // 娣诲姞CompositeDisposable鏉ョ鐞嗘墍鏈夎闃�
     private CompositeDisposable compositeDisposable = new CompositeDisposable();
@@ -178,6 +188,8 @@
      * 寮傛鍔犺浇鏈湴鏁版嵁
      */
     private void loadLocalData() {
+
+
         // 寮傛鍔犺浇涓績鐐规暟鎹�
         compositeDisposable.add(
                 DaoSingleton.getAsynchInstance(this.getContext()).centerPointDao().findFirst()
@@ -198,7 +210,7 @@
                             getCenterPoint();
                         })
         );
-
+        isShowMarker = SharedPreferencesHelper.getInstance(this.getContext()).get(CommonKeyName.markerKeyIsShow, true);
         // 寮傛鍔犺浇鍙栨按鍙f暟鎹�
         compositeDisposable.add(
                 DaoSingleton.getAsynchInstance(this.getContext()).markerDao().getAll()
@@ -221,7 +233,7 @@
                             getMarkerData();
                         })
         );
-
+        isShowDivide = SharedPreferencesHelper.getInstance(this.getContext()).get(CommonKeyName.divideIsShow, true);
         // 寮傛鍔犺浇鍒嗘按鎴挎暟鎹�
         compositeDisposable.add(
                 DaoSingleton.getAsynchInstance(this.getContext()).divideDao().getAll()
@@ -244,6 +256,8 @@
                             getDivideList();
                         })
         );
+
+        isShowPipeNetwork = SharedPreferencesHelper.getInstance(this.getContext()).get(CommonKeyName.pipeNetworkIsShow, true);
         //寮傛鍔犺浇绠$綉鏁版嵁
         compositeDisposable.add(
                 DaoSingleton.getAsynchInstance(this.getContext()).pipeNetDao().getAll()
@@ -254,16 +268,15 @@
                                 getPipeNetworkList();
                             } else {
                                 for (PipeNetworkBean pipeNetworkBean : pipeNetworkBeans) {
-
-
+                                    setMapPipe(pipeNetworkBean);
                                 }
                             }
                         }, throwable -> {
-                            Log.e(TAG, "Load divides error: " + throwable.getMessage());
-                            getDivideList();
+                            Log.e(TAG, "Load PipeNetworkBean error: " + throwable.getMessage());
+                            getPipeNetworkList();
                         }, () -> {
                             // 褰揗aybe涓虹┖鏃惰皟鐢�
-                            getDivideList();
+                            getPipeNetworkList();
                         })
         );
     }
@@ -353,6 +366,12 @@
                 setMapDivide(bean);
             }
         }
+        if (!webNoFinishPipeNetworkData.isEmpty()) {
+            for (PipeNetworkBean bean : webNoFinishPipeNetworkData) {
+                setMapPipe(bean);
+            }
+        }
+
         //鏄剧ず鎵�鏈夊彇姘村彛
         MarkerUtils.showLocoMarks(MapFragment.this);
         //鏄剧ず宸℃鐘舵�佸苟涓旀樉绀哄洜鎰忓鍏抽棴鐨勫巻鍙叉暟鎹�
@@ -391,7 +410,7 @@
                                     return markerBean;
                                 })
                                 .collect(Collectors.toList());
-
+                        DaoSingleton.getInstance(MapFragment.this.getContext()).markerDao().deleteAll();
                         // 浣跨敤 CompositeDisposable 绠$悊鏁版嵁搴撴彃鍏ユ搷浣�
                         compositeDisposable.add(
                                 DaoSingleton.getAsynchInstance(MapFragment.this.getContext()).markerDao().insertAll(markerBeans)
@@ -424,7 +443,7 @@
         //宸℃鎸夐挳
         binding.inspectButton.setOnClickListener(v -> {
             if (XXPermissions.isGranted(MapFragment.this.getContext(), Permission.ACCESS_BACKGROUND_LOCATION)) {
-                new ConfirmDialog(MapFragment.this.getActivity(), (confirmDialog, v1) -> {
+                new ConfirmDialog(MapFragment.this.getActivity(), "纭寮�濮嬪贰妫�鍚楋紵",(confirmDialog, v1) -> {
                     chageInspecState(InspectionUtils.STAT_INSPECTION_ONCLICK);
                     confirmDialog.dismiss();
                 }).show();
@@ -456,28 +475,88 @@
             Intent issue = new Intent(MapFragment.this.getActivity(), AddIssueActivity.class);
             MapFragment.this.getActivity().startActivity(issue);
         });
-        binding.expandButton.setLegendsArray(new Triple<>(
+        binding.expandButton.setLegendsArray(new ExpandButton.Quadruple(
                         ContextCompat.getDrawable(requireContext(), R.drawable.marker_blue),
                         ContextCompat.getDrawable(requireContext(), R.drawable.marker_unselected),
-                        "鍙栨按鍙�"
+                        "鍙栨按鍙�", isShowMarker
                 ),
-                new Triple<>(
+                new ExpandButton.Quadruple(
                         ContextCompat.getDrawable(requireContext(), R.drawable.divide_home_blue),
                         ContextCompat.getDrawable(requireContext(), R.drawable.divide_home_unselected),
-                        "鍒嗘按鎴�"
-                ));
+                        "鍒嗘按鎴�", isShowDivide
+                ),
+                new ExpandButton.Quadruple(
+                        ContextCompat.getDrawable(requireContext(), R.drawable.ic_pipenetwork_line),
+                        ContextCompat.getDrawable(requireContext(), R.drawable.ic_pipenetwork_line_unselected),
+                        "绠$綉", isShowPipeNetwork
+                )
+        );
         binding.expandButton.setOnLegendItemClickListener((position, isSelected) -> {
             switch (position) {
                 case 0:
                     showMarkers(isSelected);
+                    SharedPreferencesHelper.getInstance(this.getContext()).put(CommonKeyName.markerKeyIsShow, isSelected);
                     break;
                 case 1:
                     showDivideMarkers(isSelected);
+                    SharedPreferencesHelper.getInstance(this.getContext()).put(CommonKeyName.divideIsShow, isSelected);
+                    break;
+                case 2:
+                    showPipeLine(isSelected);
+                    SharedPreferencesHelper.getInstance(this.getContext()).put(CommonKeyName.pipeNetworkIsShow, isSelected);
                     break;
 
             }
         });
+        binding.searchButton.setOnSearchClickListener(s -> {
+            if (s != null && !s.isEmpty()) {
+                SearchResultDialog searchDialog = new SearchResultDialog(requireContext());
+                searchDialog.setOnItemClickListener(item -> {
+                    // 鏍规嵁绫诲瀷澶勭悊鐐瑰嚮浜嬩欢
+//                    if ("marker".equals(item.getType())) {
+//                        MarkerBean markerBean = new MarkerBean();
+//                        markerBean.setId(item.getId());
+//                        getInstakeDetail(markerBean);
+//                    } else {
+//                        DivideBean divideBean = new DivideBean();
+//                        divideBean.setDivideId(item.getId());
+//                        getDivideDetail(divideBean);
+//                    }
+                    // 璺宠浆鍒伴�夋嫨鐨勪綅缃�
+                    mWebView.evaluateJavascript(
+                        String.format("javascript:setCenterAndZoom(\"%s\",\"%s\",\"17\")", 
+                        item.getLng(), 
+                        item.getLat()), 
+                        null
+                    );
+                });
+                
+                // 鎵ц鎼滅储
+                compositeDisposable.add(
+                    DaoSingleton.getAsynchInstance(requireContext())
+                        .divideDao()
+                        .searchAllByKeyword(s)
+                        .subscribeOn(Schedulers.io())
+                        .observeOn(AndroidSchedulers.mainThread())
+                        .subscribe(
+                            results -> {
+                                if (results != null && !results.isEmpty()) {
+                                    searchDialog.setData(results);
+                                    searchDialog.show();
+                                } else {
+                                    ToastUtil.showToast(requireContext(), "鏈壘鍒扮浉鍏崇粨鏋�");
+                                }
+                            },
+                            throwable -> {
+                                ToastUtil.showToast(requireContext(), "鎼滅储澶辫触锛�" + throwable.getMessage());
+                            }
+                        )
+                );
+            }
+            return null;
+        });
     }
+
 
     /**
      * 鏄剧ず鍙栨按鍙h鎯�
@@ -522,6 +601,7 @@
                     centerPointBean.setLat(t.getContent().getLat());
                     centerPointBean.setLng(t.getContent().getLng());
                     centerPointBean.setZoomMp(t.getContent().getZoomMp());
+                    DaoSingleton.getInstance(MapFragment.this.getContext()).centerPointDao().deleteAll();
                     DaoSingleton.getInstance(MapFragment.this.getContext()).centerPointDao().insert(centerPointBean);
                     jumpCenterPoint();
                 } else {
@@ -715,13 +795,13 @@
     }
 
     /**
-     * 娣诲姞鏍囨敞鐐�
+     * 娣诲姞鍙栨按鍙�
      */
     public void setMapMarker(MarkerBean markerBean) {
         if (markerBean != null) {
             if (webViewIsFinished) {
                 if (!TextUtils.isEmpty(markerBean.getLng()) && !TextUtils.isEmpty(markerBean.getLat())) {
-                    mWebView.evaluateJavascript("javascript:addMarker(\"" + markerBean.getId() + "\",\"" + markerBean.getLng() + "\",\"" + markerBean.getLat() + "\",\"" + markerBean.getName() + "\")", new ValueCallback<String>() {
+                    mWebView.evaluateJavascript("javascript:addMarker(\"" + markerBean.getId() + "\",\"" + markerBean.getLng() + "\",\"" + markerBean.getLat() + "\",\"" + markerBean.getName() + "\",\"" + isShowMarker + "\")", new ValueCallback<String>() {
                         @Override
                         public void onReceiveValue(String value) {
                         }
@@ -737,13 +817,13 @@
     }
 
     /**
-     * 娣诲姞鍙栨按鍙f爣娉�
+     * 娣诲姞鍒嗘按鎴�
      */
     public void setMapDivide(DivideBean divide) {
         if (divide != null) {
             if (webViewIsFinished) {
                 if (!TextUtils.isEmpty(divide.getLng()) && !TextUtils.isEmpty(divide.getLat())) {
-                    mWebView.evaluateJavascript("javascript:addDivide(\"" + divide.getId() + "\",\"" + divide.getLng() + "\",\"" + divide.getLat() + "\",\"" + divide.getDivideName() + "\")", new ValueCallback<String>() {
+                    mWebView.evaluateJavascript("javascript:addDivide(\"" + divide.getId() + "\",\"" + divide.getLng() + "\",\"" + divide.getLat() + "\",\"" + divide.getDivideName() + "\",\"" + isShowDivide + "\")", new ValueCallback<String>() {
                         @Override
                         public void onReceiveValue(String value) {
                         }
@@ -761,24 +841,24 @@
     /**
      * 娣诲姞绠$綉鏍囨敞
      */
-    public void setMapDivide(PipeNetworkBean pipeNetworkBean) {
-//        if (divide != null) {
-//            if (webViewIsFinished) {
-//                for ()
-//                if (!TextUtils.isEmpty(divide.getLng()) && !TextUtils.isEmpty(divide.getLat())) {
-//                    mWebView.evaluateJavascript("javascript:addDivide(\"" + divide.getId() + "\",\"" + divide.getLng() + "\",\"" + divide.getLat() + "\",\"" + divide.getDivideName() + "\")", new ValueCallback<String>() {
-//                        @Override
-//                        public void onReceiveValue(String value) {
-//                        }
-//                    });
-//                    divideBeanMap.put(divide.getId(), divide);
-//                } else {
-//                    MyLog.d("setMapDivide>" + divide.getDivideName() + "缁忕含搴︿负绌�");
-//                }
-//            } else {
-//                webNoFinishDivideData.add(divide);
-//            }
-//        }
+    public void setMapPipe(PipeNetworkBean pipeNetworkBean) {
+        if (pipeNetworkBean != null) {
+            if (webViewIsFinished) {
+                boolean isfrist = true;
+                for (PipeNetworkDataCoordinateBean data : pipeNetworkBean.getData().getCoordinates()) {
+                    if (!TextUtils.isEmpty(data.getLat()) && !TextUtils.isEmpty(data.getLng())) {
+                        mWebView.evaluateJavascript("javascript:addPipeNetwork(\"" + data.getLng() + "\",\"" + data.getLat() + "\",\"" + isfrist +  "\",\"" + isShowPipeNetwork +"\")", new ValueCallback<String>() {
+                            @Override
+                            public void onReceiveValue(String value) {
+                            }
+                        });
+                        isfrist = false;
+                    }
+                }
+            } else {
+                webNoFinishPipeNetworkData.add(pipeNetworkBean);
+            }
+        }
     }
 
     /**
@@ -1053,7 +1133,7 @@
                                 setMapDivide(divideBean);
                                 divideBeans.add(divideBean);
                             }
-
+                            DaoSingleton.getInstance(MapFragment.this.getContext()).divideDao().deleteAll();
                             // 浣跨敤 CompositeDisposable 绠$悊鏁版嵁搴撴彃鍏ユ搷浣�
                             compositeDisposable.add(
                                     DaoSingleton.getAsynchInstance(MapFragment.this.getContext()).divideDao().insertAll(divideBeans)
@@ -1094,23 +1174,40 @@
                         if (t.getContent() != null && t.getContent().size() > 0) {
 
                             List<PipeNetworkBean> pipeNetBeans = new ArrayList<>();
-                            PipeNetworkBean pipeNetBean = new PipeNetworkBean();
+
                             for (PipeNetworkResult pipeNetworkResult : t.getContent()) {
+                                PipeNetworkBean pipeNetBean = new PipeNetworkBean();
                                 pipeNetBean.setNetworkId(pipeNetworkResult.getNetworkId());
                                 pipeNetBean.setType(pipeNetworkResult.getType());
-                                pipeNetBean.setData(pipeNetworkResult.getData());
+                                PipeNetWorkDataBean data = new PipeNetWorkDataBean();
+                                data.setType(pipeNetworkResult.getData().getType());
+                                List<PipeNetworkDataCoordinateBean> coordinates = new ArrayList<>();
+                                for (PipeNetworkResult.Data.Coordinate dataBean : pipeNetworkResult.getData().getCoordinates()) {
+                                    PipeNetworkDataCoordinateBean coordinate = new PipeNetworkDataCoordinateBean();
+                                    coordinate.setLat(dataBean.getLat());
+                                    coordinate.setLng(dataBean.getLng());
+                                    coordinates.add(coordinate);
+                                }
+                                data.setCoordinates(coordinates);
+                                pipeNetBean.setData(data);
+                                setMapPipe(pipeNetBean);
+                                pipeNetBeans.add(pipeNetBean);
                             }
+
+                            DaoSingleton.getInstance(MapFragment.this.getContext()).pipeNetDao().deleteAll();
                             // 浣跨敤 RxJava 寮傛鎻掑叆鏁版嵁
-                            DaoSingleton.getAsynchInstance(MapFragment.this.getContext()).pipeNetDao().insertAll(pipeNetBeans)
-                                    .subscribeOn(Schedulers.io()) // 鍦� IO 绾跨▼涓婃墽琛�
-                                    .observeOn(AndroidSchedulers.mainThread()) // 鍦ㄤ富绾跨▼涓婅瀵�
-                                    .subscribe(() -> {
-                                        // 鎻掑叆鎴愬姛
-                                        Log.i("mWebView", "鏁版嵁鎻掑叆鎴愬姛");
-                                    }, throwable -> {
-                                        // 鎻掑叆澶辫触
-                                        Log.e("mWebView", "鏁版嵁鎻掑叆澶辫触: " + throwable.getMessage());
-                                    });
+                            compositeDisposable.add(
+                                    DaoSingleton.getAsynchInstance(MapFragment.this.getContext()).pipeNetDao().insertAll(pipeNetBeans)
+                                            .subscribeOn(Schedulers.io()) // 鍦� IO 绾跨▼涓婃墽琛�
+                                            .observeOn(AndroidSchedulers.mainThread()) // 鍦ㄤ富绾跨▼涓婅瀵�
+                                            .subscribe(() -> {
+                                                // 鎻掑叆鎴愬姛
+                                                Log.i("mWebView", "鏁版嵁鎻掑叆鎴愬姛");
+                                            }, throwable -> {
+                                                // 鎻掑叆澶辫触
+                                                Log.e("mWebView", "鏁版嵁鎻掑叆澶辫触: " + throwable.getMessage());
+                                            })
+                            );
                         }
 
 
@@ -1233,4 +1330,14 @@
         }
     }
 
+    private void showPipeLine(boolean isSelected) {
+        if (isSelected) {
+            mWebView.evaluateJavascript("javascript:showAllPipeLines()", value -> {
+            });
+        } else {
+            mWebView.evaluateJavascript("javascript:hideAllPipeLines()", value -> {
+            });
+        }
+    }
+
 }
diff --git a/app/src/main/java/com/dayu/pipirrapp/service/MyCommonService.java b/app/src/main/java/com/dayu/pipirrapp/service/MyCommonService.java
deleted file mode 100644
index 35b0fe4..0000000
--- a/app/src/main/java/com/dayu/pipirrapp/service/MyCommonService.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.dayu.pipirrapp.service;
-
-//import cn.jpush.android.service.JCommonService;
-
-/**
- * author: zuo
- * Date: 2024-01-10
- * Time: 11:51
- * 澶囨敞锛�
- */
-//public class MyCommonService extends JCommonService {
-//}
diff --git a/app/src/main/java/com/dayu/pipirrapp/utils/CommonKeyName.java b/app/src/main/java/com/dayu/pipirrapp/utils/CommonKeyName.java
index 1adf529..bd2f6fe 100644
--- a/app/src/main/java/com/dayu/pipirrapp/utils/CommonKeyName.java
+++ b/app/src/main/java/com/dayu/pipirrapp/utils/CommonKeyName.java
@@ -24,13 +24,20 @@
     public final static String NetworkCallback = "NetworkCallback";
 
     //鍒锋柊鏂板伐鍗曞皬绾㈢偣
-    public final static String RedLotRefresh="RedLotRefresh";
+    public final static String RedLotRefresh = "RedLotRefresh";
 
     //鍒涘缓閫氱煡
-    public final static String CreateNotification="CreateNotification";
+    public final static String CreateNotification = "CreateNotification";
 
     /**
      * 鍒锋柊鏁版嵁浜嬩欢
      */
     public static final String refreshData = "refreshData";
+
+    //鍙栨按鍙f槸鍚︽樉绀虹殑key
+    public static final String markerKeyIsShow = "markerKeyIsShow";
+
+    public static final String divideIsShow = "divideIsShow";
+
+    public static final String pipeNetworkIsShow = "pipeNetworkIsShow";
 }
diff --git a/app/src/main/java/com/dayu/pipirrapp/view/SearchResultDialog.java b/app/src/main/java/com/dayu/pipirrapp/view/SearchResultDialog.java
new file mode 100644
index 0000000..3ecd1b6
--- /dev/null
+++ b/app/src/main/java/com/dayu/pipirrapp/view/SearchResultDialog.java
@@ -0,0 +1,129 @@
+package com.dayu.pipirrapp.view;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+
+import com.dayu.pipirrapp.R;
+import com.dayu.pipirrapp.bean.db.SearchResultBean;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SearchResultDialog extends Dialog {
+    private Context context;
+    private List<SearchResultBean> searchResults = new ArrayList<>();
+    private OnItemClickListener onItemClickListener;
+
+    public interface OnItemClickListener {
+        void onItemClick(SearchResultBean item);
+    }
+
+    public SearchResultDialog(@NonNull Context context) {
+        super(context, R.style.CustomDialog);
+        this.context = context;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.dialog_search_result);
+
+        // 璁剧疆瀵硅瘽妗嗕綅缃拰澶у皬
+        Window window = getWindow();
+        if (window != null) {
+            WindowManager.LayoutParams params = window.getAttributes();
+            params.gravity = Gravity.TOP;
+            params.width = WindowManager.LayoutParams.MATCH_PARENT;
+            params.height = WindowManager.LayoutParams.WRAP_CONTENT;
+            window.setAttributes(params);
+        }
+
+        ListView listView = findViewById(R.id.listView);
+        SearchResultAdapter adapter = new SearchResultAdapter();
+        listView.setAdapter(adapter);
+
+        listView.setOnItemClickListener((parent, view, position, id) -> {
+            if (onItemClickListener != null) {
+                onItemClickListener.onItemClick(searchResults.get(position));
+            }
+            dismiss();
+        });
+    }
+
+    public void setData(List<SearchResultBean> results) {
+        this.searchResults.clear();
+        this.searchResults.addAll(results);
+        if (isShowing()) {
+            ListView listView = findViewById(R.id.listView);
+            ((SearchResultAdapter) listView.getAdapter()).notifyDataSetChanged();
+        }
+    }
+
+    public void setOnItemClickListener(OnItemClickListener listener) {
+        this.onItemClickListener = listener;
+    }
+
+    private class SearchResultAdapter extends BaseAdapter {
+        @Override
+        public int getCount() {
+            return searchResults.size();
+        }
+
+        @Override
+        public SearchResultBean getItem(int position) {
+            return searchResults.get(position);
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            ViewHolder holder;
+            if (convertView == null) {
+                convertView = LayoutInflater.from(context).inflate(R.layout.item_search_result, parent, false);
+                holder = new ViewHolder();
+                holder.nameText = convertView.findViewById(R.id.nameText);
+                holder.addressText = convertView.findViewById(R.id.addressText);
+                holder.typeIcon = convertView.findViewById(R.id.typeIcon);
+                convertView.setTag(holder);
+            } else {
+                holder = (ViewHolder) convertView.getTag();
+            }
+
+            SearchResultBean item = getItem(position);
+            holder.nameText.setText(item.getName());
+            holder.addressText.setText(item.getAddress());
+            
+            // 鏍规嵁绫诲瀷璁剧疆涓嶅悓鐨勫浘鏍�
+            if ("marker".equals(item.getType())) {
+                holder.typeIcon.setImageResource(R.drawable.marker_blue);
+            } else {
+                holder.typeIcon.setImageResource(R.drawable.divide_home_blue);
+            }
+
+            return convertView;
+        }
+
+        class ViewHolder {
+            TextView nameText;
+            TextView addressText;
+            ImageView typeIcon;
+        }
+    }
+} 
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_pipenetwork_line.xml b/app/src/main/res/drawable/ic_pipenetwork_line.xml
new file mode 100644
index 0000000..a60a4c1
--- /dev/null
+++ b/app/src/main/res/drawable/ic_pipenetwork_line.xml
@@ -0,0 +1,12 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="2dp"
+    android:viewportWidth="24"
+    android:viewportHeight="2">
+    
+    <path
+        android:pathData="M0,1L24,1"
+        android:strokeWidth="2"
+        android:strokeColor="#1890FF"
+        android:strokeLineCap="round"/>
+</vector> 
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_pipenetwork_line_unselected.xml b/app/src/main/res/drawable/ic_pipenetwork_line_unselected.xml
new file mode 100644
index 0000000..7093974
--- /dev/null
+++ b/app/src/main/res/drawable/ic_pipenetwork_line_unselected.xml
@@ -0,0 +1,12 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="2dp"
+    android:viewportWidth="24"
+    android:viewportHeight="2">
+
+    <path
+        android:pathData="M0,1L24,1"
+        android:strokeWidth="2"
+        android:strokeColor="#757575"
+        android:strokeLineCap="round"/>
+</vector>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/location_marker_bg.xml b/app/src/main/res/drawable/location_marker_bg.xml
new file mode 100644
index 0000000..41bc759
--- /dev/null
+++ b/app/src/main/res/drawable/location_marker_bg.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- 澶栧彂鍏� -->
+    <item>
+        <shape android:shape="oval">
+            <gradient
+                android:type="radial"
+                android:gradientRadius="40dp"
+                android:startColor="#803D8BFF"
+                android:endColor="#003D8BFF"/>
+            <size android:width="80dp" android:height="80dp"/>
+        </shape>
+    </item>
+    <!-- 鍐呭渾鐜� -->
+    <item
+        android:left="20dp"
+        android:top="20dp"
+        android:right="20dp"
+        android:bottom="20dp">
+        <shape android:shape="oval">
+            <solid android:color="#FFFFFF"/>
+            <stroke
+                android:width="4dp"
+                android:color="#3D8BFF"/>
+        </shape>
+    </item>
+    <!-- 鍔ㄧ敾鍥炬爣灏嗗湪浠g爜涓缃负璇ュ浘灞傜殑鍓嶆櫙 -->
+</layer-list> 
\ No newline at end of file
diff --git a/app/src/main/res/drawable/walking_worker_animation.xml b/app/src/main/res/drawable/walking_worker_animation.xml
new file mode 100644
index 0000000..7a05cf9
--- /dev/null
+++ b/app/src/main/res/drawable/walking_worker_animation.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
+    android:oneshot="false">
+    <item
+        android:drawable="@drawable/worker_frame1"
+        android:duration="500" />
+    <item
+        android:drawable="@drawable/worker_frame2"
+        android:duration="500" />
+</animation-list> 
\ No newline at end of file
diff --git a/app/src/main/res/drawable/worker_frame1.xml b/app/src/main/res/drawable/worker_frame1.xml
new file mode 100644
index 0000000..e0ccfaa
--- /dev/null
+++ b/app/src/main/res/drawable/worker_frame1.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="48dp"
+    android:height="48dp"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+    <path
+        android:fillColor="#3D8BFF"
+        android:pathData="M24,12m-6,0a6,6 0,1 1,12 0a6,6 0,1 1,-12 0"/>
+    <path
+        android:fillColor="#3D8BFF"
+        android:pathData="M32,28h-2v-6c0,-3.31 -2.69,-6 -6,-6s-6,2.69 -6,6v6h-2v-6c0,-4.42 3.58,-8 8,-8s8,3.58 8,8V28z"/>
+    <path
+        android:fillColor="#3D8BFF"
+        android:pathData="M22,30l-4,12h2l4,-10l4,10h2l-4,-12H22z"/>
+</vector> 
\ No newline at end of file
diff --git a/app/src/main/res/drawable/worker_frame2.xml b/app/src/main/res/drawable/worker_frame2.xml
new file mode 100644
index 0000000..63ee5ff
--- /dev/null
+++ b/app/src/main/res/drawable/worker_frame2.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="48dp"
+    android:height="48dp"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+    <path
+        android:fillColor="#3D8BFF"
+        android:pathData="M24,12m-6,0a6,6 0,1 1,12 0a6,6 0,1 1,-12 0"/>
+    <path
+        android:fillColor="#3D8BFF"
+        android:pathData="M32,28h-2v-6c0,-3.31 -2.69,-6 -6,-6s-6,2.69 -6,6v6h-2v-6c0,-4.42 3.58,-8 8,-8s8,3.58 8,8V28z"/>
+    <path
+        android:fillColor="#3D8BFF" 
+        android:pathData="M20,30l-2,12h2l2,-10l6,10h2l-6,-12H20z"/>
+</vector> 
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_search_result.xml b/app/src/main/res/layout/dialog_search_result.xml
new file mode 100644
index 0000000..3711c14
--- /dev/null
+++ b/app/src/main/res/layout/dialog_search_result.xml
@@ -0,0 +1,21 @@
+<?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="wrap_content"
+    android:layout_marginTop="50dp"
+    android:layout_marginBottom="50dp"
+    android:layout_marginLeft="20dp"
+    android:layout_marginRight="20dp"
+    android:background="@android:color/white"
+    android:orientation="vertical">
+
+    <ListView
+        android:id="@+id/listView"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+
+        android:divider="@android:color/darker_gray"
+        android:dividerHeight="0.5dp"
+        android:maxHeight="300dp" />
+
+</LinearLayout> 
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_map.xml b/app/src/main/res/layout/fragment_map.xml
index 9a71ebc..dc6e3a4 100644
--- a/app/src/main/res/layout/fragment_map.xml
+++ b/app/src/main/res/layout/fragment_map.xml
@@ -79,15 +79,31 @@
     </RelativeLayout>
 
 
+
+    <com.example.expand_button.CustomSearchBar
+        android:id="@+id/searchButton"
+        android:layout_width="40dp"
+        android:layout_height="40dp"
+        android:layout_alignParentRight="true"
+        android:layout_below="@+id/inspectRL"
+        android:layout_marginTop="20dp"
+        android:layout_marginRight="15dp"
+        android:background="@drawable/ic_blue_background_down"
+        android:textColor="@color/white"
+        android:textSize="18sp" />
+
+
     <TextView
         android:id="@+id/inspectButton"
         android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
+        android:layout_height="40dp"
+        android:minWidth="40dp"
+        android:layout_below="@+id/searchButton"
         android:layout_alignParentRight="true"
-        android:layout_marginTop="60dp"
+        android:layout_marginTop="10dp"
         android:layout_marginRight="15dp"
         android:background="@drawable/ic_blue_background"
-        android:padding="10dp"
+     android:gravity="center"
         android:text="宸�"
         android:textColor="@color/white"
         android:textSize="18sp" />
@@ -96,13 +112,15 @@
     <TextView
         android:id="@+id/putButton"
         android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
+        android:layout_height="40dp"
         android:layout_alignParentRight="true"
-        android:layout_marginTop="120dp"
+        android:layout_marginTop="10dp"
+        android:layout_below="@+id/inspectButton"
         android:layout_marginRight="15dp"
         android:background="@drawable/ic_green_bg"
-        android:padding="10dp"
         android:text="鎶�"
+        android:minWidth="40dp"
+        android:gravity="center"
         android:textColor="@color/white"
         android:textSize="18sp" />
 
@@ -111,10 +129,11 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_alignParentRight="true"
-        android:layout_marginTop="180dp"
+        android:layout_marginTop="10dp"
         android:layout_marginRight="15dp"
+        android:layout_marginLeft="15dp"
+        android:layout_below="@+id/putButton"
         android:background="@drawable/ic_green_bg"
-        android:padding="10dp"
         android:textColor="@color/white"
         android:textSize="18sp"
         app:animDuration="300"
diff --git a/app/src/main/res/layout/item_search_result.xml b/app/src/main/res/layout/item_search_result.xml
new file mode 100644
index 0000000..6962549
--- /dev/null
+++ b/app/src/main/res/layout/item_search_result.xml
@@ -0,0 +1,36 @@
+<?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="wrap_content"
+    android:orientation="horizontal"
+    android:padding="12dp">
+
+    <ImageView
+        android:id="@+id/typeIcon"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:layout_gravity="center_vertical" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="12dp"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/nameText"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textColor="#333333"
+            android:textSize="16sp" />
+
+        <TextView
+            android:id="@+id/addressText"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="4dp"
+            android:textColor="#666666"
+            android:textSize="14sp" />
+    </LinearLayout>
+
+</LinearLayout> 
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 8f9e4f6..83c3f71 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -13,6 +13,16 @@
         <item name="android:windowSoftInputMode">adjustPan</item>
     </style>
 
+    <!-- 鑷畾涔夊璇濇鏍峰紡 -->
+    <style name="CustomDialog" parent="Theme.AppCompat.Light.Dialog">
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowIsFloating">true</item>
+        <item name="android:windowContentOverlay">@null</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
+        <item name="android:backgroundDimEnabled">true</item>
+    </style>
+
 
 
 
diff --git a/expand_button/src/main/java/com/example/expand_button/CustomSearchBar.kt b/expand_button/src/main/java/com/example/expand_button/CustomSearchBar.kt
new file mode 100644
index 0000000..864c060
--- /dev/null
+++ b/expand_button/src/main/java/com/example/expand_button/CustomSearchBar.kt
@@ -0,0 +1,178 @@
+package com.example.expand_button
+
+import android.animation.ValueAnimator
+import android.content.Context
+import android.graphics.drawable.Drawable
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.EditText
+import android.widget.ImageView
+import android.widget.RelativeLayout
+import android.widget.TextView
+import androidx.core.content.ContextCompat
+
+class CustomSearchBar @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet? = null,
+    defStyleAttr: Int = 0
+) : RelativeLayout(context, attrs, defStyleAttr) {
+
+    private var isExpanded = false
+    private var searchIcon: ImageView
+    private var searchInput: EditText
+    private var searchButton: TextView
+    private var onSearchClickListener: ((String) -> Unit)? = null
+    private var expandedWidth = 0
+    private var animationDuration: Long = 300
+    private var initialWidth = 0
+
+    init {
+        // 鍒涘缓涓�涓柊鐨凩ayoutInflater锛岄伩鍏嶄娇鐢ㄥ甫鑳屾櫙鐨勫竷灞�
+        val inflater = LayoutInflater.from(context).cloneInContext(context)
+        val root = inflater.inflate(R.layout.layout_search_bar, this, false)
+        // 娓呴櫎甯冨眬鏂囦欢涓殑鑳屾櫙
+        root.background = null
+        // 娣诲姞甯冨眬
+        addView(root)
+
+        // 鍒濆鍖栬鍥�
+        searchIcon = findViewById(R.id.iv_search)
+        searchInput = findViewById(R.id.et_search)
+        searchButton = findViewById(R.id.tv_search)
+
+        // 璁剧疆鍒濆鐘舵��
+        post {
+            // 淇濆瓨鍒濆瀹藉害
+            initialWidth = width
+            
+            // 纭繚鎼滅储鍥炬爣灞呬腑鏄剧ず
+            (searchIcon.layoutParams as RelativeLayout.LayoutParams).apply {
+                removeRule(ALIGN_PARENT_START)
+                addRule(CENTER_IN_PARENT)
+                setMargins(0, 0, 0, 0)
+            }
+            
+            // 鍒濆鐘舵�侀殣钘忚緭鍏ユ鍜屾悳绱㈡寜閽�
+            searchInput.visibility = View.GONE
+            searchButton.visibility = View.GONE
+        }
+
+        // 璁剧疆鐐瑰嚮鐩戝惉
+        searchIcon.setOnClickListener {
+            if (!isExpanded) {
+                expand()
+            }
+        }
+
+        searchButton.setOnClickListener {
+            onSearchClickListener?.invoke(searchInput.text.toString())
+            collapse()
+        }
+
+        // 璁剧疆鏁翠釜甯冨眬鐨勭偣鍑荤洃鍚�
+        setOnClickListener {
+            if (!isExpanded) {
+                expand()
+            }
+        }
+    }
+
+    private fun expand() {
+        if (isExpanded) return
+
+        // 璁$畻灞曞紑鍚庣殑瀹藉害锛堝睆骞曞搴﹀噺鍘诲乏鍙宠竟璺濓級
+        if (expandedWidth == 0) {
+            expandedWidth = context.resources.displayMetrics.widthPixels -
+                    (32 * context.resources.displayMetrics.density).toInt()
+        }
+
+        // 鍒涘缓瀹藉害鍔ㄧ敾
+        ValueAnimator.ofInt(initialWidth, expandedWidth).apply {
+            duration = animationDuration
+            addUpdateListener { animator ->
+                layoutParams = layoutParams.apply {
+                    width = animator.animatedValue as Int
+                }
+            }
+            start()
+        }
+
+        // 閲嶇疆鎼滅储鍥炬爣浣嶇疆
+        (searchIcon.layoutParams as RelativeLayout.LayoutParams).apply {
+            removeRule(CENTER_VERTICAL)
+            addRule(ALIGN_PARENT_START)
+            setMargins(
+                (8 * context.resources.displayMetrics.density).toInt(),
+                0,
+                0,
+                0
+            )
+        }
+
+        // 鏄剧ず杈撳叆妗嗗拰鎼滅储鎸夐挳
+        searchInput.visibility = View.VISIBLE
+        searchButton.visibility = View.VISIBLE
+        searchInput.requestFocus()
+
+        isExpanded = true
+    }
+
+    private fun collapse() {
+        if (!isExpanded) return
+
+        // 鍒涘缓瀹藉害鍔ㄧ敾
+        ValueAnimator.ofInt(expandedWidth, initialWidth).apply {
+            duration = animationDuration
+            addUpdateListener { animator ->
+                layoutParams = layoutParams.apply {
+                    width = animator.animatedValue as Int
+                }
+            }
+            start()
+        }
+
+        // 閲嶇疆鎼滅储鍥炬爣鍒颁腑蹇冧綅缃�
+        (searchIcon.layoutParams as RelativeLayout.LayoutParams).apply {
+            removeRule(ALIGN_PARENT_START)
+            addRule(CENTER_IN_PARENT)
+            setMargins(0, 0, 0, 0)
+        }
+
+        // 闅愯棌杈撳叆妗嗗拰鎼滅储鎸夐挳
+        searchInput.visibility = View.GONE
+        searchButton.visibility = View.GONE
+        searchInput.setText("")
+
+        isExpanded = false
+    }
+
+    /**
+     * 璁剧疆鎼滅储鎸夐挳鐐瑰嚮鐩戝惉鍣�
+     * @param listener 鍥炶皟鍑芥暟锛屽弬鏁颁负杈撳叆妗嗕腑鐨勬枃鏈唴瀹�
+     */
+    fun setOnSearchClickListener(listener: (String) -> Unit) {
+        onSearchClickListener = listener
+    }
+
+    /**
+     * 璁剧疆鍔ㄧ敾鏃堕暱
+     */
+    fun setAnimationDuration(duration: Long) {
+        animationDuration = duration
+    }
+
+    /**
+     * 璁剧疆鎻愮ず鏂囧瓧
+     */
+    fun setHint(hint: String) {
+        searchInput.hint = hint
+    }
+
+    /**
+     * 鑾峰彇杈撳叆鐨勬枃鏈�
+     */
+    fun getText(): String {
+        return searchInput.text.toString()
+    }
+} 
\ No newline at end of file
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 3671c76..007713c 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
@@ -499,49 +499,20 @@
     fun setButtonId(id: String) {
         this.buttonId = id
         // 鍔犺浇淇濆瓨鐨勭姸鎬�
-        loadStates()
+
     }
 
-    /**
-     * 淇濆瓨鎵�鏈夊浘渚嬮」鐨勭姸鎬�
-     */
-    private fun saveStates() {
-        val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
-        val states = legendItems.map { it.isSelected }
-        prefs.edit().putString("${KEY_LEGEND_STATES}_$buttonId", states.joinToString(",")).apply()
-    }
-
-    /**
-     * 鍔犺浇淇濆瓨鐨勭姸鎬�
-     */
-    private fun loadStates() {
-        val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
-        val savedStates = prefs.getString("${KEY_LEGEND_STATES}_$buttonId", null)
-        
-        if (savedStates != null && legendItems.isNotEmpty()) {
-            val states = savedStates.split(",").map { it.toBoolean() }
-            states.forEachIndexed { index, state ->
-                if (index < legendItems.size) {
-                    legendItems[index].isSelected = state
-                }
-            }
-            invalidate()
-        }
-    }
 
     /**
      * 璁剧疆鍥句緥鍐呭
      */
     @JvmName("setLegendsList")
-    fun setLegends(items: List<Triple<Drawable, Drawable, String>>) {
-        legendItems = items.map { (selectedIcon, unselectedIcon, description) ->
+    fun setLegends(items: List<Quadruple<Drawable, Drawable, String, Boolean>>) {
+        legendItems = items.map { (selectedIcon, unselectedIcon, description, isSelected) ->
             selectedIcon.setBounds(0, 0, iconSize, iconSize)
             unselectedIcon.setBounds(0, 0, iconSize, iconSize)
-            LegendItem(selectedIcon, unselectedIcon, description)
+            LegendItem(selectedIcon, unselectedIcon, description, isSelected)
         }
-        
-        // 鍔犺浇淇濆瓨鐨勭姸鎬�
-        loadStates()
         
         if (!isExpanded) {
             text = collapsedText
@@ -553,8 +524,21 @@
 
     // 娣诲姞涓�涓� Java 鍙嬪ソ鐨勬柟娉�
     @JvmName("setLegendsArray")
-    fun setLegends(vararg items: Triple<Drawable, Drawable, String>) {
+    fun setLegends(vararg items: Quadruple<Drawable, Drawable, String, Boolean>) {
         setLegends(items.toList())
+    }
+
+    // 娣诲姞涓�涓暟鎹被鏉ヨ〃绀哄洓鍏冪粍
+    data class Quadruple<A, B, C, D>(
+        val first: A,
+        val second: B,
+        val third: C,
+        val fourth: D
+    )
+
+    // 娣诲姞涓�涓究鎹风殑鎵╁睍鍑芥暟鏉ュ垱寤� Quadruple
+    fun <A, B, C, D> quadrupleOf(first: A, second: B, third: C, fourth: D): Quadruple<A, B, C, D> {
+        return Quadruple(first, second, third, fourth)
     }
 
     /**
@@ -635,10 +619,7 @@
             index, 
             legendItems[index].isSelected
         )
-        
-        // 淇濆瓨鐘舵��
-        saveStates()
-        
+
         invalidate()
     }
 
diff --git a/expand_button/src/main/java/com/example/expand_button/ExpandSearchView.kt b/expand_button/src/main/java/com/example/expand_button/ExpandSearchView.kt
new file mode 100644
index 0000000..2b269ca
--- /dev/null
+++ b/expand_button/src/main/java/com/example/expand_button/ExpandSearchView.kt
@@ -0,0 +1,449 @@
+package com.example.expand_button
+
+import android.animation.ValueAnimator
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.RectF
+import android.graphics.drawable.Drawable
+import android.text.InputType
+import android.util.AttributeSet
+import android.view.Gravity
+import android.view.MotionEvent
+import android.view.ViewGroup
+import androidx.appcompat.widget.AppCompatEditText
+import androidx.core.content.ContextCompat
+import android.util.TypedValue
+import androidx.core.animation.addListener
+import android.util.Log
+
+class ExpandSearchView @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet? = null,
+    defStyleAttr: Int = 0
+) : AppCompatEditText(context, attrs, defStyleAttr) {
+
+    // 鎼滅储鍥炬爣
+    private val searchIcon: Drawable = ContextCompat.getDrawable(
+        context,
+        R.drawable.ic_search
+    )!!.mutate()
+
+    // 鎼滅储鎸夐挳鏂囧瓧
+    private var searchButtonText: String = "鎼滅储"
+    
+    // 鎼滅储鎸夐挳鐐瑰嚮鐩戝惉鍣�
+    private var onSearchClickListener: (() -> Unit)? = null
+
+    // 褰撳墠鏄惁澶勪簬灞曞紑鐘舵��
+    private var isExpanded: Boolean = false
+    // 鍔ㄧ敾鎸佺画鏃堕棿,榛樿300姣  
+    private var animationDuration: Long = 300
+    // 鎼滅储鍥炬爣涓庢枃瀛楃殑闂磋窛,榛樿涓�8dp
+    private var iconMargin: Float = 8 * context.resources.displayMetrics.density
+    // 鎼滅储鎸夐挳涓庤緭鍏ユ鐨勯棿璺�,榛樿涓�8dp
+    private var searchButtonMargin: Float = 8 * context.resources.displayMetrics.density
+    // 鎻愮ず鏂囧瓧
+    private var hintText: String = "璇疯緭鍏ュ彇姘村彛鎴栧垎姘存埧鍚嶇О"
+
+    // 灏哾efaultHeight绉诲埌绫荤殑灞炴�т腑
+    private val defaultHeight = (40 * context.resources.displayMetrics.density).toInt()
+
+    // 娣诲姞灞曞紑鏂瑰悜鐨勫睘鎬�
+    private var expandDirection: Int = EXPAND_LEFT
+    
+    companion object {
+        const val EXPAND_LEFT = 0
+        const val EXPAND_RIGHT = 1
+    }
+
+    init {
+        // 璁剧疆鍗曡杈撳叆
+        maxLines = 1
+        isSingleLine = true
+        
+        // 璁剧疆鎼滅储鍥炬爣鐨勫ぇ灏�
+        val iconSize = (24 * context.resources.displayMetrics.density).toInt()
+        // 涓嶅湪杩欓噷璁剧疆鍥炬爣杈圭晫锛岃�屾槸鍦╫nDraw涓缃�
+        
+        // 璁剧疆鎻愮ず鏂囧瓧
+        hint = hintText
+        
+        // 璁剧疆鏂囧瓧鍨傜洿灞呬腑
+        gravity = Gravity.CENTER_VERTICAL or Gravity.START
+        
+        // 璁剧疆鍥哄畾楂樺害
+        layoutParams = ViewGroup.LayoutParams(
+            ViewGroup.LayoutParams.WRAP_CONTENT,
+            defaultHeight
+        )
+        
+        // 鍒濆鐘舵�佷笅绂佺敤杈撳叆
+        inputType = InputType.TYPE_NULL
+        
+        // 鍒濆鐘舵�佷笅闅愯棌杈撳叆妗�
+        if (!isExpanded) {
+            hint = ""
+            setText("")
+            isEnabled = false
+            
+            // 纭繚鍒濆瀹藉害涓烘敹璧风姸鎬佺殑瀹藉害
+            post {
+                layoutParams = layoutParams?.apply {
+                    width = defaultHeight // 浣跨敤鐩稿悓鐨勯珮搴︿綔涓哄搴︼紝淇濇寔姝f柟褰�
+                    height = defaultHeight // 淇濇寔鍥哄畾楂樺害
+                }
+                invalidate() // 娣诲姞杩欒纭繚鍥炬爣閲嶇粯
+            }
+        }
+    }
+
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+        
+        // 璁剧疆鍥哄畾楂樺害
+        val defaultHeight = (40 * context.resources.displayMetrics.density).toInt()
+        
+        if (!isExpanded) {
+            // 鏀剁缉鐘舵�佷笅鐨勫搴﹁涓烘鏂瑰舰
+            setMeasuredDimension(defaultHeight, defaultHeight)
+        } else {
+            // 灞曞紑鐘舵�佷笅淇濇寔鎸囧畾鐨勫搴︼紝浣嗛珮搴﹀浐瀹�
+            setMeasuredDimension(measuredWidth, defaultHeight)
+        }
+    }
+
+    override fun onDraw(canvas: Canvas) {
+        if (!isExpanded) {
+            // 璁$畻鍥炬爣浣嶇疆骞剁粯鍒�
+            val centerX = width / 2
+            val centerY = height / 2
+            val iconSize = (24 * context.resources.displayMetrics.density).toInt()
+            val iconHalfWidth = iconSize / 2
+            val iconHalfHeight = iconSize / 2
+            searchIcon.setBounds(
+                centerX - iconHalfWidth,
+                centerY - iconHalfHeight,
+                centerX + iconHalfWidth,
+                centerY + iconHalfHeight
+            )
+            searchIcon.draw(canvas)
+        } else {
+            val iconSize = searchIcon.intrinsicWidth
+            val centerY = height / 2
+            val iconLeftMargin = (5 * context.resources.displayMetrics.density).toInt()
+
+            // 缁樺埗鍥炬爣
+            searchIcon.setBounds(
+                iconLeftMargin,
+                centerY - iconSize / 2,
+                iconLeftMargin + iconSize,
+                centerY + iconSize / 2
+            )
+            searchIcon.draw(canvas)
+
+            // 缁樺埗鍒嗛殧绾�
+            paint.apply {
+                color = 0xFFFFFFFF.toInt()
+                strokeWidth = (1 * context.resources.displayMetrics.density)
+            }
+            val dividerX = iconLeftMargin + iconSize + (iconMargin / 2)
+            canvas.drawLine(
+                dividerX,
+                height * 0.2f,
+                dividerX,
+                height * 0.8f,
+                paint
+            )
+
+            // 璁板綍鏂囨湰缁樺埗鍖哄煙鐨勪俊鎭�
+            val buttonWidth = paint.measureText(searchButtonText)
+            val textLeft = compoundPaddingLeft.toFloat()  // 浣跨敤澶嶅悎鍐呰竟璺�
+            val textRight = width - compoundPaddingRight.toFloat()  // 浣跨敤澶嶅悎鍐呰竟璺�
+
+            // 鍙湪瀹為檯缁樺埗鏂囨湰鏃惰褰曚竴娆″尯鍩熶俊鎭�
+            if (text!!.isNotEmpty() && !text.toString().endsWith("\n")) {
+                Log.d("ExpandSearchView", "鏂囨湰缁樺埗鍖哄煙淇℃伅: 鎺т欢灏哄[瀹藉害:$width, 楂樺害:$height], " +
+                    "鏂囨湰鍖哄煙[宸﹁竟鐣�:$textLeft, 鍙宠竟鐣�:$textRight, 鍙敤瀹藉害:${textRight - textLeft}], " +
+                    "鍐呰竟璺漑宸�:$paddingLeft, 鍙�:$paddingRight, 澶嶅悎宸�:$compoundPaddingLeft, 澶嶅悎鍙�:$compoundPaddingRight], " +
+                    "鏂囨湰淇℃伅[褰撳墠鏂囨湰:'${text}', 闀垮害:${text?.length}, 鍏夋爣浣嶇疆:$selectionStart], " +
+                    "缁樺埗鍙傛暟[鍥炬爣澶у皬:$iconSize, 鍥炬爣宸﹁竟璺�:$iconLeftMargin, 鎸夐挳瀹藉害:$buttonWidth, 鎸夐挳杈硅窛:$searchButtonMargin], " +
+                    "浣嶇疆淇℃伅[translationX:$translationX, scrollX:$scrollX, 鏂囨湰鍋忕Щ:${textLeft - compoundPaddingLeft}]")
+            }
+
+            // 鐢绘枃鏈�
+            super.onDraw(canvas)
+
+            // 缁樺埗鎸夐挳鏂囨湰
+            paint.apply {
+                color = currentTextColor
+                textSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16f, context.resources.displayMetrics)
+                textAlign = Paint.Align.CENTER
+            }
+            val buttonText = searchButtonText
+            val fontMetrics = paint.fontMetrics
+            val textY = height / 2f + (fontMetrics.bottom - fontMetrics.top) / 2f - fontMetrics.bottom
+            val buttonX = width - buttonWidth / 2 - searchButtonMargin
+            
+            // 璁板綍鎼滅储鎸夐挳浣嶇疆淇℃伅
+            Log.d("ExpandSearchView", "鎼滅储鎸夐挳淇℃伅: 浣嶇疆[X:$buttonX, Y:$textY], " +
+                "鍖哄煙[宸�:${buttonX - buttonWidth/2}, 鍙�:${buttonX + buttonWidth/2}, 涓�:0, 涓�:$height], " +
+                "灏哄[瀹藉害:$buttonWidth, 楂樺害:$height]")
+                
+            canvas.drawText(
+                buttonText,
+                buttonX,
+                textY,
+                paint
+            )
+        }
+    }
+
+    override fun onTextChanged(
+        text: CharSequence?,
+        start: Int,
+        lengthBefore: Int,
+        lengthAfter: Int
+    ) {
+        super.onTextChanged(text, start, lengthBefore, lengthAfter)
+        // 鍙湪灞曞紑鐘舵�佷笖瀹為檯鏈夋柊瀛楃杈撳叆鏃舵墠杈撳嚭鏃ュ織
+        if (isExpanded && lengthAfter > lengthBefore) {
+            val newChar = text?.subSequence(start, start + lengthAfter - lengthBefore)
+            Log.d("ExpandSearchView", "鏂板瓧绗﹁緭鍏ヤ俊鎭�: 杈撳叆鍐呭[鏂板瓧绗�:'$newChar', 瀹屾暣鏂囨湰:'$text'], " +
+                "浣嶇疆淇℃伅[杈撳叆浣嶇疆:$start, 鍏夋爣浣嶇疆:$selectionStart], " +
+                "鏂囨湰鍖哄煙[宸﹀唴杈硅窛:$paddingLeft, 鍙冲唴杈硅窛:$paddingRight, 鍙瀹藉害:${width - paddingLeft - paddingRight}], " +
+                "婊氬姩鐘舵�乕scrollX:$scrollX, translationX:$translationX]")
+        }
+    }
+
+    override fun onTouchEvent(event: MotionEvent): Boolean {
+        if (event.action == MotionEvent.ACTION_UP) {
+            if (isExpanded) {
+                // 灞曞紑鐘舵�佷笅锛屾鏌ユ槸鍚︾偣鍑讳簡鎼滅储鎸夐挳
+                val buttonText = searchButtonText
+                val buttonWidth = paint.measureText(buttonText)
+                val buttonArea = RectF(
+                    width - buttonWidth - searchButtonMargin * 2,
+                    0f,
+                    width.toFloat(),
+                    height.toFloat()
+                )
+                
+                if (buttonArea.contains(event.x, event.y)) {
+                    onSearchClickListener?.invoke()
+                    post { toggleExpand() }
+                    return true
+                }
+            } else {
+                toggleExpand()
+                return true
+            }
+        }
+        return super.onTouchEvent(event)
+    }
+
+    override fun performClick(): Boolean {
+        // 纭繚鍙闂�ф湇鍔℃甯稿伐浣�
+        super.performClick()
+        return true
+    }
+
+    /**
+     * 鍒囨崲灞曞紑/鏀惰捣鐘舵��
+     */
+    private fun toggleExpand() {
+        isExpanded = !isExpanded
+
+        val startWidth = width
+        val screenWidth = context.resources.displayMetrics.widthPixels
+        val location = IntArray(2)
+        getLocationInWindow(location)
+
+        // 鑾峰彇鐖跺竷灞�淇℃伅
+        val parent = parent as? ViewGroup
+        val parentWidth = parent?.width ?: screenWidth
+        
+        // 鑾峰彇鎴栬缃竟璺�
+        var params = layoutParams as? ViewGroup.MarginLayoutParams
+        if (params == null) {
+            params = ViewGroup.MarginLayoutParams(layoutParams)
+            layoutParams = params
+        }
+        val margin = params.rightMargin.takeIf { it > 0 } 
+            ?: (45 * context.resources.displayMetrics.density).toInt() // 榛樿45dp鐨勮竟璺�
+
+        // 璁$畻鐩爣瀹藉害锛岃�冭檻涓よ竟鐨勮竟璺�
+        val endWidth = if (isExpanded) {
+            val iconSize = searchIcon.intrinsicWidth
+            val iconMarginPx = (5 * context.resources.displayMetrics.density).toInt()
+            val buttonWidth = paint.measureText(searchButtonText).toInt()
+            val hintWidth = paint.measureText(hintText)
+            val minRequiredWidth = iconMarginPx + iconSize + iconMargin.toInt() + // 宸︿晶鍥炬爣鍖哄煙
+                hintWidth.toInt() + // 鎻愮ず鏂囧瓧瀹藉害
+                buttonWidth + (searchButtonMargin * 2).toInt() + // 鎸夐挳鍖哄煙
+                (16 * context.resources.displayMetrics.density).toInt() // 棰濆杈硅窛
+            
+            maxOf(minRequiredWidth, parentWidth - (margin * 2)) // 鍙栨墍闇�瀹藉害鍜岀埗瀹瑰櫒瀹藉害鐨勮緝澶у��
+        } else {
+            defaultHeight
+        }
+
+        val initialTranslationX = translationX
+        ValueAnimator.ofFloat(0f, 1f).apply {
+            duration = animationDuration
+            addUpdateListener { animator ->
+                val fraction = animator.animatedValue as Float
+                val currentWidth = if (isExpanded) {
+                    startWidth + ((endWidth - startWidth) * fraction).toInt()
+                } else {
+                    startWidth - ((startWidth - endWidth) * fraction).toInt()
+                }
+
+                (layoutParams as? ViewGroup.MarginLayoutParams)?.apply {
+                    width = currentWidth
+                    rightMargin = margin
+                    leftMargin = if (isExpanded) margin else 0 // 灞曞紑鏃舵坊鍔犲乏杈硅窛
+                }?.also { params ->
+                    layoutParams = params
+                }
+
+                // 淇浣嶇Щ锛屽綋鎺т欢灞曞紑鏃秚ranslationX璁剧疆涓�0
+                if (isExpanded) {
+                    translationX = 0f
+                } else {
+                    translationX = initialTranslationX * (1 - fraction)
+                }
+
+                requestLayout()
+                invalidate()
+            }
+
+            addListener(onStart = {
+                if (!isExpanded) {
+                    setText("")
+                }
+            }, onEnd = {
+                if (!isExpanded) {
+                    translationX = 0f
+                    setPadding(
+                        defaultHeight / 4,
+                        defaultHeight / 4,
+                        defaultHeight / 4,
+                        defaultHeight / 4
+                    )
+                    hint = ""
+                    isEnabled = false
+                    clearFocus()
+                    inputType = InputType.TYPE_NULL
+                    isFocusable = false
+                    isFocusableInTouchMode = false
+                    
+                    // 鏀惰捣鏃剁Щ闄ゅ乏杈硅窛
+                    (layoutParams as? ViewGroup.MarginLayoutParams)?.apply {
+                        leftMargin = 0
+                    }?.also { params ->
+                        layoutParams = params
+                    }
+                }
+                if (isExpanded) {
+                    hint = hintText
+                    isEnabled = true
+                    inputType = InputType.TYPE_CLASS_TEXT
+                    isFocusable = true
+                    isFocusableInTouchMode = true
+                    
+                    val iconSize = searchIcon.intrinsicWidth
+                    val iconMarginPx = (5 * context.resources.displayMetrics.density).toInt()
+                    val verticalPadding = (8 * context.resources.displayMetrics.density).toInt()
+                    val buttonWidth = paint.measureText(searchButtonText).toInt()
+                    val hintWidth = paint.measureText(hintText)
+                    
+                    // 璁板綍鎻愮ず鏂囧瓧淇℃伅
+                    Log.d("ExpandSearchView", "鎻愮ず鏂囧瓧淇℃伅: 鏂囨湰['$hintText'], " +
+                        "瀹藉害淇℃伅[鏂囨湰瀹藉害:$hintWidth, 鍙敤瀹藉害:${width - iconMarginPx - iconSize - iconMargin - buttonWidth - searchButtonMargin * 2}], " +
+                        "鍐呰竟璺漑宸�:${iconMarginPx + iconSize + iconMargin.toInt()}, 鍙�:${buttonWidth + (searchButtonMargin * 2).toInt()}]")
+                    
+                    setPadding(
+                        iconMarginPx + iconSize + iconMargin.toInt(), // 宸﹁竟璺濆寘鍚浘鏍囧拰闂磋窛
+                        verticalPadding,
+                        buttonWidth + (searchButtonMargin * 2).toInt(), // 鍙宠竟璺濆寘鍚寜閽拰闂磋窛
+                        verticalPadding
+                    )
+                    requestFocus()
+                }
+            })
+            start()
+        }
+    }
+
+
+    /**
+     * 璁剧疆鎼滅储鍥炬爣
+     */
+    fun setSearchIcon(icon: Drawable) {
+        val size = (24 * context.resources.displayMetrics.density).toInt()
+        icon.setBounds(0, 0, size, size)
+        searchIcon.bounds = icon.bounds
+        invalidate()
+    }
+
+    /**
+     * 璁剧疆鎼滅储鍥炬爣涓庢枃瀛楃殑闂磋窛
+     */
+    fun setIconMargin(margin: Float) {
+        iconMargin = margin
+        invalidate()
+    }
+
+    /**
+     * 璁剧疆鎻愮ず鏂囧瓧
+     */
+    fun setHintText(text: String) {
+        hintText = text
+        if (isExpanded) {
+            hint = hintText
+        }
+    }
+
+    /**
+     * 璁剧疆鍔ㄧ敾鏃堕暱
+     */
+    fun setAnimationDuration(duration: Long) {
+        animationDuration = duration
+    }
+
+    /**
+     * 璁剧疆鎼滅储鎸夐挳涓庤緭鍏ユ鐨勯棿璺�
+     */
+    fun setSearchButtonMargin(margin: Float) {
+        searchButtonMargin = margin
+        invalidate()
+    }
+
+    /**
+     * 璁剧疆鎼滅储鎸夐挳鐐瑰嚮鐩戝惉鍣�
+     */
+    fun setOnSearchClickListener(listener: () -> Unit) {
+        onSearchClickListener = listener
+    }
+
+    /**
+     * 璁剧疆鎼滅储鎸夐挳鏂囧瓧
+     */
+    fun setSearchButtonText(text: String) {
+        searchButtonText = text
+        if (isExpanded) {
+            invalidate()
+        }
+    }
+
+    /**
+     * 璁剧疆灞曞紑鏂瑰悜
+     */
+    fun setExpandDirection(direction: Int) {
+        require(direction == EXPAND_LEFT || direction == EXPAND_RIGHT) {
+            "Direction must be either EXPAND_LEFT or EXPAND_RIGHT"
+        }
+        expandDirection = direction
+    }
+} 
diff --git a/expand_button/src/main/res/drawable/bg_search_bar.xml b/expand_button/src/main/res/drawable/bg_search_bar.xml
new file mode 100644
index 0000000..da386f2
--- /dev/null
+++ b/expand_button/src/main/res/drawable/bg_search_bar.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="#80000000" />
+    <corners android:radius="20dp" />
+</shape> 
\ No newline at end of file
diff --git a/expand_button/src/main/res/drawable/ic_search.xml b/expand_button/src/main/res/drawable/ic_search.xml
new file mode 100644
index 0000000..870d21c
--- /dev/null
+++ b/expand_button/src/main/res/drawable/ic_search.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:fillColor="#FFffffff"
+      android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
+</vector> 
\ No newline at end of file
diff --git a/expand_button/src/main/res/layout/layout_search_bar.xml b/expand_button/src/main/res/layout/layout_search_bar.xml
new file mode 100644
index 0000000..5655ad9
--- /dev/null
+++ b/expand_button/src/main/res/layout/layout_search_bar.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <ImageView
+        android:id="@+id/iv_search"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:layout_centerInParent="true"
+        android:src="@drawable/ic_search" />
+
+    <EditText
+        android:id="@+id/et_search"
+        android:layout_width="0dp"
+        android:layout_height="40dp"
+        android:layout_centerVertical="true"
+        android:layout_toEndOf="@id/iv_search"
+        android:layout_toStartOf="@id/tv_search"
+        android:layout_marginStart="8dp"
+        android:layout_marginEnd="8dp"
+        android:background="@null"
+        android:hint="璇疯緭鍏ュ垎姘存埧鎴栧彇姘村彛鍚嶇О"
+        android:textColorHint="#80FFFFFF"
+        android:textColor="#FFFFFF"
+        android:textSize="14sp"
+        android:singleLine="true"
+        android:visibility="gone"/>
+
+    <TextView
+        android:id="@+id/tv_search"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentEnd="true"
+        android:layout_centerVertical="true"
+        android:layout_marginEnd="8dp"
+        android:text="鎼滅储"
+        android:textColor="#FFFFFF"
+        android:textSize="14sp"
+        android:visibility="gone"/>
+
+</RelativeLayout> 
\ 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 aca0c25..b3cbaa3 100644
--- a/expand_button/src/main/res/values/attrs.xml
+++ b/expand_button/src/main/res/values/attrs.xml
@@ -18,4 +18,17 @@
         <!-- 鏂板灞曞紑鍚庣殑瀛椾綋澶у皬灞炴�� -->
         <attr name="expandedTextSize" format="dimension"/>
     </declare-styleable>
+
+    <declare-styleable name="CustomSearchBar">
+        <!-- 浣跨敤android:background灞炴�� -->
+        <attr name="android:background"/>
+        <!-- 鎼滅储鍥炬爣澶у皬 -->
+        <attr name="searchIconSize" format="dimension"/>
+        <!-- 鎼滅储鎸夐挳鏂囧瓧 -->
+        <attr name="searchButtonText" format="string"/>
+        <!-- 鎻愮ず鏂囧瓧 -->
+        <attr name="searchHint" format="string"/>
+        <!-- 鍔ㄧ敾鏃堕暱 -->
+        <attr name="searchAnimDuration" format="integer"/>
+    </declare-styleable>
 </resources> 
\ No newline at end of file

--
Gitblit v1.8.0