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