From 994d205a7efd0f0ee99f2c7d3c0f45cf638c2043 Mon Sep 17 00:00:00 2001 From: renhaoting <370797079@qq.com> Date: Tue, 16 Dec 2025 15:26:22 +0800 Subject: [PATCH] =?UTF-8?q?guide=E5=88=9D=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 1 + .../vididin/main/BeginnerGiftDialog.kt | 11 +- .../vididin/main/fragments/TasksFragment.kt | 47 ++++ app/src/main/res/layout/guide_step_cash.xml | 33 +++ app/src/main/res/layout/guide_step_gold.xml | 35 +++ ...inapp_feature_message_fragment_message.xml | 211 +++++++------- .../main/res/mipmap-xxhdpi/guide_bg_left.webp | Bin 0 -> 4030 bytes .../res/mipmap-xxhdpi/guide_bg_right.webp | Bin 0 -> 4022 bytes .../res/mipmap-xxhdpi/guide_finger_b.webp | Bin 0 -> 32252 bytes .../res/mipmap-xxhdpi/guide_finger_s.webp | Bin 0 -> 18636 bytes app/src/main/res/values/strings.xml | 2 + .../architecture/highlightpro/HighlightPro.kt | 138 +++++++++ .../highlightpro/HighlightProImpl.kt | 226 +++++++++++++++ .../HighlightViewInteractiveAction.kt | 16 ++ .../highlightpro/parameter/Constraints.kt | 22 ++ .../parameter/HighlightParameter.kt | 153 ++++++++++ .../highlightpro/parameter/MarginOffset.kt | 9 + .../highlightpro/shape/CircleShape.kt | 17 ++ .../highlightpro/shape/HighlightShape.kt | 50 ++++ .../highlightpro/shape/OvalShape.kt | 16 ++ .../highlightpro/shape/RectShape.kt | 16 ++ .../highlightpro/util/ViewUtils.kt | 88 ++++++ .../highlightpro/view/MaskContainer.kt | 262 ++++++++++++++++++ 23 files changed, 1243 insertions(+), 110 deletions(-) create mode 100644 app/src/main/res/layout/guide_step_cash.xml create mode 100644 app/src/main/res/layout/guide_step_gold.xml create mode 100644 app/src/main/res/mipmap-xxhdpi/guide_bg_left.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/guide_bg_right.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/guide_finger_b.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/guide_finger_s.webp create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/highlightpro/HighlightPro.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/highlightpro/HighlightProImpl.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/highlightpro/HighlightViewInteractiveAction.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/highlightpro/parameter/Constraints.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/highlightpro/parameter/HighlightParameter.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/highlightpro/parameter/MarginOffset.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/highlightpro/shape/CircleShape.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/highlightpro/shape/HighlightShape.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/highlightpro/shape/OvalShape.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/highlightpro/shape/RectShape.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/highlightpro/util/ViewUtils.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/highlightpro/view/MaskContainer.kt diff --git a/app/build.gradle b/app/build.gradle index ca8183c..97910e5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -88,6 +88,7 @@ dependencies { implementation(libs.okhttp.logging) implementation(libs.retrofit) implementation(libs.retrofit.kotlin.serialization) + //implementation 'com.github.hyy920109:GuidePro:1.0.3' } \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/main/BeginnerGiftDialog.kt b/app/src/main/java/com/gamedog/vididin/main/BeginnerGiftDialog.kt index 4ffa0a6..57232d9 100644 --- a/app/src/main/java/com/gamedog/vididin/main/BeginnerGiftDialog.kt +++ b/app/src/main/java/com/gamedog/vididin/main/BeginnerGiftDialog.kt @@ -1,12 +1,9 @@ package com.gamedog.vididin.main import android.app.Activity -import com.ama.core.architecture.util.eventbus.NotifyMan import com.ama.core.architecture.util.setOnClickBatch import com.ama.core.architecture.widget.BindingDialog -import com.gamedog.vididin.VididinEvents import com.vididin.real.money.game.databinding.DialogBeginnerGiftBinding -import com.gamedog.vididin.router.Router class BeginnerGiftDialog(activity: Activity) : BindingDialog(activity, DialogBeginnerGiftBinding::inflate) { @@ -26,10 +23,10 @@ class BeginnerGiftDialog(activity: Activity) : BindingDialog { - /*if (mActivity is MainActivity) { + if (mActivity is MainActivity) { (mActivity as MainActivity).switchTab(1) } - NotifyMan.instance().sendEvent(VididinEvents.EVENT_JUMP_2_FIRST_WITHDRAW, null)*/ + //NotifyMan.instance().sendEvent(VididinEvents.EVENT_JUMP_2_FIRST_WITHDRAW, null)*/ dismiss() } } @@ -37,9 +34,7 @@ class BeginnerGiftDialog(activity: Activity) : BindingDialog(), OnTab lifecycleScope.launch { mTaskConfig = TaskManager.instance().getTaskConfig() } + + binding?.llTaskGame?.postDelayed({ + showGuide() + }, 50) } private fun addDailySubTasks() { @@ -422,4 +434,39 @@ class TasksFragment : AppViewsFragment(), OnTab } + private fun showGuide() { + HighlightPro.with(this@TasksFragment) + .setHighlightParameter { + HighlightParameter.Builder() + .setHighlightView(binding!!.goldContainer) + .setTipsViewId(R.layout.guide_step_gold) + .setHighlightShape(RectShape(10.dp, 10.dp, 10.dp)) + .setHighlightHorizontalPadding(0.dp) + .setConstraints(Constraints.TopToBottomOfHighlight + Constraints.EndToEndOfHighlight) + .setMarginOffset(MarginOffset(top = -20.dp.toInt())) + .build() + } + .setHighlightParameter { + HighlightParameter.Builder() + .setHighlightView(binding!!.cashContainer) + .setTipsViewId(R.layout.guide_step_cash) + .setHighlightShape(RectShape(10.dp, 10.dp, 10.dp)) + .setHighlightHorizontalPadding(0.dp) + .setConstraints(Constraints.TopToBottomOfHighlight + Constraints.EndToEndOfHighlight) + .setMarginOffset(MarginOffset(top = -20.dp.toInt())) + .build() + } + .setBackgroundColor("#cc000000".toColorInt()) + .setOnShowCallback { index -> + + } + .setOnDismissCallback { + + } + .interceptBackPressed(true) + .show() + + + } + } \ No newline at end of file diff --git a/app/src/main/res/layout/guide_step_cash.xml b/app/src/main/res/layout/guide_step_cash.xml new file mode 100644 index 0000000..f50fe1d --- /dev/null +++ b/app/src/main/res/layout/guide_step_cash.xml @@ -0,0 +1,33 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/guide_step_gold.xml b/app/src/main/res/layout/guide_step_gold.xml new file mode 100644 index 0000000..3a8459f --- /dev/null +++ b/app/src/main/res/layout/guide_step_gold.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/layout/vididinapp_feature_message_fragment_message.xml b/app/src/main/res/layout/vididinapp_feature_message_fragment_message.xml index 86d604e..4a1d1ef 100644 --- a/app/src/main/res/layout/vididinapp_feature_message_fragment_message.xml +++ b/app/src/main/res/layout/vididinapp_feature_message_fragment_message.xml @@ -32,138 +32,147 @@ android:orientation="horizontal" android:layout_marginTop="15dp"> - - - - + android:layout_weight="1"> - + - + android:orientation="horizontal" + android:gravity="center_vertical" + android:layout_gravity="center_vertical" + android:layout_marginTop="10dp"> + + + + + + + + + - - - - - - - + android:layout_marginLeft="10dp"> - + android:layout_height="match_parent" + android:orientation="vertical" + android:background="@mipmap/task_bg_cash" + android:padding="10dp" + > + + + + + + + + + + - - - - - + - - - - \ No newline at end of file diff --git a/app/src/main/res/mipmap-xxhdpi/guide_bg_left.webp b/app/src/main/res/mipmap-xxhdpi/guide_bg_left.webp new file mode 100644 index 0000000000000000000000000000000000000000..656e2453655f528dd8645b79d1d1fbea42dc288e GIT binary patch literal 4030 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxhdpi/guide_finger_b.webp b/app/src/main/res/mipmap-xxhdpi/guide_finger_b.webp new file mode 100644 index 0000000000000000000000000000000000000000..c20031bd1384e5cfe63d8c7b052134100ca5d096 GIT binary patch literal 32252 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 de moedas % Vincular conta para saque + Clique no botão para converter todas \nas “Moedas” em “Dinheiro”. + Clique aqui para ir para o saque. \ No newline at end of file diff --git a/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/HighlightPro.kt b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/HighlightPro.kt new file mode 100644 index 0000000..7b19320 --- /dev/null +++ b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/HighlightPro.kt @@ -0,0 +1,138 @@ +package com.ama.core.architecture.highlightpro + +import android.app.Activity +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import androidx.fragment.app.Fragment +import com.ama.core.architecture.highlightpro.parameter.HighlightParameter +import com.ama.core.architecture.highlightpro.view.MaskContainer + + +class HighlightPro : HighlightViewInteractiveAction { + + private val highlightProImpl: HighlightProImpl + + private constructor(activity: Activity) { + highlightProImpl = HighlightProImpl(activity) + } + + private constructor(fragment: Fragment) { + highlightProImpl = HighlightProImpl(fragment) + } + + private constructor(view: ViewGroup) { + highlightProImpl = HighlightProImpl(view) + } + + /** + * [show] is a final method to call then show a guide or a popup window + */ + override fun show() { + highlightProImpl.show() + } + + /** + * Dismiss [HighlightPro] auto in common. + * we can manually call this method([dismiss]) to dismiss [HighlightPro] + */ + override fun dismiss() { + highlightProImpl.dismiss() + } + + /** + * Set your mask background [color] of [MaskContainer] + */ + fun setBackgroundColor(color: Int): HighlightPro { + highlightProImpl.setBackgroundColor(color) + return this + } + + /** + * Set a List of [HighlightParameter] so we can show more Highlight at once + */ + fun setHighlightParameters(highlightParameters: List): HighlightPro { + highlightProImpl.setGuideViewParameters(highlightParameters) + return this + } + + /** + * Set single [HighlightParameter] + * + * With [setHighlightParameter] we can use kotlin function with return + */ + fun setHighlightParameter(block: ()-> HighlightParameter): HighlightPro { + highlightProImpl.setGuideViewParameter(block = block) + return this + } + + /** + * [showCallback] is a function which will be invoked when the [HighlightPro] show + */ + fun setOnShowCallback(showCallback: (Int) -> Unit) : HighlightPro{ + highlightProImpl.setOnShowCallback(showCallback = showCallback) + return this + } + + /** + * [dismissCallback] is a function which will be invoked when the [HighlightPro] dismiss + */ + fun setOnDismissCallback(dismissCallback: () -> Unit) : HighlightPro{ + highlightProImpl.setOnDismissCallback(dismissCallback) + return this + } + + /** + * [clickCallback] is a callback when user clicked any place in [MaskContainer] + */ + fun setOnMaskViewClickCallback(clickCallback: (View) -> Unit): HighlightPro { + highlightProImpl.setOnGuideViewClickCallback(clickCallback) + return this + } + + /** + * [enableHighlight] give you access to make Highlight dismiss and show UI like popup window + */ + fun enableHighlight(enableHighlight: Boolean): HighlightPro { + highlightProImpl.enableHighlight(enableHighlight) + return this + } + + /** + * [interceptBackPressed] is [true] will intercept activity onBackPressed and [HighlightPro] will dismiss + */ + fun interceptBackPressed(interceptBackPressed: Boolean): HighlightPro { + highlightProImpl.interceptBackPressed(interceptBackPressed) + return this + } + + fun needAnchorTipView(needAnchorTipView: Boolean) : HighlightPro{ + highlightProImpl.needAnchorTipView(needAnchorTipView) + return this + } + + companion object { + + /** + * DecorView of [activity] treat as the rootView + */ + fun with(activity: Activity): HighlightPro { + return HighlightPro(activity) + } + + /** + * DecorView of [fragment]'s [activity] treat as the rootView + */ + fun with(fragment: Fragment): HighlightPro { + return HighlightPro(fragment) + } + + /** + * the [container] treat as rootView and the container should be a FrameLayout or a viewGroup extends FrameLayout + * to ensure the UI can display normally + */ + fun with(container: FrameLayout): HighlightPro { + return HighlightPro(container) + } + } +} \ No newline at end of file diff --git a/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/HighlightProImpl.kt b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/HighlightProImpl.kt new file mode 100644 index 0000000..8f3a24b --- /dev/null +++ b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/HighlightProImpl.kt @@ -0,0 +1,226 @@ +package com.ama.core.architecture.highlightpro + +import android.app.Activity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.view.doOnPreDraw +import androidx.fragment.app.Fragment +import com.ama.core.architecture.highlightpro.parameter.HighlightParameter +import com.ama.core.architecture.highlightpro.shape.RectShape +import com.ama.core.architecture.highlightpro.util.calculateHighLightViewRect +import com.ama.core.architecture.highlightpro.util.dp +import com.ama.core.architecture.highlightpro.util.isAttachToWindow +import com.ama.core.architecture.highlightpro.view.MaskContainer + + +internal class HighlightProImpl : HighlightViewInteractiveAction { + + companion object { + const val TAG = "HYY-GuideProImpl" + } + + private var isFragmentRoot: Boolean = false + private var fragmentRootView: View? = null + private var curIndex: Int = 0 + private val highlightParameters: MutableList> = mutableListOf() + private var hasShow: Boolean = false + private val rootView: ViewGroup + private val maskContainer: MaskContainer + private var released = false + private var showCallback: ((index: Int) -> Unit)? = null + private var dismissCallback: (() -> Unit)? = null + private var clickCallback: ((View) -> Unit)? = null + private var autoNext = true + private var needAnchorTipView = true + + // private var + private val onClickListener = View.OnClickListener { + clickCallback?.invoke(it) + if (autoNext) { + showNextHighLightView() + } + } + + internal constructor(activity: Activity) { + rootView = activity.window.decorView as ViewGroup + maskContainer = MaskContainer(activity) + } + + internal constructor(view: ViewGroup) { + rootView = view + maskContainer = MaskContainer(view.context) + } + + internal constructor(fragment: Fragment) { + if (fragment.view == null) + throw IllegalStateException("The fragment's view not created yet,please call this after fragment's onViewCreated()") + if (fragment.isDetached) + throw IllegalStateException("The fragment have detached. It is not attach to an activity!") + rootView = fragment.requireActivity().window.decorView as ViewGroup + fragmentRootView = fragment.view + isFragmentRoot = true + maskContainer = MaskContainer(rootView.context) + + } + + override fun show() { + if (released) return + println("$TAG show") + //todo give user access to intercept click event +// if (!intercept) { + maskContainer.setOnClickListener(onClickListener) +// } + + //if constructor's param is activity or view we care about rootView's attachedToWindow + //if constructor's param is fragment we care about [fragmentRootView]'s width is not 0 + if ((isFragmentRoot.not() && rootView.isAttachToWindow()) || + (isFragmentRoot && fragmentRootView?.width != 0) + ) { + if (maskContainer.parent == null) { + //add guideViewContainer to rootView + rootView.addView( + maskContainer, + ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) + ) + if (maskContainer.interceptBackPressed) { + maskContainer.apply { + //three line below enable maskContainer focusable and got focused + isFocusable = true + isFocusableInTouchMode = true + requestFocus() + setOnBackPressedCallback { + showNextHighLightView() + } + } + } + + showNextHighLightView() + } + } else { + if (isFragmentRoot) { + fragmentRootView?.doOnPreDraw { + println("$TAG fragmentRootView pre draw") + //ensure this method will be call once + if (hasShow) return@doOnPreDraw + hasShow = false + show() + } + } else { + rootView.doOnPreDraw { + //ensure this method will be call once + if (hasShow) return@doOnPreDraw + hasShow = false + show() + } + } + + } + + } + + /** + * this is the function which real show highLightView rect and tipView + */ + private fun showNextHighLightView() { + if (released) return + + println("$TAG showNextHighLightView") + + if (hasHighLightView().not()) { + dismiss() + } else { + highlightParameters[0].forEach { + checkOrInitParameter(it) + } + showCallback?.invoke(curIndex) + curIndex++ + maskContainer.setRootWidth(rootView.width-rootView.paddingLeft-rootView.paddingRight)//ignore padding + maskContainer.setRootHeight(rootView.height-rootView.paddingTop-rootView.paddingBottom)//ignore padding + maskContainer.setHighLightParameters(highlightParameters[0]) + highlightParameters.removeAt(0) + } + } + + /** + * check valid for each parameter if invalid set default value + */ + private fun checkOrInitParameter(parameter: HighlightParameter) { + + if (parameter.highLightView == null) { + parameter.highLightView = rootView.findViewById(parameter.highLightViewId) + } + + if (parameter.tipsView == null && checkTipViewIdIsValid(parameter)) { + parameter.tipsView = LayoutInflater.from(maskContainer.context) + .inflate(parameter.tipsViewId, maskContainer, false) + } + + if (parameter.highlightShape == null) { + parameter.highlightShape = RectShape(2f.dp, 2f.dp, 2f.dp) + } + + parameter.calculateHighLightViewRect(rootView) + } + + private fun checkTipViewIdIsValid(parameter: HighlightParameter): Boolean = parameter.tipsViewId != -1 + + + private fun hasHighLightView(): Boolean = highlightParameters.isNotEmpty() + + override fun dismiss() { + if (released) return + //release every thing + released = true + //todo if we want have a dismiss animation these code need rewrite + maskContainer.isFocusable = false + maskContainer.clearFocus() + + rootView.removeView(maskContainer) + maskContainer.removeAllViews() + dismissCallback?.invoke() + } + + fun setBackgroundColor(color: Int) { + maskContainer.setBackgroundColor(color) + } + + fun setGuideViewParameters(highlightParameters: List) { + if (released) return + this.highlightParameters.add(highlightParameters) + } + + fun setGuideViewParameter(block: () -> HighlightParameter) { + if (released) return + highlightParameters.add(listOf(block.invoke())) + } + + fun setOnShowCallback(showCallback: (Int) -> Unit) { + this.showCallback = showCallback + } + + fun setOnDismissCallback(dismissCallback: () -> Unit) { + this.dismissCallback = dismissCallback + } + + fun setOnGuideViewClickCallback(clickCallback: (View) -> Unit) { + this.clickCallback = clickCallback + } + + fun enableHighlight(enableHighlight: Boolean) { + this.maskContainer.enableHighlight = enableHighlight + } + + fun interceptBackPressed(interceptBackPressed: Boolean) { + this.maskContainer.interceptBackPressed = interceptBackPressed + } + + fun needAnchorTipView(needAnchorTipView: Boolean) { + this.needAnchorTipView = needAnchorTipView + this.maskContainer.needAnchorTipView = needAnchorTipView + } + +} \ No newline at end of file diff --git a/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/HighlightViewInteractiveAction.kt b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/HighlightViewInteractiveAction.kt new file mode 100644 index 0000000..f4eac45 --- /dev/null +++ b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/HighlightViewInteractiveAction.kt @@ -0,0 +1,16 @@ +package com.ama.core.architecture.highlightpro + + +interface HighlightViewInteractiveAction { + + /** + * show [HighlightPro] + */ + fun show() + + /** + * dismiss [HighlightPro] + */ + fun dismiss() + +} \ No newline at end of file diff --git a/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/parameter/Constraints.kt b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/parameter/Constraints.kt new file mode 100644 index 0000000..a138386 --- /dev/null +++ b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/parameter/Constraints.kt @@ -0,0 +1,22 @@ +package com.ama.core.architecture.highlightpro.parameter + + +sealed class Constraints { + //vertical constraints + object TopToTopOfHighlight : Constraints() + object BottomToTopOfHighlight : Constraints() + object BottomToBottomOfHighlight : Constraints() + object TopToBottomOfHighlight : Constraints() + //horizontal constraints + object StartToStartOfHighlight : Constraints() + object StartToEndOfHighlight : Constraints() + object EndToEndOfHighlight : Constraints() + object EndToStartOfHighlight : Constraints() + //center constraints + object CenterHorizontalOfHighlight : Constraints() + object CenterVerticalOfHighlight : Constraints() + + operator fun plus(locationGravity: Constraints): List { + return listOf(this, locationGravity) + } +} diff --git a/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/parameter/HighlightParameter.kt b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/parameter/HighlightParameter.kt new file mode 100644 index 0000000..11ffb63 --- /dev/null +++ b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/parameter/HighlightParameter.kt @@ -0,0 +1,153 @@ +package com.ama.core.architecture.highlightpro.parameter + +import android.graphics.RectF +import android.view.View +import android.view.animation.Animation +import com.ama.core.architecture.highlightpro.shape.HighlightShape + + +class HighlightParameter { + + internal var highLightViewId: Int = -1 + + internal var highLightView: View? = null + + internal var tipsViewId: Int = -1 + + internal var tipsView: View? = null + + internal var highlightShape: HighlightShape? = null + + internal var rect: RectF = RectF() + + internal var horizontalPadding: Float = 0f + + internal var verticalPadding: Float = 0f + + internal var marginOffset: MarginOffset = MarginOffset() + + internal var offsetX = 0 + internal var offsetY = 0 + + internal val constraints = + mutableListOf(Constraints.TopToBottomOfHighlight, Constraints.StartToStartOfHighlight) + + internal var tipViewDisplayAnimation: Animation? = null + + fun setHighLightViewId(viewId: Int) { + this.highLightViewId = viewId + } + + fun setHighLightView(highLightView: View) { + this.highLightView = highLightView + } + + operator fun plus(highlightParameter: HighlightParameter): List { + return listOf(this, highlightParameter) + } + + class Builder { + private val highlightParameter: HighlightParameter = HighlightParameter() + + /** + * [viewId] is the highLightView's id + * it will be override by [setHighlightView]. + */ + fun setHighlightViewId(viewId: Int): Builder { + highlightParameter.highLightViewId = viewId + return this + } + + /** + * [highLightView] is the view which you want to make it highLight + * And it will make [setHighlightViewId] useless. + */ + fun setHighlightView(highLightView: View): Builder { + highlightParameter.highLightView = highLightView + return this + } + + /** + * [viewId] is the tipsView's id + * it will be override by [setTipsView]. + */ + fun setTipsViewId(viewId: Int): Builder { + highlightParameter.tipsViewId = viewId + return this + } + + /** + * [tipsView] is the view which you want to add it on [GuideViewContainer] + * And it will make [setTipsViewId] useless. + */ + fun setTipsView(tipsView: View): Builder { + highlightParameter.tipsView = tipsView + return this + } + + /** + * [highlightShape] is the highlight out rect shape and you can + * custom your shape reference our shapes exit. + */ + fun setHighlightShape(highlightShape: HighlightShape): Builder { + highlightParameter.highlightShape = highlightShape + return this + } + + /** + * [padding] is the vertical dimension padding use by expand the rect area of + * highlight. + */ + fun setHighlightVerticalPadding(padding: Float): Builder { + highlightParameter.verticalPadding = padding + return this + } + + /** + * [marginOffset] is the extra dimension use by position highlight rect. + */ + fun setMarginOffset(marginOffset: MarginOffset): Builder { + highlightParameter.marginOffset = marginOffset + return this + } + + /** + * [constraints] is a list of constraints provides some constraints of highlight + * rect position. + */ + fun setConstraints(constraints: List): Builder { + highlightParameter.constraints.clear() + highlightParameter.constraints.addAll(constraints) + return this + } + + /** + * [padding] is the horizontal dimension padding use by expand the rect area of + * highlight. + */ + fun setHighlightHorizontalPadding(padding: Float): Builder { + highlightParameter.horizontalPadding = padding + return this + } + + /** + * [tipViewDisplayAnimation] is the animation to display for Highlight tips view + */ + fun setTipViewDisplayAnimation(tipViewDisplayAnimation: Animation?): Builder { + highlightParameter.tipViewDisplayAnimation = tipViewDisplayAnimation + return this + } + + fun offsetX(offsetX: Int): Builder { + highlightParameter.offsetX = offsetX + return this + } + + fun offsetY(offsetY: Int): Builder { + highlightParameter.offsetY = offsetY + return this + } + + fun build(): HighlightParameter = highlightParameter + } +} \ No newline at end of file diff --git a/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/parameter/MarginOffset.kt b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/parameter/MarginOffset.kt new file mode 100644 index 0000000..4715625 --- /dev/null +++ b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/parameter/MarginOffset.kt @@ -0,0 +1,9 @@ +package com.ama.core.architecture.highlightpro.parameter + + +class MarginOffset( + val start: Int = 0, + val top: Int = 0, + val end: Int = 0, + val bottom: Int = 0 +) \ No newline at end of file diff --git a/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/shape/CircleShape.kt b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/shape/CircleShape.kt new file mode 100644 index 0000000..e470afb --- /dev/null +++ b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/shape/CircleShape.kt @@ -0,0 +1,17 @@ +package com.ama.core.architecture.highlightpro.shape + +import android.graphics.Path +import android.graphics.RectF +import kotlin.math.max + + +class CircleShape(private val radius: Float = 0f) : HighlightShape(radius) { + + override fun initRect(rectF: RectF) { + super.initRect(rectF) + rect?.run { + path.reset() + path.addCircle((left+right)/2,(top+bottom)/2, max(height(),width()) /2,Path.Direction.CW) + } + } +} \ No newline at end of file diff --git a/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/shape/HighlightShape.kt b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/shape/HighlightShape.kt new file mode 100644 index 0000000..81ff828 --- /dev/null +++ b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/shape/HighlightShape.kt @@ -0,0 +1,50 @@ +package com.ama.core.architecture.highlightpro.shape + +import android.graphics.* + + + +open class HighlightShape(val blurRadius: Float = 0.0f) { + + private lateinit var paint: Paint + + //clip path + internal val path by lazy { + Path() + } + + init { + paint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + isDither = true + color = Color.WHITE + } + //paint blur style + if (blurRadius > 0) { + paint.maskFilter = BlurMaskFilter(blurRadius, BlurMaskFilter.Blur.SOLID) + } + } + + protected var rect: RectF? = null + + /** + * init rect child should override initRect and init path + * */ + open fun initRect(rectF: RectF) { + this.rect = rectF + } + + /** + * draw our path + */ + fun drawPath(canvas: Canvas) { + rect?.run { + if (isEmpty.not()) { + canvas.drawPath(path, paint) + } + } + } + + fun setPaint(paint: Paint) { + this.paint = paint + } +} \ No newline at end of file diff --git a/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/shape/OvalShape.kt b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/shape/OvalShape.kt new file mode 100644 index 0000000..d4cabb0 --- /dev/null +++ b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/shape/OvalShape.kt @@ -0,0 +1,16 @@ +package com.ama.core.architecture.highlightpro.shape + +import android.graphics.Path +import android.graphics.RectF + + +class OvalShape(private val radius: Float = 0f) : HighlightShape(radius) { + + override fun initRect(rectF: RectF) { + super.initRect(rectF) + rect?.run { + path.reset() + path.addOval(this,Path.Direction.CW) + } + } +} \ No newline at end of file diff --git a/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/shape/RectShape.kt b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/shape/RectShape.kt new file mode 100644 index 0000000..fb5ba08 --- /dev/null +++ b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/shape/RectShape.kt @@ -0,0 +1,16 @@ +package com.ama.core.architecture.highlightpro.shape + +import android.graphics.Path +import android.graphics.RectF + + +class RectShape(private val rx: Float = 0f, private val ry: Float = 0f, private val radius: Float = 0f) : HighlightShape(radius) { + + override fun initRect(rectF: RectF) { + super.initRect(rectF) + rect?.run { + path.reset() + path.addRoundRect(this, rx, ry, Path.Direction.CW) + } + } +} \ No newline at end of file diff --git a/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/util/ViewUtils.kt b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/util/ViewUtils.kt new file mode 100644 index 0000000..4080b9f --- /dev/null +++ b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/util/ViewUtils.kt @@ -0,0 +1,88 @@ +package com.ama.core.architecture.highlightpro.util + +import android.content.res.Resources +import android.graphics.RectF +import android.os.Build +import android.util.TypedValue +import android.view.View +import android.view.ViewGroup +import com.ama.core.architecture.highlightpro.parameter.HighlightParameter + + +fun View.isAttachToWindow(): Boolean { + return if (Build.VERSION.SDK_INT >= 19) { + isAttachedToWindow + } else { + windowToken != null + } +} + +fun View?.getRectOnScreen(): RectF { + if (this == null) { + return RectF() + } + val pos = intArrayOf(0, 0) + getLocationOnScreen(pos) + + return RectF().apply { + left = pos[0].toFloat() + top = pos[1].toFloat() + right = pos[0].toFloat() + width + bottom = pos[1].toFloat() + height + } +} + +fun HighlightParameter.calculateHighLightViewRect(rootView: ViewGroup) { + if (highLightView == null) return + val rectOnScreen = highLightView.getRectOnScreen() + + //consider rootView's position + val rootViewPos = IntArray(2) + rootView.getLocationOnScreen(rootViewPos) + rectOnScreen.left -= rootViewPos[0] + rectOnScreen.right -= rootViewPos[0] + rectOnScreen.top -= rootViewPos[1] + rectOnScreen.bottom -= rootViewPos[1] + + rectOnScreen.left -= rootView.paddingLeft.toFloat() + rectOnScreen.right -= rootView.paddingLeft.toFloat() + rectOnScreen.top -= rootView.paddingTop.toFloat() + rectOnScreen.bottom -= rootView.paddingTop.toFloat() + rect = rectOnScreen + rect.run { + left -= horizontalPadding + top -= verticalPadding + right += horizontalPadding + bottom += verticalPadding + + highlightShape?.initRect(this) + } +} + +val Float.dp + get() = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + this, + Resources.getSystem().displayMetrics + ) + +val Float.sp + get() = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_SP, + this, + Resources.getSystem().displayMetrics + ) + +val Int.dp + get() = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + this.toFloat(), + Resources.getSystem().displayMetrics + ).toInt() + +val Int.sp + get() = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_SP, + this.toFloat(), + Resources.getSystem().displayMetrics + ).toInt() \ No newline at end of file diff --git a/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/view/MaskContainer.kt b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/view/MaskContainer.kt new file mode 100644 index 0000000..f0e6fd2 --- /dev/null +++ b/core/architecture/src/main/java/com/ama/core/architecture/highlightpro/view/MaskContainer.kt @@ -0,0 +1,262 @@ +package com.ama.core.architecture.highlightpro.view + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Region +import android.util.AttributeSet +import android.view.Gravity +import android.view.KeyEvent +import android.view.View +import android.widget.FrameLayout +import androidx.core.graphics.toColorInt +import androidx.core.view.children +import androidx.core.view.doOnPreDraw +import com.ama.core.architecture.highlightpro.parameter.Constraints +import com.ama.core.architecture.highlightpro.parameter.HighlightParameter + + +internal class MaskContainer constructor(context: Context, attributeSet: AttributeSet? = null) : + FrameLayout(context, attributeSet) { + companion object { + const val TAG = "MaskContainer" + } + + private var rootWidth: Int = 0 + private var rootHeight: Int = 0 + private var bgColor: Int = -1 + private val highLightViewParameters = mutableListOf() + private val defaultHighlightBgColor: Int + get() = "#80000000".toColorInt() + + private val defaultBgColor: Int + get() = "#00000000".toColorInt() + + private var backPressedCallback: (() -> Unit)? = null + internal var enableHighlight = true + internal var interceptBackPressed = false + internal var needAnchorTipView = true + + init { + setWillNotDraw(false) + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + if (enableHighlight) { + canvas.save() + + //clip rect + highLightViewParameters.forEach { parameter -> + parameter.highlightShape?.run { + canvas.clipPath(path, Region.Op.DIFFERENCE) + } + } + + if (bgColor == -1) { + bgColor = defaultHighlightBgColor + } + canvas.drawColor(bgColor) + + highLightViewParameters.forEach { parameter -> + parameter.highlightShape?.run { + drawPath(canvas) + } + } + canvas.restore() + } else { + if (bgColor == -1) { + bgColor = defaultBgColor + } + canvas.drawColor(bgColor) + } + } + + override fun setBackgroundColor(color: Int) { +// super.setBackgroundColor(color) + bgColor = color + } + + fun setOnBackPressedCallback(block: () -> Unit) { + backPressedCallback = block + } + + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { + if (keyCode == KeyEvent.KEYCODE_BACK) { + backPressedCallback?.invoke() + return interceptBackPressed + } + return super.onKeyDown(keyCode, event) + } + + fun setHighLightParameters(list: List) { + children.forEach { + it.clearAnimation() + } + //clear all childView + removeAllViews() + + highLightViewParameters.clear() + highLightViewParameters.addAll(list) + + addTipsView() + + } + + private fun addTipsView() { + if (needAnchorTipView) { + highLightViewParameters.forEach { highLightViewParameters -> + highLightViewParameters.tipsView?.run { + val layoutParams = calculateTipsViewLayoutParams(this, highLightViewParameters) + if (highLightViewParameters.tipViewDisplayAnimation != null) { + startAnimation(highLightViewParameters.tipViewDisplayAnimation) + } + addView(this, layoutParams) + highLightViewParameters.tipsView?.doOnPreDraw { + + } + } + } + } else { + highLightViewParameters.forEach { highLightViewParameters -> + highLightViewParameters.tipsView?.run { + var layoutParams = (this.layoutParams ?: LayoutParams( + LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT + )) as LayoutParams + layoutParams.topMargin = highLightViewParameters.offsetY + layoutParams.leftMargin = highLightViewParameters.offsetX + if (highLightViewParameters.tipViewDisplayAnimation != null) { + startAnimation(highLightViewParameters.tipViewDisplayAnimation) + } + addView(this, layoutParams) + } + } + } + + } + + private fun calculateTipsViewLayoutParams( + view: View, + parameter: HighlightParameter + ): LayoutParams { + var layoutParams = (view.layoutParams ?: LayoutParams( + LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT + )) as LayoutParams + + println("$TAG calculateTipsViewLayoutParams tipsView layoutParams--> $layoutParams") + val margin = parameter.marginOffset + val highLightRect = parameter.rect + val gravities = mutableListOf() + parameter.constraints.forEach { + when (it) { + Constraints.StartToStartOfHighlight -> { + layoutParams.leftMargin = (highLightRect.left + margin.start).toInt() + gravities.add(Gravity.START) + } + + Constraints.EndToStartOfHighlight -> { + //if constraint start to end of Highlight we need set right rightMargin + //and if margin.end is not 0 we should add the margin end + layoutParams.rightMargin = + (rootWidth - highLightRect.right + highLightRect.width() + margin.end).toInt() + gravities.add(Gravity.END) + } + + Constraints.StartToEndOfHighlight -> { + layoutParams.leftMargin = (highLightRect.right + margin.start).toInt() + gravities.add(Gravity.START) + } + + Constraints.EndToEndOfHighlight -> { + layoutParams.rightMargin = + (rootWidth - highLightRect.right + margin.end).toInt() + gravities.add(Gravity.END) + } + + Constraints.TopToTopOfHighlight -> { + layoutParams.topMargin = (highLightRect.top + margin.top).toInt() + gravities.add(Gravity.TOP) + } + + Constraints.BottomToBottomOfHighlight -> { + layoutParams.bottomMargin = + (rootHeight - highLightRect.bottom + margin.bottom).toInt() + gravities.add(Gravity.BOTTOM) + + } + + Constraints.BottomToTopOfHighlight -> { + layoutParams.bottomMargin = + (rootHeight - highLightRect.bottom + highLightRect.height() + margin.bottom).toInt() + gravities.add(Gravity.BOTTOM) + } + + Constraints.TopToBottomOfHighlight -> { + layoutParams.topMargin = (highLightRect.bottom + margin.top).toInt() + gravities.add(Gravity.TOP) + } + + Constraints.CenterHorizontalOfHighlight -> { + val width = layoutParams.width + + if (width <= 0) { + layoutParams.leftMargin = + (highLightRect.left + highLightRect.width() / 2f).toInt() + gravities.add(Gravity.START) + view.doOnPreDraw { tipsView -> + layoutParams.leftMargin = + (highLightRect.left + highLightRect.width() / 2f - tipsView.width / 2f).toInt() + view.layoutParams = layoutParams + } + } else { + layoutParams.leftMargin = + (highLightRect.left + highLightRect.width() / 2f - width / 2f).toInt() + gravities.add(Gravity.START) + } + } + + Constraints.CenterVerticalOfHighlight -> { + val height = layoutParams.height + if (height <= 0) { + layoutParams.topMargin = + (highLightRect.top + highLightRect.height() / 2f).toInt() + gravities.add(Gravity.TOP) + view.doOnPreDraw { tipsView -> + layoutParams.topMargin = + (highLightRect.top + highLightRect.height() / 2f - tipsView.height / 2f).toInt() + view.layoutParams = layoutParams + } + } else { + layoutParams.topMargin = + (highLightRect.top + highLightRect.height() / 2f - height / 2f).toInt() + gravities.add(Gravity.TOP) + } + } + } + } + gravities.forEachIndexed { index, gravity -> + if (index == 0) layoutParams.gravity = gravity + else layoutParams.gravity = layoutParams.gravity or gravity + } + return layoutParams + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + highLightViewParameters.clear() + } + + fun setRootWidth(width: Int) { + this.rootWidth = width + } + + fun setRootHeight(height: Int) { + this.rootHeight = height + } + +} \ No newline at end of file