最近开发车主相关的App功能, 做一个出行功能大致和高德路线规划功能相当。 对高德的路线规划交做了细致的调研。 功能拆分开来,路线规划逻辑主要涉及:POI搜索和 路线规划; UI部分主要任务在搜索输入框开发, 列表开发, 路线图层开发。 路线的搜索和路线规划及其规划线路绘制方面高德开放平台均有文档详细介绍,就不再细谈了;此篇主要介绍仿高德的路线搜索交互界面的开发,本文简称为路线搜索框开发。
此路线搜索框有两种状态,编辑途径点态和无途径点态; 此外 编辑途径点态还包含拖动地址改变顺序功能。 考虑拖动的交互,Android里常选的方案是RecyclerView实现;但是今天我们采用Tween动画实现拖动的交互效果。 Tween Animation 和属性动画不一样,不改变View的真实属性数据(也就不改变子View真实位置),仅动画效果的显示,可利用此特性来展示拖动时的切换效果,和拖动结束时回到真实状态的一个切换。 利用数据交换来刷新 拖动后台的UI。
UI整体布局采用XML硬编码的形式引入,使用include的方式复用每条位置POI搜索框。
ini
<LinearLayout
android:id="@+id/ll_more_edit_line"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/ll_edit_action"
android:orientation="vertical">
<include
android:id="@+id/ll_start_location"
layout="@layout/edit_search_key" />
<include
android:id="@+id/ll_end_location"
layout="@layout/edit_search_key" />
</LinearLayout>
edit_search_key.xml文件, 定义每条搜索POI的子View
ini
<?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">
<RelativeLayout
android:id="@+id/ll_edit_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_edt"
android:layout_width="@dimen/dp_32"
android:layout_height="@dimen/dp_32"
android:scaleType="centerInside"
android:src="@drawable/start_location_point" />
<EditText
android:id="@+id/edt_input_key"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/iv_edt"
android:background="@color/transparent"
android:hint=""
android:minHeight="@dimen/dp_32"
android:paddingVertical="@dimen/dp_6"
android:singleLine="true"
android:text="@string/confirm"
android:textColor="@color/text_content_first"
android:textColorHint="@color/text_content_five"
android:textSize="@dimen/dp_14" />
<ImageView
android:id="@+id/iv_edit_move_tag"
android:layout_width="@dimen/fit_dp_20"
android:layout_height="@dimen/fit_dp_20"
android:layout_alignRight="@+id/edt_input_key"
android:layout_centerVertical="true"
android:layout_marginRight="@dimen/fit_dp_8"
android:src="@drawable/icon_edit_move"
android:visibility="gone" />
</RelativeLayout>
<ImageView
android:id="@+id/iv_del_edit"
android:layout_width="@dimen/dp_20"
android:layout_height="@dimen/dp_20"
android:layout_gravity="center_vertical"
android:layout_marginLeft="@dimen/dp_8"
android:scaleType="centerInside"
android:src="@drawable/ic_close"
android:visibility="gone" />
</LinearLayout>
增删途径点,通过LinearLayout布局动态AddView()和RemoveView()实现; 增加途径点
ini
/**
* @param middleIndex 从0开始,排除起点和终点之外的列表
*/
private fun addMiddleLocation(middleIndex: Int = 0): EditText {
val params = LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
val top: Int = resources.getDimensionPixelSize(R.dimen.dp_6)
val bottom = 0
params.topMargin = top
params.bottomMargin = bottom
val middleViewBinding = createMiddleLocationEditView();
var middlePos: Int = middleIndex
if (getMiddleCount() > middleIndex) {
binding.llMoreEditLine.addView(middleViewBinding.root, middleIndex + 1, params)
} else {
val index = binding.llMoreEditLine.childCount - 1;
binding.llMoreEditLine.addView(middleViewBinding.root, index, params)
middlePos = getMiddleCount() - 1;
}
val middleData = EditLocation.createMiddleLocation()
middleViewBinding.root.setTag(R.id.cb_item_tag, middleData)
middleViewBinding.edtInputKey.setTag(R.id.cb_item_tag, middleData)
locationList.add(middlePos + 1, middleData)
updateAddMoreUIState()
post {
middleViewBinding.edtInputKey.requestFocus()
}
return middleViewBinding.edtInputKey
}
删除途径点
kotlin
/**
* @param middleIndex 从0开始,排除起点和终点之外的列表
*/
private fun removeMiddleLocation(middleIndex: Int) {
getMiddleItemViewAt(middleIndex)?.let { child ->
binding.llMoreEditLine.removeView(child)
(child.getTag(R.id.cb_item_tag) as? EditLocation).let { data ->
locationList.remove(data)
}
}
val count = getMiddleCount()
switchUIState(true, count)
updateAddMoreUIState()
}
长按事件的触发直接在事件分发的顶层拦截触摸事件判断是否长按:
kotlin
val mainHandler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
when (msg.what) {
MSG_LONG_CLICK -> {
val obj = msg.obj as Point
val windowX = obj.x;
val windowY = obj.y
findLongTouchValidView(windowX, windowY)?.let { findDragView ->
onDragStart(findDragView, msg.arg1, msg.arg2)
}
}
}
}
}
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
var dy = 0f
val tempDragView = dragSelectedView;
when (ev?.action) {
MotionEvent.ACTION_DOWN -> {
yPos = ev.y
mainHandler.removeMessages(MSG_LONG_CLICK)
val msg = mainHandler.obtainMessage(MSG_LONG_CLICK)
msg.arg1 = ev.x.toInt()
msg.arg2 = ev.y.toInt()
msg.obj = Point(ev.rawX.toInt(), ev.rawY.toInt())
mainHandler.sendMessageDelayed(msg, LONG_TIME)
}
MotionEvent.ACTION_MOVE -> {
dy = ev.y - yPos;
yPos = ev.y
if (tempDragView != null && dy != 0f) {
mainHandler.removeMessages(MSG_LONG_CLICK)
onDragMove(tempDragView!!, ev.x.toInt(), ev.y.toInt(), dy)
}
}
MotionEvent.ACTION_CANCEL -> {
mainHandler.removeMessages(MSG_LONG_CLICK)
if (tempDragView != null) {
onDragEnd()
}
}
MotionEvent.ACTION_UP -> {
mainHandler.removeMessages(MSG_LONG_CLICK)
if (tempDragView != null) {
onDragEnd()
}
}
}
if (tempDragView != null) {
return true
}
return super.dispatchTouchEvent(ev);
}
拖动的View是一个可以悬浮在容器之上的空间中, 需要定义一个View来显示拖拽的目标View,这里采用的是ImageView; 把即将拖拽的View生成对应Bitmap来显示到悬浮的ImageView中,并把悬浮的位置设定在拖拽View的位置,实现拖拽重合移动效果。 代码片段如下:
scss
/**
* 开始拖拽,在长按事件触发之后
*/
private fun onDragStart(dragItemVIew: View, touchX: Int, touchY: Int) {
try {
if (itemEditHeight != 0 && isDragEnable()) {
val itemView = dragItemVIew
val vImage = vToBitmap(itemView)
floatView.setImageBitmap(vImage)
val top = itemView.top + ((itemView.parent as? View)?.top ?: 0)
Log.w(TAG, "top === $top");
floatView.tag = top;
setViewTopMargin(floatView, top)
floatView.visibility = View.VISIBLE
itemView.visibility = INVISIBLE
dragSelectedView = itemView;
dragInsertViewStack.clear();
resetItemViewRectInfo()
ClickVibrator.clickSingle(context, 100L)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
/**
* 拖拽移动
*/
private fun onDragMove(dragItemVIew: View, touchX: Int, touchY: Int, dy: Float) {
val newTop: Int = floatView.tag as Int + dy.toInt()
val newBottom: Int = newTop + itemEditHeight;
if (newTop in minDragTop..maxDragTop) {
floatView.tag = newTop
setViewTopMargin(floatView, newTop)
//碰撞检测
for (rect in itemRectHashMap.keys) {
val line = rect.top + rect.height() / 2
val itemView = itemRectHashMap.get(rect)
if (itemView == dragSelectedView) {
continue
}
if (line in newTop..newBottom) {
//发生碰撞
val dTop = line - newTop;
val dBottom = newBottom - line;
Log.w(TAG, "move === $dTop -- $dBottom")
val fromTop = rect.top;
val animDistance = rect.height() + resources.getDimensionPixelSize(R.dimen.dp_6)
if (dTop < dBottom) {
//item down
post {
val destTop = fromTop + animDistance
itemView?.let {
itemRectHashMap.remove(rect)
val newRect =
Rect(rect.left, destTop, rect.right, destTop + itemEditHeight)
itemRectHashMap.put(newRect, itemView)
trans(itemView, rect, newRect)
}
}
} else {
//item up
post {
val destTop = fromTop - animDistance
itemView?.let {
itemRectHashMap.remove(rect)
val newRect =
Rect(rect.left, destTop, rect.right, destTop + itemEditHeight)
itemRectHashMap.put(newRect, itemView)
trans(itemView, rect, newRect)
}
}
}
break;
}
}
}
}
/**
* 拖拽结束
*/
private fun onDragEnd() {
val replaceView = if (dragInsertViewStack.isEmpty()) null else dragInsertViewStack.pop()
if (dragSelectedView != null && replaceView != null) {
val dragData = dragSelectedView?.getTag(R.id.cb_item_tag) as? EditLocation
val replaceData = replaceView.getTag(R.id.cb_item_tag) as? EditLocation
callEditLocationDataChange(dragData, replaceData)
}
clearDragUIState()
}
平移动画实现,需要注意的是:平移的参数主要是相对View的原始位置 计算上下移动的位置。 所以需要改根据位置计算坐标变换。
kotlin
private fun trans(item: View?, fromRect: Rect, toRect: Rect) {
val divideTop = binding.rlEditLocationContainer.top
val fromTop = fromRect.top - divideTop
val destTop = toRect.top - divideTop
val originTop = (item?.top ?: 0) + ((item?.parent as? View)?.top ?: 0)
val animationDis = destTop - fromTop
val moveOut = originTop == fromTop
if (moveOut) {
dragInsertViewStack.push(item)
} else if (!dragInsertViewStack.isEmpty()) {
dragInsertViewStack.pop();
}
val fromY = if (moveOut) 0 else -1 * animationDis
val toY = if (moveOut) animationDis else 0;
Log.w(TAG, "trans start == $originTop --- $fromY,$toY")
val tran = TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f,
Animation.ABSOLUTE, fromY.toFloat(), Animation.ABSOLUTE, toY.toFloat()
)
tran.duration = (300L)
tran.fillAfter = true;
item?.startAnimation(tran)
}
在拖动结束时清空所用动画和 计算交换后的数据,重新更新对应位置的显示数据。
ini
private fun callEditLocationDataChange(dragData: EditLocation?, replaceData: EditLocation?) {
if (dragData == null || replaceData == null) {
return;
}
val tempList = ArrayList<EditLocation>();
val tempPoiList = ArrayList<EditLocation>();
tempList.addAll(locationList)
val dragIndex = tempList.indexOf(dragData)
val replaceIndex = tempList.indexOf(replaceData);
if (dragIndex != -1 && replaceIndex != -1 && dragIndex != replaceIndex) {
tempList.removeAt(dragIndex);
val insertIndex = tempList.indexOf(replaceData);
if (insertIndex != -1) {
val addIndex = if (dragIndex > replaceIndex) insertIndex else insertIndex + 1
tempList.add(addIndex, dragData)
}
if (tempList.size == locationList.size) {
for (item in tempList) {
val temp = EditLocation()
temp.poi = item.poi;
temp.editContent = item.editContent
tempPoiList.add(temp)
}
for (i in 0 until locationList.size) {
val item = locationList[i]
val tempData = tempPoiList[i]
item.poi = tempData.poi;
item.editContent = tempData.editContent
val tv = findLocationTextView(i)
updateLocationUI(item, tv)
}
}
}
tempList.clear()
tempPoiList.clear()
}
private fun clearDragUIState() {
dragSelectedView?.visibility = View.VISIBLE
floatView.visibility = View.GONE
dragSelectedView = null
for (i in 0 until binding.llMoreEditLine.childCount) {
binding.llMoreEditLine.getChildAt(i)?.clearAnimation()
}
dragInsertViewStack.clear()
}
附上完整代码:
kotlin
package com.cw.widget.map
import android.content.Context
import android.graphics.*
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.View
import android.view.animation.Animation
import android.view.animation.TranslateAnimation
import android.widget.ImageView
import com.cw.widget.R
import com.cw.widget.utils.ClickVibrator
import java.util.*
class DragEditTripLocationView : EditTripLocationListView {
val TAG = "Car-EditTrip %s"
constructor(context: Context) : super(context) {}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
) {
}
constructor(
context: Context,
attrs: AttributeSet?,
defStyleAttr: Int,
defStyleRes: Int
) : super(context, attrs, defStyleAttr, defStyleRes) {
}
companion object {
const val LONG_TIME = 1000L;
const val MSG_LONG_CLICK = 100;
const val isDebug = false;
}
val floatView: ImageView
var itemEditHeight: Int = 0;
var itemEditWidth: Int = 0;
var minDragTop: Int = 0;
var maxDragTop: Int = 0;
var testPaint: Paint = Paint()
var dragSelectedView: View? = null;
val itemRectHashMap = HashMap<Rect, View>();
val floatPaint = Paint();
/**
* 脱拽过程中插入的View
*/
private val dragInsertViewStack = Stack<View?>();
val mainHandler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
when (msg.what) {
MSG_LONG_CLICK -> {
val obj = msg.obj as Point
val windowX = obj.x;
val windowY = obj.y
findLongTouchValidView(windowX, windowY)?.let { findDragView ->
onDragStart(findDragView, msg.arg1, msg.arg2)
}
}
}
}
}
init {
floatView = ImageView(context)
binding.rlEditTwoLocation.addView(
floatView,
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT
)
floatView.visibility = View.GONE
testPaint.color = Color.RED;
testPaint.style = Paint.Style.STROKE
floatPaint.color = Color.parseColor("#ffc0df17");
floatPaint.strokeWidth = 2f;
floatPaint.style = Paint.Style.STROKE
}
private fun setViewTopMargin(v: View, top: Int) {
(v.layoutParams as? MarginLayoutParams)?.let { p ->
p.topMargin = top;
v.layoutParams = p;
}
}
private fun vToBitmap(v: View): Bitmap {
val w = v.width;
val h = v.height;
val bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565)
val canvas = Canvas(bitmap)
canvas.drawColor(Color.WHITE)
v.draw(canvas)
val editWidth = v.findViewById<View>(R.id.ll_edit_content)?.width ?: w
val corners = resources.getDimensionPixelSize(R.dimen.dp_2)
canvas.drawRoundRect(
RectF(0f, 0f, editWidth.toFloat(), h.toFloat()),
corners.toFloat(),
corners.toFloat(),
floatPaint
)
canvas.setBitmap(null)
return bitmap
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
itemEditWidth = getMiddleItemViewAt(0)?.width ?: 0
itemEditHeight = getMiddleItemViewAt(0)?.height ?: 0
}
override fun dispatchDraw(canvas: Canvas?) {
super.dispatchDraw(canvas)
if (isDebug) {
if (itemRectHashMap.isNotEmpty()) {
for (item in itemRectHashMap.keys) {
canvas?.drawRect(item, testPaint)
}
}
}
}
private fun resetItemViewRectInfo() {
minDragTop = 0;
maxDragTop = binding.rlEditTwoLocation.height - itemEditHeight;
itemRectHashMap.clear();
for (i in 0 until binding.llMoreEditLine.childCount) {
val itemView = binding.llMoreEditLine.getChildAt(i)
if (itemView != null && itemView != dragSelectedView) {
itemRectHashMap.put(getViewRect(itemView), itemView)
}
}
}
/**
* 获取相对于整个View 的Rect数据
*/
private fun getViewRect(v: View): Rect {
val pTop = binding.rlEditLocationContainer.top + ((v.parent as? View)?.top ?: 0)
val top = v.top + pTop
val bottom = v.bottom + pTop;
val left = 0;
val right = v.width;
return Rect(left, top, right, bottom)
}
private fun findLongTouchValidView(x: Int, y: Int): View? {
val rect = Rect();
for (i in 0 until binding.llMoreEditLine.childCount) {
binding.llMoreEditLine.getChildAt(i)?.let {
it.getGlobalVisibleRect(rect)
if (rect.contains(x, y)) {
return it
}
}
}
return null;
}
private fun isDragEnable(): Boolean {
return binding.rlMoreAddLocation.visibility == View.VISIBLE
}
/**
* 开始拖拽,在长按事件触发之后
*/
private fun onDragStart(dragItemVIew: View, touchX: Int, touchY: Int) {
try {
if (itemEditHeight != 0 && isDragEnable()) {
val itemView = dragItemVIew
val vImage = vToBitmap(itemView)
floatView.setImageBitmap(vImage)
val top = itemView.top + ((itemView.parent as? View)?.top ?: 0)
Log.w(TAG, "top === $top");
floatView.tag = top;
setViewTopMargin(floatView, top)
floatView.visibility = View.VISIBLE
itemView.visibility = INVISIBLE
dragSelectedView = itemView;
dragInsertViewStack.clear();
resetItemViewRectInfo()
ClickVibrator.clickSingle(context, 100L)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
/**
* 拖拽移动
*/
private fun onDragMove(dragItemVIew: View, touchX: Int, touchY: Int, dy: Float) {
val newTop: Int = floatView.tag as Int + dy.toInt()
val newBottom: Int = newTop + itemEditHeight;
if (newTop in minDragTop..maxDragTop) {
floatView.tag = newTop
setViewTopMargin(floatView, newTop)
//碰撞检测
for (rect in itemRectHashMap.keys) {
val line = rect.top + rect.height() / 2
val itemView = itemRectHashMap.get(rect)
if (itemView == dragSelectedView) {
continue
}
if (line in newTop..newBottom) {
//发生碰撞
val dTop = line - newTop;
val dBottom = newBottom - line;
Log.w(TAG, "move === $dTop -- $dBottom")
val fromTop = rect.top;
val animDistance = rect.height() + resources.getDimensionPixelSize(R.dimen.dp_6)
if (dTop < dBottom) {
//item down
post {
val destTop = fromTop + animDistance
itemView?.let {
itemRectHashMap.remove(rect)
val newRect =
Rect(rect.left, destTop, rect.right, destTop + itemEditHeight)
itemRectHashMap.put(newRect, itemView)
trans(itemView, rect, newRect)
}
}
} else {
//item up
post {
val destTop = fromTop - animDistance
itemView?.let {
itemRectHashMap.remove(rect)
val newRect =
Rect(rect.left, destTop, rect.right, destTop + itemEditHeight)
itemRectHashMap.put(newRect, itemView)
trans(itemView, rect, newRect)
}
}
}
break;
}
}
}
}
private fun trans(item: View?, fromRect: Rect, toRect: Rect) {
val divideTop = binding.rlEditLocationContainer.top
val fromTop = fromRect.top - divideTop
val destTop = toRect.top - divideTop
val originTop = (item?.top ?: 0) + ((item?.parent as? View)?.top ?: 0)
val animationDis = destTop - fromTop
val moveOut = originTop == fromTop
if (moveOut) {
dragInsertViewStack.push(item)
} else if (!dragInsertViewStack.isEmpty()) {
dragInsertViewStack.pop();
}
val fromY = if (moveOut) 0 else -1 * animationDis
val toY = if (moveOut) animationDis else 0;
Log.w(TAG, "trans start == $originTop --- $fromY,$toY")
val tran = TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f,
Animation.ABSOLUTE, fromY.toFloat(), Animation.ABSOLUTE, toY.toFloat()
)
tran.duration = (300L)
tran.fillAfter = true;
item?.startAnimation(tran)
}
/**
* 拖拽结束
*/
private fun onDragEnd() {
val replaceView = if (dragInsertViewStack.isEmpty()) null else dragInsertViewStack.pop()
if (dragSelectedView != null && replaceView != null) {
val dragData = dragSelectedView?.getTag(R.id.cb_item_tag) as? EditLocation
val replaceData = replaceView.getTag(R.id.cb_item_tag) as? EditLocation
callEditLocationDataChange(dragData, replaceData)
}
clearDragUIState()
}
private fun callEditLocationDataChange(dragData: EditLocation?, replaceData: EditLocation?) {
if (dragData == null || replaceData == null) {
return;
}
val tempList = ArrayList<EditLocation>();
val tempPoiList = ArrayList<EditLocation>();
tempList.addAll(locationList)
val dragIndex = tempList.indexOf(dragData)
val replaceIndex = tempList.indexOf(replaceData);
if (dragIndex != -1 && replaceIndex != -1 && dragIndex != replaceIndex) {
tempList.removeAt(dragIndex);
val insertIndex = tempList.indexOf(replaceData);
if (insertIndex != -1) {
val addIndex = if (dragIndex > replaceIndex) insertIndex else insertIndex + 1
tempList.add(addIndex, dragData)
}
if (tempList.size == locationList.size) {
for (item in tempList) {
val temp = EditLocation()
temp.poi = item.poi;
temp.editContent = item.editContent
tempPoiList.add(temp)
}
for (i in 0 until locationList.size) {
val item = locationList[i]
val tempData = tempPoiList[i]
item.poi = tempData.poi;
item.editContent = tempData.editContent
val tv = findLocationTextView(i)
updateLocationUI(item, tv)
}
}
}
tempList.clear()
tempPoiList.clear()
}
private fun clearDragUIState() {
dragSelectedView?.visibility = View.VISIBLE
floatView.visibility = View.GONE
dragSelectedView = null
for (i in 0 until binding.llMoreEditLine.childCount) {
binding.llMoreEditLine.getChildAt(i)?.clearAnimation()
}
dragInsertViewStack.clear()
}
private var yPos = 0f;
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
var dy = 0f
val tempDragView = dragSelectedView;
when (ev?.action) {
MotionEvent.ACTION_DOWN -> {
yPos = ev.y
mainHandler.removeMessages(MSG_LONG_CLICK)
val msg = mainHandler.obtainMessage(MSG_LONG_CLICK)
msg.arg1 = ev.x.toInt()
msg.arg2 = ev.y.toInt()
msg.obj = Point(ev.rawX.toInt(), ev.rawY.toInt())
mainHandler.sendMessageDelayed(msg, LONG_TIME)
}
MotionEvent.ACTION_MOVE -> {
dy = ev.y - yPos;
yPos = ev.y
if (tempDragView != null && dy != 0f) {
mainHandler.removeMessages(MSG_LONG_CLICK)
onDragMove(tempDragView!!, ev.x.toInt(), ev.y.toInt(), dy)
}
}
MotionEvent.ACTION_CANCEL -> {
mainHandler.removeMessages(MSG_LONG_CLICK)
if (tempDragView != null) {
onDragEnd()
}
}
MotionEvent.ACTION_UP -> {
mainHandler.removeMessages(MSG_LONG_CLICK)
if (tempDragView != null) {
onDragEnd()
}
}
}
if (tempDragView != null) {
return true
}
return super.dispatchTouchEvent(ev);
}
}
kotlin
package com.cw.widget.map
import android.app.Activity
import android.content.Context
import android.graphics.ColorMatrix
import android.graphics.ColorMatrixColorFilter
import android.graphics.Paint
import android.text.Editable
import android.text.TextWatcher
import android.util.AttributeSet
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.EditText
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.TextView
import com.blankj.utilcode.util.KeyboardUtils
import com.blankj.utilcode.util.ToastUtils
import com.cw.widget.R
import com.cw.widget.bean.POIType
import com.cw.widget.bean.SearchPOI
import com.cw.widget.databinding.EditSearchKeyBinding
import com.cw.widget.databinding.EditTripLocationListBinding
/**
* 新建,编辑行程的编辑View
*/
open class EditTripLocationListView : FrameLayout {
constructor(context: Context) : super(context) {}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
) {
}
constructor(
context: Context,
attrs: AttributeSet?,
defStyleAttr: Int,
defStyleRes: Int
) : super(context, attrs, defStyleAttr, defStyleRes) {
}
val binding: EditTripLocationListBinding
val MAX_MIDDLE_NUM = 3;
val locationList: ArrayList<EditLocation>
private val startLocation: EditLocation
private val endLocation: EditLocation
var onEventListener: OnEventListener? = null
/**
* 文字变化忽略改动
*/
var textChangeIgnoreTask: TextChangeIgnore? = null
init {
startLocation = EditLocation.createStartLocation(context)
endLocation = EditLocation.createEndLocation()
locationList = ArrayList<EditLocation>()
locationList.add(startLocation)
locationList.add(endLocation)
binding = EditTripLocationListBinding.inflate(LayoutInflater.from(context))
addView(binding.root, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
binding.llStartLocation.ivEdt.setImageResource(R.drawable.start_location_point)
binding.llStartLocation.edtInputKey.setText("")
binding.llStartLocation.edtInputKey.hint = "请输入起点"
binding.llStartLocation.edtInputKey.contentDescription = "起点"
setUpEditViewKeyboard(binding.llStartLocation.edtInputKey)
val startWatcher = EditTextWatcher(this, binding.llStartLocation.edtInputKey)
binding.llStartLocation.edtInputKey.addTextChangedListener(startWatcher)
binding.llStartLocation.root.setTag(R.id.cb_item_tag, startLocation)
binding.llStartLocation.edtInputKey.setTag(R.id.cb_item_tag, startLocation)
updateLocationUI(startLocation)
binding.llEndLocation.ivEdt.setImageResource(R.drawable.end_location_point)
binding.llEndLocation.root.setTag(R.id.cb_item_tag, endLocation)
binding.llEndLocation.edtInputKey.setTag(R.id.cb_item_tag, endLocation)
binding.llEndLocation.edtInputKey.contentDescription = "终点"
setUpEditViewKeyboard(binding.llEndLocation.edtInputKey)
val endWatcher = EditTextWatcher(this, binding.llEndLocation.edtInputKey)
binding.llEndLocation.edtInputKey.addTextChangedListener(endWatcher)
binding.llEndLocation.edtInputKey.setText("")
binding.llEndLocation.edtInputKey.hint = "请输入终点"
switchUIState(false)
post {
if (binding.llStartLocation.edtInputKey.text.isNullOrEmpty()) {
binding.llStartLocation.edtInputKey.requestFocus()
} else {
binding.llEndLocation.edtInputKey.requestFocus()
}
}
binding.ivAddLocation.setOnClickListener {
val index = getMiddleCount()
if (index < MAX_MIDDLE_NUM) {
var addIndex = index
(findFocusEditTextView()?.getTag(R.id.cb_item_tag) as? EditLocation)?.let {
val findIndex = locationList.indexOf(it)
if (findIndex != -1) {
addIndex = findIndex;
}
}
addMiddleLocation(addIndex)
switchUIState(true)
} else {
ToastUtils.showShort("最多可添加${MAX_MIDDLE_NUM}个途经点")
}
}
binding.rlMoreAdd.setOnClickListener {
binding.ivAddLocation.performClick()
}
binding.llStartLocation.ivDelEdit.setOnClickListener {
if (locationList.size > 2 &&
locationList[1].locationType == EditLocation.TYPE_MIDDLE
) {
startLocation.poi = locationList[1].poi
removeMiddleLocation(0)
} else {
startLocation.poi = null
}
updateLocationUI(startLocation)
}
binding.llEndLocation.ivDelEdit.setOnClickListener {
val index = locationList.size - 2
if (locationList.size > 2 &&
locationList[index].locationType == EditLocation.TYPE_MIDDLE
) {
endLocation.poi = locationList[index].poi
val middleIndex = getMiddleCount() - 1
removeMiddleLocation(middleIndex)
} else {
endLocation.poi = null
}
updateLocationUI(endLocation)
}
binding.ivBackFinish.setOnClickListener { v ->
onEventListener?.onCloseClick(v)
}
binding.ivLocationChangeMore.setOnClickListener {
binding.ivSwitchLocation.performClick();
}
binding.ivSwitchLocation.setOnClickListener { v ->
val temp = startLocation.poi
val tempEditContent = startLocation.editContent
startLocation.poi = endLocation.poi
startLocation.editContent = endLocation.editContent
endLocation.poi = temp
endLocation.editContent = tempEditContent
updateLocationUI(startLocation)
updateLocationUI(endLocation)
val start = 1;
val end = locationList.lastIndex - 1
//途经点交换次数
val switchCount = locationList.size / 2 - 1
for (i in 0 until switchCount) {
val index = start + i;
val switchIndex = end - i;
if (switchIndex != index && switchIndex >= 0) {
val temp = locationList.getOrNull(index)?.poi
locationList.getOrNull(index)?.poi = locationList.getOrNull(switchIndex)?.poi
locationList.getOrNull(switchIndex)?.poi = temp;
locationList.getOrNull(index)?.let {
updateLocationUI(it, findMidLocationTextView(index))
}
locationList.getOrNull(switchIndex)?.let {
updateLocationUI(it, findMidLocationTextView(switchIndex))
}
}
}
findFirstNoneEditTextView()?.let {
if (!it.text.isNullOrEmpty()) {
callOnTextChanged(it, it.text)
}
requestFocus(it, true)
}
}
binding.btnEditLocationComplete.setOnClickListener {
val dataList = ArrayList<EditLocation>()
for (item in locationList) {
if (item.poi != null) {
dataList.add(item)
}
}
if (startLocation.poi == null && !startLocation.editContent.isNullOrEmpty()) {
ToastUtils.showShort("请选择起点")
requestFocus(binding.llStartLocation.edtInputKey)
return@setOnClickListener
}
if (endLocation.poi == null && !endLocation.editContent.isNullOrEmpty()) {
ToastUtils.showShort("请选择终点")
requestFocus(binding.llEndLocation.edtInputKey)
return@setOnClickListener
}
if (dataList.size < 2) {
if (startLocation?.poi == null) {
ToastUtils.showShort("请选择起点")
requestFocus(binding.llStartLocation.edtInputKey)
} else if (endLocation?.poi == null) {
ToastUtils.showShort("请选择终点")
requestFocus(binding.llEndLocation.edtInputKey)
}
return@setOnClickListener
}
if (getMiddleCount() + 2 != dataList.size) {
for (i in 0 until getMiddleCount()) {
val editInText = !findMidLocationTextView(i + 1)?.text.isNullOrEmpty()
val poiNoSelected = locationList.getOrNull(i + 1)?.poi == null
if (editInText && poiNoSelected) {
ToastUtils.showShort("请选择第${i + 1}个途经点")
return@setOnClickListener
}
}
}
val resultList = ArrayList<EditLocation>()
var latestData: EditLocation? = null
for (data in dataList) {
if (data.poi?.poiName != latestData?.poi?.poiName ||
data.poi?.poiType != latestData?.poi?.poiType
) {
resultList.add(data)
}
latestData = data
}
if (resultList.size == 2) {
if (isSamePOI(resultList[0].poi, resultList[1].poi)) {
ToastUtils.showShort("起点与终点不能相同")
return@setOnClickListener
}
} else if (resultList.size < 2) {
ToastUtils.showShort("起点与终点不能相同")
return@setOnClickListener
}
hideSoftInput()
onEventListener?.onLocationEditComplete(resultList)
}
}
/**
* 获取途经点个数
*/
protected fun getMiddleCount(): Int {
val allCount = binding.llMoreEditLine.childCount - 2
if (allCount >= 0) {
return allCount;
}
return 0;
}
private fun isSamePOI(poi1: SearchPOI?, poi2: SearchPOI?): Boolean {
return poi1 == poi2 || poi1?.poiName == poi2?.poiName ||
(poi1?.poiType == POIType.userPosition && POIType.userPosition == poi2?.poiType)
|| (poi1?.poiType == POIType.carPosition && POIType.carPosition == poi2?.poiType)
}
private fun requestFocus(view: TextView, isSelectedText: Boolean = false) {
post {
view.requestFocus()
if (view is EditText && isSelectedText) {
val length = view.text.length;
(view as EditText).setSelection(0, length)
KeyboardUtils.showSoftInput(view)
}
}
}
fun setLocationList(list: List<EditLocation>) {
list.getOrNull(0)?.let {
startLocation.poi = it.poi
updateLocationUI(startLocation)
}
list.getOrNull(list.lastIndex)?.let {
endLocation.poi = it.poi
updateLocationUI(endLocation)
}
locationList.clear()
locationList.add(startLocation)
locationList.add(endLocation)
removeAllMiddleView()
switchUIState(list.size > 2)
for (i in 1 until list.lastIndex) {
val v = addMiddleLocation(i - 1)
val item = list[i]
locationList[i].poi = item.poi
updateLocationUI(locationList[i], v)
}
}
private fun removeAllMiddleView() {
var hasCount = binding.llMoreEditLine.childCount
while (hasCount > 2) {
val index = hasCount - 1 - 1;
binding.llMoreEditLine.getChildAt(index)?.let { v ->
binding.llMoreEditLine.removeView(v)
}
hasCount = binding.llMoreEditLine.childCount
}
}
fun setIndexFocus(focusIndex: Int) {
locationList.getOrNull(focusIndex)?.let {
if (it.locationType == EditLocation.TYPE_START) {
requestFocus(binding.llStartLocation.edtInputKey, true)
} else if (it.locationType == EditLocation.TYPE_END) {
requestFocus(binding.llEndLocation.edtInputKey, true)
} else {
getMiddleItemViewAt(focusIndex - 1)
?.findViewById<EditText>(R.id.edt_input_key)
?.let { v ->
requestFocus(v, true)
}
}
}
}
/**
* @param middleIndex 从0开始,排除起点和终点之外的列表
*/
protected fun getMiddleItemViewAt(middleIndex: Int): View? {
return binding.llMoreEditLine.getChildAt(middleIndex + 1)
}
fun showSoftInput() {
if (context is Activity) {
KeyboardUtils.showSoftInput(context as Activity)
} else {
KeyboardUtils.showSoftInput();
}
}
fun showSoftInput(editText: View) {
KeyboardUtils.showSoftInput(editText)
}
fun hideSoftInput() {
if (context is Activity) {
KeyboardUtils.hideSoftInput(context as Activity)
} else {
KeyboardUtils.hideSoftInput(this)
}
}
/**
* 设置POI ; 有光标时就填充对应的项;没有光标时优先填充未填写项,顺序:终点、起点、途经点
*/
fun setPoi(poi: SearchPOI) {
val v = findFocusEditTextView()
if (v != null) {
val tagData = v.getTag(R.id.cb_item_tag)
if (tagData is EditLocation) {
tagData.poi = poi
updateLocationUI(tagData, v)
}
} else if (endLocation.poi == null) {
endLocation.poi = poi
updateLocationUI(endLocation)
} else if (startLocation.poi == null) {
startLocation.poi = poi
updateLocationUI(startLocation)
} else {
val index = findNonePoiMiddleLocation()
if (index <= 0) {
endLocation.poi = poi
updateLocationUI(endLocation)
} else {
locationList[index].poi = poi
getMiddleItemViewAt(index - 1)
?.findViewById<EditText>(R.id.edt_input_key)
?.let { v ->
updateLocationUI(locationList[index], v)
}
}
}
//光标自动聚焦到下一个空的输入框
findFirstNoneEditTextView()?.let {
requestFocus(it)
callOnTextChanged(it, it.text)
} ?: let {
callOnTextChanged(null, "")
hideSoftInput()
}
//无途经点
if (getMiddleCount() <= 0) {
if (startLocation.poi != null && endLocation.poi != null) {
if (isSamePOI(startLocation.poi, endLocation.poi)) {
ToastUtils.showShort("起点与终点不能相同")
} else {
val resultList = ArrayList<EditLocation>();
resultList.add(startLocation)
resultList.add(endLocation)
hideSoftInput()
onEventListener?.onLocationEditComplete(resultList)
}
}
}
}
private fun setUpEditViewKeyboard(editText: EditText?) {
editText?.imeOptions = EditorInfo.IME_ACTION_SEARCH
editText?.setOnEditorActionListener { v, actionId, event ->
val isClick = event?.keyCode == KeyEvent.KEYCODE_ENTER;
if (actionId == EditorInfo.IME_ACTION_SEARCH || isClick) {
onEventListener?.onEditTextChange(v as? EditText, v.text)
return@setOnEditorActionListener true;
}
return@setOnEditorActionListener false;
}
editText?.isLongClickable = false;
editText?.setOnFocusChangeListener { v, hasFocus ->
if (hasFocus) {
(v as? EditText)?.let { edit ->
edit.postDelayed({
edit.setSelection(0, edit.text?.length ?: 0)
}, 100);
}
}
}
editText?.setOnClickListener { v ->
(v as? EditText)?.let { edit ->
edit.setSelection(0, edit.text?.length ?: 0)
}
}
}
private fun findNonePoiMiddleLocation(): Int {
for (index in 1..locationList.size - 2) {
val item = locationList[index]
if (item.poi == null) {
return index
}
}
return -1;
}
private fun findFirstNoneEditTextView(): EditText? {
if (startLocation.poi == null) {
return binding.llStartLocation.edtInputKey
}
if (endLocation.poi == null) {
return binding.llEndLocation.edtInputKey
}
for (i in 0 until getMiddleCount()) {
val itemView = getMiddleItemViewAt(i)
val editText = itemView?.findViewById<EditText>(R.id.edt_input_key)
if (editText != null && (editText.getTag(R.id.cb_item_tag) as? EditLocation)?.poi == null) {
return editText
}
}
return null
}
private fun findFocusEditTextView(): EditText? {
if (binding.llStartLocation.edtInputKey.hasFocus()) {
return binding.llStartLocation.edtInputKey
}
if (binding.llEndLocation.edtInputKey.hasFocus()) {
return binding.llEndLocation.edtInputKey
}
for (i in 0 until getMiddleCount()) {
val itemView = getMiddleItemViewAt(i)
val editText = itemView?.findViewById<EditText>(R.id.edt_input_key)
if (editText != null && editText.hasFocus()) {
return editText
}
}
return null
}
private fun findMidLocationTextView(index: Int): EditText? {
val middleIndex = index - 1;
val itemView = getMiddleItemViewAt(middleIndex)
return itemView?.findViewById<EditText>(R.id.edt_input_key)
}
protected fun findLocationTextView(index: Int): EditText? {
val itemView = binding.llMoreEditLine.getChildAt(index)
return itemView?.findViewById<EditText>(R.id.edt_input_key)
}
protected fun updateLocationUI(location: EditLocation, textView: TextView? = null) {
var addressName: String = location.poi?.poiName ?: ""
if (location.poi?.poiType == POIType.userPosition) {
addressName = "我的位置"
} else if (location.poi?.poiType == POIType.carPosition) {
addressName = "车辆位置"
}
var editView: TextView? = null
if (location.locationType == EditLocation.TYPE_START) {
editView = binding.llStartLocation.edtInputKey;
} else if (location.locationType == EditLocation.TYPE_END) {
editView = binding.llEndLocation.edtInputKey
} else {
editView = textView
}
if (editView != null && !addressName.isNullOrEmpty()) {
textChangeIgnoreTask = TextChangeIgnore(editView, addressName)
}
val showText = addressName.ifEmpty { (location.editContent ?: "") }
editView?.text = showText
editView?.text?.length?.let { l ->
(editView as? EditText)?.setSelection(l)
}
}
private fun setViewMargin(v: View, left: Int, top: Int, right: Int, bottom: Int) {
v.layoutParams?.let {
val p = it as MarginLayoutParams
if (p.leftMargin != left ||
p.topMargin != top ||
p.rightMargin != right ||
p.bottomMargin != bottom
) {
p.setMargins(left, top, right, bottom)
v.layoutParams = p
}
}
}
private fun switchUIState(isHasMiddleLocation: Boolean, middleCount: Int = 1) {
if (isHasMiddleLocation) {
binding.rlEditLocationContainer.setBackgroundResource(R.drawable.bg_transparent)
binding.llStartLocation.llEditContent.setBackgroundResource(R.drawable.bg_edit_box)
binding.llEndLocation.llEditContent.setBackgroundResource(R.drawable.bg_edit_box)
binding.llStartLocation.ivDelEdit.visibility =
if (middleCount == 0) View.GONE else View.VISIBLE
binding.llEndLocation.ivDelEdit.visibility =
if (middleCount == 0) View.GONE else View.VISIBLE
binding.llEditAction.visibility = View.GONE
binding.llStartLocation.ivEditMoveTag.visibility = View.VISIBLE
binding.llEndLocation.ivEditMoveTag.visibility = View.VISIBLE
binding.ivLocationChangeMore.visibility = View.VISIBLE
binding.rlMoreAddLocation.visibility = View.VISIBLE
binding.twoLineSplit.visibility = View.GONE
setViewMargin(
binding.llEndLocation.root, 0, resources.getDimensionPixelSize(R.dimen.dp_6),
0, 0
)
} else {
binding.rlEditLocationContainer.setBackgroundResource(R.drawable.bg_edit_box)
binding.llStartLocation.llEditContent.setBackgroundResource(R.drawable.bg_transparent)
binding.llEndLocation.llEditContent.setBackgroundResource(R.drawable.bg_transparent)
binding.llStartLocation.ivDelEdit.visibility = View.GONE
binding.llEndLocation.ivDelEdit.visibility = View.GONE
binding.llStartLocation.ivEditMoveTag.visibility = View.GONE
binding.llEndLocation.ivEditMoveTag.visibility = View.GONE
binding.llEditAction.visibility = View.VISIBLE
binding.ivLocationChangeMore.visibility = View.GONE
binding.rlMoreAddLocation.visibility = View.GONE
removeAllMiddleView()
binding.twoLineSplit.visibility = View.VISIBLE
setViewMargin(
binding.llEndLocation.root, 0, 0,
0, 0
)
}
}
/**
* @param middleIndex 从0开始,排除起点和终点之外的列表
*/
private fun addMiddleLocation(middleIndex: Int = 0): EditText {
val params = LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
val top: Int = resources.getDimensionPixelSize(R.dimen.dp_6)
val bottom = 0
params.topMargin = top
params.bottomMargin = bottom
val middleViewBinding = createMiddleLocationEditView();
var middlePos: Int = middleIndex
if (getMiddleCount() > middleIndex) {
binding.llMoreEditLine.addView(middleViewBinding.root, middleIndex + 1, params)
} else {
val index = binding.llMoreEditLine.childCount - 1;
binding.llMoreEditLine.addView(middleViewBinding.root, index, params)
middlePos = getMiddleCount() - 1;
}
val middleData = EditLocation.createMiddleLocation()
middleViewBinding.root.setTag(R.id.cb_item_tag, middleData)
middleViewBinding.edtInputKey.setTag(R.id.cb_item_tag, middleData)
locationList.add(middlePos + 1, middleData)
updateAddMoreUIState()
post {
middleViewBinding.edtInputKey.requestFocus()
}
return middleViewBinding.edtInputKey
}
private fun updateAddMoreUIState() {
val couldAddSize = MAX_MIDDLE_NUM - getMiddleCount()
binding.tvAddNum.text = if (couldAddSize <= 0) "已到达上限" else "还可添加${couldAddSize}个"
if (couldAddSize <= 0) {
binding.rlMoreAdd.tag = false
setViewColorFilter(binding.rlMoreAdd, 0.5f)
} else {
binding.rlMoreAdd.tag = true;
setViewColorFilter(binding.rlMoreAdd, 1f)
}
}
private fun setViewColorFilter(view: View, alphaScale: Float) {
val paint = Paint()
val cm = ColorMatrix()
cm.setScale(1f, 1f, 1f, alphaScale)
paint.colorFilter = ColorMatrixColorFilter(cm)
view.setLayerType(View.LAYER_TYPE_HARDWARE, paint)
}
/**
* @param middleIndex 从0开始,排除起点和终点之外的列表
*/
private fun removeMiddleLocation(middleIndex: Int) {
getMiddleItemViewAt(middleIndex)?.let { child ->
binding.llMoreEditLine.removeView(child)
(child.getTag(R.id.cb_item_tag) as? EditLocation).let { data ->
locationList.remove(data)
}
}
/*val index = middleIndex + 1
val location = locationList.getOrNull(index)
if (location != null && location.locationType == EditLocation.TYPE_MIDDLE) {
locationList.removeAt(index)
}*/
val count = getMiddleCount()
switchUIState(true, count)
updateAddMoreUIState()
}
private fun createMiddleLocationEditView(): EditSearchKeyBinding {
val tempBinding = EditSearchKeyBinding.inflate(LayoutInflater.from(context))
val itemView: View = tempBinding.root
tempBinding.ivEdt.setImageResource(R.drawable.middle_location_point)
tempBinding.llEditContent.setBackgroundResource(R.drawable.bg_edit_box)
tempBinding.edtInputKey.setText("")
tempBinding.edtInputKey.hint = "请输入途经点"
setUpEditViewKeyboard(tempBinding.edtInputKey)
val middleWatcher = EditTextWatcher(this, tempBinding.edtInputKey)
tempBinding.edtInputKey.addTextChangedListener(middleWatcher)
tempBinding.ivEditMoveTag.visibility = View.VISIBLE
tempBinding.ivDelEdit.visibility = View.VISIBLE
tempBinding.ivDelEdit.setTag(itemView)
tempBinding.ivDelEdit.setOnClickListener { v ->
if (v.tag != null && v.tag is View) {
val index = binding.llMoreEditLine.indexOfChild(v.tag as View) - 1
removeMiddleLocation(index)
}
}
return tempBinding
}
private fun callOnTextChanged(editText: EditText?, text: CharSequence?) {
if (textChangeIgnoreTask?.isIgnore(editText, text?.toString() ?: "") != true) {
(editText?.getTag(R.id.cb_item_tag) as? EditLocation)?.let {
it.editContent = text?.toString();
it.poi = null;
}
onEventListener?.onEditTextChange(editText, text)
}
textChangeIgnoreTask = null
}
interface OnEventListener {
fun onEditTextChange(editText: EditText?, text: CharSequence?)
fun onCloseClick(v: View)
fun onLocationEditComplete(locationList: List<EditLocation>)
}
class TextChangeIgnore(val tagView: View, val ignoreText: String) {
fun isIgnore(changeView: View?, changeText: String): Boolean {
return tagView == changeView && changeText == ignoreText;
}
}
class EditTextWatcher(val v: EditTripLocationListView, val editText: EditText) : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
var inputText = s?.toString() ?: ""
if (inputText.length > 200) {
inputText = inputText.substring(0, 200)
editText.setText(inputText)
val selection = editText.text.length
editText.setSelection(selection)
}
v.callOnTextChanged(editText, inputText)
}
}
}
class EditLocation {
companion object {
const val TYPE_START = 0;
const val TYPE_MIDDLE = 1;
const val TYPE_END = 2;
fun createStartLocation(context: Context): EditLocation {
val location = EditLocation()
location.locationType = TYPE_START
val userPoi = SearchPOI()
userPoi.poiType = POIType.userPosition;
location.poi = userPoi;
return location
}
fun createMiddleLocation(): EditLocation {
val location = EditLocation()
location.locationType = TYPE_MIDDLE
return location
}
fun createEndLocation(): EditLocation {
val location = EditLocation()
location.locationType = TYPE_END
return location
}
}
var locationType: Int = TYPE_START
var poi: SearchPOI? = null
/**
* 编辑的文字
*/
var editContent: String? = null;
}
最终的效果: