[6.7.0][Feat]高精地图和高德地图切换动效

This commit is contained in:
chenfufeng
2024-09-23 14:40:12 +08:00
parent bf28316b3f
commit 3d9640c8a6
8 changed files with 808 additions and 165 deletions

View File

@@ -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()
}
}
}

View File

@@ -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
}
}
}

View File

@@ -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)
}
}
}

View File

@@ -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>

View File

@@ -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) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 B