diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/map/ExchangeChildLayout.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/map/ExchangeChildLayout.kt index 6daa544d86..9f461f9006 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/map/ExchangeChildLayout.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/map/ExchangeChildLayout.kt @@ -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() + } } } \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/map/MapContainerLayout.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/map/MapContainerLayout.kt new file mode 100644 index 0000000000..9b47dfafff --- /dev/null +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/map/MapContainerLayout.kt @@ -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 + } + } +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/util/ConstraintUtil.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/util/ConstraintUtil.kt new file mode 100644 index 0000000000..bd5639eaee --- /dev/null +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/util/ConstraintUtil.kt @@ -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 { + /** + * 清除关系

+ * 注意:这里不仅仅会清除关系,还会清除对应控件的宽高为 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) + } + } +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_map_container.xml b/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_map_container.xml new file mode 100644 index 0000000000..5617a6b5d7 --- /dev/null +++ b/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_map_container.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/view/TravelRealityView.kt b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/view/TravelRealityView.kt index 2c9f3a37a2..0974cec97e 100644 --- a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/view/TravelRealityView.kt +++ b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/view/TravelRealityView.kt @@ -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, 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) { diff --git a/core/mogo-core-res/src/main/res/drawable-nodpi/taxi_orvermap_road_trajectory.png b/core/mogo-core-res/src/main/res/drawable-nodpi/taxi_orvermap_road_trajectory.png new file mode 100644 index 0000000000..97d6b8470a Binary files /dev/null and b/core/mogo-core-res/src/main/res/drawable-nodpi/taxi_orvermap_road_trajectory.png differ diff --git a/core/mogo-core-res/src/main/res/drawable-nodpi/taxi_overmap_endpoint.png b/core/mogo-core-res/src/main/res/drawable-nodpi/taxi_overmap_endpoint.png new file mode 100644 index 0000000000..61527f37c1 Binary files /dev/null and b/core/mogo-core-res/src/main/res/drawable-nodpi/taxi_overmap_endpoint.png differ diff --git a/core/mogo-core-res/src/main/res/drawable-nodpi/taxi_overmap_road_range.png b/core/mogo-core-res/src/main/res/drawable-nodpi/taxi_overmap_road_range.png new file mode 100644 index 0000000000..a6b03d50c6 Binary files /dev/null and b/core/mogo-core-res/src/main/res/drawable-nodpi/taxi_overmap_road_range.png differ