[6.7.0][Feat]高精地图和高德地图切换动效
This commit is contained in:
@@ -1,14 +1,23 @@
|
||||
package com.mogo.eagle.core.function.hmi.map
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.animation.AnimatorSet
|
||||
import android.animation.ObjectAnimator
|
||||
import android.animation.PropertyValuesHolder
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.view.animation.AccelerateDecelerateInterpolator
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.constraintlayout.widget.ConstraintSet
|
||||
import com.mogo.eagle.core.function.hmi.R
|
||||
import com.mogo.eagle.core.function.hmi.util.ConstraintUtil
|
||||
import kotlinx.android.synthetic.main.view_map_container.view.exchangeLayout
|
||||
import me.jessyan.autosize.utils.AutoSizeUtils
|
||||
|
||||
/**
|
||||
* 可自定义绘制顺序的ConstraintLayout
|
||||
*/
|
||||
class ExchangeChildLayout @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
@@ -16,8 +25,6 @@ class ExchangeChildLayout @JvmOverloads constructor(
|
||||
) : ConstraintLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
private var mContext: Context? = null
|
||||
private var isChange = false
|
||||
private var isPlayingAnim = false
|
||||
|
||||
private var maxWidth = 0
|
||||
private var maxHeight = 0
|
||||
@@ -27,11 +34,16 @@ class ExchangeChildLayout @JvmOverloads constructor(
|
||||
private var bottomY = 0f
|
||||
private var topX = 0f
|
||||
private var topY = 0f
|
||||
private var bScaleX = 0f
|
||||
private var bScaleY = 0f
|
||||
private var tScaleX = 0f
|
||||
private var tScaleY = 0f
|
||||
|
||||
companion object {
|
||||
private const val TAG = "ExchangeChildLayout"
|
||||
private const val ANIM_DURATION = 600L
|
||||
}
|
||||
private var isSwapped = false
|
||||
private var isPlayingAnim = false
|
||||
|
||||
private var animatorSet: AnimatorSet? = null
|
||||
private var constraintUtil: ConstraintUtil? = null
|
||||
|
||||
init {
|
||||
try {
|
||||
@@ -41,19 +53,53 @@ class ExchangeChildLayout @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ANIM_DURATION = 500L
|
||||
}
|
||||
|
||||
private fun initView(context: Context) {
|
||||
mContext = context
|
||||
isChildrenDrawingOrderEnabled = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启ViewGroup自定义绘制顺序
|
||||
*/
|
||||
fun setSwapped(isSwapped: Boolean) {
|
||||
if (!isPlayingAnim) {
|
||||
this.isSwapped = isSwapped
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
fun swapViews() {
|
||||
if (!isPlayingAnim) {
|
||||
isSwapped = !isSwapped
|
||||
startAnim()
|
||||
}
|
||||
}
|
||||
|
||||
fun getSwapFlag() = isSwapped
|
||||
|
||||
override fun onWindowFocusChanged(hasWindowFocus: Boolean) {
|
||||
super.onWindowFocusChanged(hasWindowFocus)
|
||||
if (hasWindowFocus) {
|
||||
calculate()
|
||||
}
|
||||
}
|
||||
|
||||
private fun calculate() {
|
||||
if (maxWidth == 0 && maxHeight == 0) {
|
||||
val bottomView = getChildAt(0)
|
||||
val topView = getChildAt(childCount - 1)
|
||||
maxWidth = bottomView.width
|
||||
maxHeight = bottomView.height
|
||||
minWidth = topView.width
|
||||
minHeight = topView.height
|
||||
bScaleX = (topView.width.toDouble() / bottomView.width.toDouble()).toFloat()
|
||||
bScaleY = (topView.height.toDouble() / bottomView.height.toDouble()).toFloat()
|
||||
tScaleX = (bottomView.width.toDouble() / topView.width.toDouble()).toFloat()
|
||||
tScaleY = (bottomView.height.toDouble() / topView.height.toDouble()).toFloat()
|
||||
bottomX = bottomView.x
|
||||
bottomY = bottomView.y
|
||||
topX = topView.x
|
||||
@@ -61,150 +107,101 @@ class ExchangeChildLayout @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启ViewGroup自定义绘制顺序
|
||||
*/
|
||||
fun setCustomOrder(enable: Boolean) {
|
||||
isChildrenDrawingOrderEnabled = enable
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换高精地图和高德地图View的位置
|
||||
*/
|
||||
fun exchange() {
|
||||
if (!isPlayingAnim) {
|
||||
isChange = !isChange
|
||||
startAnim()
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
private fun startAnim() {
|
||||
calculate()
|
||||
val bottomView = getChildAt(0)
|
||||
val topView = getChildAt(childCount - 1)
|
||||
|
||||
val bottomXAnimator: ObjectAnimator
|
||||
val bottomYAnimator: ObjectAnimator
|
||||
val bottomWidthAnimator: ObjectAnimator
|
||||
val bottomHeightAnimator: ObjectAnimator
|
||||
val topXAnimator: ObjectAnimator
|
||||
val topYAnimator: ObjectAnimator
|
||||
val topWidthAnimator: ObjectAnimator
|
||||
val topHeightAnimator: ObjectAnimator
|
||||
val bxPro: PropertyValuesHolder
|
||||
val byPro: PropertyValuesHolder
|
||||
val bWidthPro: PropertyValuesHolder
|
||||
val bHeightPro: PropertyValuesHolder
|
||||
val alphaPro: PropertyValuesHolder
|
||||
val bOA: ObjectAnimator
|
||||
|
||||
if (isChange) {
|
||||
exchangeRule(bottomView.layoutParams as LayoutParams, true, true)
|
||||
bottomXAnimator = ObjectAnimator.ofFloat(bottomView, "x", bottomX, topX)
|
||||
bottomYAnimator = ObjectAnimator.ofFloat(bottomView, "y", bottomY, topY)
|
||||
bottomWidthAnimator =
|
||||
ObjectAnimator.ofInt(
|
||||
WrapperViewWidth(bottomView),
|
||||
"width",
|
||||
maxWidth,
|
||||
minWidth
|
||||
)
|
||||
bottomHeightAnimator =
|
||||
ObjectAnimator.ofInt(
|
||||
WrapperViewHeight(bottomView),
|
||||
"height",
|
||||
maxHeight,
|
||||
minHeight
|
||||
)
|
||||
exchangeRule(topView.layoutParams as LayoutParams, false, true)
|
||||
topXAnimator = ObjectAnimator.ofFloat(topView, "x", topX, bottomX)
|
||||
topYAnimator = ObjectAnimator.ofFloat(topView, "y", topY, bottomY)
|
||||
topWidthAnimator =
|
||||
ObjectAnimator.ofInt(
|
||||
WrapperViewWidth(topView),
|
||||
"width",
|
||||
minWidth,
|
||||
maxWidth
|
||||
)
|
||||
topHeightAnimator =
|
||||
ObjectAnimator.ofInt(
|
||||
WrapperViewHeight(topView),
|
||||
"height",
|
||||
minHeight,
|
||||
maxHeight
|
||||
)
|
||||
val txPro: PropertyValuesHolder
|
||||
val tyPro: PropertyValuesHolder
|
||||
val tWidthPro: PropertyValuesHolder
|
||||
val tHeightPro: PropertyValuesHolder
|
||||
val tOA: ObjectAnimator
|
||||
|
||||
if (isSwapped) {
|
||||
bxPro = PropertyValuesHolder.ofFloat("translationX", 0f, topX - bottomX - maxWidth * (1 - bScaleX) / 2)
|
||||
byPro = PropertyValuesHolder.ofFloat("translationY",0f, topY - bottomY - maxHeight * (1 - bScaleY) / 2)
|
||||
bWidthPro = PropertyValuesHolder.ofFloat("scaleX", 1f, bScaleX)
|
||||
bHeightPro = PropertyValuesHolder.ofFloat("scaleY", 1f, bScaleY)
|
||||
bOA = ObjectAnimator.ofPropertyValuesHolder(bottomView, bxPro, byPro, bWidthPro, bHeightPro)
|
||||
|
||||
txPro = PropertyValuesHolder.ofFloat("translationX", 0f, bottomX - topX - minWidth * (1 - tScaleX) / 2)
|
||||
tyPro = PropertyValuesHolder.ofFloat("translationY", 0f, bottomY - topY - minHeight * (1 - tScaleY) / 2)
|
||||
tWidthPro = PropertyValuesHolder.ofFloat("scaleX", 1f, tScaleX/1.5f)
|
||||
tHeightPro = PropertyValuesHolder.ofFloat("scaleY", 1f, tScaleY/1.5f)
|
||||
alphaPro = PropertyValuesHolder.ofFloat("alpha", 1f, 0.1f)
|
||||
tOA = ObjectAnimator.ofPropertyValuesHolder(topView, tWidthPro, tHeightPro, txPro, tyPro, alphaPro)
|
||||
} else {
|
||||
exchangeRule(bottomView.layoutParams as LayoutParams, true, false)
|
||||
bottomXAnimator = ObjectAnimator.ofFloat(bottomView, "x", topX, bottomX)
|
||||
bottomYAnimator = ObjectAnimator.ofFloat(bottomView, "y", topY, bottomY)
|
||||
bottomWidthAnimator =
|
||||
ObjectAnimator.ofInt(
|
||||
WrapperViewWidth(bottomView),
|
||||
"width",
|
||||
minWidth,
|
||||
maxWidth
|
||||
)
|
||||
bottomHeightAnimator =
|
||||
ObjectAnimator.ofInt(
|
||||
WrapperViewHeight(bottomView),
|
||||
"height",
|
||||
minHeight,
|
||||
maxHeight
|
||||
)
|
||||
exchangeRule(topView.layoutParams as LayoutParams, false, false)
|
||||
topXAnimator = ObjectAnimator.ofFloat(topView, "x", bottomX, topX)
|
||||
topYAnimator = ObjectAnimator.ofFloat(topView, "y", bottomY, topY)
|
||||
topWidthAnimator =
|
||||
ObjectAnimator.ofInt(
|
||||
WrapperViewWidth(topView),
|
||||
"width",
|
||||
maxWidth,
|
||||
minWidth
|
||||
)
|
||||
topHeightAnimator =
|
||||
ObjectAnimator.ofInt(
|
||||
WrapperViewHeight(topView),
|
||||
"height",
|
||||
maxHeight,
|
||||
minHeight
|
||||
)
|
||||
bxPro = PropertyValuesHolder.ofFloat("translationX", 0f, topX - bottomX - maxWidth * (1 - bScaleX) / 2)
|
||||
byPro = PropertyValuesHolder.ofFloat("translationY",0f, topY - bottomY - maxHeight * (1 - bScaleY) / 2)
|
||||
bWidthPro = PropertyValuesHolder.ofFloat("scaleX", 1f, bScaleX)
|
||||
bHeightPro = PropertyValuesHolder.ofFloat("scaleY", 1f, bScaleY)
|
||||
bOA = ObjectAnimator.ofPropertyValuesHolder(topView, bxPro, byPro, bWidthPro, bHeightPro)
|
||||
|
||||
txPro = PropertyValuesHolder.ofFloat("translationX", 0f, bottomX - topX - minWidth * (1 - tScaleX) / 2)
|
||||
tyPro = PropertyValuesHolder.ofFloat("translationY", 0f, bottomY - topY - minHeight * (1 - tScaleY) / 2)
|
||||
tWidthPro = PropertyValuesHolder.ofFloat("scaleX", 1f, tScaleX/1.5f)
|
||||
tHeightPro = PropertyValuesHolder.ofFloat("scaleY", 1f, tScaleY/1.5f)
|
||||
alphaPro = PropertyValuesHolder.ofFloat("alpha", 1f, 0.1f)
|
||||
tOA = ObjectAnimator.ofPropertyValuesHolder(bottomView, tWidthPro, tHeightPro, txPro, tyPro, alphaPro)
|
||||
|
||||
// // 如果只对内容做动画而不改变LayoutParams
|
||||
// bxPro = PropertyValuesHolder.ofFloat("translationX", bottomView.translationX, 0f)
|
||||
// byPro = PropertyValuesHolder.ofFloat("translationY", bottomView.translationY, 0f)
|
||||
// bWidthPro = PropertyValuesHolder.ofFloat("scaleX", bScaleX, 1f)
|
||||
// bHeightPro = PropertyValuesHolder.ofFloat("scaleY", bScaleY, 1f)
|
||||
// bOA = ObjectAnimator.ofPropertyValuesHolder(bottomView, bxPro, byPro, bWidthPro, bHeightPro)
|
||||
//
|
||||
// txPro = PropertyValuesHolder.ofFloat("translationX", topView.translationX, 0f)
|
||||
// tyPro = PropertyValuesHolder.ofFloat("translationY", topView.translationY, 0f)
|
||||
// tWidthPro = PropertyValuesHolder.ofFloat("scaleX", tScaleX, 1f)
|
||||
// tHeightPro = PropertyValuesHolder.ofFloat("scaleY", tScaleY, 1f)
|
||||
// tOA = ObjectAnimator.ofPropertyValuesHolder(topView, txPro, tyPro, tWidthPro, tHeightPro)
|
||||
}
|
||||
|
||||
// 将多个动画组合在一起
|
||||
val animatorSet = AnimatorSet()
|
||||
animatorSet.playTogether(
|
||||
bottomXAnimator,
|
||||
bottomYAnimator,
|
||||
bottomWidthAnimator,
|
||||
bottomHeightAnimator,
|
||||
topXAnimator,
|
||||
topYAnimator,
|
||||
topWidthAnimator,
|
||||
topHeightAnimator
|
||||
animatorSet = AnimatorSet()
|
||||
animatorSet?.playTogether(
|
||||
bOA, tOA
|
||||
)
|
||||
animatorSet.addListener(object : Animator.AnimatorListener {
|
||||
override fun onAnimationStart(animation: Animator) {
|
||||
isPlayingAnim = true
|
||||
}
|
||||
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
isPlayingAnim = false
|
||||
}
|
||||
|
||||
override fun onAnimationCancel(animation: Animator) {
|
||||
isPlayingAnim = false
|
||||
}
|
||||
|
||||
override fun onAnimationRepeat(animation: Animator) {
|
||||
|
||||
}
|
||||
})
|
||||
animatorSet.duration = ANIM_DURATION
|
||||
animatorSet.interpolator = AccelerateDecelerateInterpolator()
|
||||
// 启动动画
|
||||
animatorSet.start()
|
||||
animatorSet?.duration = ANIM_DURATION
|
||||
animatorSet?.addListener(animatorListener)
|
||||
animatorSet?.start()
|
||||
}
|
||||
|
||||
fun getChangeFlag() = isChange
|
||||
private val animatorListener = object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationStart(animation: Animator) {
|
||||
super.onAnimationStart(animation)
|
||||
isPlayingAnim = true
|
||||
}
|
||||
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
super.onAnimationEnd(animation)
|
||||
// updateLayoutParams()
|
||||
swapLayoutParamsWithoutAnim()
|
||||
invalidate()
|
||||
isPlayingAnim = false
|
||||
}
|
||||
|
||||
override fun onAnimationCancel(animation: Animator) {
|
||||
super.onAnimationCancel(animation)
|
||||
// updateLayoutParams()
|
||||
swapLayoutParamsWithoutAnim()
|
||||
invalidate()
|
||||
isPlayingAnim = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun isChildrenDrawingOrderEnabled() = super.isChildrenDrawingOrderEnabled()
|
||||
|
||||
override fun getChildDrawingOrder(childCount: Int, i: Int): Int {
|
||||
return if (isChange) {
|
||||
return if (isSwapped) {
|
||||
when (i) {
|
||||
0 -> {
|
||||
childCount - 1
|
||||
@@ -223,60 +220,112 @@ class ExchangeChildLayout @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
// 用于包装 View 的宽度,以便可以使用 ObjectAnimator 来改变宽度
|
||||
class WrapperViewWidth(
|
||||
private val view: View,
|
||||
) {
|
||||
var width: Int
|
||||
get() = view.layoutParams.width
|
||||
set(width) {
|
||||
val layoutParams = view.layoutParams as LayoutParams
|
||||
layoutParams.width = width
|
||||
view.layoutParams = layoutParams
|
||||
}
|
||||
private fun updateLayoutParams() {
|
||||
// if (childCount > 2) return
|
||||
// children.forEachIndexed { index, view ->
|
||||
// if (index == 0) {
|
||||
// changeRule(view, true)
|
||||
// } else {
|
||||
// changeRule(view, false)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
class WrapperViewHeight(
|
||||
private val view: View,
|
||||
) {
|
||||
|
||||
var height: Int
|
||||
get() = view.layoutParams.height
|
||||
set(height) {
|
||||
val layoutParams = view.layoutParams as LayoutParams
|
||||
layoutParams.height = height
|
||||
view.layoutParams = layoutParams
|
||||
}
|
||||
}
|
||||
|
||||
private fun exchangeRule(
|
||||
layoutParams: LayoutParams, isBottom: Boolean,
|
||||
isChange: Boolean
|
||||
private fun changeRule(
|
||||
view: View, isBottom: Boolean,
|
||||
) {
|
||||
val layoutParams = view.layoutParams as LayoutParams
|
||||
if (isBottom) {
|
||||
if (isChange) {
|
||||
if (isSwapped) {
|
||||
layoutParams.startToStart = LayoutParams.UNSET
|
||||
layoutParams.topToTop = LayoutParams.UNSET
|
||||
layoutParams.endToEnd = LayoutParams.PARENT_ID
|
||||
layoutParams.bottomToBottom = LayoutParams.PARENT_ID
|
||||
layoutParams.width = minWidth
|
||||
layoutParams.height = minHeight
|
||||
} else {
|
||||
layoutParams.startToStart = LayoutParams.PARENT_ID
|
||||
layoutParams.topToTop = LayoutParams.PARENT_ID
|
||||
layoutParams.endToEnd = LayoutParams.UNSET
|
||||
layoutParams.bottomToBottom = LayoutParams.UNSET
|
||||
layoutParams.width = maxWidth
|
||||
layoutParams.height = maxHeight
|
||||
}
|
||||
} else {
|
||||
if (isChange) {
|
||||
if (isSwapped) {
|
||||
layoutParams.startToStart = LayoutParams.PARENT_ID
|
||||
layoutParams.topToTop = LayoutParams.PARENT_ID
|
||||
layoutParams.endToEnd = LayoutParams.UNSET
|
||||
layoutParams.bottomToBottom = LayoutParams.UNSET
|
||||
layoutParams.width = maxWidth
|
||||
layoutParams.height = maxHeight
|
||||
} else {
|
||||
layoutParams.startToStart = LayoutParams.UNSET
|
||||
layoutParams.topToTop = LayoutParams.UNSET
|
||||
layoutParams.endToEnd = LayoutParams.PARENT_ID
|
||||
layoutParams.bottomToBottom = LayoutParams.PARENT_ID
|
||||
layoutParams.width = minWidth
|
||||
layoutParams.height = minHeight
|
||||
}
|
||||
}
|
||||
view.layoutParams = layoutParams
|
||||
}
|
||||
|
||||
private fun swapLayoutParamsWithoutAnim() {
|
||||
if (constraintUtil == null) {
|
||||
constraintUtil = ConstraintUtil(exchangeLayout)
|
||||
}
|
||||
if (isSwapped) {
|
||||
val begin = constraintUtil!!.begin()
|
||||
// 清除约束关系
|
||||
begin.clear(R.id.mapBizView, R.id.overMapView)
|
||||
// 设置新的约束关系
|
||||
begin.Left_toLeftOf(R.id.overMapView, ConstraintSet.PARENT_ID)
|
||||
begin.Top_toTopOf(R.id.overMapView, ConstraintSet.PARENT_ID)
|
||||
begin.Right_toRightOf(R.id.overMapView, ConstraintSet.PARENT_ID)
|
||||
begin.Bottom_toBottomOf(R.id.overMapView, ConstraintSet.PARENT_ID)
|
||||
|
||||
begin.Left_toLeftOf(R.id.mapBizView, ConstraintSet.UNSET)
|
||||
begin.Top_toTopOf(R.id.mapBizView, ConstraintSet.UNSET)
|
||||
begin.Right_toRightOf(R.id.mapBizView, ConstraintSet.PARENT_ID)
|
||||
begin.Bottom_toBottomOf(R.id.mapBizView, ConstraintSet.PARENT_ID)
|
||||
begin.setWidth(R.id.mapBizView, AutoSizeUtils.dp2px(context, 270f))
|
||||
begin.setHeight(R.id.mapBizView, AutoSizeUtils.dp2px(context, 270f))
|
||||
begin.setMargin(
|
||||
R.id.mapBizView,
|
||||
0,
|
||||
0,
|
||||
AutoSizeUtils.dp2px(context, 60f),
|
||||
AutoSizeUtils.dp2px(context, 60f)
|
||||
)
|
||||
// 应用新的属性集
|
||||
begin.commit()
|
||||
} else {
|
||||
// constraintUtil?.reSet()
|
||||
val begin = constraintUtil!!.begin()
|
||||
// 清除约束关系
|
||||
begin.clear(R.id.mapBizView, R.id.overMapView)
|
||||
// 设置新的约束关系
|
||||
begin.Left_toLeftOf(R.id.mapBizView, ConstraintSet.PARENT_ID)
|
||||
begin.Top_toTopOf(R.id.mapBizView, ConstraintSet.PARENT_ID)
|
||||
begin.Right_toRightOf(R.id.mapBizView, ConstraintSet.PARENT_ID)
|
||||
begin.Bottom_toBottomOf(R.id.mapBizView, ConstraintSet.PARENT_ID)
|
||||
|
||||
begin.Left_toLeftOf(R.id.overMapView, ConstraintSet.UNSET)
|
||||
begin.Top_toTopOf(R.id.overMapView, ConstraintSet.UNSET)
|
||||
begin.Right_toRightOf(R.id.overMapView, ConstraintSet.PARENT_ID)
|
||||
begin.Bottom_toBottomOf(R.id.overMapView, ConstraintSet.PARENT_ID)
|
||||
begin.setWidth(R.id.overMapView, AutoSizeUtils.dp2px(context, 270f))
|
||||
begin.setHeight(R.id.overMapView, AutoSizeUtils.dp2px(context, 270f))
|
||||
begin.setMargin(
|
||||
R.id.overMapView,
|
||||
0,
|
||||
0,
|
||||
AutoSizeUtils.dp2px(context, 60f),
|
||||
AutoSizeUtils.dp2px(context, 60f)
|
||||
)
|
||||
// 应用新的属性集
|
||||
begin.commit()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
package com.mogo.eagle.core.function.hmi.map
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.transition.Transition
|
||||
import android.transition.Transition.TransitionListener
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.animation.DecelerateInterpolator
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.constraintlayout.widget.ConstraintSet
|
||||
import com.mogo.eagle.core.data.map.MogoLatLng
|
||||
import com.mogo.eagle.core.function.hmi.R
|
||||
import com.mogo.eagle.core.function.hmi.util.ConstraintUtil
|
||||
import com.mogo.eagle.core.function.view.TravelRealityView
|
||||
import com.mogo.map.listener.IMogoMapListener
|
||||
import com.mogo.map.listener.MogoMapListenerHandler
|
||||
import kotlinx.android.synthetic.main.view_map_container.view.exchangeLayout
|
||||
import kotlinx.android.synthetic.main.view_map_container.view.mapBizView
|
||||
import kotlinx.android.synthetic.main.view_map_container.view.overMapView
|
||||
import me.jessyan.autosize.utils.AutoSizeUtils
|
||||
|
||||
class MapContainerLayout @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : ConstraintLayout(context, attrs, defStyleAttr), IMogoMapListener {
|
||||
|
||||
private var isSwapped = false
|
||||
private var isPlayingAnim = false
|
||||
private var constraintUtil: ConstraintUtil? = null
|
||||
|
||||
init {
|
||||
LayoutInflater.from(context).inflate(R.layout.view_map_container, this, true)
|
||||
initView()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "MapContainerLayout"
|
||||
}
|
||||
|
||||
fun onCreate(savedInstanceState: Bundle?) {
|
||||
mapBizView.onCreate(savedInstanceState)
|
||||
overMapView.onCreateView(savedInstanceState)
|
||||
}
|
||||
|
||||
fun onResume() {
|
||||
mapBizView.onResume()
|
||||
overMapView.onResume()
|
||||
}
|
||||
|
||||
fun onPause() {
|
||||
mapBizView.onPause()
|
||||
overMapView.onPause()
|
||||
}
|
||||
|
||||
fun onLowMemory() {
|
||||
mapBizView.onLowMemory()
|
||||
}
|
||||
|
||||
fun onSaveInstanceState(outState: Bundle) {
|
||||
mapBizView.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
fun onDestroy() {
|
||||
mapBizView.onDestroy()
|
||||
overMapView.onDestroy()
|
||||
}
|
||||
|
||||
override fun onAttachedToWindow() {
|
||||
super.onAttachedToWindow()
|
||||
MogoMapListenerHandler.mogoMapListenerHandler.registerHostMapListener("${TAG}${this.hashCode()}",this)
|
||||
}
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow()
|
||||
MogoMapListenerHandler.mogoMapListenerHandler.unregisterHostMapListener("${TAG}${this.hashCode()}")
|
||||
}
|
||||
|
||||
private fun initView() {
|
||||
overMapView.setOnGestureListener(object : TravelRealityView.OnGestureListener {
|
||||
override fun onSingleTap(lng: Float, lat: Float) {
|
||||
if (!exchangeLayout.getSwapFlag()) {
|
||||
exchangeLayout.swapViews()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onMapClick(latLng: MogoLatLng?) {
|
||||
super.onMapClick(latLng)
|
||||
if (exchangeLayout.getSwapFlag()) {
|
||||
exchangeLayout.swapViews()
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated(message = "会多次requestLayout导致高精地图卡顿")
|
||||
private fun swapViewsWithAnim() {
|
||||
if (isPlayingAnim) return
|
||||
if (constraintUtil == null) {
|
||||
constraintUtil = ConstraintUtil(exchangeLayout, 300, DecelerateInterpolator())
|
||||
constraintUtil?.addTransitionListener(transitionListener)
|
||||
}
|
||||
if (!isSwapped) {
|
||||
// 获取属性集并设置动画
|
||||
val begin = constraintUtil!!.beginWithAnim()
|
||||
// 清除约束关系
|
||||
begin.clear(R.id.mapBizView, R.id.overMapView)
|
||||
// 设置新的约束关系
|
||||
begin.Left_toLeftOf(R.id.overMapView, ConstraintSet.PARENT_ID)
|
||||
begin.Top_toTopOf(R.id.overMapView, ConstraintSet.PARENT_ID)
|
||||
begin.Right_toRightOf(R.id.overMapView, ConstraintSet.PARENT_ID)
|
||||
begin.Bottom_toBottomOf(R.id.overMapView, ConstraintSet.PARENT_ID)
|
||||
|
||||
begin.Left_toLeftOf(R.id.mapBizView, ConstraintSet.UNSET)
|
||||
begin.Top_toTopOf(R.id.mapBizView, ConstraintSet.UNSET)
|
||||
begin.Right_toRightOf(R.id.mapBizView, ConstraintSet.PARENT_ID)
|
||||
begin.Bottom_toBottomOf(R.id.mapBizView, ConstraintSet.PARENT_ID)
|
||||
begin.setWidth(R.id.mapBizView, AutoSizeUtils.dp2px(context, 270f))
|
||||
begin.setHeight(R.id.mapBizView, AutoSizeUtils.dp2px(context, 270f))
|
||||
begin.setMargin(
|
||||
R.id.mapBizView,
|
||||
0,
|
||||
0,
|
||||
AutoSizeUtils.dp2px(context, 60f),
|
||||
AutoSizeUtils.dp2px(context, 60f)
|
||||
)
|
||||
// 应用新的属性集
|
||||
begin.commit()
|
||||
exchangeLayout.setSwapped(true)
|
||||
isSwapped = true
|
||||
} else {
|
||||
constraintUtil?.reSetWidthAnim()
|
||||
exchangeLayout.setSwapped(false)
|
||||
isSwapped = false
|
||||
}
|
||||
}
|
||||
|
||||
private val transitionListener = object : TransitionListener {
|
||||
override fun onTransitionStart(transition: Transition?) {
|
||||
isPlayingAnim = true
|
||||
}
|
||||
|
||||
override fun onTransitionEnd(transition: Transition?) {
|
||||
isPlayingAnim = false
|
||||
}
|
||||
|
||||
override fun onTransitionCancel(transition: Transition?) {
|
||||
isPlayingAnim = false
|
||||
}
|
||||
|
||||
override fun onTransitionPause(transition: Transition?) {
|
||||
isPlayingAnim = false
|
||||
}
|
||||
|
||||
override fun onTransitionResume(transition: Transition?) {
|
||||
isPlayingAnim = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,350 @@
|
||||
package com.mogo.eagle.core.function.hmi.util
|
||||
|
||||
import android.animation.TimeInterpolator
|
||||
import android.transition.AutoTransition
|
||||
import android.transition.Transition
|
||||
import android.transition.TransitionManager
|
||||
import android.view.animation.AccelerateDecelerateInterpolator
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.constraintlayout.widget.ConstraintSet
|
||||
|
||||
/**
|
||||
* ConstraintSet工具类
|
||||
*/
|
||||
class ConstraintUtil private constructor() {
|
||||
private var constraintLayout: ConstraintLayout? = null
|
||||
private var begin: ConstraintBegin? = null
|
||||
private val applyConstraintSet by lazy {
|
||||
ConstraintSet()
|
||||
}
|
||||
private val resetConstraintSet by lazy {
|
||||
ConstraintSet()
|
||||
}
|
||||
|
||||
private val sDefaultTransition: Transition = AutoTransition()
|
||||
|
||||
constructor(constraintLayout: ConstraintLayout?) : this() {
|
||||
this.constraintLayout = constraintLayout
|
||||
resetConstraintSet.clone(constraintLayout)
|
||||
}
|
||||
|
||||
constructor(constraintLayout: ConstraintLayout?, duration: Long, interpolator: TimeInterpolator) : this() {
|
||||
this.constraintLayout = constraintLayout
|
||||
resetConstraintSet.clone(constraintLayout)
|
||||
sDefaultTransition.duration = duration
|
||||
sDefaultTransition.interpolator = interpolator
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始修改
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
fun begin(): ConstraintBegin {
|
||||
synchronized(ConstraintBegin::class.java) {
|
||||
if (begin == null) {
|
||||
begin = ConstraintBegin()
|
||||
}
|
||||
}
|
||||
applyConstraintSet.clone(constraintLayout)
|
||||
return begin!!
|
||||
}
|
||||
|
||||
/**
|
||||
* 带动画的修改
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
fun beginWithAnim(): ConstraintBegin {
|
||||
TransitionManager.beginDelayedTransition(constraintLayout, sDefaultTransition)
|
||||
return begin()
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置
|
||||
*/
|
||||
fun reSet() {
|
||||
resetConstraintSet.applyTo(constraintLayout)
|
||||
}
|
||||
|
||||
/**
|
||||
* 带动画的重置
|
||||
*/
|
||||
fun reSetWidthAnim() {
|
||||
TransitionManager.beginDelayedTransition(constraintLayout, sDefaultTransition)
|
||||
resetConstraintSet.applyTo(constraintLayout)
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加动画监听
|
||||
*
|
||||
* @param listener
|
||||
*/
|
||||
fun addTransitionListener(listener: Transition.TransitionListener) {
|
||||
sDefaultTransition.addListener(listener)
|
||||
}
|
||||
|
||||
inner class ConstraintBegin {
|
||||
/**
|
||||
* 清除关系<br></br>
|
||||
* 注意:这里不仅仅会清除关系,还会清除对应控件的宽高为 w:0,h:0
|
||||
*
|
||||
* @param viewIds
|
||||
* @return
|
||||
*/
|
||||
fun clear(@IdRes vararg viewIds: Int): ConstraintBegin {
|
||||
for (viewId in viewIds) {
|
||||
applyConstraintSet.clear(viewId)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除某个控件的,某个关系
|
||||
*
|
||||
* @param viewId
|
||||
* @param anchor
|
||||
* @return
|
||||
*/
|
||||
fun clear(viewId: Int, anchor: Long): ConstraintBegin {
|
||||
applyConstraintSet.clear(viewId, anchor.toInt())
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 为某个控件设置 margin
|
||||
*
|
||||
* @param viewId 某个控件ID
|
||||
* @param left marginLeft
|
||||
* @param top marginTop
|
||||
* @param right marginRight
|
||||
* @param bottom marginBottom
|
||||
* @return
|
||||
*/
|
||||
fun setMargin(
|
||||
@IdRes viewId: Int,
|
||||
left: Int,
|
||||
top: Int,
|
||||
right: Int,
|
||||
bottom: Int
|
||||
): ConstraintBegin {
|
||||
setMarginLeft(viewId, left)
|
||||
setMarginTop(viewId, top)
|
||||
setMarginRight(viewId, right)
|
||||
setMarginBottom(viewId, bottom)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 为某个控件设置 marginLeft
|
||||
*
|
||||
* @param viewId 某个控件ID
|
||||
* @param left marginLeft
|
||||
* @return
|
||||
*/
|
||||
fun setMarginLeft(@IdRes viewId: Int, left: Int): ConstraintBegin {
|
||||
applyConstraintSet.setMargin(viewId, ConstraintSet.LEFT, left)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 为某个控件设置 marginRight
|
||||
*
|
||||
* @param viewId 某个控件ID
|
||||
* @param right marginRight
|
||||
* @return
|
||||
*/
|
||||
fun setMarginRight(@IdRes viewId: Int, right: Int): ConstraintBegin {
|
||||
applyConstraintSet.setMargin(viewId, ConstraintSet.RIGHT, right)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 为某个控件设置 marginTop
|
||||
*
|
||||
* @param viewId 某个控件ID
|
||||
* @param top marginTop
|
||||
* @return
|
||||
*/
|
||||
fun setMarginTop(@IdRes viewId: Int, top: Int): ConstraintBegin {
|
||||
applyConstraintSet.setMargin(viewId, ConstraintSet.TOP, top)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 为某个控件设置marginBottom
|
||||
*
|
||||
* @param viewId 某个控件ID
|
||||
* @param bottom marginBottom
|
||||
* @return
|
||||
*/
|
||||
fun setMarginBottom(@IdRes viewId: Int, bottom: Int): ConstraintBegin {
|
||||
applyConstraintSet.setMargin(viewId, ConstraintSet.BOTTOM, bottom)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 为某个控件设置关联关系 left_to_left_of
|
||||
*
|
||||
* @param startId
|
||||
* @param endId
|
||||
* @return
|
||||
*/
|
||||
fun Left_toLeftOf(@IdRes startId: Int, @IdRes endId: Int): ConstraintBegin {
|
||||
applyConstraintSet.connect(startId, ConstraintSet.LEFT, endId, ConstraintSet.LEFT)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 为某个控件设置关联关系 start_to_start_of
|
||||
*
|
||||
* @param startId
|
||||
* @param endId
|
||||
* @return
|
||||
*/
|
||||
fun Start_toStartOf(@IdRes startId: Int, @IdRes endId: Int): ConstraintBegin {
|
||||
applyConstraintSet.connect(startId, ConstraintSet.START, endId, ConstraintSet.START)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 为某个控件设置关联关系 left_to_right_of
|
||||
*
|
||||
* @param startId
|
||||
* @param endId
|
||||
* @return
|
||||
*/
|
||||
fun Left_toRightOf(@IdRes startId: Int, @IdRes endId: Int): ConstraintBegin {
|
||||
applyConstraintSet.connect(startId, ConstraintSet.LEFT, endId, ConstraintSet.RIGHT)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 为某个控件设置关联关系 top_to_top_of
|
||||
*
|
||||
* @param startId
|
||||
* @param endId
|
||||
* @return
|
||||
*/
|
||||
fun Top_toTopOf(@IdRes startId: Int, @IdRes endId: Int): ConstraintBegin {
|
||||
applyConstraintSet.connect(startId, ConstraintSet.TOP, endId, ConstraintSet.TOP)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 为某个控件设置关联关系 top_to_bottom_of
|
||||
*
|
||||
* @param startId
|
||||
* @param endId
|
||||
* @return
|
||||
*/
|
||||
fun Top_toBottomOf(@IdRes startId: Int, @IdRes endId: Int): ConstraintBegin {
|
||||
applyConstraintSet.connect(startId, ConstraintSet.TOP, endId, ConstraintSet.BOTTOM)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 为某个控件设置关联关系 right_to_left_of
|
||||
*
|
||||
* @param startId
|
||||
* @param endId
|
||||
* @return
|
||||
*/
|
||||
fun Right_toLeftOf(@IdRes startId: Int, @IdRes endId: Int): ConstraintBegin {
|
||||
applyConstraintSet.connect(startId, ConstraintSet.RIGHT, endId, ConstraintSet.LEFT)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 为某个控件设置关联关系 right_to_right_of
|
||||
*
|
||||
* @param startId
|
||||
* @param endId
|
||||
* @return
|
||||
*/
|
||||
fun Right_toRightOf(@IdRes startId: Int, @IdRes endId: Int): ConstraintBegin {
|
||||
applyConstraintSet.connect(startId, ConstraintSet.RIGHT, endId, ConstraintSet.RIGHT)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 为某个控件设置关联关系 bottom_to_bottom_of
|
||||
*
|
||||
* @param startId
|
||||
* @param endId
|
||||
* @return
|
||||
*/
|
||||
fun Bottom_toBottomOf(@IdRes startId: Int, @IdRes endId: Int): ConstraintBegin {
|
||||
applyConstraintSet.connect(startId, ConstraintSet.BOTTOM, endId, ConstraintSet.BOTTOM)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 为某个控件设置关联关系 bottom_to_top_of
|
||||
*
|
||||
* @param startId
|
||||
* @param endId
|
||||
* @return
|
||||
*/
|
||||
fun Bottom_toTopOf(@IdRes startId: Int, @IdRes endId: Int): ConstraintBegin {
|
||||
applyConstraintSet.connect(startId, ConstraintSet.BOTTOM, endId, ConstraintSet.TOP)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 为某个控件设置宽度
|
||||
*
|
||||
* @param viewId
|
||||
* @param width
|
||||
* @return
|
||||
*/
|
||||
fun setWidth(@IdRes viewId: Int, width: Int): ConstraintBegin {
|
||||
applyConstraintSet.constrainWidth(viewId, width)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 某个控件设置高度
|
||||
*
|
||||
* @param viewId
|
||||
* @param height
|
||||
* @return
|
||||
*/
|
||||
fun setHeight(@IdRes viewId: Int, height: Int): ConstraintBegin {
|
||||
applyConstraintSet.constrainHeight(viewId, height)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 为某个控件设置宽度百分比
|
||||
*
|
||||
* @param viewId
|
||||
* @param percent
|
||||
* @return
|
||||
*/
|
||||
fun setWidthPercent(@IdRes viewId: Int, percent: Float): ConstraintBegin {
|
||||
applyConstraintSet.constrainPercentWidth(viewId, percent)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 某个控件设置高度百分比
|
||||
*
|
||||
* @param viewId
|
||||
* @param percent
|
||||
* @return
|
||||
*/
|
||||
fun setHeightPercent(@IdRes viewId: Int, percent: Float): ConstraintBegin {
|
||||
applyConstraintSet.constrainPercentHeight(viewId, percent)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交应用生效
|
||||
*/
|
||||
fun commit() {
|
||||
applyConstraintSet.applyTo(constraintLayout)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="1560dp"
|
||||
android:layout_height="1534dp"
|
||||
tools:ignore="MissingDefaultResource">
|
||||
|
||||
<com.mogo.eagle.core.function.hmi.map.ExchangeChildLayout
|
||||
android:id="@+id/exchangeLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
>
|
||||
<!--高精地图-->
|
||||
<com.mogo.eagle.core.function.view.MapBizView
|
||||
android:id="@+id/mapBizView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:isWeatherEnable="false"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
/>
|
||||
|
||||
<!--高德地图-->
|
||||
<com.mogo.eagle.core.function.view.TravelRealityView
|
||||
android:id="@+id/overMapView"
|
||||
android:layout_width="270dp"
|
||||
android:layout_height="270dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_marginEnd="60dp"
|
||||
android:layout_marginBottom="60dp"
|
||||
app:roadRangeDrawable="@drawable/taxi_overmap_road_range"
|
||||
app:roadTrajectoryDrawable="@drawable/taxi_orvermap_road_trajectory"
|
||||
app:globalPathColor="#39BA90"
|
||||
app:carDrawable="@drawable/taxt_u_p_map_car"
|
||||
app:compassDrawable="@drawable/taxt_u_p_map_car_light"
|
||||
app:endPointDrawable="@drawable/taxi_overmap_endpoint"
|
||||
app:mapStyleExtraPath="over_view_style_extra.data"
|
||||
app:mapStylePath="over_view_style.data"
|
||||
app:resetDrawable="@null"
|
||||
app:leftPadding="70"
|
||||
app:topPadding="70"
|
||||
app:rightPadding="70"
|
||||
app:bottomPadding="160"
|
||||
/>
|
||||
</com.mogo.eagle.core.function.hmi.map.ExchangeChildLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -19,6 +19,7 @@ import com.amap.api.maps.CameraUpdate
|
||||
import com.amap.api.maps.CameraUpdateFactory
|
||||
import com.amap.api.maps.CoordinateConverter
|
||||
import com.amap.api.maps.TextureMapView
|
||||
import com.amap.api.maps.model.AMapGestureListener
|
||||
import com.amap.api.maps.model.BitmapDescriptor
|
||||
import com.amap.api.maps.model.BitmapDescriptorFactory
|
||||
import com.amap.api.maps.model.CustomMapStyleOptions
|
||||
@@ -205,6 +206,7 @@ class TravelRealityView @JvmOverloads constructor(
|
||||
private var testTime = 0L
|
||||
|
||||
private var listener: OnDrawListener? = null
|
||||
private var gestureListener: OnGestureListener? = null
|
||||
|
||||
init {
|
||||
try {
|
||||
@@ -272,6 +274,10 @@ class TravelRealityView @JvmOverloads constructor(
|
||||
this.listener = listener
|
||||
}
|
||||
|
||||
fun setOnGestureListener(listener: OnGestureListener) {
|
||||
this.gestureListener = listener
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有Marker和Polyline
|
||||
*/
|
||||
@@ -366,6 +372,32 @@ class TravelRealityView @JvmOverloads constructor(
|
||||
mAMap?.uiSettings?.isZoomControlsEnabled = false
|
||||
// mAMap?.animateCamera(CameraUpdateFactory.changeTilt(30f))
|
||||
}
|
||||
mAMap?.setAMapGestureListener(object : AMapGestureListener {
|
||||
override fun onDoubleTap(p0: Float, p1: Float) {
|
||||
}
|
||||
|
||||
override fun onSingleTap(p0: Float, p1: Float) {
|
||||
gestureListener?.onSingleTap(p0, p1)
|
||||
}
|
||||
|
||||
override fun onFling(p0: Float, p1: Float) {
|
||||
}
|
||||
|
||||
override fun onScroll(p0: Float, p1: Float) {
|
||||
}
|
||||
|
||||
override fun onLongPress(p0: Float, p1: Float) {
|
||||
}
|
||||
|
||||
override fun onDown(p0: Float, p1: Float) {
|
||||
}
|
||||
|
||||
override fun onUp(p0: Float, p1: Float) {
|
||||
}
|
||||
|
||||
override fun onMapStable() {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onVisibilityChanged(changedView: View, visibility: Int) {
|
||||
@@ -1285,6 +1317,10 @@ class TravelRealityView @JvmOverloads constructor(
|
||||
fun onDraw(eventList: List<EventDrawBean>, isEvent: Boolean)
|
||||
}
|
||||
|
||||
interface OnGestureListener {
|
||||
fun onSingleTap(lng: Float, lat: Float)
|
||||
}
|
||||
|
||||
private inner class NonFrequentHandler(looper: Looper) : Handler(looper) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun handleMessage(msg: Message) {
|
||||
|
||||
Reference in New Issue
Block a user