guide初步
This commit is contained in:
parent
e0ede99c67
commit
994d205a7e
|
|
@ -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'
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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<DialogBeginnerGiftBinding>(activity, DialogBeginnerGiftBinding::inflate) {
|
||||
|
|
@ -26,10 +23,10 @@ class BeginnerGiftDialog(activity: Activity) : BindingDialog<DialogBeginnerGiftB
|
|||
setOnClickBatch(tvAction) {
|
||||
when (this) {
|
||||
tvAction -> {
|
||||
/*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<DialogBeginnerGiftB
|
|||
}
|
||||
}
|
||||
|
||||
private fun gotoWatchVideo() {
|
||||
Router.Withdraw.startActivity(mActivity)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ import android.Manifest
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.graphics.toColorInt
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.updatePadding
|
||||
|
|
@ -14,6 +16,7 @@ import com.ama.core.architecture.appBase.AppViewsFragment
|
|||
import com.ama.core.architecture.appBase.OnFragmentBackgroundListener
|
||||
import com.ama.core.architecture.util.AndroidUtil
|
||||
import com.ama.core.architecture.util.ResUtil
|
||||
import com.ama.core.architecture.util.ResUtil.dp
|
||||
import com.ama.core.architecture.util.eventbus.NotifyMan
|
||||
import com.ama.core.architecture.util.permission.PermissionUtil
|
||||
import com.ama.core.architecture.util.setOnClickBatch
|
||||
|
|
@ -33,6 +36,11 @@ import com.gamedog.vididin.manager.TaskManager
|
|||
import com.gamedog.vididin.manager.taskbeans.BaseTaskState.Companion.STATE_FINISH
|
||||
import com.gamedog.vididin.manager.taskbeans.BaseTaskState.Companion.STATE_ONGOING
|
||||
import com.gamedog.vididin.router.Router
|
||||
import com.ama.core.architecture.highlightpro.HighlightPro
|
||||
import com.ama.core.architecture.highlightpro.parameter.Constraints
|
||||
import com.ama.core.architecture.highlightpro.parameter.HighlightParameter
|
||||
import com.ama.core.architecture.highlightpro.parameter.MarginOffset
|
||||
import com.ama.core.architecture.highlightpro.shape.RectShape
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.Runnable
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -136,6 +144,10 @@ class TasksFragment : AppViewsFragment<ViewBinding, UiState, ViewModel>(), OnTab
|
|||
lifecycleScope.launch {
|
||||
mTaskConfig = TaskManager.instance().getTaskConfig()
|
||||
}
|
||||
|
||||
binding?.llTaskGame?.postDelayed({
|
||||
showGuide()
|
||||
}, 50)
|
||||
}
|
||||
|
||||
private fun addDailySubTasks() {
|
||||
|
|
@ -422,4 +434,39 @@ class TasksFragment : AppViewsFragment<ViewBinding, UiState, ViewModel>(), 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()
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/tv_tips"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_gravity="right"
|
||||
android:layout_marginLeft="100dp"
|
||||
android:layout_height="70dp"
|
||||
android:src="@mipmap/guide_finger_b" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="15dp"
|
||||
android:layout_marginTop="70dp"
|
||||
android:padding="15dp"
|
||||
android:background="@mipmap/guide_bg_right">
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_gravity="center"
|
||||
android:textSize="16sp"
|
||||
android:textColor="@color/gray3"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/guide_hint_cash"
|
||||
/>
|
||||
</FrameLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/tv_tips"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:layout_marginLeft="100dp"
|
||||
android:layout_height="70dp"
|
||||
android:src="@mipmap/guide_finger_b" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="15dp"
|
||||
android:layout_marginTop="70dp"
|
||||
android:padding="15dp"
|
||||
android:background="@mipmap/guide_bg_left">
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_gravity="center"
|
||||
android:textSize="16sp"
|
||||
android:textColor="@color/gray3"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/guide_hint_gold"
|
||||
/>
|
||||
</FrameLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
|
|
@ -32,138 +32,147 @@
|
|||
android:orientation="horizontal"
|
||||
android:layout_marginTop="15dp">
|
||||
|
||||
<LinearLayout
|
||||
<FrameLayout
|
||||
android:id="@+id/gold_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:background="@mipmap/task_bg_glod"
|
||||
android:padding="10dp"
|
||||
>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/pink_0b"
|
||||
android:text="Centro de Missões"
|
||||
/>
|
||||
|
||||
android:layout_weight="1">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginTop="10dp">
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@mipmap/task_bg_glod"
|
||||
android:padding="10dp"
|
||||
>
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:textSize="21sp"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/pink_0b"
|
||||
android:src="@mipmap/home_gold"
|
||||
android:text="Centro de Missões"
|
||||
/>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/tv_gold_total"
|
||||
android:layout_width="wrap_content"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:textSize="21sp"
|
||||
android:textColor="@color/pink_0b"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:text="0"
|
||||
/>
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginTop="10dp">
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:textSize="21sp"
|
||||
android:textColor="@color/pink_0b"
|
||||
android:src="@mipmap/home_gold"
|
||||
/>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/tv_gold_total"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:textSize="21sp"
|
||||
android:textColor="@color/pink_0b"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:text="0"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/tv_watch_video_for_convert_gold_to_cash"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:drawableLeft="@mipmap/task_video"
|
||||
android:drawablePadding="10dp"
|
||||
android:gravity="center"
|
||||
android:text="Resgatar"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/tv_watch_video_for_convert_gold_to_cash"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:drawableLeft="@mipmap/task_video"
|
||||
android:drawablePadding="10dp"
|
||||
android:gravity="center"
|
||||
android:text="Resgatar"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
<FrameLayout
|
||||
android:id="@+id/cash_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:background="@mipmap/task_bg_cash"
|
||||
android:padding="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/green_39"
|
||||
android:text="Meu Dinheiro"
|
||||
/>
|
||||
|
||||
android:layout_marginLeft="10dp">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginTop="10dp">
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:textSize="21sp"
|
||||
android:textColor="@color/pink_0b"
|
||||
android:src="@mipmap/task_cash"
|
||||
/>
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@mipmap/task_bg_cash"
|
||||
android:padding="10dp"
|
||||
>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/tv_cash_total"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:textSize="21sp"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/green_39"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:text="R$ 0"
|
||||
android:text="Meu Dinheiro"
|
||||
/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginTop="10dp">
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:textSize="21sp"
|
||||
android:textColor="@color/pink_0b"
|
||||
android:src="@mipmap/task_cash"
|
||||
/>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/tv_cash_total"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:textSize="21sp"
|
||||
android:textColor="@color/green_39"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:text="R$ 0"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/tv_withdraw"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:textSize="15sp"
|
||||
android:textColor="@color/white"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="Sacar"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:gravity="center"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/tv_withdraw"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:textSize="15sp"
|
||||
android:textColor="@color/white"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="Sacar"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:gravity="center"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -492,8 +501,6 @@
|
|||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.ama.core.architecture.widget.MyScrollView>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
|
|
@ -149,5 +149,7 @@
|
|||
<string name="cost_gold">Consumo de moedas</string>
|
||||
<string name="percent">%</string>
|
||||
<string name="pix2_hint">Vincular conta para saque</string>
|
||||
<string name="guide_hint_gold">Clique no botão para converter todas \nas “Moedas” em “Dinheiro”.</string>
|
||||
<string name="guide_hint_cash">Clique aqui para ir para o saque.</string>
|
||||
|
||||
</resources>
|
||||
|
|
@ -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<HighlightParameter>): 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<List<HighlightParameter>> = 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<HighlightParameter>) {
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.ama.core.architecture.highlightpro
|
||||
|
||||
|
||||
interface HighlightViewInteractiveAction {
|
||||
|
||||
/**
|
||||
* show [HighlightPro]
|
||||
*/
|
||||
fun show()
|
||||
|
||||
/**
|
||||
* dismiss [HighlightPro]
|
||||
*/
|
||||
fun dismiss()
|
||||
|
||||
}
|
||||
|
|
@ -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<Constraints> {
|
||||
return listOf(this, locationGravity)
|
||||
}
|
||||
}
|
||||
|
|
@ -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<HighlightParameter> {
|
||||
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<Constraints>): 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
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
)
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
|
|
@ -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<HighlightParameter>()
|
||||
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<HighlightParameter>) {
|
||||
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<Int>()
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue