From e77f38fb39e57fb9c618b9a9dbcdec2ae21df8bc Mon Sep 17 00:00:00 2001 From: petterp Date: Fri, 3 Nov 2023 00:17:52 +0800 Subject: [PATCH 1/8] =?UTF-8?q?perf:=E8=B0=83=E6=95=B4fx=E7=9A=84=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 1 + app/src/main/AndroidManifest.xml | 41 +++--- .../com/petterp/floatingx/app/MainActivity.kt | 66 +++++++++- .../app/java/CustomJavaApplication.java | 8 +- .../app/kotlin/CustomKtApplication.kt | 5 - .../floatingx/app/test/ScopeActivity.kt | 2 +- build.gradle | 2 + floatingx/proguard-floatingx.pro | 2 +- .../java/com/petterp/floatingx/FloatingX.kt | 8 +- .../{util => assist}/FxAdsorbDirection.kt | 2 +- .../petterp/floatingx/assist/FxDisplayMode.kt | 2 +- .../floatingx/{util => assist}/FxScopeEnum.kt | 5 +- .../helper/{AppHelper.kt => FxAppHelper.kt} | 16 +-- .../{BasisHelper.kt => FxBasisHelper.kt} | 6 +- .../{ScopeHelper.kt => FxScopeHelper.kt} | 8 +- .../floatingx/assist/helper/FxSystemHelper.kt | 21 ++++ .../impl/control/FxAppControlImpl.kt | 6 +- .../impl/control/FxBasisControlImpl.kt | 118 +++++++++--------- .../floatingx/impl/control/FxScopeControl.kt | 8 +- .../lifecycle/FxProxyLifecycleCallBackImpl.kt | 6 +- .../listener/control/IFxConfigControl.kt | 2 +- .../floatingx/listener/control/IFxControl.kt | 4 +- .../java/com/petterp/floatingx/util/FxExt.kt | 9 +- .../petterp/floatingx/view/FxClickHelper.kt | 6 +- .../floatingx/view/FxLocationHelper.kt | 2 +- .../floatingx/view/IFxInternalViewControl.kt | 27 ++++ 26 files changed, 251 insertions(+), 132 deletions(-) rename floatingx/src/main/java/com/petterp/floatingx/{util => assist}/FxAdsorbDirection.kt (75%) rename floatingx/src/main/java/com/petterp/floatingx/{util => assist}/FxScopeEnum.kt (64%) rename floatingx/src/main/java/com/petterp/floatingx/assist/helper/{AppHelper.kt => FxAppHelper.kt} (94%) rename floatingx/src/main/java/com/petterp/floatingx/assist/helper/{BasisHelper.kt => FxBasisHelper.kt} (99%) rename floatingx/src/main/java/com/petterp/floatingx/assist/helper/{ScopeHelper.kt => FxScopeHelper.kt} (88%) create mode 100644 floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxSystemHelper.kt create mode 100644 floatingx/src/main/java/com/petterp/floatingx/view/IFxInternalViewControl.kt diff --git a/app/build.gradle b/app/build.gradle index 22b7ebb1..c2c91246 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -74,4 +74,5 @@ dependencies { debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.10' // debugImplementation 'com.squareup.leakcanary:leakcanary-object-watcher-android-startup:2.10' implementation isDev ? project(path: ':floatingx') : "io.github.petterpx:floatingx:$version_name" + debugImplementation "com.bytedance.tools.codelocator:codelocator-core:2.0.3" } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 533b23f8..d090e67b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,20 +1,23 @@ + xmlns:tools="http://schemas.android.com/tools" + package="com.petterp.floatingx.app"> + + + + android:name=".kotlin.CustomKtApplication" + android:icon="@mipmap/ic_launcher" + android:label="@string/app_name" + android:roundIcon="@mipmap/ic_launcher_round" + android:supportsRtl="true" + android:theme="@style/Theme.FloatingX"> + android:name="com.petterp.floatingx.app.MainActivity" + android:configChanges="keyboard|orientation|keyboardHidden|screenSize|smallestScreenSize|screenLayout|locale|navigation|fontScale|mcc|mnc|uiMode" + android:exported="true" + android:windowSoftInputMode="adjustPan"> @@ -22,19 +25,19 @@ + android:name=".test.ImmersedActivity" + android:configChanges="keyboard|orientation|keyboardHidden|screenSize|smallestScreenSize|screenLayout|locale|navigation|fontScale|mcc|mnc|uiMode" /> + android:name=".test.ScopeActivity" + android:configChanges="keyboard|orientation|keyboardHidden|screenSize|smallestScreenSize|screenLayout|locale|navigation|fontScale|mcc|mnc|uiMode" /> + android:name=".test.SimpleRvActivity" + android:configChanges="keyboard|orientation|keyboardHidden|screenSize|smallestScreenSize|screenLayout|locale|navigation|fontScale|mcc|mnc|uiMode" + android:exported="true" /> \ No newline at end of file diff --git a/app/src/main/java/com/petterp/floatingx/app/MainActivity.kt b/app/src/main/java/com/petterp/floatingx/app/MainActivity.kt index acde2a24..8fb5e5c7 100644 --- a/app/src/main/java/com/petterp/floatingx/app/MainActivity.kt +++ b/app/src/main/java/com/petterp/floatingx/app/MainActivity.kt @@ -19,7 +19,7 @@ class MainActivity : AppCompatActivity() { private val activityFx by createFx { setLayout(R.layout.item_floating) - setEnableLog(true, "act") + setEnableLog(true, "activityFx") build().toControl(this@MainActivity) } @@ -80,6 +80,37 @@ class MainActivity : AppCompatActivity() { .setCardBackgroundColor(Color.GREEN) } } + addItemView("显示windows级别悬浮窗") { +// val config = +// FxAppHelper.builder().setLayout(R.layout.item_floating) +// .setEnableLog(true, "windows") +// .setContext(applicationContext).build() +// val layoutParam = WindowManager.LayoutParams().apply { +// // 设置大小 自适应 +// width = WindowManager.LayoutParams.WRAP_CONTENT +// height = WindowManager.LayoutParams.WRAP_CONTENT +// format = PixelFormat.TRANSPARENT +// /** +// * 注意,flag的值可以为: +// * 下面的flags属性的效果形同“锁定”。 +// * 悬浮窗不可触摸,不接受任何事件,同时不影响后面的事件响应。 +// * LayoutParams.FLAG_NOT_TOUCH_MODAL 不影响后面的事件 +// * LayoutParams.FLAG_NOT_FOCUSABLE 不可聚焦 +// * LayoutParams.FLAG_NOT_TOUCHABLE 不可触摸 +// */ +// flags = +// WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE +// type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { +// WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY +// } else { +// WindowManager.LayoutParams.TYPE_SYSTEM_ALERT +// } +// } +// val fx = FxManagerView(applicationContext).init(config) +// fx.windowManager = windowManager +// windowManager.addView(fx, layoutParam) + windowManager + } addItemView("进入测试页面") { TestActivity::class.java.start(this@MainActivity) } @@ -105,3 +136,36 @@ class MainActivity : AppCompatActivity() { return viewGroup } } + +class ItemViewTouchListener(val wl: WindowManager.LayoutParams, val windowManager: WindowManager) : + View.OnTouchListener { + private var x = 0 + private var y = 0 + override fun onTouch(view: View, motionEvent: MotionEvent): Boolean { + when (motionEvent.action) { + MotionEvent.ACTION_DOWN -> { + x = motionEvent.rawX.toInt() + y = motionEvent.rawY.toInt() + } + + MotionEvent.ACTION_MOVE -> { + val nowX = motionEvent.rawX.toInt() + val nowY = motionEvent.rawY.toInt() + val movedX = nowX - x + val movedY = nowY - y + x = nowX + y = nowY + wl.apply { + x += movedX + y += movedY + } + // 更新悬浮球控件位置 + windowManager?.updateViewLayout(view, wl) + } + + else -> { + } + } + return false + } +} diff --git a/app/src/main/java/com/petterp/floatingx/app/java/CustomJavaApplication.java b/app/src/main/java/com/petterp/floatingx/app/java/CustomJavaApplication.java index d5e7ec41..651578a8 100644 --- a/app/src/main/java/com/petterp/floatingx/app/java/CustomJavaApplication.java +++ b/app/src/main/java/com/petterp/floatingx/app/java/CustomJavaApplication.java @@ -12,8 +12,8 @@ import com.petterp.floatingx.app.simple.FxAnimationImpl; import com.petterp.floatingx.app.simple.FxConfigStorageToSpImpl; import com.petterp.floatingx.assist.FxDisplayMode; -import com.petterp.floatingx.assist.helper.AppHelper; -import com.petterp.floatingx.assist.helper.ScopeHelper; +import com.petterp.floatingx.assist.helper.FxAppHelper; +import com.petterp.floatingx.assist.helper.FxScopeHelper; import com.petterp.floatingx.impl.lifecycle.FxTagActivityLifecycleImpl; /** @@ -25,7 +25,7 @@ public class CustomJavaApplication extends Application { @Override public void onCreate() { super.onCreate(); - AppHelper helper = AppHelper.builder() + FxAppHelper helper = FxAppHelper.builder() .setLayout(R.layout.item_floating) // 设置启用日志,tag可以自定义,最终显示为FloatingX-xxx .setEnableLog(true, "自定义的tag") @@ -85,7 +85,7 @@ public void onCreated(@NonNull Activity activity, @Nullable Bundle bundle) { * 创建一个局部悬浮窗 */ public void createScopeFxSimple(Activity activity) { - ScopeHelper.builder() + FxScopeHelper.builder() .setLayout(R.layout.item_floating) .build() .toControl(activity); diff --git a/app/src/main/java/com/petterp/floatingx/app/kotlin/CustomKtApplication.kt b/app/src/main/java/com/petterp/floatingx/app/kotlin/CustomKtApplication.kt index 9cafe53a..20f283fd 100644 --- a/app/src/main/java/com/petterp/floatingx/app/kotlin/CustomKtApplication.kt +++ b/app/src/main/java/com/petterp/floatingx/app/kotlin/CustomKtApplication.kt @@ -4,7 +4,6 @@ import android.app.Activity import android.app.Application import android.graphics.Color import android.os.Bundle -import android.util.Log import android.view.Gravity import android.view.MotionEvent import android.view.View @@ -112,22 +111,18 @@ class CustomKtApplication : Application() { setScrollListener(object : FxScrollImpl() { override fun down() { // 按下 - Log.e("petterp", "down") } override fun up() { // 释放 - Log.e("petterp", "up") } override fun dragIng(event: MotionEvent, x: Float, y: Float) { // 正在拖动 -// Log.e("petterp", "dragIng-$x,$y") } override fun eventIng(event: MotionEvent) { // 接收所有事件传递 - Log.e("petterp", "eventIng,${event.x},${event.y}") } }) // 设置浮窗展示类型,默认可移动可点击,无需配置 diff --git a/app/src/main/java/com/petterp/floatingx/app/test/ScopeActivity.kt b/app/src/main/java/com/petterp/floatingx/app/test/ScopeActivity.kt index 972e8ff3..efe18ea8 100644 --- a/app/src/main/java/com/petterp/floatingx/app/test/ScopeActivity.kt +++ b/app/src/main/java/com/petterp/floatingx/app/test/ScopeActivity.kt @@ -16,7 +16,7 @@ import com.petterp.floatingx.app.createLinearLayoutToParent import com.petterp.floatingx.app.simple.FxAnimationImpl import com.petterp.floatingx.assist.FxDisplayMode import com.petterp.floatingx.assist.FxGravity -import com.petterp.floatingx.util.FxAdsorbDirection +import com.petterp.floatingx.assist.FxAdsorbDirection import com.petterp.floatingx.util.createFx /** @author petterp */ diff --git a/build.gradle b/build.gradle index 5cea2fc0..19fd7d25 100644 --- a/build.gradle +++ b/build.gradle @@ -9,4 +9,6 @@ buildscript { plugins { id 'io.gitlab.arturbosch.detekt' version '1.22.0' apply false id "com.vanniktech.maven.publish" version "0.25.3" + id 'com.android.library' version '7.4.2' apply false + id 'org.jetbrains.kotlin.android' version '1.5.21' apply false } diff --git a/floatingx/proguard-floatingx.pro b/floatingx/proguard-floatingx.pro index 6e44c7c4..f3c38b60 100644 --- a/floatingx/proguard-floatingx.pro +++ b/floatingx/proguard-floatingx.pro @@ -1,7 +1,7 @@ -dontwarn com.petterp.floatingx.** -keep public class com.petterp.floatingx.view.FxManagerView{*;} -keep public class com.petterp.floatingx.view.FxViewHolder{*;} --keep public class com.petterp.floatingx.util.FxScopeEnum{*;} +-keep public class com.petterp.floatingx.assist.FxScopeEnum{*;} -keep public class com.petterp.floatingx.assist.FxGravity{*;} -keep public class com.petterp.floatingx.util.FxScreenExtKt{ private boolean checkNavigationBarShow(android.content.Context); diff --git a/floatingx/src/main/java/com/petterp/floatingx/FloatingX.kt b/floatingx/src/main/java/com/petterp/floatingx/FloatingX.kt index 7f904c5a..c885bf14 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/FloatingX.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/FloatingX.kt @@ -3,7 +3,7 @@ package com.petterp.floatingx import android.annotation.SuppressLint import android.app.Activity import android.app.Application -import com.petterp.floatingx.assist.helper.AppHelper +import com.petterp.floatingx.assist.helper.FxAppHelper import com.petterp.floatingx.impl.control.FxAppControlImpl import com.petterp.floatingx.impl.lifecycle.FxLifecycleCallbackImpl import com.petterp.floatingx.impl.lifecycle.FxProxyLifecycleCallBackImpl @@ -29,8 +29,8 @@ object FloatingX { * 方法含义见 [install(helper: AppHelper)] */ @JvmSynthetic - inline fun install(obj: AppHelper.Builder.() -> Unit) = - install(AppHelper.builder().apply(obj).build()) + inline fun install(obj: FxAppHelper.Builder.() -> Unit) = + install(FxAppHelper.builder().apply(obj).build()) /** * 安装一个新的全局浮窗 @@ -41,7 +41,7 @@ object FloatingX { * */ @JvmStatic - fun install(helper: AppHelper): IFxAppControl { + fun install(helper: FxAppHelper): IFxAppControl { if (context == null) { throw NullPointerException("context == null, please call AppHelper.setContext(context) to set context") } diff --git a/floatingx/src/main/java/com/petterp/floatingx/util/FxAdsorbDirection.kt b/floatingx/src/main/java/com/petterp/floatingx/assist/FxAdsorbDirection.kt similarity index 75% rename from floatingx/src/main/java/com/petterp/floatingx/util/FxAdsorbDirection.kt rename to floatingx/src/main/java/com/petterp/floatingx/assist/FxAdsorbDirection.kt index 286da684..b3bab8fa 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/util/FxAdsorbDirection.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/assist/FxAdsorbDirection.kt @@ -1,4 +1,4 @@ -package com.petterp.floatingx.util +package com.petterp.floatingx.assist /** * Fx吸附方向 diff --git a/floatingx/src/main/java/com/petterp/floatingx/assist/FxDisplayMode.kt b/floatingx/src/main/java/com/petterp/floatingx/assist/FxDisplayMode.kt index 7ce5d3f5..a7abf017 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/assist/FxDisplayMode.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/assist/FxDisplayMode.kt @@ -12,5 +12,5 @@ enum class FxDisplayMode { ClickOnly, // 展示模式:只用于展示,不响应任何事件不能移动 - DisplayOnly + DisplayOnly, } diff --git a/floatingx/src/main/java/com/petterp/floatingx/util/FxScopeEnum.kt b/floatingx/src/main/java/com/petterp/floatingx/assist/FxScopeEnum.kt similarity index 64% rename from floatingx/src/main/java/com/petterp/floatingx/util/FxScopeEnum.kt rename to floatingx/src/main/java/com/petterp/floatingx/assist/FxScopeEnum.kt index 2adbc216..8be1457e 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/util/FxScopeEnum.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/assist/FxScopeEnum.kt @@ -1,9 +1,10 @@ -package com.petterp.floatingx.util +package com.petterp.floatingx.assist /** Fx插入的不同位置 */ enum class FxScopeEnum(val tag: String) { + SYSTEM("system"), APP_SCOPE("app"), ACTIVITY_SCOPE("activity"), FRAGMENT_SCOPE("fragment"), - VIEW_GROUP_SCOPE("view"), + VIEW_GROUP_SCOPE("view") } diff --git a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/AppHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxAppHelper.kt similarity index 94% rename from floatingx/src/main/java/com/petterp/floatingx/assist/helper/AppHelper.kt rename to floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxAppHelper.kt index 26d8fedc..39ba7d04 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/AppHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxAppHelper.kt @@ -5,12 +5,12 @@ import android.app.Application import android.content.Context import com.petterp.floatingx.FloatingX import com.petterp.floatingx.listener.IFxProxyTagActivityLifecycle -import com.petterp.floatingx.util.FxScopeEnum +import com.petterp.floatingx.assist.FxScopeEnum import com.petterp.floatingx.util.navigationBarHeight import com.petterp.floatingx.util.statusBarHeight -/** AppHelper构建器 */ -class AppHelper( +/** FxAppConfig 构建器 */ +class FxAppHelper( /** 浮窗tag,默认为 [FloatingX.FX_DEFAULT_TAG] */ @JvmSynthetic internal var tag: String, @@ -26,7 +26,7 @@ class AppHelper( /** 显示悬浮窗的Activity生命周期回调 */ @JvmSynthetic internal val fxLifecycleExpand: IFxProxyTagActivityLifecycle? -) : BasisHelper() { +) : FxBasisHelper() { @JvmSynthetic internal fun updateNavigationBar(activity: Activity?) { @@ -51,7 +51,7 @@ class AppHelper( (!isAllInstall && whiteInsertList.contains(cls)) } - class Builder : BasisHelper.Builder() { + class Builder : FxBasisHelper.Builder() { private var whiteInsertList: MutableList> = mutableListOf() private var blackFilterList: MutableList> = mutableListOf() private var fxLifecycleExpand: IFxProxyTagActivityLifecycle? = null @@ -147,8 +147,8 @@ class AppHelper( return this } - override fun buildHelper(): AppHelper = - AppHelper( + override fun buildHelper(): FxAppHelper = + FxAppHelper( tag, blackFilterList, whiteInsertList, @@ -156,7 +156,7 @@ class AppHelper( fxLifecycleExpand, ) - override fun build(): AppHelper { + override fun build(): FxAppHelper { return super.build().apply { enableFx = this@Builder.enableFx // 有可能用户会使用多个浮窗,这里为了防止日志混乱,将浮窗tag赋值给日志tag diff --git a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/BasisHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxBasisHelper.kt similarity index 99% rename from floatingx/src/main/java/com/petterp/floatingx/assist/helper/BasisHelper.kt rename to floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxBasisHelper.kt index 159ce647..51a18a8f 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/BasisHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxBasisHelper.kt @@ -3,6 +3,7 @@ package com.petterp.floatingx.assist.helper import android.view.View import android.widget.FrameLayout import androidx.annotation.LayoutRes +import com.petterp.floatingx.assist.FxAdsorbDirection import com.petterp.floatingx.assist.FxAnimation import com.petterp.floatingx.assist.FxBorderMargin import com.petterp.floatingx.assist.FxDisplayMode @@ -10,12 +11,11 @@ import com.petterp.floatingx.assist.FxGravity import com.petterp.floatingx.listener.IFxConfigStorage import com.petterp.floatingx.listener.IFxScrollListener import com.petterp.floatingx.listener.IFxViewLifecycle -import com.petterp.floatingx.util.FxAdsorbDirection import com.petterp.floatingx.util.FxLog import kotlin.math.abs /** 通用构建器helper */ -open class BasisHelper { +open class FxBasisHelper { @JvmField internal var layoutId: Int = 0 @@ -113,7 +113,7 @@ open class BasisHelper { fxAnimation?.cancelAnimation() } - abstract class Builder { + abstract class Builder { @LayoutRes private var layoutId: Int = 0 private var layoutView: View? = null diff --git a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/ScopeHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxScopeHelper.kt similarity index 88% rename from floatingx/src/main/java/com/petterp/floatingx/assist/helper/ScopeHelper.kt rename to floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxScopeHelper.kt index 25058608..86d5d484 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/ScopeHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxScopeHelper.kt @@ -5,11 +5,11 @@ import android.widget.FrameLayout import androidx.fragment.app.Fragment import com.petterp.floatingx.impl.control.FxScopeControl import com.petterp.floatingx.listener.control.IFxScopeControl -import com.petterp.floatingx.util.FxScopeEnum +import com.petterp.floatingx.assist.FxScopeEnum import com.petterp.floatingx.util.contentView /** 特定范围的Helper构建器 */ -class ScopeHelper : BasisHelper() { +class FxScopeHelper : FxBasisHelper() { /** 插入到Activity中 */ fun toControl(activity: Activity): IFxScopeControl { @@ -49,7 +49,7 @@ class ScopeHelper : BasisHelper() { inline fun build(obj: Builder.() -> Unit) = builder().apply(obj).build() } - class Builder : BasisHelper.Builder() { - override fun buildHelper(): ScopeHelper = ScopeHelper() + class Builder : FxBasisHelper.Builder() { + override fun buildHelper(): FxScopeHelper = FxScopeHelper() } } diff --git a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxSystemHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxSystemHelper.kt new file mode 100644 index 00000000..3f881aa0 --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxSystemHelper.kt @@ -0,0 +1,21 @@ +package com.petterp.floatingx.assist.helper + +/** + * FxSystemConfig 构建器 + * @author petterp + */ +class FxSystemHelper : FxBasisHelper() { + + class Builder : FxBasisHelper.Builder() { + override fun buildHelper(): FxSystemHelper = FxSystemHelper() + + override fun build(): FxSystemHelper { + return super.build() + } + } + + companion object { + @JvmStatic + fun builder() = Builder() + } +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxAppControlImpl.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxAppControlImpl.kt index ef0a13a2..a276adef 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxAppControlImpl.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxAppControlImpl.kt @@ -8,7 +8,7 @@ import android.view.ViewGroup import androidx.core.view.OnApplyWindowInsetsListener import androidx.core.view.ViewCompat import com.petterp.floatingx.FloatingX -import com.petterp.floatingx.assist.helper.AppHelper +import com.petterp.floatingx.assist.helper.FxAppHelper import com.petterp.floatingx.impl.lifecycle.FxProxyLifecycleCallBackImpl import com.petterp.floatingx.listener.control.IFxAppControl import com.petterp.floatingx.util.decorView @@ -16,7 +16,7 @@ import com.petterp.floatingx.util.topActivity /** 全局控制器 */ class FxAppControlImpl( - private val helper: AppHelper, + private val helper: FxAppHelper, private val proxyLifecycleImpl: FxProxyLifecycleCallBackImpl, ) : FxBasisControlImpl(helper), IFxAppControl, @@ -38,7 +38,7 @@ class FxAppControlImpl( override fun show(activity: Activity) { if (!helper.isCanInstall(activity) || isShow()) return if (attach(activity)) { - getManagerView()?.show() + internalShow() updateEnableStatus(true) FloatingX.checkAppLifecycleInstall() } diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxBasisControlImpl.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxBasisControlImpl.kt index 299b5d1e..82b3e7b1 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxBasisControlImpl.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxBasisControlImpl.kt @@ -3,11 +3,13 @@ package com.petterp.floatingx.impl.control import android.content.Context import android.view.View import android.view.ViewGroup +import android.widget.FrameLayout import androidx.annotation.LayoutRes import androidx.core.view.ViewCompat +import com.petterp.floatingx.assist.FxAdsorbDirection import com.petterp.floatingx.assist.FxAnimation import com.petterp.floatingx.assist.FxDisplayMode -import com.petterp.floatingx.assist.helper.BasisHelper +import com.petterp.floatingx.assist.helper.FxBasisHelper import com.petterp.floatingx.listener.IFxConfigStorage import com.petterp.floatingx.listener.IFxScrollListener import com.petterp.floatingx.listener.IFxViewLifecycle @@ -15,30 +17,27 @@ import com.petterp.floatingx.listener.control.IFxConfigControl import com.petterp.floatingx.listener.control.IFxControl import com.petterp.floatingx.listener.provider.IFxContextProvider import com.petterp.floatingx.listener.provider.IFxHolderProvider -import com.petterp.floatingx.util.FxAdsorbDirection import com.petterp.floatingx.util.lazyLoad import com.petterp.floatingx.view.FxManagerView import com.petterp.floatingx.view.FxViewHolder +import com.petterp.floatingx.view.IFxInternalViewControl import java.lang.ref.WeakReference /** Fx基础控制器实现 */ -open class FxBasisControlImpl(private val helper: BasisHelper) : IFxControl, IFxConfigControl { - private var managerView: FxManagerView? = null +open class FxBasisControlImpl(private val helper: FxBasisHelper) : IFxControl, IFxConfigControl { private var viewHolder: FxViewHolder? = null private var mContainer: WeakReference? = null + private var internalViewControl: IFxInternalViewControl? = null private val cancelAnimationRunnable by lazyLoad { Runnable { reset() } } private val hideAnimationRunnable by lazyLoad { Runnable { detach() } } - /* - * 控制接口相关实现 - * */ override val configControl: IFxConfigControl get() = this override fun cancel() { - if ((managerView == null && viewHolder == null)) return + if ((getManagerView() == null && viewHolder == null)) return if (isShow() && helper.enableAnimation && helper.fxAnimation != null) { - managerView?.removeCallbacks(cancelAnimationRunnable) - val duration = helper.fxAnimation!!.toEndAnimator(managerView) + getManagerView()?.removeCallbacks(cancelAnimationRunnable) + val duration = helper.fxAnimation!!.toEndAnimator(internalViewControl?.containerView) animatorCallback(duration, cancelAnimationRunnable) } else { reset() @@ -54,22 +53,24 @@ open class FxBasisControlImpl(private val helper: BasisHelper) : IFxControl, IFx return } helper.fxLog?.d("fxView->Animation ,endAnimation Running") - managerView?.removeCallbacks(hideAnimationRunnable) - val duration = helper.fxAnimation!!.toEndAnimator(managerView) + getManagerView()?.removeCallbacks(hideAnimationRunnable) + val duration = helper.fxAnimation!!.toEndAnimator(getManagerView()) animatorCallback(duration, hideAnimationRunnable) } else { detach() } } - override fun isShow(): Boolean = - managerView != null && ViewCompat.isAttachedToWindow(managerView!!) && managerView!!.visibility == View.VISIBLE + override fun isShow(): Boolean { + val managerView = getManagerView() ?: return false + return ViewCompat.isAttachedToWindow(managerView) && managerView.visibility == View.VISIBLE + } - override fun getView(): View? = managerView?.childFxView + override fun getView(): View? = internalViewControl?.childView override fun getViewHolder(): FxViewHolder? = viewHolder - override fun getManagerView(): FxManagerView? = managerView + override fun getManagerView(): FrameLayout? = internalViewControl?.containerView override fun updateView(@LayoutRes resource: Int) { if (resource == 0) throw IllegalArgumentException("resource cannot be 0!") @@ -109,11 +110,11 @@ open class FxBasisControlImpl(private val helper: BasisHelper) : IFxControl, IFx } override fun move(x: Float, y: Float, useAnimation: Boolean) { - managerView?.moveLocation(x, y, useAnimation) + internalViewControl?.moveLocation(x, y, useAnimation) } override fun moveByVector(x: Float, y: Float, useAnimation: Boolean) { - managerView?.moveLocationByVector(x, y, useAnimation) + internalViewControl?.moveLocationByVector(x, y, useAnimation) } /* @@ -139,27 +140,27 @@ open class FxBasisControlImpl(private val helper: BasisHelper) : IFxControl, IFx this.b = b this.r = r } - managerView?.moveToEdge() + internalViewControl?.moveToEdge() } override fun setEnableEdgeAdsorption(isEnable: Boolean) { helper.enableEdgeAdsorption = isEnable - managerView?.moveToEdge() + internalViewControl?.moveToEdge() } override fun setEdgeAdsorbDirection(direction: FxAdsorbDirection) { helper.adsorbDirection = direction - managerView?.moveToEdge() + internalViewControl?.moveToEdge() } override fun setEdgeOffset(edgeOffset: Float) { helper.edgeOffset = edgeOffset - managerView?.moveToEdge() + internalViewControl?.moveToEdge() } override fun setEnableEdgeRebound(isEnable: Boolean) { helper.enableEdgeRebound = isEnable - managerView?.moveToEdge() + internalViewControl?.moveToEdge() } override fun setScrollListener(listener: IFxScrollListener) { @@ -190,7 +191,11 @@ open class FxBasisControlImpl(private val helper: BasisHelper) : IFxControl, IFx override fun setDisplayMode(mode: FxDisplayMode) { helper.displayMode = mode - managerView?.updateDisplayMode() + } + + @JvmSynthetic + internal fun setContainerGroup(viewGroup: ViewGroup) { + mContainer = WeakReference(viewGroup) } /* @@ -199,23 +204,23 @@ open class FxBasisControlImpl(private val helper: BasisHelper) : IFxControl, IFx protected open fun updateMangerView(@LayoutRes layout: Int = 0) { helper.layoutId = layout if (getContainerGroup() == null) throw NullPointerException("FloatingX window The parent container cannot be null!") - val x = managerView?.x ?: 0f - val y = managerView?.y ?: 0f + val x = internalViewControl?.getX() ?: 0f + val y = internalViewControl?.getY() ?: 0f initManagerView() - managerView?.restoreLocation(x, y) - getContainerGroup()?.addView(managerView) + internalViewControl?.restoreLocation(x, y) + getContainerGroup()?.addView(getManagerView()) } protected fun initManagerView() { if (helper.layoutId == 0 && helper.layoutView == null) throw RuntimeException("The layout id cannot be 0 ,and layoutView==null") - getContainerGroup()?.removeView(managerView) + getContainerGroup()?.removeView(getManagerView()) initManager() } protected open fun initManager() { val context = context() ?: return - managerView = FxManagerView(context).init(helper) - val fxContentView = managerView?.childFxView ?: return + internalViewControl = FxManagerView(context).initView(helper) + val fxContentView = internalViewControl?.childView ?: return viewHolder = FxViewHolder(fxContentView) val fxViewLifecycle = helper.iFxViewLifecycle ?: return // 后续此方法将会移除,建议进行过渡 @@ -223,9 +228,9 @@ open class FxBasisControlImpl(private val helper: BasisHelper) : IFxControl, IFx fxViewLifecycle.initView(viewHolder!!) } - protected fun getOrInitManagerView(): FxManagerView? { - if (managerView == null) initManagerView() - return managerView + protected fun getOrInitManagerView(): FrameLayout? { + if (getManagerView() == null) initManagerView() + return getManagerView() } protected fun getContainerGroup(): ViewGroup? { @@ -233,10 +238,10 @@ open class FxBasisControlImpl(private val helper: BasisHelper) : IFxControl, IFx } protected open fun detach(container: ViewGroup?) { - if (managerView != null && container != null) { + if (internalViewControl != null && container != null) { helper.fxLog?.d("fxView-lifecycle-> code->removeView") helper.iFxViewLifecycle?.postDetached() - container.removeView(managerView) + container.removeView(getManagerView()) } } @@ -258,27 +263,13 @@ open class FxBasisControlImpl(private val helper: BasisHelper) : IFxControl, IFx mContainer = null } - @JvmSynthetic - protected fun FxManagerView.show() { - helper.enableFx = true - visibility = View.VISIBLE - val fxAnimation = helper.fxAnimation ?: return - if (helper.enableAnimation) { - if (fxAnimation.fromJobIsRunning()) { - helper.fxLog?.d("fxView->Animation ,startAnimation Executing, cancel this operation!") - return - } - helper.fxLog?.d("fxView->Animation ,startAnimation Executing, cancel this operation.") - fxAnimation.fromStartAnimator(this) - } - } - - @JvmSynthetic protected open fun reset() { - managerView?.removeCallbacks(hideAnimationRunnable) - managerView?.removeCallbacks(cancelAnimationRunnable) + getManagerView()?.apply { + removeCallbacks(hideAnimationRunnable) + removeCallbacks(cancelAnimationRunnable) + } detach(mContainer?.get()) - managerView = null + internalViewControl = null viewHolder = null helper.clear() clearContainer() @@ -291,12 +282,23 @@ open class FxBasisControlImpl(private val helper: BasisHelper) : IFxControl, IFx helper.enableFx = newStatus } - internal fun setContainerGroup(viewGroup: ViewGroup) { - mContainer = WeakReference(viewGroup) + protected open fun internalShow() { + val managerView = getManagerView() ?: return + helper.enableFx = true + managerView.visibility = View.VISIBLE + val fxAnimation = helper.fxAnimation ?: return + if (helper.enableAnimation) { + if (fxAnimation.fromJobIsRunning()) { + helper.fxLog?.d("fxView->Animation ,startAnimation Executing, cancel this operation!") + return + } + helper.fxLog?.d("fxView->Animation ,startAnimation Executing, cancel this operation.") + fxAnimation.fromStartAnimator(managerView) + } } private fun animatorCallback(long: Long, runnable: Runnable) { - val magnetView = managerView ?: return + val magnetView = getManagerView() ?: return magnetView.removeCallbacks(runnable) magnetView.postDelayed(runnable, long) } diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxScopeControl.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxScopeControl.kt index 1f926fd3..5a71d9ca 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxScopeControl.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxScopeControl.kt @@ -3,11 +3,11 @@ package com.petterp.floatingx.impl.control import android.app.Application import android.view.View import androidx.core.view.ViewCompat -import com.petterp.floatingx.assist.helper.BasisHelper +import com.petterp.floatingx.assist.helper.FxBasisHelper import com.petterp.floatingx.listener.control.IFxScopeControl /** Fx普通View控制器 */ -class FxScopeControl(helper: BasisHelper) : +class FxScopeControl(helper: FxBasisHelper) : FxBasisControlImpl(helper), IFxScopeControl { @@ -18,12 +18,12 @@ class FxScopeControl(helper: BasisHelper) : if (!ViewCompat.isAttachedToWindow(managerView)) { getContainerGroup()?.addView(managerView) } - managerView.show() + internalShow() } override fun updateView(view: View) { if (view.context is Application) { - throw IllegalArgumentException("view == Application,Scope floating windows cannot use application-level views!") + throw IllegalArgumentException("view = Application,Scope floating windows cannot use application-level views!") } super.updateView(view) } diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxProxyLifecycleCallBackImpl.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxProxyLifecycleCallBackImpl.kt index 73c2bfdc..0c7723ee 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxProxyLifecycleCallBackImpl.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxProxyLifecycleCallBackImpl.kt @@ -3,7 +3,7 @@ package com.petterp.floatingx.impl.lifecycle import android.app.Activity import android.app.Application import android.os.Bundle -import com.petterp.floatingx.assist.helper.AppHelper +import com.petterp.floatingx.assist.helper.FxAppHelper import com.petterp.floatingx.impl.control.FxAppControlImpl import com.petterp.floatingx.listener.IFxProxyTagActivityLifecycle import com.petterp.floatingx.util.FxLog @@ -17,7 +17,7 @@ import com.petterp.floatingx.util.lazyLoad */ class FxProxyLifecycleCallBackImpl : Application.ActivityLifecycleCallbacks { - private var helper: AppHelper? = null + private var helper: FxAppHelper? = null private var appControl: FxAppControlImpl? = null private val fxLog: FxLog? @@ -45,7 +45,7 @@ class FxProxyLifecycleCallBackImpl : Application.ActivityLifecycleCallbacks { } /** 初始化helper与app控制器 */ - fun init(helper: AppHelper, control: FxAppControlImpl) { + fun init(helper: FxAppHelper, control: FxAppControlImpl) { this.helper = helper this.appControl = control } diff --git a/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxConfigControl.kt b/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxConfigControl.kt index b418d960..2ecbc25d 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxConfigControl.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxConfigControl.kt @@ -5,7 +5,7 @@ import com.petterp.floatingx.assist.FxDisplayMode import com.petterp.floatingx.listener.IFxConfigStorage import com.petterp.floatingx.listener.IFxScrollListener import com.petterp.floatingx.listener.IFxViewLifecycle -import com.petterp.floatingx.util.FxAdsorbDirection +import com.petterp.floatingx.assist.FxAdsorbDirection /** * 配置更改接口,使用此接口运行时更改配置层 diff --git a/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxControl.kt b/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxControl.kt index d318af47..0a916182 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxControl.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxControl.kt @@ -1,10 +1,10 @@ package com.petterp.floatingx.listener.control import android.view.View +import android.widget.FrameLayout import androidx.annotation.LayoutRes import com.petterp.floatingx.listener.provider.IFxContextProvider import com.petterp.floatingx.listener.provider.IFxHolderProvider -import com.petterp.floatingx.view.FxManagerView import com.petterp.floatingx.view.FxViewHolder /** FloatingX 基础控制器 */ @@ -33,7 +33,7 @@ interface IFxControl { fun getViewHolder(): FxViewHolder? /** 获取浮窗管理器view,即浮窗底层容器 */ - fun getManagerView(): FxManagerView? + fun getManagerView(): FrameLayout? /** 用于快速刷新视图内容 */ fun updateViewContent(provider: IFxHolderProvider) diff --git a/floatingx/src/main/java/com/petterp/floatingx/util/FxExt.kt b/floatingx/src/main/java/com/petterp/floatingx/util/FxExt.kt index b6c2368b..49401e09 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/util/FxExt.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/util/FxExt.kt @@ -1,10 +1,12 @@ package com.petterp.floatingx.util +import android.os.Handler +import android.os.Looper import android.app.Activity import android.content.Context import android.content.ContextWrapper import android.view.MotionEvent -import com.petterp.floatingx.assist.helper.ScopeHelper +import com.petterp.floatingx.assist.helper.FxScopeHelper import java.lang.Exception @JvmSynthetic @@ -22,6 +24,7 @@ internal const val INVALID_TOUCH_ID = -1 internal const val INVALID_LAYOUT_ID = 0 internal const val INVALID_TOUCH_IDX = -1 internal const val DEFAULT_MOVE_ANIMATOR_DURATION = 200L +internal val HANDLER = Handler(Looper.getMainLooper()) /** * 创建一个fx,自行初始化并控制插入位置 @@ -35,9 +38,9 @@ internal const val DEFAULT_MOVE_ANIMATOR_DURATION = 200L * } */ @JvmSynthetic -inline fun createFx(crossinline obj: ScopeHelper.Builder.() -> T) = +inline fun createFx(crossinline obj: FxScopeHelper.Builder.() -> T) = lazy(LazyThreadSafetyMode.NONE) { - ScopeHelper.Builder().run(obj) + FxScopeHelper.Builder().run(obj) } @JvmSynthetic diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/FxClickHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/view/FxClickHelper.kt index 76b3c2b0..e2b5511f 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/FxClickHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/FxClickHelper.kt @@ -1,7 +1,7 @@ package com.petterp.floatingx.view import androidx.annotation.Keep -import com.petterp.floatingx.assist.helper.BasisHelper +import com.petterp.floatingx.assist.helper.FxBasisHelper import com.petterp.floatingx.util.TOUCH_CLICK_OFFSET import com.petterp.floatingx.util.TOUCH_TIME_THRESHOLD import kotlin.math.abs @@ -16,9 +16,9 @@ class FxClickHelper { private var isClickEvent = false private var clickEnable = true private var mLastTouchDownTime = 0L - private lateinit var helper: BasisHelper + private lateinit var helper: FxBasisHelper - fun initConfig(helper: BasisHelper) { + fun initConfig(helper: FxBasisHelper) { reset() this.helper = helper } diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/FxLocationHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/view/FxLocationHelper.kt index 5b1602d0..59fbf8f5 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/FxLocationHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/FxLocationHelper.kt @@ -1,7 +1,7 @@ package com.petterp.floatingx.view import android.content.res.Configuration -import com.petterp.floatingx.assist.helper.BasisHelper +import com.petterp.floatingx.assist.helper.FxBasisHelper import com.petterp.floatingx.util.coerceInFx /** diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/IFxInternalViewControl.kt b/floatingx/src/main/java/com/petterp/floatingx/view/IFxInternalViewControl.kt new file mode 100644 index 00000000..35df2256 --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/view/IFxInternalViewControl.kt @@ -0,0 +1,27 @@ +package com.petterp.floatingx.view + +import android.view.View +import android.widget.FrameLayout + +/** + * + * @author petterp + */ +internal interface IFxInternalViewControl { + + val containerView: FrameLayout + + val childView: View? + + fun moveLocation(x: Float, y: Float, useAnimation: Boolean = true) + + fun moveLocationByVector(x: Float, y: Float, useAnimation: Boolean = true) + + fun moveToEdge() + + fun getX(): Float + + fun getY(): Float + + fun restoreLocation(x: Float, y: Float) +} From 7e1c89d29ba439ee87f1c45564fe9061b8392b4a Mon Sep 17 00:00:00 2001 From: petterp Date: Sun, 5 Nov 2023 20:50:33 +0800 Subject: [PATCH 2/8] =?UTF-8?q?perf:=E4=BC=98=E5=8C=96=E6=B5=AE=E7=AA=97vi?= =?UTF-8?q?ew=E7=9A=84=E5=B0=81=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- floatingx/src/main/java/com/petterp/floatingx/util/FxExt.kt | 4 ++-- .../src/main/java/com/petterp/floatingx/view/FxViewHolder.kt | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/floatingx/src/main/java/com/petterp/floatingx/util/FxExt.kt b/floatingx/src/main/java/com/petterp/floatingx/util/FxExt.kt index 49401e09..7f855ff7 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/util/FxExt.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/util/FxExt.kt @@ -1,10 +1,10 @@ package com.petterp.floatingx.util -import android.os.Handler -import android.os.Looper import android.app.Activity import android.content.Context import android.content.ContextWrapper +import android.os.Handler +import android.os.Looper import android.view.MotionEvent import com.petterp.floatingx.assist.helper.FxScopeHelper import java.lang.Exception diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/FxViewHolder.kt b/floatingx/src/main/java/com/petterp/floatingx/view/FxViewHolder.kt index 26150452..622fb4fe 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/FxViewHolder.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/FxViewHolder.kt @@ -31,7 +31,9 @@ class FxViewHolder(private val itemView: View?) { views.put(viewId, it) it } - } else view as? T + } else { + view as? T + } } fun setOnClickListener(@IdRes viewId: Int, listener: OnClickListener): FxViewHolder { From 2e006415f8be309773bc0b643905c109f3322c94 Mon Sep 17 00:00:00 2001 From: petterp Date: Sun, 19 Nov 2023 14:18:43 +0800 Subject: [PATCH 3/8] =?UTF-8?q?perf:=E9=87=8D=E6=9E=84fx=E7=9A=84=E5=B0=81?= =?UTF-8?q?=E8=A3=85=E9=80=BB=E8=BE=91=EF=BC=8C=E9=A2=84=E6=94=AF=E6=8C=81?= =?UTF-8?q?system=E6=B5=AE=E7=AA=97=E5=87=86=E5=A4=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 2 + .../com/petterp/floatingx/app/MainActivity.kt | 70 ++++++------- .../app/java/CustomJavaApplication.java | 4 +- .../app/kotlin/CustomKtApplication.kt | 5 +- .../floatingx/app/test/BlackActivity.kt | 2 +- .../floatingx/app/test/ImmersedActivity.kt | 20 ++-- .../floatingx/app/test/MultipleFxActivity.kt | 6 +- .../floatingx/app/test/ScopeActivity.kt | 2 +- .../floatingx/app/test/SimpleRvActivity.kt | 2 +- floatingx/proguard-floatingx.pro | 2 +- floatingx/src/main/AndroidManifest.xml | 12 ++- .../java/com/petterp/floatingx/FloatingX.kt | 78 ++++----------- .../floatingx/assist/FxContentProvider.kt | 41 ++++++++ .../petterp/floatingx/assist/FxScopeEnum.kt | 11 +-- .../floatingx/assist/helper/FxAppHelper.kt | 40 ++++++-- .../floatingx/assist/helper/FxBasisHelper.kt | 1 + .../floatingx/assist/helper/FxScopeHelper.kt | 10 +- .../floatingx/assist/helper/FxSystemHelper.kt | 21 ---- .../impl/control/FxAppControlImpl.kt | 89 +++++++++-------- .../impl/control/FxBasisControlImpl.kt | 56 +++++------ .../impl/control/FxSystemControlImpl.kt | 22 +++++ .../impl/lifecycle/FxAppLifecycleProvider.kt | 48 +++++++++ .../impl/lifecycle/FxLifecycleCallbackImpl.kt | 97 ------------------- ...cycleImpl.kt => FxProxyTagLifecycleImp.kt} | 2 +- ...llBackImpl.kt => FxTempAppLifecycleImp.kt} | 2 +- .../listener/control/IFxAppControl.kt | 7 +- .../listener/control/IFxSystemControl.kt | 9 ++ .../java/com/petterp/floatingx/util/FxExt.kt | 41 +++++--- .../com/petterp/floatingx/util/FxScreenExt.kt | 2 + .../com/petterp/floatingx/util/FxUiExt.kt | 23 ----- ...ernalViewControl.kt => IFxInternalView.kt} | 8 +- .../view/{ => default}/FxClickHelper.kt | 4 +- .../FxDefaultContainerView.kt} | 61 ++++++------ .../view/{ => default}/FxLocationHelper.kt | 6 +- .../view/{ => default}/FxViewConfigHelper.kt | 10 +- .../view/system/FxSystemContainerView.kt | 38 ++++++++ 36 files changed, 446 insertions(+), 408 deletions(-) create mode 100644 floatingx/src/main/java/com/petterp/floatingx/assist/FxContentProvider.kt delete mode 100644 floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxSystemHelper.kt create mode 100644 floatingx/src/main/java/com/petterp/floatingx/impl/control/FxSystemControlImpl.kt create mode 100644 floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxAppLifecycleProvider.kt delete mode 100644 floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxLifecycleCallbackImpl.kt rename floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/{FxTagActivityLifecycleImpl.kt => FxProxyTagLifecycleImp.kt} (89%) rename floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/{FxProxyLifecycleCallBackImpl.kt => FxTempAppLifecycleImp.kt} (98%) create mode 100644 floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxSystemControl.kt delete mode 100644 floatingx/src/main/java/com/petterp/floatingx/util/FxUiExt.kt rename floatingx/src/main/java/com/petterp/floatingx/view/{IFxInternalViewControl.kt => IFxInternalView.kt} (73%) rename floatingx/src/main/java/com/petterp/floatingx/view/{ => default}/FxClickHelper.kt (94%) rename floatingx/src/main/java/com/petterp/floatingx/view/{FxManagerView.kt => default/FxDefaultContainerView.kt} (87%) rename floatingx/src/main/java/com/petterp/floatingx/view/{ => default}/FxLocationHelper.kt (94%) rename floatingx/src/main/java/com/petterp/floatingx/view/{ => default}/FxViewConfigHelper.kt (94%) create mode 100644 floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt diff --git a/app/build.gradle b/app/build.gradle index c2c91246..d894d171 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -65,6 +65,7 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(path: ':floatingx') detektPlugins 'io.gitlab.arturbosch.detekt:detekt-formatting:1.22.0' implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation 'androidx.appcompat:appcompat:1.2.0' @@ -75,4 +76,5 @@ dependencies { // debugImplementation 'com.squareup.leakcanary:leakcanary-object-watcher-android-startup:2.10' implementation isDev ? project(path: ':floatingx') : "io.github.petterpx:floatingx:$version_name" debugImplementation "com.bytedance.tools.codelocator:codelocator-core:2.0.3" + implementation 'com.github.princekin-f:EasyFloat:2.0.4' } \ No newline at end of file diff --git a/app/src/main/java/com/petterp/floatingx/app/MainActivity.kt b/app/src/main/java/com/petterp/floatingx/app/MainActivity.kt index 8fb5e5c7..cafd6ee2 100644 --- a/app/src/main/java/com/petterp/floatingx/app/MainActivity.kt +++ b/app/src/main/java/com/petterp/floatingx/app/MainActivity.kt @@ -38,7 +38,7 @@ class MainActivity : AppCompatActivity() { addNestedScrollView { addLinearLayout { addItemView("显示全局悬浮窗") { - FloatingX.control(MultipleFxActivity.TAG_1).show(this@MainActivity) + FloatingX.control(MultipleFxActivity.TAG_1).show() } addItemView("隐藏全局悬浮窗") { FloatingX.control(MultipleFxActivity.TAG_1).hide() @@ -49,7 +49,7 @@ class MainActivity : AppCompatActivity() { this.updateViewContent { it.setText(R.id.tvItemFx, "App") } - }.show(this@MainActivity) + }.show() } addItemView("更新当前[全局浮窗]内容-(传递view方式)") { FloatingX.control(MultipleFxActivity.TAG_1).apply { @@ -62,7 +62,7 @@ class MainActivity : AppCompatActivity() { setBackgroundColor(Color.GRAY) } } - show(this@MainActivity) + show() } } addItemView("显示一个Activity悬浮窗-(展示与多指触摸)") { @@ -137,35 +137,35 @@ class MainActivity : AppCompatActivity() { } } -class ItemViewTouchListener(val wl: WindowManager.LayoutParams, val windowManager: WindowManager) : - View.OnTouchListener { - private var x = 0 - private var y = 0 - override fun onTouch(view: View, motionEvent: MotionEvent): Boolean { - when (motionEvent.action) { - MotionEvent.ACTION_DOWN -> { - x = motionEvent.rawX.toInt() - y = motionEvent.rawY.toInt() - } - - MotionEvent.ACTION_MOVE -> { - val nowX = motionEvent.rawX.toInt() - val nowY = motionEvent.rawY.toInt() - val movedX = nowX - x - val movedY = nowY - y - x = nowX - y = nowY - wl.apply { - x += movedX - y += movedY - } - // 更新悬浮球控件位置 - windowManager?.updateViewLayout(view, wl) - } - - else -> { - } - } - return false - } -} +// class ItemViewTouchListener(val wl: WindowManager.LayoutParams, val windowManager: WindowManager) : +// View.OnTouchListener { +// private var x = 0 +// private var y = 0 +// override fun onTouch(view: View, motionEvent: MotionEvent): Boolean { +// when (motionEvent.action) { +// MotionEvent.ACTION_DOWN -> { +// x = motionEvent.rawX.toInt() +// y = motionEvent.rawY.toInt() +// } +// +// MotionEvent.ACTION_MOVE -> { +// val nowX = motionEvent.rawX.toInt() +// val nowY = motionEvent.rawY.toInt() +// val movedX = nowX - x +// val movedY = nowY - y +// x = nowX +// y = nowY +// wl.apply { +// x += movedX +// y += movedY +// } +// // 更新悬浮球控件位置 +// windowManager?.updateViewLayout(view, wl) +// } +// +// else -> { +// } +// } +// return false +// } +// } diff --git a/app/src/main/java/com/petterp/floatingx/app/java/CustomJavaApplication.java b/app/src/main/java/com/petterp/floatingx/app/java/CustomJavaApplication.java index 651578a8..0a756367 100644 --- a/app/src/main/java/com/petterp/floatingx/app/java/CustomJavaApplication.java +++ b/app/src/main/java/com/petterp/floatingx/app/java/CustomJavaApplication.java @@ -14,7 +14,7 @@ import com.petterp.floatingx.assist.FxDisplayMode; import com.petterp.floatingx.assist.helper.FxAppHelper; import com.petterp.floatingx.assist.helper.FxScopeHelper; -import com.petterp.floatingx.impl.lifecycle.FxTagActivityLifecycleImpl; +import com.petterp.floatingx.impl.lifecycle.FxProxyTagLifecycleImp; /** * java 中的配置示例 @@ -69,7 +69,7 @@ public void onCreate() { // 设置浮窗展示类型,默认可移动可点击,无需配置 .setDisplayMode(FxDisplayMode.Normal) //启用悬浮窗,即默认会插入到允许的activity中 - .setTagActivityLifecycle(new FxTagActivityLifecycleImpl() { + .setTagActivityLifecycle(new FxProxyTagLifecycleImp() { @Override public void onCreated(@NonNull Activity activity, @Nullable Bundle bundle) { // 允许插入的浮窗activity执行到onCreated时会回调相应方法 diff --git a/app/src/main/java/com/petterp/floatingx/app/kotlin/CustomKtApplication.kt b/app/src/main/java/com/petterp/floatingx/app/kotlin/CustomKtApplication.kt index 20f283fd..355c6c31 100644 --- a/app/src/main/java/com/petterp/floatingx/app/kotlin/CustomKtApplication.kt +++ b/app/src/main/java/com/petterp/floatingx/app/kotlin/CustomKtApplication.kt @@ -20,7 +20,7 @@ import com.petterp.floatingx.app.test.MultipleFxActivity import com.petterp.floatingx.assist.FxDisplayMode import com.petterp.floatingx.assist.FxGravity import com.petterp.floatingx.impl.FxScrollImpl -import com.petterp.floatingx.impl.lifecycle.FxTagActivityLifecycleImpl +import com.petterp.floatingx.impl.lifecycle.FxProxyTagLifecycleImp import com.petterp.floatingx.listener.IFxViewLifecycle /** Kotlin-Application */ @@ -97,7 +97,7 @@ class CustomKtApplication : Application() { Toast.makeText(context, "浮窗被点击", Toast.LENGTH_SHORT).show() } // 设置tag-Activity生命周期回调时的触发 - setTagActivityLifecycle(object : FxTagActivityLifecycleImpl() { + setTagActivityLifecycle(object : FxProxyTagLifecycleImp() { override fun onCreated(activity: Activity, bundle: Bundle?) { // 允许插入的浮窗activity执行到onCreated时会回调相应方法 } @@ -139,6 +139,7 @@ class CustomKtApplication : Application() { fun installTag2(context: Application) { FloatingX.install { + setContext(context) setLayoutView( CardView(context).apply { setCardBackgroundColor(Color.GRAY) diff --git a/app/src/main/java/com/petterp/floatingx/app/test/BlackActivity.kt b/app/src/main/java/com/petterp/floatingx/app/test/BlackActivity.kt index 7b1f097f..6c8076ab 100644 --- a/app/src/main/java/com/petterp/floatingx/app/test/BlackActivity.kt +++ b/app/src/main/java/com/petterp/floatingx/app/test/BlackActivity.kt @@ -17,7 +17,7 @@ class BlackActivity : AppCompatActivity() { textSize = 50f } addItemView("显示全局悬浮窗") { - FloatingX.control(MultipleFxActivity.TAG_1).show(this@BlackActivity) + FloatingX.control(MultipleFxActivity.TAG_1).show() } } } diff --git a/app/src/main/java/com/petterp/floatingx/app/test/ImmersedActivity.kt b/app/src/main/java/com/petterp/floatingx/app/test/ImmersedActivity.kt index cb74e1a3..4ed8aaba 100644 --- a/app/src/main/java/com/petterp/floatingx/app/test/ImmersedActivity.kt +++ b/app/src/main/java/com/petterp/floatingx/app/test/ImmersedActivity.kt @@ -1,12 +1,8 @@ package com.petterp.floatingx.app.test -import android.graphics.Color import android.os.Bundle -import android.view.View import android.view.Window -import android.view.WindowManager import androidx.appcompat.app.AppCompatActivity -import com.petterp.floatingx.app.createLinearLayoutToParent /** 全屏Activity */ class ImmersedActivity : AppCompatActivity() { @@ -14,13 +10,13 @@ class ImmersedActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) requestWindowFeature(Window.FEATURE_NO_TITLE) // 这行代码一定要在setContentView之前,不然会闪退 - createLinearLayoutToParent { - window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) - window.decorView.systemUiVisibility = ( - View.SYSTEM_UI_FLAG_LAYOUT_STABLE // 防止状态栏、底部导航栏隐藏时,内容区域大小发生变化 - or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - ) // Activity会全屏显示,但状态栏不会被隐藏,状态栏依然可见,Activity 顶端布局部分会被状态栏盖住 - window.statusBarColor = Color.TRANSPARENT - } +// createLinearLayoutToParent { +// window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) +// window.decorView.systemUiVisibility = ( +// View.SYSTEM_UI_FLAG_LAYOUT_STABLE // 防止状态栏、底部导航栏隐藏时,内容区域大小发生变化 +// or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN +// ) // Activity会全屏显示,但状态栏不会被隐藏,状态栏依然可见,Activity 顶端布局部分会被状态栏盖住 +// window.statusBarColor = Color.TRANSPARENT +// } } } diff --git a/app/src/main/java/com/petterp/floatingx/app/test/MultipleFxActivity.kt b/app/src/main/java/com/petterp/floatingx/app/test/MultipleFxActivity.kt index 7f536d32..35696e06 100644 --- a/app/src/main/java/com/petterp/floatingx/app/test/MultipleFxActivity.kt +++ b/app/src/main/java/com/petterp/floatingx/app/test/MultipleFxActivity.kt @@ -24,17 +24,17 @@ class MultipleFxActivity : AppCompatActivity() { if (!FloatingX.isInstalled(TAG_1)) { CustomKtApplication.installTag1(application) } - FloatingX.control(TAG_1).show(this@MultipleFxActivity) + FloatingX.control(TAG_1).show() } addItemView("显示全局悬浮窗(tag2)") { if (!FloatingX.isInstalled(TAG_2)) { CustomKtApplication.installTag2(application) } - FloatingX.control(TAG_2).show(this@MultipleFxActivity) + FloatingX.control(TAG_2).show() } addItemView("重复安装全局悬浮窗(tag1)") { CustomKtApplication.installTag1(application) - FloatingX.control(TAG_1).show(this@MultipleFxActivity) + FloatingX.control(TAG_1).show() } addItemView("隐藏全局悬浮窗(tag1)") { FloatingX.controlOrNull(TAG_1)?.hide() diff --git a/app/src/main/java/com/petterp/floatingx/app/test/ScopeActivity.kt b/app/src/main/java/com/petterp/floatingx/app/test/ScopeActivity.kt index efe18ea8..bb57f921 100644 --- a/app/src/main/java/com/petterp/floatingx/app/test/ScopeActivity.kt +++ b/app/src/main/java/com/petterp/floatingx/app/test/ScopeActivity.kt @@ -14,9 +14,9 @@ import com.petterp.floatingx.app.addNestedScrollView import com.petterp.floatingx.app.addTextView import com.petterp.floatingx.app.createLinearLayoutToParent import com.petterp.floatingx.app.simple.FxAnimationImpl +import com.petterp.floatingx.assist.FxAdsorbDirection import com.petterp.floatingx.assist.FxDisplayMode import com.petterp.floatingx.assist.FxGravity -import com.petterp.floatingx.assist.FxAdsorbDirection import com.petterp.floatingx.util.createFx /** @author petterp */ diff --git a/app/src/main/java/com/petterp/floatingx/app/test/SimpleRvActivity.kt b/app/src/main/java/com/petterp/floatingx/app/test/SimpleRvActivity.kt index 6314c084..57150f5f 100644 --- a/app/src/main/java/com/petterp/floatingx/app/test/SimpleRvActivity.kt +++ b/app/src/main/java/com/petterp/floatingx/app/test/SimpleRvActivity.kt @@ -36,7 +36,7 @@ class SimpleRvActivity : AppCompatActivity() { } } FloatingX.controlOrNull(TAG)?.apply { - if (!isShow()) show(this@SimpleRvActivity) + if (!isShow()) show() } } addItemView("隐藏浮窗") { diff --git a/floatingx/proguard-floatingx.pro b/floatingx/proguard-floatingx.pro index f3c38b60..f735c83d 100644 --- a/floatingx/proguard-floatingx.pro +++ b/floatingx/proguard-floatingx.pro @@ -1,5 +1,5 @@ -dontwarn com.petterp.floatingx.** --keep public class com.petterp.floatingx.view.FxManagerView{*;} +-keep public class com.petterp.floatingx.view.default.FxManagerView{*;} -keep public class com.petterp.floatingx.view.FxViewHolder{*;} -keep public class com.petterp.floatingx.assist.FxScopeEnum{*;} -keep public class com.petterp.floatingx.assist.FxGravity{*;} diff --git a/floatingx/src/main/AndroidManifest.xml b/floatingx/src/main/AndroidManifest.xml index 127a4e5e..2459ee17 100644 --- a/floatingx/src/main/AndroidManifest.xml +++ b/floatingx/src/main/AndroidManifest.xml @@ -1,2 +1,12 @@ - \ No newline at end of file + + + + + + \ No newline at end of file diff --git a/floatingx/src/main/java/com/petterp/floatingx/FloatingX.kt b/floatingx/src/main/java/com/petterp/floatingx/FloatingX.kt index c885bf14..1e19198b 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/FloatingX.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/FloatingX.kt @@ -1,27 +1,20 @@ package com.petterp.floatingx import android.annotation.SuppressLint -import android.app.Activity -import android.app.Application import com.petterp.floatingx.assist.helper.FxAppHelper import com.petterp.floatingx.impl.control.FxAppControlImpl -import com.petterp.floatingx.impl.lifecycle.FxLifecycleCallbackImpl -import com.petterp.floatingx.impl.lifecycle.FxProxyLifecycleCallBackImpl +import com.petterp.floatingx.impl.lifecycle.FxTempAppLifecycleImp import com.petterp.floatingx.listener.control.IFxAppControl import com.petterp.floatingx.listener.control.IFxConfigControl +import com.petterp.floatingx.util.FX_APP_DEFAULT_TAG /** Single Control To Fx */ @SuppressLint("StaticFieldLeak") object FloatingX { private const val FX_DEFAULT_INITIAL_CAPACITY = 3 - private var fxs = HashMap(FX_DEFAULT_INITIAL_CAPACITY) - private var fxLifecycleCallback: FxLifecycleCallbackImpl? = null @JvmSynthetic - internal var context: Application? = null - - @JvmSynthetic - internal const val FX_DEFAULT_TAG = "FX_DEFAULT_TAG" + internal val fxs = HashMap(FX_DEFAULT_INITIAL_CAPACITY) /** * 安装一个新的全局浮窗,以dsl方式 @@ -42,13 +35,9 @@ object FloatingX { */ @JvmStatic fun install(helper: FxAppHelper): IFxAppControl { - if (context == null) { - throw NullPointerException("context == null, please call AppHelper.setContext(context) to set context") - } - if (fxs.isNotEmpty()) fxs[helper.tag]?.cancel() - val fxAppControlImpl = FxAppControlImpl(helper, FxProxyLifecycleCallBackImpl()) + fxs[helper.tag]?.cancel() + val fxAppControlImpl = FxAppControlImpl(helper, FxTempAppLifecycleImp()) fxs[helper.tag] = fxAppControlImpl - if (helper.enableFx) checkAppLifecycleInstall() return fxAppControlImpl } @@ -59,7 +48,7 @@ object FloatingX { */ @JvmStatic @JvmOverloads - fun control(tag: String = FX_DEFAULT_TAG): IFxAppControl { + fun control(tag: String = FX_APP_DEFAULT_TAG): IFxAppControl { return getTagFxControl(tag) } @@ -70,7 +59,7 @@ object FloatingX { */ @JvmStatic @JvmOverloads - fun controlOrNull(tag: String = FX_DEFAULT_TAG): IFxAppControl? { + fun controlOrNull(tag: String = FX_APP_DEFAULT_TAG): IFxAppControl? { return fxs[tag] } @@ -81,7 +70,7 @@ object FloatingX { */ @JvmStatic @JvmOverloads - fun configControl(tag: String = FX_DEFAULT_TAG): IFxConfigControl { + fun configControl(tag: String = FX_APP_DEFAULT_TAG): IFxConfigControl { return getTagFxControl(tag).configControl } @@ -92,7 +81,7 @@ object FloatingX { */ @JvmStatic @JvmOverloads - fun configControlOrNull(tag: String = FX_DEFAULT_TAG): IFxConfigControl? { + fun configControlOrNull(tag: String = FX_APP_DEFAULT_TAG): IFxConfigControl? { return fxs[tag]?.configControl } @@ -101,7 +90,7 @@ object FloatingX { * */ @JvmStatic @JvmOverloads - fun isInstalled(tag: String = FX_DEFAULT_TAG): Boolean { + fun isInstalled(tag: String = FX_APP_DEFAULT_TAG): Boolean { return fxs[tag] != null } @@ -109,48 +98,15 @@ object FloatingX { @JvmStatic fun uninstallAll() { if (fxs.isEmpty()) return - // 这里需要避免 ConcurrentModificationException - val keys = fxs.keys.toList() - keys.forEach { - fxs[it]?.cancel() - } - } - - @JvmSynthetic - internal fun getFxList(): Map = fxs - - @JvmSynthetic - internal fun uninstall(tag: String, control: FxAppControlImpl) { - if (fxs.values.contains(control)) fxs.remove(tag) - // 如果全局浮窗为null,自动清空配置 - if (fxs.isEmpty()) { - release() + fxs.values.forEach { + it.cancel() } + fxs.clear() } - /** - * 检查AppLifecycle是否安装 - * - * @param activity 初始化时的activity - */ - @JvmSynthetic - internal fun checkAppLifecycleInstall(activity: Activity? = null) { - if (fxLifecycleCallback != null) return - FxLifecycleCallbackImpl.updateTopActivity(activity) - fxLifecycleCallback = FxLifecycleCallbackImpl() - context?.registerActivityLifecycleCallbacks(fxLifecycleCallback) - } - - private fun getTagFxControl(tag: String): FxAppControlImpl { - val errorMessage = - "fxs[$tag]==null!,Please check if FloatingX.install() or AppHelper.setTag() is called." - return fxs[tag] ?: throw NullPointerException(errorMessage) - } - - private fun release() { - if (fxLifecycleCallback == null && FxLifecycleCallbackImpl.topActivity == null) return - context?.unregisterActivityLifecycleCallbacks(fxLifecycleCallback) - FxLifecycleCallbackImpl.releaseTopActivity() - fxLifecycleCallback = null + private fun getTagFxControl(tag: String): IFxAppControl { + val control = fxs[tag] + checkNotNull(control) { "fxs[$tag]==null!,Please check if FloatingX.install() or AppHelper.setTag() is called." } + return control } } diff --git a/floatingx/src/main/java/com/petterp/floatingx/assist/FxContentProvider.kt b/floatingx/src/main/java/com/petterp/floatingx/assist/FxContentProvider.kt new file mode 100644 index 00000000..d286d13a --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/assist/FxContentProvider.kt @@ -0,0 +1,41 @@ +package com.petterp.floatingx.assist + +import android.app.Application +import android.content.ContentProvider +import android.content.ContentValues +import android.database.Cursor +import android.net.Uri +import com.petterp.floatingx.impl.lifecycle.FxAppLifecycleProvider + +/** + * FxDefaultProvider + * @author petterp + */ +class FxContentProvider : ContentProvider() { + override fun onCreate(): Boolean { + val application = context?.applicationContext as? Application ?: return true + application.registerActivityLifecycleCallbacks(FxAppLifecycleProvider()) + return true + } + + override fun query( + uri: Uri, + projection: Array?, + selection: String?, + selectionArgs: Array?, + sortOrder: String? + ): Cursor? = null + + override fun getType(uri: Uri): String? = null + + override fun insert(uri: Uri, values: ContentValues?): Uri? = null + + override fun delete(uri: Uri, selection: String?, selectionArgs: Array?): Int = 0 + + override fun update( + uri: Uri, + values: ContentValues?, + selection: String?, + selectionArgs: Array? + ): Int = 0 +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/assist/FxScopeEnum.kt b/floatingx/src/main/java/com/petterp/floatingx/assist/FxScopeEnum.kt index 8be1457e..b5c716ee 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/assist/FxScopeEnum.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/assist/FxScopeEnum.kt @@ -1,10 +1,9 @@ package com.petterp.floatingx.assist /** Fx插入的不同位置 */ -enum class FxScopeEnum(val tag: String) { - SYSTEM("system"), - APP_SCOPE("app"), - ACTIVITY_SCOPE("activity"), - FRAGMENT_SCOPE("fragment"), - VIEW_GROUP_SCOPE("view") +enum class FxScopeEnum { + SYSTEM, // 在系统中展示,必须有权限 + AUTO_APP, // 根据用户的权限授予状态,Windows||Activity 自适应处理 + APP_WINDOWS, // 在应用内展示,需要权限 + APP_ACTIVITY, // 在应用内展示,无需权限 } diff --git a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxAppHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxAppHelper.kt index 39ba7d04..cc4a5e24 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxAppHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxAppHelper.kt @@ -4,8 +4,11 @@ import android.app.Activity import android.app.Application import android.content.Context import com.petterp.floatingx.FloatingX -import com.petterp.floatingx.listener.IFxProxyTagActivityLifecycle import com.petterp.floatingx.assist.FxScopeEnum +import com.petterp.floatingx.listener.IFxProxyTagActivityLifecycle +import com.petterp.floatingx.util.FX_APP_DEFAULT_TAG +import com.petterp.floatingx.util.FX_INSTALL_SCOPE_APP_TAG +import com.petterp.floatingx.util.FX_INSTALL_SCOPE_SYSTEM_TAG import com.petterp.floatingx.util.navigationBarHeight import com.petterp.floatingx.util.statusBarHeight @@ -14,6 +17,8 @@ class FxAppHelper( /** 浮窗tag,默认为 [FloatingX.FX_DEFAULT_TAG] */ @JvmSynthetic internal var tag: String, + @JvmSynthetic + internal var context: Application, /** 黑名单list */ @JvmSynthetic internal val blackFilterList: MutableList>, @@ -23,6 +28,8 @@ class FxAppHelper( /** 是否允许插入全部Activity */ @JvmSynthetic internal val isAllInstall: Boolean, + @JvmSynthetic + internal val scope: FxScopeEnum, /** 显示悬浮窗的Activity生命周期回调 */ @JvmSynthetic internal val fxLifecycleExpand: IFxProxyTagActivityLifecycle? @@ -56,8 +63,10 @@ class FxAppHelper( private var blackFilterList: MutableList> = mutableListOf() private var fxLifecycleExpand: IFxProxyTagActivityLifecycle? = null private var isEnableAllInstall: Boolean = true - private var tag = FloatingX.FX_DEFAULT_TAG + private var context: Application? = null + private var tag = FX_APP_DEFAULT_TAG private var enableFx = false + private var scopeEnum: FxScopeEnum = FxScopeEnum.APP_ACTIVITY /** 设置启用fx */ fun enableFx(): Builder { @@ -71,9 +80,9 @@ class FxAppHelper( * */ fun setContext(context: Context): Builder { if (context is Application) { - FloatingX.context = context + this.context = context } else { - FloatingX.context = context.applicationContext as Application + this.context = context.applicationContext as Application } return this } @@ -115,11 +124,18 @@ class FxAppHelper( */ @Throws(IllegalArgumentException::class) fun setTag(tag: String): Builder { - if (tag.isEmpty()) throw IllegalArgumentException("浮窗 tag 不能为 [\"\"],请设置一个合法的tag") + check(tag.isNotEmpty()) { + "浮窗 tag 不能为 [\"\"],请设置一个合法的tag" + } this.tag = tag return this } + fun setSystemScope(scope: FxScopeEnum): Builder { + this.scopeEnum = scope + return this + } + /** * 允许显示浮窗的activity * @@ -147,14 +163,18 @@ class FxAppHelper( return this } - override fun buildHelper(): FxAppHelper = - FxAppHelper( + override fun buildHelper(): FxAppHelper { + checkNotNull(context) { "context == null, please call AppHelper.setContext(context) to set context" } + return FxAppHelper( tag, + context!!, blackFilterList, whiteInsertList, isEnableAllInstall, + scopeEnum, fxLifecycleExpand, ) + } override fun build(): FxAppHelper { return super.build().apply { @@ -163,7 +183,11 @@ class FxAppHelper( if (enableDebugLog && fxLogTag.isEmpty()) { fxLogTag = tag } - initLog(FxScopeEnum.APP_SCOPE.tag) + if (scopeEnum == FxScopeEnum.SYSTEM) { + initLog(FX_INSTALL_SCOPE_SYSTEM_TAG) + } else { + initLog(FX_INSTALL_SCOPE_APP_TAG) + } } } } diff --git a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxBasisHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxBasisHelper.kt index 51a18a8f..1ef9f3d4 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxBasisHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxBasisHelper.kt @@ -52,6 +52,7 @@ open class FxBasisHelper { @JvmField internal var adsorbDirection: FxAdsorbDirection = FxAdsorbDirection.LEFT_OR_RIGHT + // TODO: 这里需要在考虑 @JvmField internal var enableFx: Boolean = false diff --git a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxScopeHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxScopeHelper.kt index 86d5d484..699175a6 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxScopeHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxScopeHelper.kt @@ -5,7 +5,9 @@ import android.widget.FrameLayout import androidx.fragment.app.Fragment import com.petterp.floatingx.impl.control.FxScopeControl import com.petterp.floatingx.listener.control.IFxScopeControl -import com.petterp.floatingx.assist.FxScopeEnum +import com.petterp.floatingx.util.FX_INSTALL_SCOPE_ACTIVITY_TAG +import com.petterp.floatingx.util.FX_INSTALL_SCOPE_FRAGMENT_TAG +import com.petterp.floatingx.util.FX_INSTALL_SCOPE_VIEW_GROUP_TAG import com.petterp.floatingx.util.contentView /** 特定范围的Helper构建器 */ @@ -13,7 +15,7 @@ class FxScopeHelper : FxBasisHelper() { /** 插入到Activity中 */ fun toControl(activity: Activity): IFxScopeControl { - initLog(FxScopeEnum.ACTIVITY_SCOPE.tag) + initLog(FX_INSTALL_SCOPE_ACTIVITY_TAG) val control = FxScopeControl(this) activity.contentView?.let { control.setContainerGroup(it) @@ -23,7 +25,7 @@ class FxScopeHelper : FxBasisHelper() { /** 插入到Fragment中 */ fun toControl(fragment: Fragment): IFxScopeControl { - initLog(FxScopeEnum.FRAGMENT_SCOPE.tag) + initLog(FX_INSTALL_SCOPE_FRAGMENT_TAG) val rootView = fragment.view as? FrameLayout checkNotNull(rootView) { "Check if your root layout is FrameLayout, or if the init call timing is after onCreateView()!" @@ -35,7 +37,7 @@ class FxScopeHelper : FxBasisHelper() { /** 插入到ViewGroup中 */ fun toControl(group: FrameLayout): IFxScopeControl { - initLog(FxScopeEnum.VIEW_GROUP_SCOPE.tag) + initLog(FX_INSTALL_SCOPE_VIEW_GROUP_TAG) val control = FxScopeControl(this) control.setContainerGroup(group) return control diff --git a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxSystemHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxSystemHelper.kt deleted file mode 100644 index 3f881aa0..00000000 --- a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxSystemHelper.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.petterp.floatingx.assist.helper - -/** - * FxSystemConfig 构建器 - * @author petterp - */ -class FxSystemHelper : FxBasisHelper() { - - class Builder : FxBasisHelper.Builder() { - override fun buildHelper(): FxSystemHelper = FxSystemHelper() - - override fun build(): FxSystemHelper { - return super.build() - } - } - - companion object { - @JvmStatic - fun builder() = Builder() - } -} diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxAppControlImpl.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxAppControlImpl.kt index a276adef..4defdb81 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxAppControlImpl.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxAppControlImpl.kt @@ -9,7 +9,7 @@ import androidx.core.view.OnApplyWindowInsetsListener import androidx.core.view.ViewCompat import com.petterp.floatingx.FloatingX import com.petterp.floatingx.assist.helper.FxAppHelper -import com.petterp.floatingx.impl.lifecycle.FxProxyLifecycleCallBackImpl +import com.petterp.floatingx.impl.lifecycle.FxTempAppLifecycleImp import com.petterp.floatingx.listener.control.IFxAppControl import com.petterp.floatingx.util.decorView import com.petterp.floatingx.util.topActivity @@ -17,15 +17,20 @@ import com.petterp.floatingx.util.topActivity /** 全局控制器 */ class FxAppControlImpl( private val helper: FxAppHelper, - private val proxyLifecycleImpl: FxProxyLifecycleCallBackImpl, + private val proxyLifecycleImpl: FxTempAppLifecycleImp, ) : FxBasisControlImpl(helper), IFxAppControl, Application.ActivityLifecycleCallbacks by proxyLifecycleImpl { + private var isRegisterAppLifecycle = false + init { proxyLifecycleImpl.init(helper, this) + checkRegisterAppLifecycle() } + override fun context(): Context = helper.context + private val windowsInsetsListener = OnApplyWindowInsetsListener { _, insets -> val statusBar = insets.stableInsetTop if (helper.statsBarHeight != statusBar) { @@ -35,18 +40,13 @@ class FxAppControlImpl( insets } - override fun show(activity: Activity) { - if (!helper.isCanInstall(activity) || isShow()) return - if (attach(activity)) { + override fun show() { + val act = topActivity ?: return + if (!helper.isCanInstall(act) || isShow()) return + checkRegisterAppLifecycle() + if (attach(act)) { internalShow() updateEnableStatus(true) - FloatingX.checkAppLifecycleInstall() - } - } - - override fun detach(activity: Activity) { - activity.decorView?.let { - detach(it) } } @@ -59,21 +59,33 @@ class FxAppControlImpl( /** 注意,全局浮窗下,view必须是全局application对应的context! */ override fun updateView(view: View) { - if (view.context !is Application) { - throw IllegalArgumentException("view.context != Application,The global floating window must use application as context!") + check(view.context is Application) { + "view.context != Application,The global floating window must use application as context!" } super.updateView(view) } - override fun context(): Context = FloatingX.context!! + override fun cancel() { + super.cancel() + clearWindowsInsetsListener() + if (!FloatingX.fxs.containsValue(this)) return + FloatingX.fxs.remove(helper.tag) + } - private fun initWindowsInsetsListener() { - getManagerView()?.let { - ViewCompat.setOnApplyWindowInsetsListener(it, windowsInsetsListener) - it.requestApplyInsets() - } + override fun detach(container: ViewGroup?) { + super.detach(container) + clearContainer() + } + + override fun initManager() { + // 在清除之前移除insets监听 + clearWindowsInsetsListener() + super.initManager() + // 移除之后再添加inset监听 + initWindowsInsetsListener() } + @JvmSynthetic internal fun attach(activity: Activity): Boolean { activity.decorView?.let { if (getContainerGroup() === it) { @@ -87,8 +99,7 @@ class FxAppControlImpl( isAnimation = true } else { if (getManagerView()?.visibility != View.VISIBLE) { - getManagerView()?.visibility = - View.VISIBLE + getManagerView()?.visibility = View.VISIBLE } detach() } @@ -104,28 +115,28 @@ class FxAppControlImpl( return true } - override fun detach(container: ViewGroup?) { - super.detach(container) - clearContainer() + @JvmSynthetic + internal fun detach(activity: Activity) { + detach(activity.decorView) } - override fun initManager() { - // 在清除之前移除insets监听 - clearWindowsInsetsListener() - super.initManager() - // 移除之后再添加inset监听 - initWindowsInsetsListener() + private fun clearWindowsInsetsListener() { + val managerView = getManagerView() ?: return + ViewCompat.setOnApplyWindowInsetsListener(managerView, null) } - override fun reset() { - // 重置之前记得移除insets - clearWindowsInsetsListener() - super.reset() - FloatingX.uninstall(helper.tag, this) + private fun initWindowsInsetsListener() { + getManagerView()?.let { + ViewCompat.setOnApplyWindowInsetsListener(it, windowsInsetsListener) + it.requestApplyInsets() + } } - private fun clearWindowsInsetsListener() { - val managerView = getManagerView() ?: return - ViewCompat.setOnApplyWindowInsetsListener(managerView, null) + private fun checkRegisterAppLifecycle() { + if (!isRegisterAppLifecycle && helper.enableFx) { + isRegisterAppLifecycle = true + helper.context.unregisterActivityLifecycleCallbacks(this) + helper.context.registerActivityLifecycleCallbacks(this) + } } } diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxBasisControlImpl.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxBasisControlImpl.kt index 82b3e7b1..0a1e6dbc 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxBasisControlImpl.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxBasisControlImpl.kt @@ -17,17 +17,18 @@ import com.petterp.floatingx.listener.control.IFxConfigControl import com.petterp.floatingx.listener.control.IFxControl import com.petterp.floatingx.listener.provider.IFxContextProvider import com.petterp.floatingx.listener.provider.IFxHolderProvider +import com.petterp.floatingx.util.INVALID_LAYOUT_ID import com.petterp.floatingx.util.lazyLoad -import com.petterp.floatingx.view.FxManagerView import com.petterp.floatingx.view.FxViewHolder -import com.petterp.floatingx.view.IFxInternalViewControl +import com.petterp.floatingx.view.IFxInternalView +import com.petterp.floatingx.view.default.FxDefaultContainerView import java.lang.ref.WeakReference /** Fx基础控制器实现 */ open class FxBasisControlImpl(private val helper: FxBasisHelper) : IFxControl, IFxConfigControl { private var viewHolder: FxViewHolder? = null private var mContainer: WeakReference? = null - private var internalViewControl: IFxInternalViewControl? = null + private var internalView: IFxInternalView? = null private val cancelAnimationRunnable by lazyLoad { Runnable { reset() } } private val hideAnimationRunnable by lazyLoad { Runnable { detach() } } @@ -37,7 +38,7 @@ open class FxBasisControlImpl(private val helper: FxBasisHelper) : IFxControl, I if ((getManagerView() == null && viewHolder == null)) return if (isShow() && helper.enableAnimation && helper.fxAnimation != null) { getManagerView()?.removeCallbacks(cancelAnimationRunnable) - val duration = helper.fxAnimation!!.toEndAnimator(internalViewControl?.containerView) + val duration = helper.fxAnimation!!.toEndAnimator(internalView?.containerView) animatorCallback(duration, cancelAnimationRunnable) } else { reset() @@ -66,21 +67,23 @@ open class FxBasisControlImpl(private val helper: FxBasisHelper) : IFxControl, I return ViewCompat.isAttachedToWindow(managerView) && managerView.visibility == View.VISIBLE } - override fun getView(): View? = internalViewControl?.childView + override fun getView(): View? = internalView?.childView override fun getViewHolder(): FxViewHolder? = viewHolder - override fun getManagerView(): FrameLayout? = internalViewControl?.containerView + override fun getManagerView(): FrameLayout? = internalView?.containerView override fun updateView(@LayoutRes resource: Int) { - if (resource == 0) throw IllegalArgumentException("resource cannot be 0!") + check(resource != INVALID_LAYOUT_ID) { "resource cannot be INVALID_LAYOUT_ID!" } helper.layoutView = null - updateMangerView(resource) + helper.layoutId = resource + updateMangerView() } override fun updateView(view: View) { + helper.layoutId = INVALID_LAYOUT_ID helper.layoutView = view - updateMangerView(0) + updateMangerView() } override fun updateView(provider: IFxContextProvider) { @@ -110,11 +113,11 @@ open class FxBasisControlImpl(private val helper: FxBasisHelper) : IFxControl, I } override fun move(x: Float, y: Float, useAnimation: Boolean) { - internalViewControl?.moveLocation(x, y, useAnimation) + internalView?.moveLocation(x, y, useAnimation) } override fun moveByVector(x: Float, y: Float, useAnimation: Boolean) { - internalViewControl?.moveLocationByVector(x, y, useAnimation) + internalView?.moveLocationByVector(x, y, useAnimation) } /* @@ -140,27 +143,27 @@ open class FxBasisControlImpl(private val helper: FxBasisHelper) : IFxControl, I this.b = b this.r = r } - internalViewControl?.moveToEdge() + internalView?.moveToEdge() } override fun setEnableEdgeAdsorption(isEnable: Boolean) { helper.enableEdgeAdsorption = isEnable - internalViewControl?.moveToEdge() + internalView?.moveToEdge() } override fun setEdgeAdsorbDirection(direction: FxAdsorbDirection) { helper.adsorbDirection = direction - internalViewControl?.moveToEdge() + internalView?.moveToEdge() } override fun setEdgeOffset(edgeOffset: Float) { helper.edgeOffset = edgeOffset - internalViewControl?.moveToEdge() + internalView?.moveToEdge() } override fun setEnableEdgeRebound(isEnable: Boolean) { helper.enableEdgeRebound = isEnable - internalViewControl?.moveToEdge() + internalView?.moveToEdge() } override fun setScrollListener(listener: IFxScrollListener) { @@ -201,26 +204,23 @@ open class FxBasisControlImpl(private val helper: FxBasisHelper) : IFxControl, I /* * 以下方法作为基础实现,供子类自行调用 * */ - protected open fun updateMangerView(@LayoutRes layout: Int = 0) { - helper.layoutId = layout + private fun updateMangerView() { if (getContainerGroup() == null) throw NullPointerException("FloatingX window The parent container cannot be null!") - val x = internalViewControl?.getX() ?: 0f - val y = internalViewControl?.getY() ?: 0f - initManagerView() - internalViewControl?.restoreLocation(x, y) - getContainerGroup()?.addView(getManagerView()) + internalView?.updateView() } protected fun initManagerView() { - if (helper.layoutId == 0 && helper.layoutView == null) throw RuntimeException("The layout id cannot be 0 ,and layoutView==null") + check(helper.layoutId != INVALID_LAYOUT_ID || helper.layoutView != null) { + "The layout id cannot be 0 ,and layoutView==null" + } getContainerGroup()?.removeView(getManagerView()) initManager() } protected open fun initManager() { val context = context() ?: return - internalViewControl = FxManagerView(context).initView(helper) - val fxContentView = internalViewControl?.childView ?: return + internalView = FxDefaultContainerView(context).init(helper) + val fxContentView = internalView?.childView ?: return viewHolder = FxViewHolder(fxContentView) val fxViewLifecycle = helper.iFxViewLifecycle ?: return // 后续此方法将会移除,建议进行过渡 @@ -238,7 +238,7 @@ open class FxBasisControlImpl(private val helper: FxBasisHelper) : IFxControl, I } protected open fun detach(container: ViewGroup?) { - if (internalViewControl != null && container != null) { + if (internalView != null && container != null) { helper.fxLog?.d("fxView-lifecycle-> code->removeView") helper.iFxViewLifecycle?.postDetached() container.removeView(getManagerView()) @@ -269,7 +269,7 @@ open class FxBasisControlImpl(private val helper: FxBasisHelper) : IFxControl, I removeCallbacks(cancelAnimationRunnable) } detach(mContainer?.get()) - internalViewControl = null + internalView = null viewHolder = null helper.clear() clearContainer() diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxSystemControlImpl.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxSystemControlImpl.kt new file mode 100644 index 00000000..a6d34939 --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxSystemControlImpl.kt @@ -0,0 +1,22 @@ +package com.petterp.floatingx.impl.control + +import com.petterp.floatingx.assist.helper.FxAppHelper +import com.petterp.floatingx.listener.control.IFxSystemControl + +/** + * + * @author petterp + */ +class FxSystemControlImpl(private val helper: FxAppHelper) : + FxBasisControlImpl(helper), IFxSystemControl { + override fun show() { + } + + override fun hide() { + super.hide() + } + + override fun isShow(): Boolean { + return true + } +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxAppLifecycleProvider.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxAppLifecycleProvider.kt new file mode 100644 index 00000000..7deec65f --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxAppLifecycleProvider.kt @@ -0,0 +1,48 @@ +package com.petterp.floatingx.impl.lifecycle + +import android.app.Activity +import android.app.Application +import android.os.Bundle +import java.lang.ref.WeakReference + +/** + * + * @author petterp + */ +class FxAppLifecycleProvider : Application.ActivityLifecycleCallbacks { + override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { + updateTopActivity(activity) + } + + override fun onActivityStarted(activity: Activity) { + } + + override fun onActivityResumed(activity: Activity) { + updateTopActivity(activity) + } + + override fun onActivityPaused(activity: Activity) { + } + + override fun onActivityStopped(activity: Activity) { + } + + override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) { + } + + override fun onActivityDestroyed(activity: Activity) { + } + + companion object { + private var _currentActivity: WeakReference? = null + + @JvmSynthetic + fun getTopActivity(): Activity? = _currentActivity?.get() + + @JvmSynthetic + internal fun updateTopActivity(activity: Activity?) { + if (activity == null || _currentActivity?.get() === activity) return + _currentActivity = WeakReference(activity) + } + } +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxLifecycleCallbackImpl.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxLifecycleCallbackImpl.kt deleted file mode 100644 index ca530702..00000000 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxLifecycleCallbackImpl.kt +++ /dev/null @@ -1,97 +0,0 @@ -package com.petterp.floatingx.impl.lifecycle - -import android.app.Activity -import android.app.Application -import android.os.Bundle -import com.petterp.floatingx.FloatingX -import com.petterp.floatingx.impl.control.FxAppControlImpl -import java.lang.ref.WeakReference - -/** App-lifecycle-CallBack */ -class FxLifecycleCallbackImpl : Application.ActivityLifecycleCallbacks { - - private val fxList: Collection - get() = FloatingX.getFxList().values - - override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { - if (isFxsNotAllow()) return - for (fx in fxList) { - fx.onActivityCreated(activity, savedInstanceState) - } - } - - override fun onActivityStarted(activity: Activity) { - if (isFxsNotAllow()) return - for (fx in fxList) { - fx.onActivityStarted(activity) - } - } - - /** 最开始想到在onActivityPostStarted后插入, 但是最后发现在Android9及以下,此方法不会被调用,故选择了onResume */ - override fun onActivityResumed(activity: Activity) { - updateTopActivity(activity) - if (isFxsNotAllow()) return - for (fx in fxList) { - fx.onActivityResumed(activity) - } - } - - override fun onActivityPaused(activity: Activity) { - if (isFxsNotAllow()) return - for (fx in fxList) { - fx.onActivityPaused(activity) - } - } - - override fun onActivityStopped(activity: Activity) { - if (isFxsNotAllow()) return - for (fx in fxList) { - fx.onActivityStopped(activity) - } - } - - override fun onActivityDestroyed(activity: Activity) { - if (isFxsNotAllow()) return - for (fx in fxList) { - fx.onActivityDestroyed(activity) - } - if (topActivity?.get() === activity) { - topActivity?.clear() - topActivity = null - } - } - - override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) { - if (isFxsNotAllow()) return - for (fx in fxList) { - fx.onActivitySaveInstanceState(activity, outState) - } - } - - private fun isFxsNotAllow(): Boolean { - return fxList.isEmpty() - } - - private fun updateTopActivity(activity: Activity) { - if (topActivity?.get() != activity) topActivity = WeakReference(activity) - } - - companion object { - internal var topActivity: WeakReference? = null - - @JvmSynthetic - fun getTopActivity(): Activity? = topActivity?.get() - - @JvmSynthetic - internal fun updateTopActivity(activity: Activity?) { - if (activity == null || topActivity?.get() === activity) return - topActivity = WeakReference(activity) - } - - @JvmSynthetic - internal fun releaseTopActivity() { - topActivity?.clear() - topActivity = null - } - } -} diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxTagActivityLifecycleImpl.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxProxyTagLifecycleImp.kt similarity index 89% rename from floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxTagActivityLifecycleImpl.kt rename to floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxProxyTagLifecycleImp.kt index 5610983e..8634c8d7 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxTagActivityLifecycleImpl.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxProxyTagLifecycleImp.kt @@ -5,7 +5,7 @@ import android.os.Bundle import com.petterp.floatingx.listener.IFxProxyTagActivityLifecycle /** IFxProxyTagActivityLifecycle的空实现 */ -open class FxTagActivityLifecycleImpl : IFxProxyTagActivityLifecycle { +open class FxProxyTagLifecycleImp : IFxProxyTagActivityLifecycle { override fun onCreated(activity: Activity, bundle: Bundle?) {} override fun onStarted(activity: Activity) {} diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxProxyLifecycleCallBackImpl.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxTempAppLifecycleImp.kt similarity index 98% rename from floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxProxyLifecycleCallBackImpl.kt rename to floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxTempAppLifecycleImp.kt index 0c7723ee..3123383c 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxProxyLifecycleCallBackImpl.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxTempAppLifecycleImp.kt @@ -15,7 +15,7 @@ import com.petterp.floatingx.util.lazyLoad * * @author petterp */ -class FxProxyLifecycleCallBackImpl : Application.ActivityLifecycleCallbacks { +class FxTempAppLifecycleImp : Application.ActivityLifecycleCallbacks { private var helper: FxAppHelper? = null private var appControl: FxAppControlImpl? = null diff --git a/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxAppControl.kt b/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxAppControl.kt index 4deda668..35a41117 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxAppControl.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxAppControl.kt @@ -14,11 +14,8 @@ interface IFxAppControl : IFxControl { * * ps:尽管我们可以做到不传递activity,但是这种方式需要以性能作为牺牲,比如需要永久维护一个顶级activity与AppLifecycle监听器 */ - fun show(activity: Activity) + fun show() - /** 从当前activity中移除 */ - fun detach(activity: Activity) - - /** 获得当前绑定的activity,不要手动保留此activity,以避免泄漏 */ + /** 获得当前浮窗绑定的activity,不要手动保留此activity,以避免泄漏 */ fun getBindActivity(): Activity? } diff --git a/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxSystemControl.kt b/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxSystemControl.kt new file mode 100644 index 00000000..ac282785 --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxSystemControl.kt @@ -0,0 +1,9 @@ +package com.petterp.floatingx.listener.control + +/** + * + * @author petterp + */ +interface IFxSystemControl { + fun show() +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/util/FxExt.kt b/floatingx/src/main/java/com/petterp/floatingx/util/FxExt.kt index 7f855ff7..fee4e8b3 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/util/FxExt.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/util/FxExt.kt @@ -1,30 +1,53 @@ +@file:JvmName("_FxExt") + package com.petterp.floatingx.util import android.app.Activity import android.content.Context import android.content.ContextWrapper -import android.os.Handler -import android.os.Looper import android.view.MotionEvent +import android.widget.FrameLayout import com.petterp.floatingx.assist.helper.FxScopeHelper +import com.petterp.floatingx.impl.lifecycle.FxAppLifecycleProvider import java.lang.Exception -@JvmSynthetic internal const val FX_GRAVITY_TOP = 0x00000001 -@JvmSynthetic internal const val FX_GRAVITY_CENTER = 0x00000002 -@JvmSynthetic internal const val FX_GRAVITY_BOTTOM = 0x00000003 internal const val TOUCH_CLICK_OFFSET = 2F -internal const val TOUCH_TIME_THRESHOLD = 150L + internal const val INVALID_TOUCH_ID = -1 internal const val INVALID_LAYOUT_ID = 0 internal const val INVALID_TOUCH_IDX = -1 +internal const val TOUCH_TIME_THRESHOLD = 150L internal const val DEFAULT_MOVE_ANIMATOR_DURATION = 200L -internal val HANDLER = Handler(Looper.getMainLooper()) +internal const val FX_APP_DEFAULT_TAG = "FX_DEFAULT_TAG" + +internal const val FX_INSTALL_SCOPE_APP_TAG = "app" +internal const val FX_INSTALL_SCOPE_SYSTEM_TAG = "system" +internal const val FX_INSTALL_SCOPE_ACTIVITY_TAG = "activity" +internal const val FX_INSTALL_SCOPE_FRAGMENT_TAG = "fragment" +internal const val FX_INSTALL_SCOPE_VIEW_GROUP_TAG = "view" + +internal val topActivity: Activity? + get() = FxAppLifecycleProvider.getTopActivity() + +internal val Activity.decorView: FrameLayout? + get() = try { + window.decorView as FrameLayout + } catch (_: Exception) { + null + } + +internal val Activity.contentView: FrameLayout? + get() = try { + window.decorView.findViewById(android.R.id.content) + } catch (_: Exception) { + null + } /** * 创建一个fx,自行初始化并控制插入位置 @@ -37,13 +60,11 @@ internal val HANDLER = Handler(Looper.getMainLooper()) * * } */ -@JvmSynthetic inline fun createFx(crossinline obj: FxScopeHelper.Builder.() -> T) = lazy(LazyThreadSafetyMode.NONE) { FxScopeHelper.Builder().run(obj) } -@JvmSynthetic internal inline fun lazyLoad( mode: LazyThreadSafetyMode = LazyThreadSafetyMode.NONE, crossinline obj: () -> T @@ -52,7 +73,6 @@ internal inline fun lazyLoad( obj() } -@JvmSynthetic internal fun Float.coerceInFx(min: Float, max: Float): Float { if (this < min) return min if (this > max) return max @@ -70,7 +90,6 @@ internal val MotionEvent.pointerId: Int INVALID_TOUCH_ID } -@JvmSynthetic internal fun Context.findActivity(): Activity? { return when (this) { is Activity -> { diff --git a/floatingx/src/main/java/com/petterp/floatingx/util/FxScreenExt.kt b/floatingx/src/main/java/com/petterp/floatingx/util/FxScreenExt.kt index 46ffddec..27e0fb0e 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/util/FxScreenExt.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/util/FxScreenExt.kt @@ -1,3 +1,5 @@ +@file:JvmName("_FxScreenExt") + package com.petterp.floatingx.util import android.annotation.SuppressLint diff --git a/floatingx/src/main/java/com/petterp/floatingx/util/FxUiExt.kt b/floatingx/src/main/java/com/petterp/floatingx/util/FxUiExt.kt deleted file mode 100644 index 0939b65e..00000000 --- a/floatingx/src/main/java/com/petterp/floatingx/util/FxUiExt.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.petterp.floatingx.util - -import android.app.Activity -import android.widget.FrameLayout -import com.petterp.floatingx.impl.lifecycle.FxLifecycleCallbackImpl - -/** App级当前设置了tag的栈顶Activity */ -internal val topActivity: Activity? - get() = FxLifecycleCallbackImpl.getTopActivity() - -internal val Activity.decorView: FrameLayout? - get() = try { - window.decorView as FrameLayout - } catch (_: Exception) { - null - } - -internal val Activity.contentView: FrameLayout? - get() = try { - window.decorView.findViewById(android.R.id.content) - } catch (_: Exception) { - null - } diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/IFxInternalViewControl.kt b/floatingx/src/main/java/com/petterp/floatingx/view/IFxInternalView.kt similarity index 73% rename from floatingx/src/main/java/com/petterp/floatingx/view/IFxInternalViewControl.kt rename to floatingx/src/main/java/com/petterp/floatingx/view/IFxInternalView.kt index 35df2256..514359ea 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/IFxInternalViewControl.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/IFxInternalView.kt @@ -7,7 +7,7 @@ import android.widget.FrameLayout * * @author petterp */ -internal interface IFxInternalViewControl { +internal interface IFxInternalView { val containerView: FrameLayout @@ -19,9 +19,5 @@ internal interface IFxInternalViewControl { fun moveToEdge() - fun getX(): Float - - fun getY(): Float - - fun restoreLocation(x: Float, y: Float) + fun updateView() } diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/FxClickHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/view/default/FxClickHelper.kt similarity index 94% rename from floatingx/src/main/java/com/petterp/floatingx/view/FxClickHelper.kt rename to floatingx/src/main/java/com/petterp/floatingx/view/default/FxClickHelper.kt index e2b5511f..e4b7acfe 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/FxClickHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/default/FxClickHelper.kt @@ -1,4 +1,4 @@ -package com.petterp.floatingx.view +package com.petterp.floatingx.view.default import androidx.annotation.Keep import com.petterp.floatingx.assist.helper.FxBasisHelper @@ -38,7 +38,7 @@ class FxClickHelper { } @Keep - fun performClick(view: FxManagerView) { + fun performClick(view: FxDefaultContainerView) { if (!isClickEffective()) return helper.iFxClickListener?.onClick(view) if (helper.clickTime > 0) { diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/FxManagerView.kt b/floatingx/src/main/java/com/petterp/floatingx/view/default/FxDefaultContainerView.kt similarity index 87% rename from floatingx/src/main/java/com/petterp/floatingx/view/FxManagerView.kt rename to floatingx/src/main/java/com/petterp/floatingx/view/default/FxDefaultContainerView.kt index 7d0f3a2b..8d21a983 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/FxManagerView.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/default/FxDefaultContainerView.kt @@ -1,17 +1,17 @@ -package com.petterp.floatingx.view +package com.petterp.floatingx.view.default import android.annotation.SuppressLint import android.content.Context import android.content.res.Configuration import android.graphics.Color import android.util.AttributeSet +import android.view.LayoutInflater import android.view.MotionEvent import android.view.View import android.view.ViewGroup import android.widget.FrameLayout import com.petterp.floatingx.assist.FxDisplayMode -import com.petterp.floatingx.assist.FxGravity -import com.petterp.floatingx.assist.helper.BasisHelper +import com.petterp.floatingx.assist.helper.FxBasisHelper import com.petterp.floatingx.util.DEFAULT_MOVE_ANIMATOR_DURATION import com.petterp.floatingx.util.FX_GRAVITY_BOTTOM import com.petterp.floatingx.util.FX_GRAVITY_TOP @@ -19,24 +19,28 @@ import com.petterp.floatingx.util.INVALID_LAYOUT_ID import com.petterp.floatingx.util.INVALID_TOUCH_ID import com.petterp.floatingx.util.pointerId import com.petterp.floatingx.util.withIn +import com.petterp.floatingx.view.IFxInternalView /** 基础悬浮窗View */ @SuppressLint("ViewConstructor") -class FxManagerView @JvmOverloads constructor( +class FxDefaultContainerView @JvmOverloads constructor( context: Context, - attrs: AttributeSet? = null, -) : FrameLayout(context, attrs), View.OnLayoutChangeListener { + attrs: AttributeSet? = null +) : FrameLayout(context, attrs), View.OnLayoutChangeListener, IFxInternalView { - private lateinit var helper: BasisHelper + private lateinit var helper: FxBasisHelper private val clickHelper = FxClickHelper() - private val restoreHelper = FxLocationHelper() + private val locationHelper = FxLocationHelper() private val configHelper = FxViewConfigHelper() private var _childFxView: View? = null - val childFxView: View? get() = _childFxView + override val childView: View? + get() = _childFxView + override val containerView: FrameLayout + get() = this @JvmSynthetic - internal fun init(config: BasisHelper): FxManagerView { + internal fun init(config: FxBasisHelper): FxDefaultContainerView { this.helper = config initView() return this @@ -45,7 +49,7 @@ class FxManagerView @JvmOverloads constructor( private fun initView() { _childFxView = inflateLayoutView() ?: inflateLayoutId() clickHelper.initConfig(helper) - restoreHelper.initConfig(helper) + locationHelper.initConfig(helper) configHelper.initConfig(context, helper) checkNotNull(_childFxView) { "initFxView -> Error,check your layoutId or layoutView." } initLocation() @@ -68,7 +72,9 @@ class FxManagerView @JvmOverloads constructor( private fun inflateLayoutId(): View? { if (helper.layoutId == INVALID_LAYOUT_ID) return null helper.fxLog?.d("fxView-->init, way:[layoutId]") - return inflate(context, helper.layoutId, this) + val view = LayoutInflater.from(context).inflate(helper.layoutId, this, false) + addView(view) + return view } private fun initLocation() { @@ -169,11 +175,11 @@ class FxManagerView @JvmOverloads constructor( super.onConfigurationChanged(newConfig) helper.fxLog?.d("fxView--lifecycle-> onConfigurationChanged--->") // use the configuration in Configuration first - val isScreenChanged = restoreHelper.updateConfig(newConfig) + val isScreenChanged = locationHelper.updateConfig(newConfig) if (!isScreenChanged) return val x = x val y = y - restoreHelper.saveLocation(x, y, configHelper) + locationHelper.saveLocation(x, y, configHelper) helper.fxLog?.d("fxView--lifecycle-> saveLocation:[x:$x,y:$y]") } @@ -192,8 +198,7 @@ class FxManagerView @JvmOverloads constructor( helper.iFxScrollListener?.down() } - @JvmSynthetic - internal fun moveLocation(x: Float, y: Float, useAnimation: Boolean = true) { + override fun moveLocation(x: Float, y: Float, useAnimation: Boolean) { val newX = configHelper.safeX(x) val newY = configHelper.safeY(y) if (useAnimation) { @@ -204,22 +209,22 @@ class FxManagerView @JvmOverloads constructor( } } - @JvmSynthetic - internal fun moveLocationByVector(x: Float, y: Float, useAnimation: Boolean = true) { + override fun moveLocationByVector(x: Float, y: Float, useAnimation: Boolean) { val currentX = this.x.plus(x) val currentY = this.y.plus(y) moveLocation(currentX, currentY, useAnimation) } - @JvmSynthetic - internal fun restoreLocation(x: Float, y: Float) { - (layoutParams as LayoutParams).gravity = FxGravity.DEFAULT.value - this.x = x - this.y = y + override fun updateView() { + removeView(_childFxView) + _childFxView = if (helper.layoutView != null) { + inflateLayoutView() + } else { + inflateLayoutId() + } } - @JvmSynthetic - internal fun moveToEdge() { + override fun moveToEdge() { configHelper.updateBoundary(false) configHelper.getAdsorbDirectionLocation(x, y)?.let { (x, y) -> moveToLocation(x, y) @@ -249,7 +254,7 @@ class FxManagerView @JvmOverloads constructor( } private fun restoreLocation() { - val (x, y) = restoreHelper.getLocation(configHelper) + val (x, y) = locationHelper.getLocation(configHelper) this.x = x this.y = y saveLocationToStorage(x, y) @@ -290,11 +295,11 @@ class FxManagerView @JvmOverloads constructor( private fun refreshLocation(w: Int, h: Int) { if (!configHelper.updateWidgetSize(w, h, this)) return // 初始化位置时,我们进行一次位置校准,避免浮窗位置异常 - if (restoreHelper.isInitLocation()) { + if (locationHelper.isInitLocation()) { checkOrFixLocation() return } - if (restoreHelper.isRestoreLocation()) { + if (locationHelper.isRestoreLocation()) { restoreLocation() } else { moveToEdge() diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/FxLocationHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/view/default/FxLocationHelper.kt similarity index 94% rename from floatingx/src/main/java/com/petterp/floatingx/view/FxLocationHelper.kt rename to floatingx/src/main/java/com/petterp/floatingx/view/default/FxLocationHelper.kt index 59fbf8f5..48650cc9 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/FxLocationHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/default/FxLocationHelper.kt @@ -1,4 +1,4 @@ -package com.petterp.floatingx.view +package com.petterp.floatingx.view.default import android.content.res.Configuration import com.petterp.floatingx.assist.helper.FxBasisHelper @@ -9,7 +9,7 @@ import com.petterp.floatingx.util.coerceInFx * @author petterp */ class FxLocationHelper { - private lateinit var config: BasisHelper + private lateinit var config: FxBasisHelper private var screenW = 0 private var screenH = 0 private var x: Float = 0f @@ -18,7 +18,7 @@ class FxLocationHelper { private var screenChanged: Boolean = false private var isInitLocation = true - fun initConfig(config: BasisHelper) { + fun initConfig(config: FxBasisHelper) { this.config = config } diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/FxViewConfigHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/view/default/FxViewConfigHelper.kt similarity index 94% rename from floatingx/src/main/java/com/petterp/floatingx/view/FxViewConfigHelper.kt rename to floatingx/src/main/java/com/petterp/floatingx/view/default/FxViewConfigHelper.kt index 1f3a4b03..af823439 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/FxViewConfigHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/default/FxViewConfigHelper.kt @@ -1,11 +1,11 @@ -package com.petterp.floatingx.view +package com.petterp.floatingx.view.default import android.content.Context import android.view.MotionEvent import android.view.ViewConfiguration import android.view.ViewGroup -import com.petterp.floatingx.assist.helper.BasisHelper -import com.petterp.floatingx.util.FxAdsorbDirection +import com.petterp.floatingx.assist.FxAdsorbDirection +import com.petterp.floatingx.assist.helper.FxBasisHelper import com.petterp.floatingx.util.INVALID_TOUCH_ID import com.petterp.floatingx.util.coerceInFx import com.petterp.floatingx.util.pointerId @@ -16,7 +16,7 @@ class FxViewConfigHelper { private var downTouchY = 0f private var mParentWidth = 0f private var mParentHeight = 0f - private lateinit var helper: BasisHelper + private lateinit var helper: FxBasisHelper private var scaledTouchSlop = 0 var minHBoundary = 0f @@ -26,7 +26,7 @@ class FxViewConfigHelper { var touchDownId = INVALID_TOUCH_ID - fun initConfig(context: Context, helper: BasisHelper) { + fun initConfig(context: Context, helper: FxBasisHelper) { this.helper = helper scaledTouchSlop = ViewConfiguration.get(context).scaledTouchSlop } diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt b/floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt new file mode 100644 index 00000000..b967928d --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt @@ -0,0 +1,38 @@ +package com.petterp.floatingx.view.system + +import android.annotation.SuppressLint +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.widget.FrameLayout +import com.petterp.floatingx.assist.helper.FxBasisHelper +import com.petterp.floatingx.view.IFxInternalView + +/** 基础悬浮窗View */ +@SuppressLint("ViewConstructor") +class FxSystemContainerView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, +) : FrameLayout(context, attrs), IFxInternalView { + + private lateinit var helper: FxBasisHelper + override val containerView: FrameLayout + get() = this + override val childView: View + get() = TODO("Not yet implemented") + + override fun moveLocation(x: Float, y: Float, useAnimation: Boolean) { + TODO("Not yet implemented") + } + + override fun moveLocationByVector(x: Float, y: Float, useAnimation: Boolean) { + TODO("Not yet implemented") + } + + override fun moveToEdge() { + TODO("Not yet implemented") + } + + override fun updateView() { + } +} From ec70b5fa5cb6be8414f52c2d75a46b6b168f7722 Mon Sep 17 00:00:00 2001 From: petterp Date: Tue, 5 Dec 2023 21:31:39 +0800 Subject: [PATCH 4/8] =?UTF-8?q?perf:=E9=87=8D=E6=9E=84fx=E6=82=AC=E6=B5=AE?= =?UTF-8?q?=E7=AA=97=E5=9F=BA=E7=A1=80=E5=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/kotlin/CustomKtApplication.kt | 10 +- .../java/com/petterp/floatingx/FloatingX.kt | 16 +- .../petterp/floatingx/assist/FxAnimation.kt | 42 ++- .../assist/{FxScopeEnum.kt => FxScopeType.kt} | 2 +- .../floatingx/assist/helper/FxAppHelper.kt | 10 +- .../floatingx/assist/helper/FxScopeHelper.kt | 17 +- .../impl/control/FxAppControlImpl.kt | 142 -------- .../impl/control/FxBasisControlImpl.kt | 305 ------------------ .../floatingx/impl/control/FxScopeControl.kt | 30 -- .../impl/lifecycle/FxTempAppLifecycleImp.kt | 35 +- .../impl/provider/FxBasicAnimationProvider.kt | 46 +++ .../impl/provider/FxBasicConfigProvider.kt | 98 ++++++ .../impl/provider/FxBasisControlImpl.kt | 144 +++++++++ .../impl/provider/app/FxAppControlImp.kt | 51 +++ .../provider/app/FxAppPlatformProvider.kt | 152 +++++++++ .../impl/provider/scope/FxScopeControl.kt | 26 ++ .../provider/scope/FxScopePlatFromProvider.kt | 65 ++++ .../listener/control/IFxAppControl.kt | 11 - .../floatingx/listener/control/IFxControl.kt | 4 + .../listener/control/IFxScopeControl.kt | 5 +- .../listener/provider/IFxAnimationProvider.kt | 17 + .../listener/provider/IFxBasicProvider.kt | 12 + .../listener/provider/IFxConfigProvider.kt | 9 + .../listener/provider/IFxPlatformProvider.kt | 14 + .../floatingx/{impl => util}/FxScrollImpl.kt | 2 +- .../floatingx/util/SimpleAnimatorListener.kt | 29 ++ .../petterp/floatingx/view/IFxInternalView.kt | 6 +- .../view/default/FxDefaultContainerView.kt | 7 + .../view/system/FxSystemContainerView.kt | 110 ++++++- 29 files changed, 858 insertions(+), 559 deletions(-) rename floatingx/src/main/java/com/petterp/floatingx/assist/{FxScopeEnum.kt => FxScopeType.kt} (92%) delete mode 100644 floatingx/src/main/java/com/petterp/floatingx/impl/control/FxAppControlImpl.kt delete mode 100644 floatingx/src/main/java/com/petterp/floatingx/impl/control/FxBasisControlImpl.kt delete mode 100644 floatingx/src/main/java/com/petterp/floatingx/impl/control/FxScopeControl.kt create mode 100644 floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasicAnimationProvider.kt create mode 100644 floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasicConfigProvider.kt create mode 100644 floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasisControlImpl.kt create mode 100644 floatingx/src/main/java/com/petterp/floatingx/impl/provider/app/FxAppControlImp.kt create mode 100644 floatingx/src/main/java/com/petterp/floatingx/impl/provider/app/FxAppPlatformProvider.kt create mode 100644 floatingx/src/main/java/com/petterp/floatingx/impl/provider/scope/FxScopeControl.kt create mode 100644 floatingx/src/main/java/com/petterp/floatingx/impl/provider/scope/FxScopePlatFromProvider.kt create mode 100644 floatingx/src/main/java/com/petterp/floatingx/listener/provider/IFxAnimationProvider.kt create mode 100644 floatingx/src/main/java/com/petterp/floatingx/listener/provider/IFxBasicProvider.kt create mode 100644 floatingx/src/main/java/com/petterp/floatingx/listener/provider/IFxConfigProvider.kt create mode 100644 floatingx/src/main/java/com/petterp/floatingx/listener/provider/IFxPlatformProvider.kt rename floatingx/src/main/java/com/petterp/floatingx/{impl => util}/FxScrollImpl.kt (91%) create mode 100644 floatingx/src/main/java/com/petterp/floatingx/util/SimpleAnimatorListener.kt diff --git a/app/src/main/java/com/petterp/floatingx/app/kotlin/CustomKtApplication.kt b/app/src/main/java/com/petterp/floatingx/app/kotlin/CustomKtApplication.kt index 355c6c31..bf51421d 100644 --- a/app/src/main/java/com/petterp/floatingx/app/kotlin/CustomKtApplication.kt +++ b/app/src/main/java/com/petterp/floatingx/app/kotlin/CustomKtApplication.kt @@ -19,7 +19,8 @@ import com.petterp.floatingx.app.test.BlackActivity import com.petterp.floatingx.app.test.MultipleFxActivity import com.petterp.floatingx.assist.FxDisplayMode import com.petterp.floatingx.assist.FxGravity -import com.petterp.floatingx.impl.FxScrollImpl +import com.petterp.floatingx.assist.FxScopeType +import com.petterp.floatingx.util.FxScrollImpl import com.petterp.floatingx.impl.lifecycle.FxProxyTagLifecycleImp import com.petterp.floatingx.listener.IFxViewLifecycle @@ -50,6 +51,9 @@ class CustomKtApplication : Application() { fun installTag1(context: Application) { FloatingX.install { setContext(context) + setSystemScope(FxScopeType.SYSTEM) + // 设置浮窗展示类型,默认可移动可点击,无需配置 + setDisplayMode(FxDisplayMode.Normal) setLayout(R.layout.item_floating) // 传递自定义的View // setLayoutView( @@ -125,8 +129,6 @@ class CustomKtApplication : Application() { // 接收所有事件传递 } }) - // 设置浮窗展示类型,默认可移动可点击,无需配置 - setDisplayMode(FxDisplayMode.Normal) // 设置是否启用日志 setEnableLog(BuildConfig.DEBUG) // 设置浮窗tag @@ -134,7 +136,7 @@ class CustomKtApplication : Application() { // 只有调用了enableFx,默认才会启用fx,否则fx不会自动插入activity // ps: 这里的只有调用了enableFx仅仅只是配置工具层的标记,后续使用control.show()也会默认启用 enableFx() - } + }.show() } fun installTag2(context: Application) { diff --git a/floatingx/src/main/java/com/petterp/floatingx/FloatingX.kt b/floatingx/src/main/java/com/petterp/floatingx/FloatingX.kt index 1e19198b..4f3e311d 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/FloatingX.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/FloatingX.kt @@ -1,9 +1,10 @@ package com.petterp.floatingx import android.annotation.SuppressLint +import com.petterp.floatingx.assist.FxScopeType import com.petterp.floatingx.assist.helper.FxAppHelper -import com.petterp.floatingx.impl.control.FxAppControlImpl -import com.petterp.floatingx.impl.lifecycle.FxTempAppLifecycleImp +import com.petterp.floatingx.impl.provider.app.FxAppControlImp +import com.petterp.floatingx.impl.provider.system.FxSystemControlImp import com.petterp.floatingx.listener.control.IFxAppControl import com.petterp.floatingx.listener.control.IFxConfigControl import com.petterp.floatingx.util.FX_APP_DEFAULT_TAG @@ -36,9 +37,14 @@ object FloatingX { @JvmStatic fun install(helper: FxAppHelper): IFxAppControl { fxs[helper.tag]?.cancel() - val fxAppControlImpl = FxAppControlImpl(helper, FxTempAppLifecycleImp()) - fxs[helper.tag] = fxAppControlImpl - return fxAppControlImpl + val fxAppControlImp = if (helper.scope == FxScopeType.SYSTEM) { + FxSystemControlImp(helper) + } else { + FxAppControlImp(helper) + } + fxAppControlImp.initProvider() + fxs[helper.tag] = fxAppControlImp + return fxAppControlImp } /** diff --git a/floatingx/src/main/java/com/petterp/floatingx/assist/FxAnimation.kt b/floatingx/src/main/java/com/petterp/floatingx/assist/FxAnimation.kt index da9318b7..d66b8dff 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/assist/FxAnimation.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/assist/FxAnimation.kt @@ -2,6 +2,7 @@ package com.petterp.floatingx.assist import android.animation.Animator import android.widget.FrameLayout +import com.petterp.floatingx.util.SimpleAnimatorListener /** * fx的动画辅助类 @@ -11,9 +12,8 @@ abstract class FxAnimation { private var startAnimatorJob: Animator? = null private var endAnimatorJob: Animator? = null - - private val Animator.animatorDuration: Long - get() = duration + startDelay + private val startListener = SimpleAnimatorListener() + private val endListener = SimpleAnimatorListener() /** 开始动画 */ abstract fun fromAnimator(view: FrameLayout?): Animator @@ -35,24 +35,36 @@ abstract class FxAnimation { internal fun endJobIsRunning(): Boolean = endAnimatorJob?.isRunning ?: false @JvmSynthetic - internal fun fromStartAnimator(view: FrameLayout?): Long { - startAnimatorJob?.cancel() - startAnimatorJob = fromAnimator(view) - if (startAnimatorJob?.isRunning == true) { - return startAnimatorJob?.duration ?: 0 + internal fun fromStartAnimator(view: FrameLayout?): Boolean { + if (startAnimatorJob == null) { + startAnimatorJob = fromAnimator(view) + startAnimatorJob?.removeListener(startListener) + startAnimatorJob?.addListener(startListener) } + if (endJobIsRunning()) endAnimatorJob?.cancel() startAnimatorJob?.start() - return startAnimatorJob?.animatorDuration ?: 0 + return true } @JvmSynthetic - internal fun toEndAnimator(view: FrameLayout?): Long { - endAnimatorJob?.cancel() - endAnimatorJob = toAnimator(view) - if (endAnimatorJob?.isRunning == true) { - return endAnimatorJob?.duration ?: 0 + internal fun toEndAnimator(view: FrameLayout?): Boolean { + if (endAnimatorJob == null) { + endAnimatorJob = toAnimator(view) + endAnimatorJob?.removeListener(endListener) + endAnimatorJob?.addListener(endListener) } + if (fromJobIsRunning()) startAnimatorJob?.cancel() endAnimatorJob?.start() - return endAnimatorJob?.animatorDuration ?: 0 + return true + } + + @JvmSynthetic + internal fun setFromAnimatorListener(obj: (() -> Unit)?) { + startListener.end = obj + } + + @JvmSynthetic + internal fun setEndAnimatorListener(obj: (() -> Unit)?) { + endListener.end = obj } } diff --git a/floatingx/src/main/java/com/petterp/floatingx/assist/FxScopeEnum.kt b/floatingx/src/main/java/com/petterp/floatingx/assist/FxScopeType.kt similarity index 92% rename from floatingx/src/main/java/com/petterp/floatingx/assist/FxScopeEnum.kt rename to floatingx/src/main/java/com/petterp/floatingx/assist/FxScopeType.kt index b5c716ee..c5acea71 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/assist/FxScopeEnum.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/assist/FxScopeType.kt @@ -1,7 +1,7 @@ package com.petterp.floatingx.assist /** Fx插入的不同位置 */ -enum class FxScopeEnum { +enum class FxScopeType { SYSTEM, // 在系统中展示,必须有权限 AUTO_APP, // 根据用户的权限授予状态,Windows||Activity 自适应处理 APP_WINDOWS, // 在应用内展示,需要权限 diff --git a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxAppHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxAppHelper.kt index cc4a5e24..6e95b1fc 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxAppHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxAppHelper.kt @@ -4,7 +4,7 @@ import android.app.Activity import android.app.Application import android.content.Context import com.petterp.floatingx.FloatingX -import com.petterp.floatingx.assist.FxScopeEnum +import com.petterp.floatingx.assist.FxScopeType import com.petterp.floatingx.listener.IFxProxyTagActivityLifecycle import com.petterp.floatingx.util.FX_APP_DEFAULT_TAG import com.petterp.floatingx.util.FX_INSTALL_SCOPE_APP_TAG @@ -29,7 +29,7 @@ class FxAppHelper( @JvmSynthetic internal val isAllInstall: Boolean, @JvmSynthetic - internal val scope: FxScopeEnum, + internal val scope: FxScopeType, /** 显示悬浮窗的Activity生命周期回调 */ @JvmSynthetic internal val fxLifecycleExpand: IFxProxyTagActivityLifecycle? @@ -66,7 +66,7 @@ class FxAppHelper( private var context: Application? = null private var tag = FX_APP_DEFAULT_TAG private var enableFx = false - private var scopeEnum: FxScopeEnum = FxScopeEnum.APP_ACTIVITY + private var scopeEnum: FxScopeType = FxScopeType.APP_ACTIVITY /** 设置启用fx */ fun enableFx(): Builder { @@ -131,7 +131,7 @@ class FxAppHelper( return this } - fun setSystemScope(scope: FxScopeEnum): Builder { + fun setSystemScope(scope: FxScopeType): Builder { this.scopeEnum = scope return this } @@ -183,7 +183,7 @@ class FxAppHelper( if (enableDebugLog && fxLogTag.isEmpty()) { fxLogTag = tag } - if (scopeEnum == FxScopeEnum.SYSTEM) { + if (scopeEnum == FxScopeType.SYSTEM) { initLog(FX_INSTALL_SCOPE_SYSTEM_TAG) } else { initLog(FX_INSTALL_SCOPE_APP_TAG) diff --git a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxScopeHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxScopeHelper.kt index 699175a6..305d7d36 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxScopeHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxScopeHelper.kt @@ -3,7 +3,7 @@ package com.petterp.floatingx.assist.helper import android.app.Activity import android.widget.FrameLayout import androidx.fragment.app.Fragment -import com.petterp.floatingx.impl.control.FxScopeControl +import com.petterp.floatingx.impl.provider.scope.FxScopeControl import com.petterp.floatingx.listener.control.IFxScopeControl import com.petterp.floatingx.util.FX_INSTALL_SCOPE_ACTIVITY_TAG import com.petterp.floatingx.util.FX_INSTALL_SCOPE_FRAGMENT_TAG @@ -14,9 +14,10 @@ import com.petterp.floatingx.util.contentView class FxScopeHelper : FxBasisHelper() { /** 插入到Activity中 */ - fun toControl(activity: Activity): IFxScopeControl { + fun toControl(activity: Activity): IFxScopeControl { initLog(FX_INSTALL_SCOPE_ACTIVITY_TAG) - val control = FxScopeControl(this) + val control = FxScopeControl(this) + control.initProvider() activity.contentView?.let { control.setContainerGroup(it) } ?: fxLog?.e("install to Activity the Error,current contentView(R.id.content) = null!") @@ -24,21 +25,23 @@ class FxScopeHelper : FxBasisHelper() { } /** 插入到Fragment中 */ - fun toControl(fragment: Fragment): IFxScopeControl { + fun toControl(fragment: Fragment): IFxScopeControl { initLog(FX_INSTALL_SCOPE_FRAGMENT_TAG) val rootView = fragment.view as? FrameLayout checkNotNull(rootView) { "Check if your root layout is FrameLayout, or if the init call timing is after onCreateView()!" } - val control = FxScopeControl(this) + val control = FxScopeControl(this) + control.initProvider() control.setContainerGroup(rootView) return control } /** 插入到ViewGroup中 */ - fun toControl(group: FrameLayout): IFxScopeControl { + fun toControl(group: FrameLayout): IFxScopeControl { initLog(FX_INSTALL_SCOPE_VIEW_GROUP_TAG) - val control = FxScopeControl(this) + val control = FxScopeControl(this) + control.initProvider() control.setContainerGroup(group) return control } diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxAppControlImpl.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxAppControlImpl.kt deleted file mode 100644 index 4defdb81..00000000 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxAppControlImpl.kt +++ /dev/null @@ -1,142 +0,0 @@ -package com.petterp.floatingx.impl.control - -import android.app.Activity -import android.app.Application -import android.content.Context -import android.view.View -import android.view.ViewGroup -import androidx.core.view.OnApplyWindowInsetsListener -import androidx.core.view.ViewCompat -import com.petterp.floatingx.FloatingX -import com.petterp.floatingx.assist.helper.FxAppHelper -import com.petterp.floatingx.impl.lifecycle.FxTempAppLifecycleImp -import com.petterp.floatingx.listener.control.IFxAppControl -import com.petterp.floatingx.util.decorView -import com.petterp.floatingx.util.topActivity - -/** 全局控制器 */ -class FxAppControlImpl( - private val helper: FxAppHelper, - private val proxyLifecycleImpl: FxTempAppLifecycleImp, -) : FxBasisControlImpl(helper), - IFxAppControl, - Application.ActivityLifecycleCallbacks by proxyLifecycleImpl { - - private var isRegisterAppLifecycle = false - - init { - proxyLifecycleImpl.init(helper, this) - checkRegisterAppLifecycle() - } - - override fun context(): Context = helper.context - - private val windowsInsetsListener = OnApplyWindowInsetsListener { _, insets -> - val statusBar = insets.stableInsetTop - if (helper.statsBarHeight != statusBar) { - helper.fxLog?.v("System--StatusBar---old-(${helper.statsBarHeight}),new-($statusBar))") - helper.statsBarHeight = statusBar - } - insets - } - - override fun show() { - val act = topActivity ?: return - if (!helper.isCanInstall(act) || isShow()) return - checkRegisterAppLifecycle() - if (attach(act)) { - internalShow() - updateEnableStatus(true) - } - } - - override fun getBindActivity(): Activity? { - if (getContainerGroup() === topActivity?.decorView) { - return topActivity - } - return null - } - - /** 注意,全局浮窗下,view必须是全局application对应的context! */ - override fun updateView(view: View) { - check(view.context is Application) { - "view.context != Application,The global floating window must use application as context!" - } - super.updateView(view) - } - - override fun cancel() { - super.cancel() - clearWindowsInsetsListener() - if (!FloatingX.fxs.containsValue(this)) return - FloatingX.fxs.remove(helper.tag) - } - - override fun detach(container: ViewGroup?) { - super.detach(container) - clearContainer() - } - - override fun initManager() { - // 在清除之前移除insets监听 - clearWindowsInsetsListener() - super.initManager() - // 移除之后再添加inset监听 - initWindowsInsetsListener() - } - - @JvmSynthetic - internal fun attach(activity: Activity): Boolean { - activity.decorView?.let { - if (getContainerGroup() === it) { - return false - } - var isAnimation = false - if (getManagerView() == null) { - helper.updateNavigationBar(activity) - helper.updateStatsBar(activity) - initManagerView() - isAnimation = true - } else { - if (getManagerView()?.visibility != View.VISIBLE) { - getManagerView()?.visibility = View.VISIBLE - } - detach() - } - setContainerGroup(it) - helper.fxLog?.d("fxView-lifecycle-> code->addView") - helper.iFxViewLifecycle?.postAttach() - getContainerGroup()?.addView(getManagerView()) - if (isAnimation && helper.enableAnimation && helper.fxAnimation != null) { - helper.fxLog?.d("fxView->Animation -----start") - helper.fxAnimation?.fromStartAnimator(getManagerView()) - } - } ?: helper.fxLog?.e("system -> fxParentView==null") - return true - } - - @JvmSynthetic - internal fun detach(activity: Activity) { - detach(activity.decorView) - } - - private fun clearWindowsInsetsListener() { - val managerView = getManagerView() ?: return - ViewCompat.setOnApplyWindowInsetsListener(managerView, null) - } - - private fun initWindowsInsetsListener() { - getManagerView()?.let { - ViewCompat.setOnApplyWindowInsetsListener(it, windowsInsetsListener) - it.requestApplyInsets() - } - } - - private fun checkRegisterAppLifecycle() { - if (!isRegisterAppLifecycle && helper.enableFx) { - isRegisterAppLifecycle = true - helper.context.unregisterActivityLifecycleCallbacks(this) - helper.context.registerActivityLifecycleCallbacks(this) - } - } -} diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxBasisControlImpl.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxBasisControlImpl.kt deleted file mode 100644 index 0a1e6dbc..00000000 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxBasisControlImpl.kt +++ /dev/null @@ -1,305 +0,0 @@ -package com.petterp.floatingx.impl.control - -import android.content.Context -import android.view.View -import android.view.ViewGroup -import android.widget.FrameLayout -import androidx.annotation.LayoutRes -import androidx.core.view.ViewCompat -import com.petterp.floatingx.assist.FxAdsorbDirection -import com.petterp.floatingx.assist.FxAnimation -import com.petterp.floatingx.assist.FxDisplayMode -import com.petterp.floatingx.assist.helper.FxBasisHelper -import com.petterp.floatingx.listener.IFxConfigStorage -import com.petterp.floatingx.listener.IFxScrollListener -import com.petterp.floatingx.listener.IFxViewLifecycle -import com.petterp.floatingx.listener.control.IFxConfigControl -import com.petterp.floatingx.listener.control.IFxControl -import com.petterp.floatingx.listener.provider.IFxContextProvider -import com.petterp.floatingx.listener.provider.IFxHolderProvider -import com.petterp.floatingx.util.INVALID_LAYOUT_ID -import com.petterp.floatingx.util.lazyLoad -import com.petterp.floatingx.view.FxViewHolder -import com.petterp.floatingx.view.IFxInternalView -import com.petterp.floatingx.view.default.FxDefaultContainerView -import java.lang.ref.WeakReference - -/** Fx基础控制器实现 */ -open class FxBasisControlImpl(private val helper: FxBasisHelper) : IFxControl, IFxConfigControl { - private var viewHolder: FxViewHolder? = null - private var mContainer: WeakReference? = null - private var internalView: IFxInternalView? = null - private val cancelAnimationRunnable by lazyLoad { Runnable { reset() } } - private val hideAnimationRunnable by lazyLoad { Runnable { detach() } } - - override val configControl: IFxConfigControl get() = this - - override fun cancel() { - if ((getManagerView() == null && viewHolder == null)) return - if (isShow() && helper.enableAnimation && helper.fxAnimation != null) { - getManagerView()?.removeCallbacks(cancelAnimationRunnable) - val duration = helper.fxAnimation!!.toEndAnimator(internalView?.containerView) - animatorCallback(duration, cancelAnimationRunnable) - } else { - reset() - } - } - - override fun hide() { - if (!isShow()) return - updateEnableStatus(false) - if (helper.enableAnimation && helper.fxAnimation != null) { - if (helper.fxAnimation!!.endJobIsRunning()) { - helper.fxLog?.d("fxView->Animation ,endAnimation Executing, cancel this operation!") - return - } - helper.fxLog?.d("fxView->Animation ,endAnimation Running") - getManagerView()?.removeCallbacks(hideAnimationRunnable) - val duration = helper.fxAnimation!!.toEndAnimator(getManagerView()) - animatorCallback(duration, hideAnimationRunnable) - } else { - detach() - } - } - - override fun isShow(): Boolean { - val managerView = getManagerView() ?: return false - return ViewCompat.isAttachedToWindow(managerView) && managerView.visibility == View.VISIBLE - } - - override fun getView(): View? = internalView?.childView - - override fun getViewHolder(): FxViewHolder? = viewHolder - - override fun getManagerView(): FrameLayout? = internalView?.containerView - - override fun updateView(@LayoutRes resource: Int) { - check(resource != INVALID_LAYOUT_ID) { "resource cannot be INVALID_LAYOUT_ID!" } - helper.layoutView = null - helper.layoutId = resource - updateMangerView() - } - - override fun updateView(view: View) { - helper.layoutId = INVALID_LAYOUT_ID - helper.layoutView = view - updateMangerView() - } - - override fun updateView(provider: IFxContextProvider) { - updateView(provider.build(context())) - } - - override fun updateViewContent(provider: IFxHolderProvider) { - provider.apply(viewHolder ?: return) - } - - override fun setClickListener(time: Long, clickListener: View.OnClickListener) { - helper.clickTime = time - helper.enableClickListener = true - helper.iFxClickListener = clickListener - } - - override fun setClickListener(clickListener: View.OnClickListener) { - setClickListener(0, clickListener) - } - - override fun move(x: Float, y: Float) { - move(x, y, true) - } - - override fun moveByVector(x: Float, y: Float) { - moveByVector(x, y, true) - } - - override fun move(x: Float, y: Float, useAnimation: Boolean) { - internalView?.moveLocation(x, y, useAnimation) - } - - override fun moveByVector(x: Float, y: Float, useAnimation: Boolean) { - internalView?.moveLocationByVector(x, y, useAnimation) - } - - /* - * config配置相关接口实现 - * */ - override fun setEnableClick(isEnable: Boolean) { - helper.enableClickListener = isEnable - } - - override fun setEnableAnimation(isEnable: Boolean, animationImpl: FxAnimation) { - helper.enableAnimation = isEnable - helper.fxAnimation = animationImpl - } - - override fun setEnableAnimation(isEnable: Boolean) { - helper.enableAnimation = isEnable - } - - override fun setBorderMargin(t: Float, l: Float, b: Float, r: Float) { - helper.fxBorderMargin.apply { - this.t = t - this.l = l - this.b = b - this.r = r - } - internalView?.moveToEdge() - } - - override fun setEnableEdgeAdsorption(isEnable: Boolean) { - helper.enableEdgeAdsorption = isEnable - internalView?.moveToEdge() - } - - override fun setEdgeAdsorbDirection(direction: FxAdsorbDirection) { - helper.adsorbDirection = direction - internalView?.moveToEdge() - } - - override fun setEdgeOffset(edgeOffset: Float) { - helper.edgeOffset = edgeOffset - internalView?.moveToEdge() - } - - override fun setEnableEdgeRebound(isEnable: Boolean) { - helper.enableEdgeRebound = isEnable - internalView?.moveToEdge() - } - - override fun setScrollListener(listener: IFxScrollListener) { - helper.iFxScrollListener = listener - } - - override fun setViewLifecycleListener(listener: IFxViewLifecycle) { - helper.iFxViewLifecycle = listener - } - - override fun setEnableSaveDirection(impl: IFxConfigStorage, isEnable: Boolean) { - helper.iFxConfigStorage = impl - helper.enableSaveDirection = isEnable - } - - override fun setEnableSaveDirection(isEnable: Boolean) { - helper.enableSaveDirection = isEnable - } - - override fun clearLocationStorage() { - helper.iFxConfigStorage?.clear() - } - - override fun setEnableTouch(isEnable: Boolean) { - val mode = if (isEnable) FxDisplayMode.Normal else FxDisplayMode.ClickOnly - setDisplayMode(mode) - } - - override fun setDisplayMode(mode: FxDisplayMode) { - helper.displayMode = mode - } - - @JvmSynthetic - internal fun setContainerGroup(viewGroup: ViewGroup) { - mContainer = WeakReference(viewGroup) - } - - /* - * 以下方法作为基础实现,供子类自行调用 - * */ - private fun updateMangerView() { - if (getContainerGroup() == null) throw NullPointerException("FloatingX window The parent container cannot be null!") - internalView?.updateView() - } - - protected fun initManagerView() { - check(helper.layoutId != INVALID_LAYOUT_ID || helper.layoutView != null) { - "The layout id cannot be 0 ,and layoutView==null" - } - getContainerGroup()?.removeView(getManagerView()) - initManager() - } - - protected open fun initManager() { - val context = context() ?: return - internalView = FxDefaultContainerView(context).init(helper) - val fxContentView = internalView?.childView ?: return - viewHolder = FxViewHolder(fxContentView) - val fxViewLifecycle = helper.iFxViewLifecycle ?: return - // 后续此方法将会移除,建议进行过渡 - fxViewLifecycle.initView(fxContentView) - fxViewLifecycle.initView(viewHolder!!) - } - - protected fun getOrInitManagerView(): FrameLayout? { - if (getManagerView() == null) initManagerView() - return getManagerView() - } - - protected fun getContainerGroup(): ViewGroup? { - return mContainer?.get() - } - - protected open fun detach(container: ViewGroup?) { - if (internalView != null && container != null) { - helper.fxLog?.d("fxView-lifecycle-> code->removeView") - helper.iFxViewLifecycle?.postDetached() - container.removeView(getManagerView()) - } - } - - protected fun detach() { - val containerGroup = getContainerGroup() ?: return - detach(containerGroup) - } - - protected open fun context(): Context? { - val context = mContainer?.get()?.context - if (context == null) { - helper.fxLog?.e("context = null,check your rule!") - } - return context - } - - protected fun clearContainer() { - mContainer?.clear() - mContainer = null - } - - protected open fun reset() { - getManagerView()?.apply { - removeCallbacks(hideAnimationRunnable) - removeCallbacks(cancelAnimationRunnable) - } - detach(mContainer?.get()) - internalView = null - viewHolder = null - helper.clear() - clearContainer() - helper.fxLog?.d("fxView-lifecycle-> code->cancelFx") - } - - /** 更新启用状态 */ - protected fun updateEnableStatus(newStatus: Boolean) { - if (helper.enableFx == newStatus) return - helper.enableFx = newStatus - } - - protected open fun internalShow() { - val managerView = getManagerView() ?: return - helper.enableFx = true - managerView.visibility = View.VISIBLE - val fxAnimation = helper.fxAnimation ?: return - if (helper.enableAnimation) { - if (fxAnimation.fromJobIsRunning()) { - helper.fxLog?.d("fxView->Animation ,startAnimation Executing, cancel this operation!") - return - } - helper.fxLog?.d("fxView->Animation ,startAnimation Executing, cancel this operation.") - fxAnimation.fromStartAnimator(managerView) - } - } - - private fun animatorCallback(long: Long, runnable: Runnable) { - val magnetView = getManagerView() ?: return - magnetView.removeCallbacks(runnable) - magnetView.postDelayed(runnable, long) - } -} diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxScopeControl.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxScopeControl.kt deleted file mode 100644 index 5a71d9ca..00000000 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxScopeControl.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.petterp.floatingx.impl.control - -import android.app.Application -import android.view.View -import androidx.core.view.ViewCompat -import com.petterp.floatingx.assist.helper.FxBasisHelper -import com.petterp.floatingx.listener.control.IFxScopeControl - -/** Fx普通View控制器 */ -class FxScopeControl(helper: FxBasisHelper) : - FxBasisControlImpl(helper), - IFxScopeControl { - - override fun show() { - if (isShow()) return - val managerView = getOrInitManagerView() ?: return - updateEnableStatus(true) - if (!ViewCompat.isAttachedToWindow(managerView)) { - getContainerGroup()?.addView(managerView) - } - internalShow() - } - - override fun updateView(view: View) { - if (view.context is Application) { - throw IllegalArgumentException("view = Application,Scope floating windows cannot use application-level views!") - } - super.updateView(view) - } -} diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxTempAppLifecycleImp.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxTempAppLifecycleImp.kt index 3123383c..eaddfeb9 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxTempAppLifecycleImp.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxTempAppLifecycleImp.kt @@ -4,7 +4,7 @@ import android.app.Activity import android.app.Application import android.os.Bundle import com.petterp.floatingx.assist.helper.FxAppHelper -import com.petterp.floatingx.impl.control.FxAppControlImpl +import com.petterp.floatingx.impl.provider.app.FxAppControlImp import com.petterp.floatingx.listener.IFxProxyTagActivityLifecycle import com.petterp.floatingx.util.FxLog import com.petterp.floatingx.util.decorView @@ -15,19 +15,19 @@ import com.petterp.floatingx.util.lazyLoad * * @author petterp */ -class FxTempAppLifecycleImp : Application.ActivityLifecycleCallbacks { - - private var helper: FxAppHelper? = null - private var appControl: FxAppControlImpl? = null +class FxTempAppLifecycleImp( + private val helper: FxAppHelper, + private val appControl: FxAppControlImp +) : Application.ActivityLifecycleCallbacks { private val fxLog: FxLog? - get() = helper?.fxLog + get() = helper.fxLog private val enableFx: Boolean - get() = helper?.enableFx ?: false + get() = helper.enableFx private val appLifecycleCallBack: IFxProxyTagActivityLifecycle? - get() = helper?.fxLifecycleExpand + get() = helper.fxLifecycleExpand private val insertCls by lazyLoad { mutableMapOf, Boolean>() @@ -36,7 +36,7 @@ class FxTempAppLifecycleImp : Application.ActivityLifecycleCallbacks { private val Activity.name: String get() = javaClass.name.split(".").last() private val Activity.isParent: Boolean - get() = appControl?.getManagerView()?.parent === decorView + get() = appControl.getManagerView()?.parent === decorView private val Activity.isActivityInValid: Boolean get() { @@ -44,12 +44,6 @@ class FxTempAppLifecycleImp : Application.ActivityLifecycleCallbacks { return insertCls[cls] ?: isInsertActivity(cls) } - /** 初始化helper与app控制器 */ - fun init(helper: FxAppHelper, control: FxAppControlImpl) { - this.helper = helper - this.appControl = control - } - override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { if (!enableFx) return if (appLifecycleCallBack != null && activity.isActivityInValid) { @@ -59,7 +53,7 @@ class FxTempAppLifecycleImp : Application.ActivityLifecycleCallbacks { override fun onActivityStarted(activity: Activity) { if (!enableFx) return - helper?.fxLifecycleExpand?.onStarted(activity) + helper.fxLifecycleExpand?.onStarted(activity) } /** 最开始想到在onActivityPostStarted后插入, 但是最后发现在Android9及以下,此方法不会被调用,故选择了onResume */ @@ -79,10 +73,7 @@ class FxTempAppLifecycleImp : Application.ActivityLifecycleCallbacks { fxLog?.d("fxApp->insert, insert [$activityName] Fail ,The current Activity has been inserted.") return } - appControl?.let { - it.attach(activity) - fxLog?.d("fxApp->insert, insert [$activityName] Success--------------->") - } ?: fxLog?.d("fxApp->insert, insert [$activityName] Fail ,appControl = null.") + appControl.reAttach(activity) } override fun onActivityPaused(activity: Activity) { @@ -106,7 +97,7 @@ class FxTempAppLifecycleImp : Application.ActivityLifecycleCallbacks { } val isParent = activity.isParent fxLog?.d("fxApp->detach? isContainActivity-${activity.isActivityInValid}--enableFx-$enableFx---isParent-$isParent") - if (isParent) appControl?.detach(activity) + if (isParent) appControl.destroyToDetach(activity) } override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) { @@ -117,7 +108,7 @@ class FxTempAppLifecycleImp : Application.ActivityLifecycleCallbacks { } private fun isInsertActivity(cls: Class<*>): Boolean = - helper?.let { + helper.let { // 条件 允许全局安装&&不在黑名单 || 禁止全局安装&&在白名单 val isInsert = it.isCanInstall(cls) insertCls[cls] = isInsert diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasicAnimationProvider.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasicAnimationProvider.kt new file mode 100644 index 00000000..e08fe6ba --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasicAnimationProvider.kt @@ -0,0 +1,46 @@ +package com.petterp.floatingx.impl.provider + +import android.widget.FrameLayout +import com.petterp.floatingx.assist.helper.FxBasisHelper +import com.petterp.floatingx.listener.provider.IFxAnimationProvider + +/** + * + * @author petterp + */ +class FxBasicAnimationProvider(override val helper: F) : IFxAnimationProvider { + + override fun start(view: FrameLayout, obj: (() -> Unit)?) { + val fxAnimation = helper.fxAnimation ?: return + if (fxAnimation.fromJobIsRunning()) { + helper.fxLog?.d("fxView->Animation,startAnimation Executing, cancel this operation!") + return + } + helper.fxLog?.d("fxView->Animation,startAnimation Running.") + fxAnimation.setFromAnimatorListener(obj) + fxAnimation.fromStartAnimator(view) + } + + override fun hide(view: FrameLayout, obj: (() -> Unit)?) { + val fxAnimation = helper.fxAnimation ?: return + if (helper.fxAnimation!!.endJobIsRunning()) { + helper.fxLog?.d("fxView->Animation,endAnimation Executing, cancel this operation!") + return + } + helper.fxLog?.d("fxView->Animation,endAnimation Running.") + fxAnimation.setEndAnimatorListener(obj) + fxAnimation.toEndAnimator(view) + } + + override fun canRunAnimation(): Boolean { + return helper.enableAnimation && helper.fxAnimation != null + } + + override fun canCancelAnimation(): Boolean { + return helper.enableAnimation && helper.fxAnimation != null + } + + override fun reset() { + helper.fxAnimation?.cancelAnimation() + } +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasicConfigProvider.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasicConfigProvider.kt new file mode 100644 index 00000000..c6466f0d --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasicConfigProvider.kt @@ -0,0 +1,98 @@ +package com.petterp.floatingx.impl.provider + +import com.petterp.floatingx.assist.FxAdsorbDirection +import com.petterp.floatingx.assist.FxAnimation +import com.petterp.floatingx.assist.FxDisplayMode +import com.petterp.floatingx.assist.helper.FxBasisHelper +import com.petterp.floatingx.listener.IFxConfigStorage +import com.petterp.floatingx.listener.IFxScrollListener +import com.petterp.floatingx.listener.IFxViewLifecycle +import com.petterp.floatingx.listener.control.IFxConfigControl +import com.petterp.floatingx.listener.provider.IFxPlatformProvider +import com.petterp.floatingx.view.IFxInternalView + +/** + * Fx基础配置更改 提供者 + * @author petterp + */ +class FxBasicConfigProvider>( + private val helper: F, + private var p: P? +) : IFxConfigControl { + + private val internalView: IFxInternalView? + get() = p?.internalView + + override fun setEnableClick(isEnable: Boolean) { + helper.enableClickListener = isEnable + } + + override fun setEnableAnimation(isEnable: Boolean, animationImpl: FxAnimation) { + helper.enableAnimation = isEnable + helper.fxAnimation = animationImpl + } + + override fun setEnableAnimation(isEnable: Boolean) { + helper.enableAnimation = isEnable + } + + override fun setBorderMargin(t: Float, l: Float, b: Float, r: Float) { + helper.fxBorderMargin.apply { + this.t = t + this.l = l + this.b = b + this.r = r + } + internalView?.moveToEdge() + } + + override fun setEnableEdgeAdsorption(isEnable: Boolean) { + helper.enableEdgeAdsorption = isEnable + internalView?.moveToEdge() + } + + override fun setEdgeAdsorbDirection(direction: FxAdsorbDirection) { + helper.adsorbDirection = direction + internalView?.moveToEdge() + } + + override fun setEdgeOffset(edgeOffset: Float) { + helper.edgeOffset = edgeOffset + internalView?.moveToEdge() + } + + override fun setEnableEdgeRebound(isEnable: Boolean) { + helper.enableEdgeRebound = isEnable + internalView?.moveToEdge() + } + + override fun setScrollListener(listener: IFxScrollListener) { + helper.iFxScrollListener = listener + } + + override fun setViewLifecycleListener(listener: IFxViewLifecycle) { + helper.iFxViewLifecycle = listener + } + + override fun setEnableSaveDirection(impl: IFxConfigStorage, isEnable: Boolean) { + helper.iFxConfigStorage = impl + helper.enableSaveDirection = isEnable + } + + override fun setEnableSaveDirection(isEnable: Boolean) { + helper.enableSaveDirection = isEnable + } + + override fun clearLocationStorage() { + helper.iFxConfigStorage?.clear() + } + + override fun setEnableTouch(isEnable: Boolean) { + val mode = if (isEnable) FxDisplayMode.Normal else FxDisplayMode.ClickOnly + setDisplayMode(mode) + } + + override fun setDisplayMode(mode: FxDisplayMode) { + helper.displayMode = mode + } +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasisControlImpl.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasisControlImpl.kt new file mode 100644 index 00000000..8bad3e2a --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasisControlImpl.kt @@ -0,0 +1,144 @@ +package com.petterp.floatingx.impl.provider + +import android.view.View +import androidx.annotation.LayoutRes +import com.petterp.floatingx.assist.helper.FxBasisHelper +import com.petterp.floatingx.listener.control.IFxConfigControl +import com.petterp.floatingx.listener.control.IFxControl +import com.petterp.floatingx.listener.provider.IFxAnimationProvider +import com.petterp.floatingx.listener.provider.IFxContextProvider +import com.petterp.floatingx.listener.provider.IFxHolderProvider +import com.petterp.floatingx.listener.provider.IFxPlatformProvider +import com.petterp.floatingx.util.INVALID_LAYOUT_ID +import com.petterp.floatingx.view.IFxInternalView + +/** + * Fx基础控制器,用于协调各provider的分发 + * */ +abstract class FxBasisControlImpl>( + protected val helper: F +) : IFxControl { + + protected lateinit var platformProvider: P + private lateinit var _configControl: IFxConfigControl + private lateinit var _animationProvider: IFxAnimationProvider + private val internalView: IFxInternalView? + get() = platformProvider.internalView + + override val configControl: IFxConfigControl get() = _configControl + override fun getView() = internalView?.childView + override fun getViewHolder() = internalView?.viewHolder + override fun getManagerView() = internalView?.containerView + + abstract fun createPlatformProvider(f: F): P + open fun createConfigProvider(f: F, p: P): IFxConfigControl = FxBasicConfigProvider(f, p) + open fun createAnimationProvider(f: F, p: P): IFxAnimationProvider = FxBasicAnimationProvider(f) + + fun initProvider() { + platformProvider = createPlatformProvider(helper) + _animationProvider = createAnimationProvider(helper, platformProvider) + _configControl = createConfigProvider(helper, platformProvider) + } + + override fun show() { + if (isShow()) return + if (!platformProvider.checkOrInit()) return + val fxView = getManagerView() ?: return + updateEnableStatus(true) + platformProvider.show() + if (_animationProvider.canRunAnimation()) { + _animationProvider.start(fxView) + } + } + + override fun hide() { + if (!isShow()) return + val fxView = getManagerView() ?: return + updateEnableStatus(false) + if (_animationProvider.canCancelAnimation()) { + _animationProvider.hide(fxView) { + platformProvider.hide() + } + } else { + platformProvider.hide() + } + } + + override fun cancel() { + val fxView = getManagerView() ?: return + if (isShow() && _animationProvider.canRunAnimation()) { + _animationProvider.hide(fxView) { + reset() + } + } else { + reset() + } + } + + override fun isShow(): Boolean { + return platformProvider.isShow() + } + + override fun updateView(@LayoutRes resource: Int) { + check(resource != INVALID_LAYOUT_ID) { "resource cannot be INVALID_LAYOUT_ID!" } + helper.layoutView = null + helper.layoutId = resource + internalView?.updateView() + } + + override fun updateView(view: View) { + helper.layoutId = INVALID_LAYOUT_ID + helper.layoutView = view + internalView?.updateView() + } + + override fun updateView(provider: IFxContextProvider) { + updateView(provider.build(platformProvider.context)) + } + + override fun updateViewContent(provider: IFxHolderProvider) { + provider.apply(getViewHolder() ?: return) + } + + override fun setClickListener(time: Long, clickListener: View.OnClickListener) { + helper.clickTime = time + helper.enableClickListener = true + helper.iFxClickListener = clickListener + } + + override fun setClickListener(clickListener: View.OnClickListener) { + setClickListener(0, clickListener) + } + + override fun move(x: Float, y: Float) { + move(x, y, true) + } + + override fun moveByVector(x: Float, y: Float) { + moveByVector(x, y, true) + } + + override fun move(x: Float, y: Float, useAnimation: Boolean) { + internalView?.moveLocation(x, y, useAnimation) + } + + override fun moveByVector(x: Float, y: Float, useAnimation: Boolean) { + internalView?.moveLocationByVector(x, y, useAnimation) + } + + override fun updateConfig(obj: IFxConfigControl.() -> Unit) { + obj.invoke(_configControl) + } + + protected open fun reset() { + platformProvider.reset() + _animationProvider.reset() + helper.clear() + helper.fxLog?.d("fxView-lifecycle-> code->cancelFx") + } + + private fun updateEnableStatus(newStatus: Boolean) { + if (helper.enableFx == newStatus) return + helper.enableFx = newStatus + } +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/app/FxAppControlImp.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/app/FxAppControlImp.kt new file mode 100644 index 00000000..ec2406fa --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/app/FxAppControlImp.kt @@ -0,0 +1,51 @@ +package com.petterp.floatingx.impl.provider.app + +import android.app.Activity +import android.app.Application +import android.view.View +import com.petterp.floatingx.FloatingX +import com.petterp.floatingx.assist.helper.FxAppHelper +import com.petterp.floatingx.impl.lifecycle.FxTempAppLifecycleImp +import com.petterp.floatingx.impl.provider.FxBasisControlImpl +import com.petterp.floatingx.listener.control.IFxAppControl +import com.petterp.floatingx.util.decorView +import com.petterp.floatingx.util.topActivity + +/** 全局控制器 */ +class FxAppControlImp(helper: FxAppHelper) : FxBasisControlImpl(helper), IFxAppControl { + + override fun createPlatformProvider(f: FxAppHelper) = + FxAppPlatformProvider(f, FxTempAppLifecycleImp(f, this)) + + override fun getBindActivity(): Activity? { + val groupView = getManagerView()?.parent ?: return null + if (groupView === topActivity?.decorView) { + return topActivity + } + return null + } + + override fun updateView(view: View) { + check(view.context is Application) { + "view.context != Application,The global floating window must use application as context!" + } + super.updateView(view) + } + + @JvmSynthetic + internal fun reAttach(activity: Activity) { + if (!platformProvider.reAttach(activity)) return + show() + } + + @JvmSynthetic + internal fun destroyToDetach(activity: Activity) { + platformProvider.destroyToDetach(activity) + } + + override fun reset() { + super.reset() + if (!FloatingX.fxs.containsValue(this)) return + FloatingX.fxs.remove(helper.tag) + } +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/app/FxAppPlatformProvider.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/app/FxAppPlatformProvider.kt new file mode 100644 index 00000000..4cf56549 --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/app/FxAppPlatformProvider.kt @@ -0,0 +1,152 @@ +package com.petterp.floatingx.impl.provider.app + +import android.app.Activity +import android.app.Application +import android.content.Context +import android.view.View +import android.view.ViewGroup +import androidx.core.view.OnApplyWindowInsetsListener +import androidx.core.view.ViewCompat +import com.petterp.floatingx.assist.FxScopeType +import com.petterp.floatingx.assist.helper.FxAppHelper +import com.petterp.floatingx.impl.lifecycle.FxTempAppLifecycleImp +import com.petterp.floatingx.listener.provider.IFxPlatformProvider +import com.petterp.floatingx.util.decorView +import com.petterp.floatingx.util.topActivity +import com.petterp.floatingx.view.IFxInternalView +import com.petterp.floatingx.view.default.FxDefaultContainerView +import java.lang.ref.WeakReference + +/** + * 免权限的浮窗提供者 + * @author petterp + */ +class FxAppPlatformProvider( + override val helper: FxAppHelper, + private val proxyLifecycleImpl: FxTempAppLifecycleImp, +) : IFxPlatformProvider, Application.ActivityLifecycleCallbacks by proxyLifecycleImpl { + + private var isRegisterAppLifecycle = false + private var _internalView: FxDefaultContainerView? = null + private var _containerGroup: WeakReference? = null + + private val windowsInsetsListener = OnApplyWindowInsetsListener { _, insets -> + val statusBar = insets.stableInsetTop + if (helper.statsBarHeight != statusBar) { + helper.fxLog?.v("System--StatusBar---old-(${helper.statsBarHeight}),new-($statusBar))") + helper.statsBarHeight = statusBar + } + insets + } + + init { + checkRegisterAppLifecycle() + } + + private val containerGroupView: ViewGroup? + get() = _containerGroup?.get() + + override val context: Context + get() = helper.context + override val internalView: IFxInternalView? + get() = _internalView + + override fun checkOrInit(): Boolean { + val act = topActivity ?: return false + if (!helper.isCanInstall(act)) return false + if (_internalView == null) { + initWindowsInsetsListener() + helper.updateNavigationBar(act) + helper.updateStatsBar(act) + _internalView = FxDefaultContainerView(helper.context).init(helper) + checkRegisterAppLifecycle() + attach(act) + } + return true + } + + override fun show() { + val fxView = _internalView ?: return + if (!ViewCompat.isAttachedToWindow(fxView)) { + fxView.visibility = View.VISIBLE + containerGroupView?.addView(fxView) + } + } + + override fun hide() { + detach() + } + + override fun isShow(): Boolean { + val managerView = _internalView ?: return false + return managerView.isAttachedToWindow && managerView.visibility == View.VISIBLE + } + + private fun attach(activity: Activity): Boolean { + val fxView = _internalView ?: return false + val decorView = activity.decorView ?: return false + if (containerGroupView === decorView) return false + if (ViewCompat.isAttachedToWindow(fxView)) containerGroupView?.removeView(fxView) + _containerGroup = WeakReference(decorView) + helper.fxLog?.d("fxView-lifecycle-> onPostAttach") + helper.iFxViewLifecycle?.postAttach() + decorView.addView(fxView) + return true + } + + fun reAttach(activity: Activity): Boolean { + val nContainer = activity.decorView ?: return false + if (_internalView == null) { + _containerGroup = WeakReference(nContainer) + return true + } else { + if (nContainer === containerGroupView) return false + containerGroupView?.removeView(_internalView) + nContainer.addView(_internalView) + _containerGroup = WeakReference(nContainer) + } + return false + } + + fun destroyToDetach(activity: Activity): Boolean { + val fxView = _internalView ?: return false + val oldContainer = containerGroupView ?: return false + if (!ViewCompat.isAttachedToWindow(fxView)) return false + val nContainer = activity.decorView ?: return false + if (nContainer !== oldContainer) return false + oldContainer.removeView(_internalView) + return true + } + + override fun reset() { + clearWindowsInsetsListener() + _internalView = null + _containerGroup?.clear() + _containerGroup = null + } + + private fun detach() { + helper.fxLog?.d("fxView-lifecycle-> onPostDetach") + _internalView?.visibility = View.GONE + containerGroupView?.removeView(_internalView) + } + + private fun initWindowsInsetsListener() { + val fxView = _internalView ?: return + ViewCompat.setOnApplyWindowInsetsListener(fxView, windowsInsetsListener) + fxView.requestApplyInsets() + } + + private fun checkRegisterAppLifecycle() { + if (!isRegisterAppLifecycle && helper.enableFx && helper.scope == FxScopeType.APP_ACTIVITY) { + isRegisterAppLifecycle = true + helper.context.unregisterActivityLifecycleCallbacks(this) + helper.context.registerActivityLifecycleCallbacks(this) + } + } + + private fun clearWindowsInsetsListener() { + val managerView = _internalView ?: return + ViewCompat.setOnApplyWindowInsetsListener(managerView, null) + } +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/scope/FxScopeControl.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/scope/FxScopeControl.kt new file mode 100644 index 00000000..ff5a981b --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/scope/FxScopeControl.kt @@ -0,0 +1,26 @@ +package com.petterp.floatingx.impl.provider.scope + +import android.app.Application +import android.view.View +import android.view.ViewGroup +import com.petterp.floatingx.assist.helper.FxScopeHelper +import com.petterp.floatingx.impl.provider.FxBasisControlImpl +import com.petterp.floatingx.listener.control.IFxScopeControl + +/** Fx普通View控制器 */ +class FxScopeControl(helper: FxScopeHelper) : + FxBasisControlImpl(helper), IFxScopeControl { + + override fun createPlatformProvider(f: FxScopeHelper) = FxScopePlatFromProvider(f) + + fun setContainerGroup(viewGroup: ViewGroup) { + platformProvider.setContainerGroup(viewGroup) + } + + override fun updateView(view: View) { + check(view.context !is Application) { + "view = Application,Scope floating windows cannot use application-level views!" + } + super.updateView(view) + } +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/scope/FxScopePlatFromProvider.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/scope/FxScopePlatFromProvider.kt new file mode 100644 index 00000000..e96568c9 --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/scope/FxScopePlatFromProvider.kt @@ -0,0 +1,65 @@ +package com.petterp.floatingx.impl.provider.scope + +import android.content.Context +import android.view.View +import android.view.ViewGroup +import com.petterp.floatingx.assist.helper.FxScopeHelper +import com.petterp.floatingx.listener.provider.IFxPlatformProvider +import com.petterp.floatingx.view.FxViewHolder +import com.petterp.floatingx.view.IFxInternalView +import com.petterp.floatingx.view.default.FxDefaultContainerView +import java.lang.ref.WeakReference + +/** + * Fx局部控制器 + * @author petterp + */ +class FxScopePlatFromProvider( + override val helper: FxScopeHelper, +) : IFxPlatformProvider { + + private var _holder: FxViewHolder? = null + private var _internalView: FxDefaultContainerView? = null + private var _containerGroup: WeakReference? = null + + private val containerGroupView: ViewGroup? + get() = _containerGroup?.get() + override val context: Context? + get() = containerGroupView?.context + + override val internalView: IFxInternalView? + get() = _internalView + + fun setContainerGroup(viewGroup: ViewGroup) { + _containerGroup = WeakReference(viewGroup) + } + + override fun show() { + _internalView?.visibility = View.VISIBLE + } + + override fun hide() { + _internalView?.visibility = View.GONE + } + + override fun isShow(): Boolean { + val managerView = _internalView ?: return false + return managerView.isAttachedToWindow && managerView.visibility == View.VISIBLE + } + + override fun checkOrInit(): Boolean { + if (_internalView == null) { + val containerGroupView = containerGroupView ?: return false + _internalView = FxDefaultContainerView(containerGroupView.context).init(helper) + _holder = FxViewHolder(_internalView?.containerView) + containerGroupView.addView(_internalView) + } + return true + } + + override fun reset() { + containerGroupView?.removeView(_internalView) + _containerGroup?.clear() + _containerGroup = null + } +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxAppControl.kt b/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxAppControl.kt index 35a41117..c63b8304 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxAppControl.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxAppControl.kt @@ -5,17 +5,6 @@ import android.app.Activity /** App特有的控制方法 */ interface IFxAppControl : IFxControl { - /** - * 在当前activity中显示浮窗 - * - * @param activity 当前要显示浮窗的activity - * - * 第一次调用该方法时,我们会插入一个AppLifecycle,用于监听activity的变化。当后续浮窗被cancel()时,我们会根据浮窗个数(=0),自动清空该lifecycle的绑定 - * - * ps:尽管我们可以做到不传递activity,但是这种方式需要以性能作为牺牲,比如需要永久维护一个顶级activity与AppLifecycle监听器 - */ - fun show() - /** 获得当前浮窗绑定的activity,不要手动保留此activity,以避免泄漏 */ fun getBindActivity(): Activity? } diff --git a/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxControl.kt b/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxControl.kt index 0a916182..89137f92 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxControl.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxControl.kt @@ -13,6 +13,8 @@ interface IFxControl { /** 获取配置层控制器,以便运行时动态调整某些基础配置 */ val configControl: IFxConfigControl + fun show() + /** 隐藏悬浮窗-不会解绑app-lifecycle */ fun hide() @@ -85,4 +87,6 @@ interface IFxControl { * @param useAnimation 是否使用动画 * */ fun moveByVector(x: Float, y: Float, useAnimation: Boolean) + + fun updateConfig(obj: IFxConfigControl.() -> Unit) } diff --git a/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxScopeControl.kt b/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxScopeControl.kt index 170c04e2..f4c34e15 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxScopeControl.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/listener/control/IFxScopeControl.kt @@ -1,7 +1,4 @@ package com.petterp.floatingx.listener.control /** Fx局部控制器 */ -interface IFxScopeControl : IFxControl { - /** 显示浮窗 */ - fun show() -} +interface IFxScopeControl : IFxControl diff --git a/floatingx/src/main/java/com/petterp/floatingx/listener/provider/IFxAnimationProvider.kt b/floatingx/src/main/java/com/petterp/floatingx/listener/provider/IFxAnimationProvider.kt new file mode 100644 index 00000000..099a3982 --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/listener/provider/IFxAnimationProvider.kt @@ -0,0 +1,17 @@ +package com.petterp.floatingx.listener.provider + +import android.widget.FrameLayout +import com.petterp.floatingx.assist.helper.FxBasisHelper + +/** + * + * @author petterp + */ +interface IFxAnimationProvider : IFxBasicProvider { + fun start(view: FrameLayout, obj: (() -> Unit)? = null) + + fun hide(view: FrameLayout, obj: (() -> Unit)? = null) + + fun canRunAnimation(): Boolean + fun canCancelAnimation(): Boolean +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/listener/provider/IFxBasicProvider.kt b/floatingx/src/main/java/com/petterp/floatingx/listener/provider/IFxBasicProvider.kt new file mode 100644 index 00000000..a6f45208 --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/listener/provider/IFxBasicProvider.kt @@ -0,0 +1,12 @@ +package com.petterp.floatingx.listener.provider + +import com.petterp.floatingx.assist.helper.FxBasisHelper + +/** + * 基础fx提供者 + * @author petterp + */ +interface IFxBasicProvider { + val helper: F + fun reset() {} +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/listener/provider/IFxConfigProvider.kt b/floatingx/src/main/java/com/petterp/floatingx/listener/provider/IFxConfigProvider.kt new file mode 100644 index 00000000..85efecfa --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/listener/provider/IFxConfigProvider.kt @@ -0,0 +1,9 @@ +package com.petterp.floatingx.listener.provider + +/** + * + * @author petterp + */ +interface IFxConfigProvider { + fun apply() +} \ No newline at end of file diff --git a/floatingx/src/main/java/com/petterp/floatingx/listener/provider/IFxPlatformProvider.kt b/floatingx/src/main/java/com/petterp/floatingx/listener/provider/IFxPlatformProvider.kt new file mode 100644 index 00000000..9d35fc5e --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/listener/provider/IFxPlatformProvider.kt @@ -0,0 +1,14 @@ +package com.petterp.floatingx.listener.provider + +import android.content.Context +import com.petterp.floatingx.assist.helper.FxBasisHelper +import com.petterp.floatingx.view.IFxInternalView + +interface IFxPlatformProvider : IFxBasicProvider { + val context: Context? + val internalView: IFxInternalView? + fun show() + fun hide() + fun isShow(): Boolean + fun checkOrInit(): Boolean +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/FxScrollImpl.kt b/floatingx/src/main/java/com/petterp/floatingx/util/FxScrollImpl.kt similarity index 91% rename from floatingx/src/main/java/com/petterp/floatingx/impl/FxScrollImpl.kt rename to floatingx/src/main/java/com/petterp/floatingx/util/FxScrollImpl.kt index 4e12d16b..1aace662 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/FxScrollImpl.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/util/FxScrollImpl.kt @@ -1,4 +1,4 @@ -package com.petterp.floatingx.impl +package com.petterp.floatingx.util import android.view.MotionEvent import com.petterp.floatingx.listener.IFxScrollListener diff --git a/floatingx/src/main/java/com/petterp/floatingx/util/SimpleAnimatorListener.kt b/floatingx/src/main/java/com/petterp/floatingx/util/SimpleAnimatorListener.kt new file mode 100644 index 00000000..d73ffa02 --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/util/SimpleAnimatorListener.kt @@ -0,0 +1,29 @@ +package com.petterp.floatingx.util + +import android.animation.Animator +import android.animation.Animator.AnimatorListener + +/** + * + * @author petterp + */ +class SimpleAnimatorListener( + var start: (() -> Unit)? = null, + var end: (() -> Unit)? = null +) : + AnimatorListener { + override fun onAnimationStart(animation: Animator?) { + start?.invoke() + } + + override fun onAnimationEnd(animation: Animator?) { + end?.invoke() + } + + override fun onAnimationCancel(animation: Animator?) { + end?.invoke() + } + + override fun onAnimationRepeat(animation: Animator?) { + } +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/IFxInternalView.kt b/floatingx/src/main/java/com/petterp/floatingx/view/IFxInternalView.kt index 514359ea..e426b043 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/IFxInternalView.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/IFxInternalView.kt @@ -7,11 +7,13 @@ import android.widget.FrameLayout * * @author petterp */ -internal interface IFxInternalView { +interface IFxInternalView { + + val childView: View? val containerView: FrameLayout - val childView: View? + val viewHolder: FxViewHolder? fun moveLocation(x: Float, y: Float, useAnimation: Boolean = true) diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/default/FxDefaultContainerView.kt b/floatingx/src/main/java/com/petterp/floatingx/view/default/FxDefaultContainerView.kt index 8d21a983..d7dd6b18 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/default/FxDefaultContainerView.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/default/FxDefaultContainerView.kt @@ -19,6 +19,7 @@ import com.petterp.floatingx.util.INVALID_LAYOUT_ID import com.petterp.floatingx.util.INVALID_TOUCH_ID import com.petterp.floatingx.util.pointerId import com.petterp.floatingx.util.withIn +import com.petterp.floatingx.view.FxViewHolder import com.petterp.floatingx.view.IFxInternalView /** 基础悬浮窗View */ @@ -32,12 +33,18 @@ class FxDefaultContainerView @JvmOverloads constructor( private val clickHelper = FxClickHelper() private val locationHelper = FxLocationHelper() private val configHelper = FxViewConfigHelper() + private var _viewHolder: FxViewHolder? = null private var _childFxView: View? = null override val childView: View? get() = _childFxView override val containerView: FrameLayout get() = this + override val viewHolder: FxViewHolder? + get() { + if (_viewHolder == null) _viewHolder = FxViewHolder(this) + return _viewHolder + } @JvmSynthetic internal fun init(config: FxBasisHelper): FxDefaultContainerView { diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt b/floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt index b967928d..a9516b03 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt @@ -2,10 +2,19 @@ package com.petterp.floatingx.view.system import android.annotation.SuppressLint import android.content.Context +import android.graphics.PixelFormat +import android.os.Build import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.MotionEvent import android.view.View +import android.view.ViewGroup +import android.view.WindowManager import android.widget.FrameLayout +import com.petterp.floatingx.assist.helper.FxAppHelper import com.petterp.floatingx.assist.helper.FxBasisHelper +import com.petterp.floatingx.util.INVALID_LAYOUT_ID +import com.petterp.floatingx.view.FxViewHolder import com.petterp.floatingx.view.IFxInternalView /** 基础悬浮窗View */ @@ -16,23 +25,114 @@ class FxSystemContainerView @JvmOverloads constructor( ) : FrameLayout(context, attrs), IFxInternalView { private lateinit var helper: FxBasisHelper + private lateinit var wl: WindowManager.LayoutParams + private lateinit var wm: WindowManager + private var _childFxView: View? = null + private var _viewHolder: FxViewHolder? = null + private var cX = 0 + private var cY = 0 + override val containerView: FrameLayout get() = this - override val childView: View - get() = TODO("Not yet implemented") + override val childView: View? + get() = _childFxView + override val viewHolder: FxViewHolder? + get() { + if (_viewHolder == null) _viewHolder = FxViewHolder(this) + return _viewHolder + } + + fun init( + config: FxAppHelper + ): FxSystemContainerView { + this.helper = config + initView() + return this + } + + private fun initView() { + _childFxView = inflateLayoutView() ?: inflateLayoutId() + wl = WindowManager.LayoutParams().apply { + // 设置大小 自适应 + width = WindowManager.LayoutParams.WRAP_CONTENT + height = WindowManager.LayoutParams.WRAP_CONTENT + format = PixelFormat.TRANSPARENT + /** + * 注意,flag的值可以为: + * 下面的flags属性的效果形同“锁定”。 + * 悬浮窗不可触摸,不接受任何事件,同时不影响后面的事件响应。 + * LayoutParams.FLAG_NOT_TOUCH_MODAL 不影响后面的事件 + * LayoutParams.FLAG_NOT_FOCUSABLE 不可聚焦 + * LayoutParams.FLAG_NOT_TOUCHABLE 不可触摸 + */ + flags = + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY + } else { + WindowManager.LayoutParams.TYPE_SYSTEM_ALERT + } + } + wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager + wm.addView(this, wl) + } + + private fun inflateLayoutView(): View? { + val view = helper.layoutView ?: return null + helper.fxLog?.d("fxView-->init, way:[layoutView]") + val lp = view.layoutParams ?: LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT, + ) + addView(view, lp) + return view + } + + private fun inflateLayoutId(): View? { + if (helper.layoutId == INVALID_LAYOUT_ID) return null + helper.fxLog?.d("fxView-->init, way:[layoutId]") + val view = LayoutInflater.from(context).inflate(helper.layoutId, this, false) + addView(view) + return view + } override fun moveLocation(x: Float, y: Float, useAnimation: Boolean) { - TODO("Not yet implemented") } override fun moveLocationByVector(x: Float, y: Float, useAnimation: Boolean) { - TODO("Not yet implemented") } override fun moveToEdge() { - TODO("Not yet implemented") } override fun updateView() { } + + override fun onTouchEvent(event: MotionEvent): Boolean { + when (event.action) { + MotionEvent.ACTION_DOWN -> { + cX = event.rawX.toInt() + cY = event.rawY.toInt() + } + + MotionEvent.ACTION_MOVE -> { + val nowX = event.rawX.toInt() + val nowY = event.rawY.toInt() + val movedX = nowX - cX + val movedY = nowY - cY + cX = nowX + cY = nowY + wl.apply { + x += movedX + y += movedY + } + // 更新悬浮球控件位置 + wm.updateViewLayout(this, wl) + } + + else -> { + } + } + return super.onTouchEvent(event) + } } From cdb5c64cb7eb30f556ceb5e85937b6eca4ba8751 Mon Sep 17 00:00:00 2001 From: petterp Date: Mon, 18 Dec 2023 23:04:01 +0800 Subject: [PATCH 5/8] =?UTF-8?q?perf:=E9=87=8D=E6=9E=84=E6=B5=AE=E7=AA=97vi?= =?UTF-8?q?ew=E8=AE=BE=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 17 +- .../com/petterp/floatingx/app/MainActivity.kt | 4 + .../floatingx/app/test/SystemActivity.kt | 34 ++++ .../java/com/petterp/floatingx/app/utils.kt | 30 ++-- .../floatingx/assist/helper/FxBasisHelper.kt | 89 ++++++++++ .../impl/control/FxSystemControlImpl.kt | 22 --- .../impl/provider/FxBasisControlImpl.kt | 5 +- .../provider/app/FxAppPlatformProvider.kt | 5 - .../provider/scope/FxScopePlatFromProvider.kt | 5 - .../provider/system/FxSystemControlImp.kt | 18 ++ .../system/FxSystemPlatformProvider.kt | 57 +++++++ .../listener/provider/IFxPlatformProvider.kt | 2 +- .../java/com/petterp/floatingx/util/FxExt.kt | 37 ++--- .../com/petterp/floatingx/util/FxScreenExt.kt | 9 + .../floatingx/view/basic/FxBasicParentView.kt | 112 +++++++++++++ .../FxViewLocationHelper.kt} | 3 +- .../floatingx/view/basic/FxViewTouchHelper.kt | 135 +++++++++++++++ .../floatingx/view/default/FxClickHelper.kt | 64 ------- .../view/default/FxDefaultContainerView.kt | 13 +- .../view/system/FxSystemContainerView.kt | 157 +++++++----------- 20 files changed, 579 insertions(+), 239 deletions(-) create mode 100644 app/src/main/java/com/petterp/floatingx/app/test/SystemActivity.kt delete mode 100644 floatingx/src/main/java/com/petterp/floatingx/impl/control/FxSystemControlImpl.kt create mode 100644 floatingx/src/main/java/com/petterp/floatingx/impl/provider/system/FxSystemControlImp.kt create mode 100644 floatingx/src/main/java/com/petterp/floatingx/impl/provider/system/FxSystemPlatformProvider.kt create mode 100644 floatingx/src/main/java/com/petterp/floatingx/view/basic/FxBasicParentView.kt rename floatingx/src/main/java/com/petterp/floatingx/view/{default/FxLocationHelper.kt => basic/FxViewLocationHelper.kt} (95%) create mode 100644 floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewTouchHelper.kt delete mode 100644 floatingx/src/main/java/com/petterp/floatingx/view/default/FxClickHelper.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d090e67b..759c3d07 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -17,13 +17,7 @@ android:name="com.petterp.floatingx.app.MainActivity" android:configChanges="keyboard|orientation|keyboardHidden|screenSize|smallestScreenSize|screenLayout|locale|navigation|fontScale|mcc|mnc|uiMode" android:exported="true" - android:windowSoftInputMode="adjustPan"> - - - - - - + android:windowSoftInputMode="adjustPan"> @@ -34,6 +28,15 @@ + + + + + + + Unit) = LinearLayout(this).apply { layoutParams = LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, - LinearLayout.LayoutParams.MATCH_PARENT + LinearLayout.LayoutParams.MATCH_PARENT, ) orientation = LinearLayout.VERTICAL obj.invoke(this) @@ -39,11 +39,11 @@ inline fun ViewGroup.addLinearLayout(obj: LinearLayout.() -> Unit) = LinearLayout(context).apply { layoutParams = LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, - LinearLayout.LayoutParams.MATCH_PARENT + LinearLayout.LayoutParams.MATCH_PARENT, ) orientation = LinearLayout.VERTICAL obj.invoke(this) - } + }, ) inline fun ViewGroup.addFrameLayout(obj: FrameLayout.() -> Unit) = @@ -51,10 +51,10 @@ inline fun ViewGroup.addFrameLayout(obj: FrameLayout.() -> Unit) = FrameLayout(context).apply { layoutParams = FrameLayout.LayoutParams( FrameLayout.LayoutParams.MATCH_PARENT, - FrameLayout.LayoutParams.MATCH_PARENT + FrameLayout.LayoutParams.MATCH_PARENT, ) obj.invoke(this) - } + }, ) inline fun ViewGroup.addNestedScrollView(obj: NestedScrollView.() -> Unit) { @@ -62,7 +62,7 @@ inline fun ViewGroup.addNestedScrollView(obj: NestedScrollView.() -> Unit) { NestedScrollView(context).apply { layoutParams = FrameLayout.LayoutParams(-1, -2) obj.invoke(this) - } + }, ) } @@ -71,20 +71,20 @@ fun ViewGroup.addItemView(text: String, click: View.OnClickListener) = Button(context).apply { layoutParams = ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT + ViewGroup.LayoutParams.WRAP_CONTENT, ) (this as TextView).isAllCaps = false gravity = Gravity.CENTER setOnClickListener(click) this.text = text - } + }, ) inline fun ViewGroup.addTextView(obj: TextView.() -> Unit) { addView( TextView(context).apply { obj.invoke(this) - } + }, ) } @@ -93,7 +93,15 @@ fun Class<*>.start(context: Context) { } val Number.dp: Int - get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, toFloat(), Resources.getSystem().displayMetrics).toInt() + get() = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + toFloat(), + Resources.getSystem().displayMetrics, + ).toInt() val Number.dpF: Float - get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, toFloat(), Resources.getSystem().displayMetrics) \ No newline at end of file + get() = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + toFloat(), + Resources.getSystem().displayMetrics, + ) diff --git a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxBasisHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxBasisHelper.kt index 1ef9f3d4..207b4795 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxBasisHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxBasisHelper.kt @@ -12,6 +12,7 @@ import com.petterp.floatingx.listener.IFxConfigStorage import com.petterp.floatingx.listener.IFxScrollListener import com.petterp.floatingx.listener.IFxViewLifecycle import com.petterp.floatingx.util.FxLog +import com.petterp.floatingx.util.coerceInFx import kotlin.math.abs /** 通用构建器helper */ @@ -19,6 +20,12 @@ open class FxBasisHelper { @JvmField internal var layoutId: Int = 0 + @JvmField + internal var offsetX: Int = 0 + + @JvmField + internal var offsetY: Int = 0 + @JvmField internal var layoutView: View? = null @@ -114,6 +121,77 @@ open class FxBasisHelper { fxAnimation?.cancelAnimation() } + private val safeEdgeOffSet: Float + get() = if (enableEdgeRebound) edgeOffset else 0F + + fun defaultXY(width: Int, height: Int, viewW: Int, viewH: Int): Pair { + return if (enableSaveDirection && iFxConfigStorage?.hasConfig() == true) { + getHistoryXY(width, viewW, height, viewH) + } else { + getDefaultXY(width, height, viewW, viewH) + } + } + + private fun getHistoryXY( + width: Int, + viewW: Int, + height: Int, + viewH: Int + ): Pair { + val configX = iFxConfigStorage!!.getX() + val configY = iFxConfigStorage!!.getY() + val bMinX = safeEdgeOffSet + fxBorderMargin.l + val bMaxX = width - viewW - safeEdgeOffSet - fxBorderMargin.r + val bMinY = safeEdgeOffSet + fxBorderMargin.t + val bMaxY = height - viewH - safeEdgeOffSet - fxBorderMargin.b + return configX.coerceInFx(bMinX, bMaxX).toInt() to configY.coerceInFx(bMinY, bMaxY).toInt() + } + + private fun getDefaultXY(width: Int, height: Int, viewW: Int, viewH: Int): Pair { + val l = (offsetX + safeEdgeOffSet + fxBorderMargin.l).toInt() + val r = (offsetX + safeEdgeOffSet + fxBorderMargin.r).toInt() + val b = (offsetY + safeEdgeOffSet + fxBorderMargin.b).toInt() + val t = (offsetY + safeEdgeOffSet + fxBorderMargin.t).toInt() + return when (gravity) { + FxGravity.DEFAULT, + FxGravity.LEFT_OR_TOP -> { + l to t + } + + FxGravity.LEFT_OR_CENTER -> { + l to (height - viewH).shr(1) + } + + FxGravity.LEFT_OR_BOTTOM -> { + 0 to height - viewH - b + } + + FxGravity.RIGHT_OR_TOP -> { + width - viewW - r to t + } + + FxGravity.RIGHT_OR_CENTER -> { + width - viewW - r to (height - viewH).shr(1) + } + + FxGravity.RIGHT_OR_BOTTOM -> { + width - viewW - r to height - viewH - b + } + + FxGravity.TOP_OR_CENTER -> { + (width - viewW).shr(1) to t + } + + FxGravity.BOTTOM_OR_CENTER -> { + (width - viewW).shr(1) to height - viewH - b + } + + else -> { + (width - viewW).shr(1) to (height - viewH).shr(1) + } + } + } + abstract class Builder { @LayoutRes private var layoutId: Int = 0 @@ -127,6 +205,8 @@ open class FxBasisHelper { private var defaultY: Float = 0f private var defaultX: Float = 0f + private var offsetX: Int = 0 + private var offsetY: Int = 0 private var edgeOffset: Float = 0f private var enableFx: Boolean = false private var fxBorderMargin: FxBorderMargin = FxBorderMargin() @@ -165,6 +245,9 @@ open class FxBasisHelper { defaultY = this@Builder.defaultY defaultX = this@Builder.defaultX + offsetX = this@Builder.offsetX + offsetY = this@Builder.offsetY + edgeOffset = this@Builder.edgeOffset fxBorderMargin = this@Builder.fxBorderMargin adsorbDirection = this@Builder.edgeAdsorbDirection @@ -228,6 +311,12 @@ open class FxBasisHelper { return this as T } + fun setOffsetXY(x: Int, y: Int): T { + this.offsetX = x + this.offsetY = x + return this as T + } + /** * 设置启用屏幕外滚动 默认为true,即悬浮窗可以拖动到全屏任意位置(除了状态栏与导航栏禁止覆盖) * false时,可拖动范围受 borderMargin-边框偏移 与 moveEdge-边缘偏移 限制 diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxSystemControlImpl.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxSystemControlImpl.kt deleted file mode 100644 index a6d34939..00000000 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/control/FxSystemControlImpl.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.petterp.floatingx.impl.control - -import com.petterp.floatingx.assist.helper.FxAppHelper -import com.petterp.floatingx.listener.control.IFxSystemControl - -/** - * - * @author petterp - */ -class FxSystemControlImpl(private val helper: FxAppHelper) : - FxBasisControlImpl(helper), IFxSystemControl { - override fun show() { - } - - override fun hide() { - super.hide() - } - - override fun isShow(): Boolean { - return true - } -} diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasisControlImpl.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasisControlImpl.kt index 8bad3e2a..94404771 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasisControlImpl.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasisControlImpl.kt @@ -76,7 +76,10 @@ abstract class FxBasisControlImpl> } override fun isShow(): Boolean { - return platformProvider.isShow() + val interView = getManagerView() ?: return false + val isShow = platformProvider.isShow() + if (isShow != null) return isShow + return interView.isAttachedToWindow && interView.visibility == View.VISIBLE } override fun updateView(@LayoutRes resource: Int) { diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/app/FxAppPlatformProvider.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/app/FxAppPlatformProvider.kt index 4cf56549..c06b6ca9 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/app/FxAppPlatformProvider.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/app/FxAppPlatformProvider.kt @@ -77,11 +77,6 @@ class FxAppPlatformProvider( detach() } - override fun isShow(): Boolean { - val managerView = _internalView ?: return false - return managerView.isAttachedToWindow && managerView.visibility == View.VISIBLE - } - private fun attach(activity: Activity): Boolean { val fxView = _internalView ?: return false val decorView = activity.decorView ?: return false diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/scope/FxScopePlatFromProvider.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/scope/FxScopePlatFromProvider.kt index e96568c9..53d8112c 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/scope/FxScopePlatFromProvider.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/scope/FxScopePlatFromProvider.kt @@ -42,11 +42,6 @@ class FxScopePlatFromProvider( _internalView?.visibility = View.GONE } - override fun isShow(): Boolean { - val managerView = _internalView ?: return false - return managerView.isAttachedToWindow && managerView.visibility == View.VISIBLE - } - override fun checkOrInit(): Boolean { if (_internalView == null) { val containerGroupView = containerGroupView ?: return false diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/system/FxSystemControlImp.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/system/FxSystemControlImp.kt new file mode 100644 index 00000000..179cf096 --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/system/FxSystemControlImp.kt @@ -0,0 +1,18 @@ +package com.petterp.floatingx.impl.provider.system + +import android.app.Activity +import com.petterp.floatingx.assist.helper.FxAppHelper +import com.petterp.floatingx.impl.provider.FxBasisControlImpl +import com.petterp.floatingx.listener.control.IFxAppControl + +/** + * + * @author petterp + */ +class FxSystemControlImp(helper: FxAppHelper) : + FxBasisControlImpl(helper), IFxAppControl { + override fun createPlatformProvider(f: FxAppHelper) = FxSystemPlatformProvider(helper) + override fun getBindActivity(): Activity? { + return null + } +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/system/FxSystemPlatformProvider.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/system/FxSystemPlatformProvider.kt new file mode 100644 index 00000000..f14c4f14 --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/system/FxSystemPlatformProvider.kt @@ -0,0 +1,57 @@ +package com.petterp.floatingx.impl.provider.system + +import android.content.Context +import android.view.View +import android.view.WindowManager +import com.petterp.floatingx.assist.helper.FxAppHelper +import com.petterp.floatingx.listener.provider.IFxPlatformProvider +import com.petterp.floatingx.util.isVisibility +import com.petterp.floatingx.view.IFxInternalView +import com.petterp.floatingx.view.system.FxSystemContainerView + +/** + * + * @author petterp + */ +class FxSystemPlatformProvider(override val helper: FxAppHelper) : + IFxPlatformProvider { + private var _internalView: FxSystemContainerView? = null + private var wm: WindowManager? = null + + override val context: Context + get() = helper.context + override val internalView: IFxInternalView? + get() = _internalView + + override fun show() { + val internalView = _internalView ?: return + internalView.registerWM(wm ?: return) + internalView.isVisibility = true + } + + override fun hide() { + val internalView = _internalView ?: return + // FIXME: 这里本来想直接remove,但是会引发LeakCanary的内存泄漏警告,故才用Gone + internalView.isVisibility = false + } + + override fun isShow(): Boolean { + val internalView = _internalView ?: return false + return internalView.isAttachToWM && internalView.visibility == View.VISIBLE + } + + override fun reset() { + val internalView = _internalView ?: return + internalView.isVisibility = false + wm?.removeViewImmediate(internalView) + } + + override fun checkOrInit(): Boolean { + if (_internalView == null) { + wm = helper.context.getSystemService(Context.WINDOW_SERVICE) as WindowManager + _internalView = FxSystemContainerView(helper, wm!!, context) + _internalView!!.initView() + } + return true + } +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/listener/provider/IFxPlatformProvider.kt b/floatingx/src/main/java/com/petterp/floatingx/listener/provider/IFxPlatformProvider.kt index 9d35fc5e..5119b7a9 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/listener/provider/IFxPlatformProvider.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/listener/provider/IFxPlatformProvider.kt @@ -9,6 +9,6 @@ interface IFxPlatformProvider : IFxBasicProvider { val internalView: IFxInternalView? fun show() fun hide() - fun isShow(): Boolean + fun isShow(): Boolean? = null fun checkOrInit(): Boolean } diff --git a/floatingx/src/main/java/com/petterp/floatingx/util/FxExt.kt b/floatingx/src/main/java/com/petterp/floatingx/util/FxExt.kt index fee4e8b3..925cbbb4 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/util/FxExt.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/util/FxExt.kt @@ -3,9 +3,8 @@ package com.petterp.floatingx.util import android.app.Activity -import android.content.Context -import android.content.ContextWrapper import android.view.MotionEvent +import android.view.View import android.widget.FrameLayout import com.petterp.floatingx.assist.helper.FxScopeHelper import com.petterp.floatingx.impl.lifecycle.FxAppLifecycleProvider @@ -17,8 +16,6 @@ internal const val FX_GRAVITY_CENTER = 0x00000002 internal const val FX_GRAVITY_BOTTOM = 0x00000003 -internal const val TOUCH_CLICK_OFFSET = 2F - internal const val INVALID_TOUCH_ID = -1 internal const val INVALID_LAYOUT_ID = 0 internal const val INVALID_TOUCH_IDX = -1 @@ -35,6 +32,16 @@ internal const val FX_INSTALL_SCOPE_VIEW_GROUP_TAG = "view" internal val topActivity: Activity? get() = FxAppLifecycleProvider.getTopActivity() +internal var View.isVisibility + set(value) { + visibility = if (value) { + View.VISIBLE + } else { + View.GONE + } + } + get() = visibility == View.VISIBLE + internal val Activity.decorView: FrameLayout? get() = try { window.decorView as FrameLayout @@ -79,6 +86,12 @@ internal fun Float.coerceInFx(min: Float, max: Float): Float { return this } +internal fun Int.coerceInFx(min: Int, max: Int): Int { + if (this < min) return min + if (this > max) return max + return this +} + internal fun Float.withIn(min: Number, max: Number): Boolean { return this in min.toFloat()..max.toFloat() } @@ -89,19 +102,3 @@ internal val MotionEvent.pointerId: Int } catch (_: Exception) { INVALID_TOUCH_ID } - -internal fun Context.findActivity(): Activity? { - return when (this) { - is Activity -> { - this - } - - is ContextWrapper -> { - baseContext.findActivity() - } - - else -> { - null - } - } -} diff --git a/floatingx/src/main/java/com/petterp/floatingx/util/FxScreenExt.kt b/floatingx/src/main/java/com/petterp/floatingx/util/FxScreenExt.kt index 27e0fb0e..32e06b2f 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/util/FxScreenExt.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/util/FxScreenExt.kt @@ -39,6 +39,15 @@ internal val Context.screenHeight: Int return dm.heightPixels } +internal val Context.screenWidth: Int + get() { + val wm = getSystemService(Context.WINDOW_SERVICE) as WindowManager + val display = wm.defaultDisplay + val dm = DisplayMetrics() + display.getMetrics(dm) + return dm.widthPixels + } + /** 状态栏高度,直接使用AppContext测量,部分情况会不准确 */ internal val Activity.statusBarHeight: Int get() { diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxBasicParentView.kt b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxBasicParentView.kt new file mode 100644 index 00000000..42fd7875 --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxBasicParentView.kt @@ -0,0 +1,112 @@ +package com.petterp.floatingx.view.basic + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.MotionEvent +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import com.petterp.floatingx.assist.helper.FxBasisHelper +import com.petterp.floatingx.util.INVALID_LAYOUT_ID +import com.petterp.floatingx.view.FxViewHolder +import com.petterp.floatingx.view.IFxInternalView + +/** + * @author petterp + */ +abstract class FxBasicParentView @JvmOverloads constructor( + open val helper: FxBasisHelper, + context: Context, + attrs: AttributeSet? = null +) : FrameLayout(context, attrs), IFxInternalView, View.OnLayoutChangeListener { + private var isCreated = false + private var _childView: View? = null + private var _viewHolder: FxViewHolder? = null + private val touchHelper = FxViewTouchHelper() + private val locationHelper = FxLocationHelper() + + abstract fun onLayoutInit() + abstract fun onTouchDown(event: MotionEvent) + abstract fun onTouchMove(event: MotionEvent) + abstract fun onTouchCancel(event: MotionEvent) + abstract fun interceptTouchEvent(ev: MotionEvent): Boolean + + override val childView: View? + get() = _childView + override val containerView: FrameLayout + get() = this + override val viewHolder: FxViewHolder? + get() { + if (_viewHolder == null) _viewHolder = FxViewHolder(this) + return _viewHolder + } + + open fun initView() { + touchHelper.initConfig(this) + locationHelper.initConfig(helper) + } + + override fun moveToEdge() { + } + + override fun moveLocation(x: Float, y: Float, useAnimation: Boolean) { + } + + override fun moveLocationByVector(x: Float, y: Float, useAnimation: Boolean) { + } + + override fun updateView() { + // 更新子view + } + + override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { + super.onLayout(changed, left, top, right, bottom) + if (!isCreated) { + isCreated = true + onLayoutInit() + } + } + + override fun onInterceptTouchEvent(event: MotionEvent): Boolean { + if (touchHelper.hasMainPointerId()) return super.onInterceptTouchEvent(event) + return interceptTouchEvent(event) || super.onInterceptTouchEvent(event) + } + + protected fun initChildView(): View? { + _childView = inflateLayoutView() ?: inflateLayoutId() + return _childView + } + + private fun inflateLayoutView(): View? { + val view = helper.layoutView ?: return null + helper.fxLog?.d("fxView-->init, way:[layoutView]") + val lp = view.layoutParams ?: LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT, + ) + addView(view, lp) + return view + } + + private fun inflateLayoutId(): View? { + if (helper.layoutId == INVALID_LAYOUT_ID) return null + helper.fxLog?.d("fxView-->init, way:[layoutId]") + val view = LayoutInflater.from(context).inflate(helper.layoutId, this, false) + addView(view) + return view + } + + override fun onLayoutChange( + v: View?, + left: Int, + top: Int, + right: Int, + bottom: Int, + oldLeft: Int, + oldTop: Int, + oldRight: Int, + oldBottom: Int + ) { + } +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/default/FxLocationHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewLocationHelper.kt similarity index 95% rename from floatingx/src/main/java/com/petterp/floatingx/view/default/FxLocationHelper.kt rename to floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewLocationHelper.kt index 48650cc9..33d3dd2d 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/default/FxLocationHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewLocationHelper.kt @@ -1,8 +1,9 @@ -package com.petterp.floatingx.view.default +package com.petterp.floatingx.view.basic import android.content.res.Configuration import com.petterp.floatingx.assist.helper.FxBasisHelper import com.petterp.floatingx.util.coerceInFx +import com.petterp.floatingx.view.default.FxViewConfigHelper /** * Fx location restore helper,Used to restore the location of the floating window after the screen is rotated diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewTouchHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewTouchHelper.kt new file mode 100644 index 00000000..3bac95cb --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewTouchHelper.kt @@ -0,0 +1,135 @@ +package com.petterp.floatingx.view.basic + +import android.annotation.SuppressLint +import android.view.MotionEvent +import android.view.View +import android.view.ViewConfiguration +import androidx.annotation.Keep +import com.petterp.floatingx.assist.helper.FxBasisHelper +import com.petterp.floatingx.util.INVALID_TOUCH_ID +import com.petterp.floatingx.util.TOUCH_TIME_THRESHOLD +import com.petterp.floatingx.util.pointerId +import kotlin.math.abs + +/** + * 手势事件辅助类,处理点击事件 + * @author petterp + */ +class FxViewTouchHelper { + private var initX = 0f + private var initY = 0f + private var scaledTouchSlop = 0F + private var isClickEvent = false + private var clickEnable = true + private var mLastTouchDownTime = 0L + private var touchDownId = INVALID_TOUCH_ID + private lateinit var helper: FxBasisHelper + private var basicView: FxBasicParentView? = null + + @SuppressLint("ClickableViewAccessibility") + fun initConfig(view: FxBasicParentView) { + reset() + this.basicView = view + this.helper = view.helper + scaledTouchSlop = ViewConfiguration.get(view.context).scaledTouchSlop.toFloat() + view.setOnTouchListener { _, event -> + when (event.actionMasked) { + MotionEvent.ACTION_DOWN -> initTouchDown(event) + MotionEvent.ACTION_MOVE -> touchToMove(event) + MotionEvent.ACTION_POINTER_DOWN -> touchToPointerDown(event) + MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL, + MotionEvent.ACTION_POINTER_UP -> touchCancel(event) + } + false + } + } + + fun hasMainPointerId() = touchDownId != INVALID_TOUCH_ID + + @Keep + fun touchCancel(view: View) { + if (isClickEffective()) { + helper.iFxClickListener?.onClick(view) + if (helper.clickTime > 0) { + clickEnable = false + view.postDelayed({ clickEnable = true }, helper.clickTime) + } else { + clickEnable = true + } + helper.fxLog?.d("fxView -> click") + } + reset() + } + + private fun initTouchDown(event: MotionEvent) { + if (hasMainPointerId()) return + initClickConfig(event) + touchDownId = event.pointerId + basicView?.onTouchDown(event) + helper.fxLog?.d("fxView->initTouchDown---id:$touchDownId->") + } + + private fun initClickConfig(event: MotionEvent) { + if (!helper.enableClickListener || helper.iFxClickListener == null) return + isClickEvent = true + this.initX = event.rawX + this.initY = event.rawY + mLastTouchDownTime = System.currentTimeMillis() + } + + private fun touchToPointerDown(event: MotionEvent) { + if (hasMainPointerId()) return + initTouchDown(event) + } + + private fun touchToMove(event: MotionEvent) { + if (!isCurrentPointerId(event)) return + checkClickState(event) + basicView?.onTouchMove(event) + helper.fxLog?.d("fxView---onTouchEvent---onTouchMove->") + } + + private fun touchCancel(event: MotionEvent) { + if (!isCurrentPointerId(event)) return + performClick() + reset() + basicView?.onTouchCancel(event) + helper.fxLog?.d("fxView---onTouchEvent---MainTouchCancel->") + } + + private fun performClick() { + if (isClickEffective()) { + clickEnable = false + helper.iFxClickListener?.onClick(basicView) + basicView?.postDelayed({ + clickEnable = true + }, 1000) + } + } + + private fun checkClickState(event: MotionEvent) { + if (!isClickEvent) return + isClickEvent = abs(event.rawX - initX) < scaledTouchSlop && + abs(event.rawY - initY) < scaledTouchSlop + } + + private fun isCurrentPointerId(ev: MotionEvent): Boolean { + if (touchDownId == INVALID_TOUCH_ID) return false + return ev.pointerId == touchDownId + } + + private fun reset() { + initX = 0f + initY = 0f + isClickEvent = false + mLastTouchDownTime = 0L + touchDownId = INVALID_TOUCH_ID + } + + private fun isClickEffective(): Boolean { + // 当前是点击事件&&点击事件目前可启用&&回调存在&&点击时间小于阈值 + return isClickEvent && clickEnable && helper.enableClickListener && + helper.iFxClickListener != null && + System.currentTimeMillis() - mLastTouchDownTime < TOUCH_TIME_THRESHOLD + } +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/default/FxClickHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/view/default/FxClickHelper.kt deleted file mode 100644 index e4b7acfe..00000000 --- a/floatingx/src/main/java/com/petterp/floatingx/view/default/FxClickHelper.kt +++ /dev/null @@ -1,64 +0,0 @@ -package com.petterp.floatingx.view.default - -import androidx.annotation.Keep -import com.petterp.floatingx.assist.helper.FxBasisHelper -import com.petterp.floatingx.util.TOUCH_CLICK_OFFSET -import com.petterp.floatingx.util.TOUCH_TIME_THRESHOLD -import kotlin.math.abs - -/** - * - * @author petterp - */ -class FxClickHelper { - private var initX = 0f - private var initY = 0f - private var isClickEvent = false - private var clickEnable = true - private var mLastTouchDownTime = 0L - private lateinit var helper: FxBasisHelper - - fun initConfig(helper: FxBasisHelper) { - reset() - this.helper = helper - } - - fun initDown(x: Float, y: Float) { - if (!helper.enableClickListener || helper.iFxClickListener == null) return - this.initX = x - this.initY = y - isClickEvent = true - mLastTouchDownTime = System.currentTimeMillis() - } - - fun checkClickEvent(x: Float, y: Float) { - if (!isClickEvent) return - isClickEvent = abs(x - initX) < TOUCH_CLICK_OFFSET && - abs(y - initY) < TOUCH_CLICK_OFFSET - } - - @Keep - fun performClick(view: FxDefaultContainerView) { - if (!isClickEffective()) return - helper.iFxClickListener?.onClick(view) - if (helper.clickTime > 0) { - clickEnable = false - view.postDelayed({ clickEnable = true }, helper.clickTime) - } - helper.fxLog?.d("fxView -> click") - reset() - } - - private fun reset() { - initX = 0f - initY = 0f - isClickEvent = false - mLastTouchDownTime = 0L - } - - private fun isClickEffective(): Boolean { - return isClickEvent && clickEnable && helper.enableClickListener && - helper.iFxClickListener != null && - System.currentTimeMillis() - mLastTouchDownTime < TOUCH_TIME_THRESHOLD - } -} diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/default/FxDefaultContainerView.kt b/floatingx/src/main/java/com/petterp/floatingx/view/default/FxDefaultContainerView.kt index d7dd6b18..86dbf882 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/default/FxDefaultContainerView.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/default/FxDefaultContainerView.kt @@ -21,6 +21,8 @@ import com.petterp.floatingx.util.pointerId import com.petterp.floatingx.util.withIn import com.petterp.floatingx.view.FxViewHolder import com.petterp.floatingx.view.IFxInternalView +import com.petterp.floatingx.view.basic.FxLocationHelper +import com.petterp.floatingx.view.basic.FxViewTouchHelper /** 基础悬浮窗View */ @SuppressLint("ViewConstructor") @@ -30,7 +32,7 @@ class FxDefaultContainerView @JvmOverloads constructor( ) : FrameLayout(context, attrs), View.OnLayoutChangeListener, IFxInternalView { private lateinit var helper: FxBasisHelper - private val clickHelper = FxClickHelper() + private val clickHelper = FxViewTouchHelper() private val locationHelper = FxLocationHelper() private val configHelper = FxViewConfigHelper() private var _viewHolder: FxViewHolder? = null @@ -55,7 +57,7 @@ class FxDefaultContainerView @JvmOverloads constructor( private fun initView() { _childFxView = inflateLayoutView() ?: inflateLayoutId() - clickHelper.initConfig(helper) +// clickHelper.initConfig(context, helper) locationHelper.initConfig(helper) configHelper.initConfig(context, helper) checkNotNull(_childFxView) { "initFxView -> Error,check your layoutId or layoutView." } @@ -197,7 +199,7 @@ class FxDefaultContainerView @JvmOverloads constructor( private fun initTouchDown(ev: MotionEvent) { if (configHelper.hasMainPointerId()) return - clickHelper.initDown(x, y) +// clickHelper.initDown(ev) configHelper.initTouchDown(ev) configHelper.updateWidgetSize(this) configHelper.updateBoundary(true) @@ -232,6 +234,7 @@ class FxDefaultContainerView @JvmOverloads constructor( } override fun moveToEdge() { + // TODO: 这里看着有点bug,如果没开启吸附,位置就不保存了 configHelper.updateBoundary(false) configHelper.getAdsorbDirectionLocation(x, y)?.let { (x, y) -> moveToLocation(x, y) @@ -295,7 +298,7 @@ class FxDefaultContainerView @JvmOverloads constructor( moveToEdge() helper.iFxScrollListener?.up() configHelper.touchDownId = INVALID_TOUCH_ID - clickHelper.performClick(this) + clickHelper.touchCancel(this) helper.fxLog?.d("fxView---onTouchEvent---MainTouchCancel->") } @@ -324,7 +327,7 @@ class FxDefaultContainerView @JvmOverloads constructor( val disY = configHelper.safeY(y, event) x = disX y = disY - clickHelper.checkClickEvent(disX, disY) +// clickHelper.touchMove(event) helper.iFxScrollListener?.dragIng(event, disX, disY) helper.fxLog?.v("fxView---scrollListener--drag-event--x($disX)-y($disY)") } diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt b/floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt index a9516b03..0c91fb26 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt @@ -5,134 +5,97 @@ import android.content.Context import android.graphics.PixelFormat import android.os.Build import android.util.AttributeSet -import android.view.LayoutInflater +import android.view.Gravity import android.view.MotionEvent -import android.view.View -import android.view.ViewGroup import android.view.WindowManager -import android.widget.FrameLayout import com.petterp.floatingx.assist.helper.FxAppHelper -import com.petterp.floatingx.assist.helper.FxBasisHelper -import com.petterp.floatingx.util.INVALID_LAYOUT_ID -import com.petterp.floatingx.view.FxViewHolder -import com.petterp.floatingx.view.IFxInternalView +import com.petterp.floatingx.util.screenHeight +import com.petterp.floatingx.util.screenWidth +import com.petterp.floatingx.view.basic.FxBasicParentView /** 基础悬浮窗View */ @SuppressLint("ViewConstructor") class FxSystemContainerView @JvmOverloads constructor( + override val helper: FxAppHelper, + private val wm: WindowManager, context: Context, attrs: AttributeSet? = null, -) : FrameLayout(context, attrs), IFxInternalView { +) : FxBasicParentView(helper, context, attrs) { - private lateinit var helper: FxBasisHelper private lateinit var wl: WindowManager.LayoutParams - private lateinit var wm: WindowManager - private var _childFxView: View? = null - private var _viewHolder: FxViewHolder? = null - private var cX = 0 - private var cY = 0 + private var cX = 0f + private var cY = 0f - override val containerView: FrameLayout - get() = this - override val childView: View? - get() = _childFxView - override val viewHolder: FxViewHolder? - get() { - if (_viewHolder == null) _viewHolder = FxViewHolder(this) - return _viewHolder - } + val isAttachToWM: Boolean + get() = windowToken != null - fun init( - config: FxAppHelper - ): FxSystemContainerView { - this.helper = config - initView() - return this + override fun initView() { + super.initView() + initChildView() ?: return + initWLParams() } - private fun initView() { - _childFxView = inflateLayoutView() ?: inflateLayoutId() - wl = WindowManager.LayoutParams().apply { - // 设置大小 自适应 - width = WindowManager.LayoutParams.WRAP_CONTENT - height = WindowManager.LayoutParams.WRAP_CONTENT - format = PixelFormat.TRANSPARENT - /** - * 注意,flag的值可以为: - * 下面的flags属性的效果形同“锁定”。 - * 悬浮窗不可触摸,不接受任何事件,同时不影响后面的事件响应。 - * LayoutParams.FLAG_NOT_TOUCH_MODAL 不影响后面的事件 - * LayoutParams.FLAG_NOT_FOCUSABLE 不可聚焦 - * LayoutParams.FLAG_NOT_TOUCHABLE 不可触摸 - */ - flags = - WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY - } else { - WindowManager.LayoutParams.TYPE_SYSTEM_ALERT - } - } - wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager + internal fun registerWM(wm: WindowManager) { + if (isAttachToWM) return wm.addView(this, wl) } - private fun inflateLayoutView(): View? { - val view = helper.layoutView ?: return null - helper.fxLog?.d("fxView-->init, way:[layoutView]") - val lp = view.layoutParams ?: LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT, - ) - addView(view, lp) - return view + override fun moveLocation(x: Float, y: Float, useAnimation: Boolean) { + wl.x = x.toInt() + wl.y = y.toInt() + wm.updateViewLayout(this, wl) } - private fun inflateLayoutId(): View? { - if (helper.layoutId == INVALID_LAYOUT_ID) return null - helper.fxLog?.d("fxView-->init, way:[layoutId]") - val view = LayoutInflater.from(context).inflate(helper.layoutId, this, false) - addView(view) - return view + override fun onLayoutInit() { + val width = helper.context.screenWidth + val height = helper.context.screenHeight + val viewH = this.height + val viewW = this.width + val (defaultX, defaultY) = helper.defaultXY(width, height, viewW, viewH) + wl.x = defaultX + wl.y = defaultY + wm.updateViewLayout(this, wl) } - override fun moveLocation(x: Float, y: Float, useAnimation: Boolean) { + override fun onTouchDown(event: MotionEvent) { + cX = event.rawX + cY = event.rawY } - override fun moveLocationByVector(x: Float, y: Float, useAnimation: Boolean) { + override fun onTouchMove(event: MotionEvent) { + val nowX = event.rawX + val nowY = event.rawY + val movedX = nowX - cX + val movedY = nowY - cY + cX = nowX + cY = nowY + wl.x += movedX.toInt() + wl.y += movedY.toInt() + wm.updateViewLayout(this, wl) } - override fun moveToEdge() { + override fun onTouchCancel(event: MotionEvent) { + cX = 0f + cY = 0f } - override fun updateView() { + override fun interceptTouchEvent(ev: MotionEvent): Boolean { + return false } - override fun onTouchEvent(event: MotionEvent): Boolean { - when (event.action) { - MotionEvent.ACTION_DOWN -> { - cX = event.rawX.toInt() - cY = event.rawY.toInt() - } - - MotionEvent.ACTION_MOVE -> { - val nowX = event.rawX.toInt() - val nowY = event.rawY.toInt() - val movedX = nowX - cX - val movedY = nowY - cY - cX = nowX - cY = nowY - wl.apply { - x += movedX - y += movedY - } - // 更新悬浮球控件位置 - wm.updateViewLayout(this, wl) - } - - else -> { + private fun initWLParams() { + wl = WindowManager.LayoutParams().apply { + width = WindowManager.LayoutParams.WRAP_CONTENT + height = WindowManager.LayoutParams.WRAP_CONTENT + format = PixelFormat.RGBA_8888 + gravity = Gravity.TOP or Gravity.START + flags = + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY + } else { + WindowManager.LayoutParams.TYPE_SYSTEM_ALERT } } - return super.onTouchEvent(event) } } From 4704bb7622e52dc3edb3654d60ec09fc0b055893 Mon Sep 17 00:00:00 2001 From: petterp Date: Tue, 26 Dec 2023 23:35:38 +0800 Subject: [PATCH 6/8] =?UTF-8?q?perf:=E4=BC=98=E5=8C=96=E5=9F=BA=E7=A1=80vi?= =?UTF-8?q?ew=E7=9A=84=E5=B0=81=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/kotlin/CustomKtApplication.kt | 15 +- .../floatingx/app/test/SystemActivity.kt | 24 +++ check/detekt/baseline.xml | 6 +- .../floatingx/assist/helper/FxAppHelper.kt | 4 +- .../floatingx/assist/helper/FxBasisHelper.kt | 78 +------ .../floatingx/assist/helper/FxScopeHelper.kt | 2 +- .../impl/lifecycle/FxTempAppLifecycleImp.kt | 12 +- .../impl/provider/FxBasicAnimationProvider.kt | 8 +- .../impl/provider/FxBasisControlImpl.kt | 2 +- .../provider/app/FxAppPlatformProvider.kt | 6 +- .../java/com/petterp/floatingx/util/FxExt.kt | 4 + .../java/com/petterp/floatingx/util/FxLog.kt | 9 +- .../floatingx/util/SimpleAnimatorListener.kt | 3 +- .../floatingx/view/basic/FxBasicParentView.kt | 69 ++++--- .../floatingx/view/basic/FxBasicViewHelper.kt | 17 ++ .../view/basic/FxViewAnimationHelper.kt | 59 ++++++ .../view/basic/FxViewLocationHelper.kt | 195 +++++++++++++----- .../floatingx/view/basic/FxViewTouchHelper.kt | 47 +++-- .../view/default/FxDefaultContainerView.kt | 56 ++--- .../view/default/FxViewConfigHelper.kt | 8 +- .../view/system/FxSystemContainerView.kt | 44 ++-- 21 files changed, 416 insertions(+), 252 deletions(-) create mode 100644 floatingx/src/main/java/com/petterp/floatingx/view/basic/FxBasicViewHelper.kt create mode 100644 floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewAnimationHelper.kt diff --git a/app/src/main/java/com/petterp/floatingx/app/kotlin/CustomKtApplication.kt b/app/src/main/java/com/petterp/floatingx/app/kotlin/CustomKtApplication.kt index bf51421d..3caf9031 100644 --- a/app/src/main/java/com/petterp/floatingx/app/kotlin/CustomKtApplication.kt +++ b/app/src/main/java/com/petterp/floatingx/app/kotlin/CustomKtApplication.kt @@ -14,15 +14,14 @@ import androidx.cardview.widget.CardView import com.petterp.floatingx.FloatingX import com.petterp.floatingx.app.* import com.petterp.floatingx.app.simple.FxAnimationImpl -import com.petterp.floatingx.app.simple.FxConfigStorageToSpImpl import com.petterp.floatingx.app.test.BlackActivity import com.petterp.floatingx.app.test.MultipleFxActivity import com.petterp.floatingx.assist.FxDisplayMode import com.petterp.floatingx.assist.FxGravity import com.petterp.floatingx.assist.FxScopeType -import com.petterp.floatingx.util.FxScrollImpl import com.petterp.floatingx.impl.lifecycle.FxProxyTagLifecycleImp import com.petterp.floatingx.listener.IFxViewLifecycle +import com.petterp.floatingx.util.FxScrollImpl /** Kotlin-Application */ class CustomKtApplication : Application() { @@ -44,6 +43,7 @@ class CustomKtApplication : Application() { // } installTag1(this) + installTag2(this) } companion object { @@ -66,9 +66,9 @@ class CustomKtApplication : Application() { // ) // 设置悬浮窗默认方向 - setGravity(FxGravity.RIGHT_OR_BOTTOM) + setGravity(FxGravity.RIGHT_OR_TOP) // 启用辅助方向,具体参加方法注释 - setEnableAssistDirection(r = 100f) + setEnableAssistDirection(r = 100f, t = 100f) // 设置启用边缘吸附,默认启用 setEnableEdgeAdsorption(true) // 设置边缘偏移量 @@ -76,7 +76,7 @@ class CustomKtApplication : Application() { // 设置启用悬浮窗可屏幕外回弹 setEnableScrollOutsideScreen(true) // 开启历史位置缓存 - setSaveDirectionImpl(FxConfigStorageToSpImpl(context)) +// setSaveDirectionImpl(FxConfigStorageToSpImpl(context)) // 设置启用动画 setEnableAnimation(true) // 设置启用动画实现 @@ -142,6 +142,7 @@ class CustomKtApplication : Application() { fun installTag2(context: Application) { FloatingX.install { setContext(context) + setSystemScope(FxScopeType.APP_ACTIVITY) setLayoutView( CardView(context).apply { setCardBackgroundColor(Color.GRAY) @@ -149,11 +150,11 @@ class CustomKtApplication : Application() { addView( TextView(this.context).apply { layoutParams = ViewGroup.LayoutParams( - 60.dp, + -2, 60.dp, ) gravity = Gravity.CENTER - text = "浮窗2" + text = "浮窗2-act" setTextColor(Color.WHITE) textSize = 15f }, diff --git a/app/src/main/java/com/petterp/floatingx/app/test/SystemActivity.kt b/app/src/main/java/com/petterp/floatingx/app/test/SystemActivity.kt index a6ba0491..eb2c0211 100644 --- a/app/src/main/java/com/petterp/floatingx/app/test/SystemActivity.kt +++ b/app/src/main/java/com/petterp/floatingx/app/test/SystemActivity.kt @@ -1,12 +1,18 @@ package com.petterp.floatingx.app.test +import android.graphics.Color import android.os.Bundle +import android.view.Gravity +import android.view.ViewGroup +import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import com.petterp.floatingx.FloatingX +import com.petterp.floatingx.app.R import com.petterp.floatingx.app.addItemView import com.petterp.floatingx.app.addLinearLayout import com.petterp.floatingx.app.addNestedScrollView import com.petterp.floatingx.app.createLinearLayoutToParent +import com.petterp.floatingx.app.dp /** * @@ -24,9 +30,27 @@ class SystemActivity : AppCompatActivity() { addItemView("移动到(-100,0)") { FloatingX.controlOrNull(MultipleFxActivity.TAG_1)?.move(-100f, 0f) } + addItemView("移动到(300,0)") { + FloatingX.controlOrNull(MultipleFxActivity.TAG_1)?.move(300f, 0f) + } addItemView("移动到(500,500)") { FloatingX.controlOrNull(MultipleFxActivity.TAG_1)?.move(500f, 500f) } + addItemView("updateView()") { + FloatingX.controlOrNull(MultipleFxActivity.TAG_1)?.updateView { + TextView(it).apply { + layoutParams = ViewGroup.LayoutParams(100.dp, 200.dp) + text = "App" + gravity = Gravity.CENTER + textSize = 15f + setBackgroundColor(Color.GRAY) + } + } + } + addItemView("updateView2()") { + FloatingX.controlOrNull(MultipleFxActivity.TAG_1) + ?.updateView(R.layout.item_floating_new) + } } } } diff --git a/check/detekt/baseline.xml b/check/detekt/baseline.xml index 6848b30e..eaf1a4d3 100644 --- a/check/detekt/baseline.xml +++ b/check/detekt/baseline.xml @@ -1,7 +1,7 @@ - MaxLineLength:FxManagerView.kt$FxManagerView$helper.fxLog?.d("fxView--lifecycle-> onConfigurationChanged--saveLocation:[${x.roundToInt()},${y.roundToInt()}]") + MaxLineLength:FxManagerView.kt$FxManagerView$helper.fxLog.d("fxView--lifecycle-> onConfigurationChanged--saveLocation:[${x.roundToInt()},${y.roundToInt()}]") TooManyFunctions:FxScreenExt.kt$com.petterp.floatingx.util.FxScreenExt.kt TooGenericExceptionCaught:FxUiExt.kt$e: Exception PrintStackTrace:FxUiExt.kt$e @@ -23,9 +23,9 @@ MaxLineLength:FxAppControlImpl.kt$FxAppControlImpl$throw IllegalArgumentException("view.context != Application,The global floating window must use application as context!") MaxLineLength:FxBasisControlImpl.kt$FxBasisControlImpl$if (getContainerGroup() == null) throw NullPointerException("FloatingX window The parent container cannot be null!") MaxLineLength:FxBasisControlImpl.kt$FxBasisControlImpl$if (helper.layoutId == 0 && helper.layoutView == null) throw RuntimeException("The layout id cannot be 0 ,and layoutView==null") - MaxLineLength:FxProxyLifecycleCallBackImpl.kt$FxProxyLifecycleCallBackImpl$fxLog?.d("fxApp->detach? isContainActivity-${activity.isActivityInValid}--enableFx-$enableFx---isParent-$isParent") + MaxLineLength:FxProxyLifecycleCallBackImpl.kt$FxProxyLifecycleCallBackImpl$fxLog.d("fxApp->detach? isContainActivity-${activity.isActivityInValid}--enableFx-$enableFx---isParent-$isParent") MaxLineLength:FxScopeControl.kt$FxScopeControl$throw IllegalArgumentException("view == Application,Scope floating windows cannot use application-level views!") - MaxLineLength:FxViewConfigHelper.kt$FxViewConfigHelper$helper.fxLog?.d("fxView->updateContainerSize: oldW-($mParentWidth),oldH-($mParentHeight),newW-($parentWidth),newH-($parentHeight)") + MaxLineLength:FxViewConfigHelper.kt$FxViewConfigHelper$helper.fxLog.d("fxView->updateContainerSize: oldW-($mParentWidth),oldH-($mParentHeight),newW-($parentWidth),newH-($parentHeight)") SwallowedException:FxScreenExt.kt$e: Exception TooGenericExceptionCaught:FxScreenExt.kt$e: Exception TooGenericExceptionThrown:FxBasisControlImpl.kt$FxBasisControlImpl$throw RuntimeException("The layout id cannot be 0 ,and layoutView==null") diff --git a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxAppHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxAppHelper.kt index 6e95b1fc..45a51713 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxAppHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxAppHelper.kt @@ -38,13 +38,13 @@ class FxAppHelper( @JvmSynthetic internal fun updateNavigationBar(activity: Activity?) { navigationBarHeight = activity?.navigationBarHeight ?: navigationBarHeight - fxLog?.v("system-> navigationBar-$navigationBarHeight") + fxLog.v("system-> navigationBar-$navigationBarHeight") } @JvmSynthetic internal fun updateStatsBar(activity: Activity?) { statsBarHeight = activity?.statusBarHeight ?: statsBarHeight - fxLog?.v("system-> statusBarHeight-$statsBarHeight") + fxLog.v("system-> statusBarHeight-$statsBarHeight") } @JvmSynthetic diff --git a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxBasisHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxBasisHelper.kt index 207b4795..19d70276 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxBasisHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxBasisHelper.kt @@ -12,7 +12,6 @@ import com.petterp.floatingx.listener.IFxConfigStorage import com.petterp.floatingx.listener.IFxScrollListener import com.petterp.floatingx.listener.IFxViewLifecycle import com.petterp.floatingx.util.FxLog -import com.petterp.floatingx.util.coerceInFx import kotlin.math.abs /** 通用构建器helper */ @@ -96,8 +95,7 @@ open class FxBasisHelper { @JvmField internal var iFxClickListener: View.OnClickListener? = null - @JvmField - internal var fxLog: FxLog? = null + internal lateinit var fxLog: FxLog @JvmField internal var fxLogTag: String = "" @@ -111,7 +109,7 @@ open class FxBasisHelper { @JvmSynthetic internal fun initLog(scope: String) { - if (enableDebugLog) fxLog = FxLog.builder("$scope-$fxLogTag") + fxLog = FxLog.builder(enableDebugLog, "$scope-$fxLogTag") } @JvmSynthetic @@ -121,77 +119,9 @@ open class FxBasisHelper { fxAnimation?.cancelAnimation() } - private val safeEdgeOffSet: Float + val safeEdgeOffSet: Float get() = if (enableEdgeRebound) edgeOffset else 0F - fun defaultXY(width: Int, height: Int, viewW: Int, viewH: Int): Pair { - return if (enableSaveDirection && iFxConfigStorage?.hasConfig() == true) { - getHistoryXY(width, viewW, height, viewH) - } else { - getDefaultXY(width, height, viewW, viewH) - } - } - - private fun getHistoryXY( - width: Int, - viewW: Int, - height: Int, - viewH: Int - ): Pair { - val configX = iFxConfigStorage!!.getX() - val configY = iFxConfigStorage!!.getY() - val bMinX = safeEdgeOffSet + fxBorderMargin.l - val bMaxX = width - viewW - safeEdgeOffSet - fxBorderMargin.r - val bMinY = safeEdgeOffSet + fxBorderMargin.t - val bMaxY = height - viewH - safeEdgeOffSet - fxBorderMargin.b - return configX.coerceInFx(bMinX, bMaxX).toInt() to configY.coerceInFx(bMinY, bMaxY).toInt() - } - - private fun getDefaultXY(width: Int, height: Int, viewW: Int, viewH: Int): Pair { - val l = (offsetX + safeEdgeOffSet + fxBorderMargin.l).toInt() - val r = (offsetX + safeEdgeOffSet + fxBorderMargin.r).toInt() - val b = (offsetY + safeEdgeOffSet + fxBorderMargin.b).toInt() - val t = (offsetY + safeEdgeOffSet + fxBorderMargin.t).toInt() - return when (gravity) { - FxGravity.DEFAULT, - FxGravity.LEFT_OR_TOP -> { - l to t - } - - FxGravity.LEFT_OR_CENTER -> { - l to (height - viewH).shr(1) - } - - FxGravity.LEFT_OR_BOTTOM -> { - 0 to height - viewH - b - } - - FxGravity.RIGHT_OR_TOP -> { - width - viewW - r to t - } - - FxGravity.RIGHT_OR_CENTER -> { - width - viewW - r to (height - viewH).shr(1) - } - - FxGravity.RIGHT_OR_BOTTOM -> { - width - viewW - r to height - viewH - b - } - - FxGravity.TOP_OR_CENTER -> { - (width - viewW).shr(1) to t - } - - FxGravity.BOTTOM_OR_CENTER -> { - (width - viewW).shr(1) to height - viewH - b - } - - else -> { - (width - viewW).shr(1) to (height - viewH).shr(1) - } - } - } - abstract class Builder { @LayoutRes private var layoutId: Int = 0 @@ -313,7 +243,7 @@ open class FxBasisHelper { fun setOffsetXY(x: Int, y: Int): T { this.offsetX = x - this.offsetY = x + this.offsetY = y return this as T } diff --git a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxScopeHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxScopeHelper.kt index 305d7d36..29131dd5 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxScopeHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/assist/helper/FxScopeHelper.kt @@ -20,7 +20,7 @@ class FxScopeHelper : FxBasisHelper() { control.initProvider() activity.contentView?.let { control.setContainerGroup(it) - } ?: fxLog?.e("install to Activity the Error,current contentView(R.id.content) = null!") + } ?: fxLog.e("install to Activity the Error,current contentView(R.id.content) = null!") return control } diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxTempAppLifecycleImp.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxTempAppLifecycleImp.kt index eaddfeb9..85240978 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxTempAppLifecycleImp.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/lifecycle/FxTempAppLifecycleImp.kt @@ -20,7 +20,7 @@ class FxTempAppLifecycleImp( private val appControl: FxAppControlImp ) : Application.ActivityLifecycleCallbacks { - private val fxLog: FxLog? + private val fxLog: FxLog get() = helper.fxLog private val enableFx: Boolean @@ -60,17 +60,17 @@ class FxTempAppLifecycleImp( override fun onActivityResumed(activity: Activity) { if (!enableFx) return val activityName = activity.name - fxLog?.d("fxApp->insert, insert [$activityName] Start ---------->") + fxLog.d("fxApp->insert, insert [$activityName] Start ---------->") val isActivityInValid = activity.isActivityInValid if (isActivityInValid) { appLifecycleCallBack?.onResumes(activity) } else { - fxLog?.d("fxApp->insert, insert [$activityName] Fail ,This activity is not in the list of allowed inserts.") + fxLog.d("fxApp->insert, insert [$activityName] Fail ,This activity is not in the list of allowed inserts.") return } val isParent = activity.isParent if (isParent) { - fxLog?.d("fxApp->insert, insert [$activityName] Fail ,The current Activity has been inserted.") + fxLog.d("fxApp->insert, insert [$activityName] Fail ,The current Activity has been inserted.") return } appControl.reAttach(activity) @@ -96,7 +96,7 @@ class FxTempAppLifecycleImp( if (activity.isActivityInValid) it.onDestroyed(activity) } val isParent = activity.isParent - fxLog?.d("fxApp->detach? isContainActivity-${activity.isActivityInValid}--enableFx-$enableFx---isParent-$isParent") + fxLog.d("fxApp->detach? isContainActivity-${activity.isActivityInValid}--enableFx-$enableFx---isParent-$isParent") if (isParent) appControl.destroyToDetach(activity) } @@ -113,5 +113,5 @@ class FxTempAppLifecycleImp( val isInsert = it.isCanInstall(cls) insertCls[cls] = isInsert isInsert - } ?: false + } } diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasicAnimationProvider.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasicAnimationProvider.kt index e08fe6ba..b92e0ca1 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasicAnimationProvider.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasicAnimationProvider.kt @@ -13,10 +13,10 @@ class FxBasicAnimationProvider(override val helper: F) : IFxA override fun start(view: FrameLayout, obj: (() -> Unit)?) { val fxAnimation = helper.fxAnimation ?: return if (fxAnimation.fromJobIsRunning()) { - helper.fxLog?.d("fxView->Animation,startAnimation Executing, cancel this operation!") + helper.fxLog.d("fxView -> Animation,startAnimation Executing, cancel this operation!") return } - helper.fxLog?.d("fxView->Animation,startAnimation Running.") + helper.fxLog.d("fxView -> Animation,startAnimation Running.") fxAnimation.setFromAnimatorListener(obj) fxAnimation.fromStartAnimator(view) } @@ -24,10 +24,10 @@ class FxBasicAnimationProvider(override val helper: F) : IFxA override fun hide(view: FrameLayout, obj: (() -> Unit)?) { val fxAnimation = helper.fxAnimation ?: return if (helper.fxAnimation!!.endJobIsRunning()) { - helper.fxLog?.d("fxView->Animation,endAnimation Executing, cancel this operation!") + helper.fxLog.d("fxView -> Animation,endAnimation Executing, cancel this operation!") return } - helper.fxLog?.d("fxView->Animation,endAnimation Running.") + helper.fxLog.d("fxView -> Animation,endAnimation Running.") fxAnimation.setEndAnimatorListener(obj) fxAnimation.toEndAnimator(view) } diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasisControlImpl.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasisControlImpl.kt index 94404771..b12b05d4 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasisControlImpl.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/FxBasisControlImpl.kt @@ -137,7 +137,7 @@ abstract class FxBasisControlImpl> platformProvider.reset() _animationProvider.reset() helper.clear() - helper.fxLog?.d("fxView-lifecycle-> code->cancelFx") + helper.fxLog.d("fxView-lifecycle-> code->cancelFx") } private fun updateEnableStatus(newStatus: Boolean) { diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/app/FxAppPlatformProvider.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/app/FxAppPlatformProvider.kt index c06b6ca9..0f322256 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/app/FxAppPlatformProvider.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/app/FxAppPlatformProvider.kt @@ -33,7 +33,7 @@ class FxAppPlatformProvider( private val windowsInsetsListener = OnApplyWindowInsetsListener { _, insets -> val statusBar = insets.stableInsetTop if (helper.statsBarHeight != statusBar) { - helper.fxLog?.v("System--StatusBar---old-(${helper.statsBarHeight}),new-($statusBar))") + helper.fxLog.v("System--StatusBar---old-(${helper.statsBarHeight}),new-($statusBar))") helper.statsBarHeight = statusBar } insets @@ -83,7 +83,7 @@ class FxAppPlatformProvider( if (containerGroupView === decorView) return false if (ViewCompat.isAttachedToWindow(fxView)) containerGroupView?.removeView(fxView) _containerGroup = WeakReference(decorView) - helper.fxLog?.d("fxView-lifecycle-> onPostAttach") + helper.fxLog.d("fxView-lifecycle-> onPostAttach") helper.iFxViewLifecycle?.postAttach() decorView.addView(fxView) return true @@ -121,7 +121,7 @@ class FxAppPlatformProvider( } private fun detach() { - helper.fxLog?.d("fxView-lifecycle-> onPostDetach") + helper.fxLog.d("fxView-lifecycle-> onPostDetach") _internalView?.visibility = View.GONE containerGroupView?.removeView(_internalView) } diff --git a/floatingx/src/main/java/com/petterp/floatingx/util/FxExt.kt b/floatingx/src/main/java/com/petterp/floatingx/util/FxExt.kt index 925cbbb4..48a99f7f 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/util/FxExt.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/util/FxExt.kt @@ -96,6 +96,10 @@ internal fun Float.withIn(min: Number, max: Number): Boolean { return this in min.toFloat()..max.toFloat() } +internal fun Float.shr(count: Int): Float { + return this / count +} + internal val MotionEvent.pointerId: Int get() = try { getPointerId(actionIndex) diff --git a/floatingx/src/main/java/com/petterp/floatingx/util/FxLog.kt b/floatingx/src/main/java/com/petterp/floatingx/util/FxLog.kt index 786829f2..ac1cddb8 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/util/FxLog.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/util/FxLog.kt @@ -5,24 +5,27 @@ import android.util.Log /** * Fx日志查看器,开启之后,将查看到Fx整个运行轨迹 * */ -class FxLog private constructor(private val tag: String) { +class FxLog private constructor(private val enable: Boolean, private val tag: String) { companion object { private var TAG = "FloatingX" - fun builder(tag: String) = - FxLog("$TAG-$tag") + fun builder(enable: Boolean, tag: String) = + FxLog(enable, "$TAG-$tag") } fun d(message: String) { + if (!enable) return Log.d(tag, message) } fun v(message: String) { + if (!enable) return Log.v(tag, message) } fun e(message: String) { + if (!enable) return Log.e(tag, message) } } diff --git a/floatingx/src/main/java/com/petterp/floatingx/util/SimpleAnimatorListener.kt b/floatingx/src/main/java/com/petterp/floatingx/util/SimpleAnimatorListener.kt index d73ffa02..6e9d5e03 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/util/SimpleAnimatorListener.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/util/SimpleAnimatorListener.kt @@ -10,8 +10,7 @@ import android.animation.Animator.AnimatorListener class SimpleAnimatorListener( var start: (() -> Unit)? = null, var end: (() -> Unit)? = null -) : - AnimatorListener { +) : AnimatorListener { override fun onAnimationStart(animation: Animator?) { start?.invoke() } diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxBasicParentView.kt b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxBasicParentView.kt index 42fd7875..4e455ec4 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxBasicParentView.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxBasicParentView.kt @@ -19,18 +19,25 @@ abstract class FxBasicParentView @JvmOverloads constructor( open val helper: FxBasisHelper, context: Context, attrs: AttributeSet? = null -) : FrameLayout(context, attrs), IFxInternalView, View.OnLayoutChangeListener { - private var isCreated = false +) : FrameLayout(context, attrs), IFxInternalView { + private var isInitLayout = true private var _childView: View? = null private var _viewHolder: FxViewHolder? = null private val touchHelper = FxViewTouchHelper() - private val locationHelper = FxLocationHelper() + private val animateHelper = FxViewAnimationHelper() + internal val locationHelper = FxViewLocationHelper() + + abstract fun currentX(): Float + abstract fun currentY(): Float + abstract fun updateXY(x: Float, y: Float) + abstract fun parentSize(): Pair - abstract fun onLayoutInit() abstract fun onTouchDown(event: MotionEvent) abstract fun onTouchMove(event: MotionEvent) abstract fun onTouchCancel(event: MotionEvent) abstract fun interceptTouchEvent(ev: MotionEvent): Boolean + open fun preCheckPointerDownTouch(event: MotionEvent): Boolean = true + open fun onLayoutInit() {} override val childView: View? get() = _childView @@ -44,28 +51,38 @@ abstract class FxBasicParentView @JvmOverloads constructor( open fun initView() { touchHelper.initConfig(this) - locationHelper.initConfig(helper) + animateHelper.initConfig(this) + locationHelper.initConfig(this) } override fun moveToEdge() { + val (x, y) = locationHelper.getDefaultEdgeXY() ?: return + moveLocation(x, y, true) } override fun moveLocation(x: Float, y: Float, useAnimation: Boolean) { + moveToXY(x, y, useAnimation) } override fun moveLocationByVector(x: Float, y: Float, useAnimation: Boolean) { + moveToXY(x + currentX(), y + currentY(), useAnimation) } override fun updateView() { - // 更新子view + helper.fxLog.d("fxView -> updateView") + locationHelper.updateLocationStatus() + removeView(_childView) + initChildView() + } + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + locationHelper.onSizeChanged() } override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { super.onLayout(changed, left, top, right, bottom) - if (!isCreated) { - isCreated = true - onLayoutInit() - } + checkOrInitLayout() } override fun onInterceptTouchEvent(event: MotionEvent): Boolean { @@ -80,7 +97,7 @@ abstract class FxBasicParentView @JvmOverloads constructor( private fun inflateLayoutView(): View? { val view = helper.layoutView ?: return null - helper.fxLog?.d("fxView-->init, way:[layoutView]") + helper.fxLog.d("fxView -> init, way:[layoutView]") val lp = view.layoutParams ?: LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, @@ -91,22 +108,28 @@ abstract class FxBasicParentView @JvmOverloads constructor( private fun inflateLayoutId(): View? { if (helper.layoutId == INVALID_LAYOUT_ID) return null - helper.fxLog?.d("fxView-->init, way:[layoutId]") + helper.fxLog.d("fxView -> init, way:[layoutId]") val view = LayoutInflater.from(context).inflate(helper.layoutId, this, false) addView(view) return view } - override fun onLayoutChange( - v: View?, - left: Int, - top: Int, - right: Int, - bottom: Int, - oldLeft: Int, - oldTop: Int, - oldRight: Int, - oldBottom: Int - ) { + private fun moveToXY(x: Float, y: Float, useAnimation: Boolean) { + val endX = locationHelper.safeX(x) + val endY = locationHelper.safeY(y) + locationHelper.checkOrSaveLocation(endX, endY) + if (useAnimation) { + animateHelper.start(endX, endY) + } else { + updateXY(endX, endY) + } + helper.fxLog.d("moveToXY: start(${currentX()},${currentY()}),end($endX,$endY)") + } + + private fun checkOrInitLayout() { + if (!isInitLayout) return + isInitLayout = false + locationHelper.initLayout(this) + onLayoutInit() } } diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxBasicViewHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxBasicViewHelper.kt new file mode 100644 index 00000000..cf9f6f1e --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxBasicViewHelper.kt @@ -0,0 +1,17 @@ +package com.petterp.floatingx.view.basic + +import com.petterp.floatingx.assist.helper.FxBasisHelper + +/** + * 基础类的辅助助手,用于分发基础逻辑 + * @author petterp + */ +abstract class FxBasicViewHelper { + protected var basicView: FxBasicParentView? = null + protected lateinit var config: FxBasisHelper + + open fun initConfig(parentView: FxBasicParentView) { + this.basicView = parentView + this.config = parentView.helper + } +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewAnimationHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewAnimationHelper.kt new file mode 100644 index 00000000..6b017677 --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewAnimationHelper.kt @@ -0,0 +1,59 @@ +package com.petterp.floatingx.view.basic + +import android.animation.ValueAnimator +import com.petterp.floatingx.util.DEFAULT_MOVE_ANIMATOR_DURATION + +/** + * FxView基础辅助类 + * @author petterp + */ +class FxViewAnimationHelper : FxBasicViewHelper() { + private var valueAnimator: ValueAnimator? = null + private var animateListener: IFxViewAnimate? = null + private var startX: Float = 0f + private var startY: Float = 0f + private var endX: Float = 0f + private var endY: Float = 0f + + fun setListener(iFxViewAnimate: IFxViewAnimate) { + this.animateListener = iFxViewAnimate + } + + fun start(endX: Float, endY: Float) { + val startX = basicView?.currentX() ?: 0f + val startY = basicView?.currentY() ?: 0f + if (startX == endX && startY == endY) return + this.startX = startX + this.startY = startY + this.endX = endX + this.endY = endY + checkOrInitAnimator() + if (valueAnimator?.isRunning == true) valueAnimator?.cancel() + valueAnimator?.start() + } + + private fun checkOrInitAnimator() { + if (valueAnimator == null) { + valueAnimator = ValueAnimator.ofFloat(0f, 1f).apply { + duration = DEFAULT_MOVE_ANIMATOR_DURATION + addUpdateListener { + val fraction = it.animatedValue as Float + val x = calculationNumber(startX, endX, fraction) + val y = calculationNumber(startY, endY, fraction) + basicView?.updateXY(x, y) + } + } + } + } + + private fun calculationNumber(start: Float, end: Float, fraction: Float): Float { + val currentX = if (start == end) { + start + } else { + start + (end - start) * fraction + } + return currentX + } +} + +typealias IFxViewAnimate = (x: Float, y: Float) -> Unit diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewLocationHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewLocationHelper.kt index 33d3dd2d..a5643b6a 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewLocationHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewLocationHelper.kt @@ -1,31 +1,33 @@ package com.petterp.floatingx.view.basic -import android.content.res.Configuration -import com.petterp.floatingx.assist.helper.FxBasisHelper +import com.petterp.floatingx.assist.FxAdsorbDirection +import com.petterp.floatingx.assist.FxGravity import com.petterp.floatingx.util.coerceInFx -import com.petterp.floatingx.view.default.FxViewConfigHelper +import com.petterp.floatingx.util.shr /** * Fx location restore helper,Used to restore the location of the floating window after the screen is rotated * @author petterp */ -class FxLocationHelper { - private lateinit var config: FxBasisHelper - private var screenW = 0 - private var screenH = 0 - private var x: Float = 0f - private var y: Float = 0f - private var isNearestLeft = false +class FxViewLocationHelper : FxBasicViewHelper() { private var screenChanged: Boolean = false private var isInitLocation = true - fun initConfig(config: FxBasisHelper) { - this.config = config - } + private var needUpdateLocation = false + private var parentW = 0f + private var parentH = 0f + private var viewW = 0f + private var viewH = 0f + + private var minHBoundary = 0f + private var maxHBoundary = 0f + private var minWBoundary = 0f + private var maxWBoundary = 0f + private val x: Float + get() = basicView?.currentX() ?: 0f + private val y: Float + get() = basicView?.currentY() ?: 0f - /** - * Whether to restore the position - * */ fun isRestoreLocation() = screenChanged fun isInitLocation(): Boolean { @@ -36,54 +38,139 @@ class FxLocationHelper { return false } - /** - * save location info - * */ - fun saveLocation( - x: Float, - y: Float, - configHelper: FxViewConfigHelper, - ): FxLocationHelper { - this.x = x - this.y = y - isNearestLeft = configHelper.isNearestLeft(x) - return this + fun updateLocationStatus() { + needUpdateLocation = true } - /** - * update screen size config - * @return Whether the screen rotation has occurred - * */ - fun updateConfig(config: Configuration): Boolean { - val isChangedScreen = - if (config.screenWidthDp != screenW || config.screenHeightDp != screenH) { - this.screenW = config.screenWidthDp - this.screenH = config.screenHeightDp - true - } else { - false - } - screenChanged = isChangedScreen - return screenChanged + fun onSizeChanged() { + updateViewSize() + if (needUpdateLocation) { + basicView?.moveToEdge() + needUpdateLocation = false + config.fxLog.d("fxView -> updateLocation") + } } - /** get location config */ - fun getLocation(viewConfig: FxViewConfigHelper): Pair { - val newX = getX(viewConfig.minWBoundary, viewConfig.minWBoundary) - val newY = getY(viewConfig.minHBoundary, viewConfig.maxHBoundary) - this.screenChanged = false - return newX to newY + fun initLayout(view: FxBasicParentView) { + val hasHistory = config.enableSaveDirection && config.iFxConfigStorage?.hasConfig() == true + val (defaultX, defaultY) = if (hasHistory) { + getHistoryXY() + } else { + getDefaultXY(parentW, parentH, viewW, viewH) + } + view.updateXY(safeX(defaultX), safeY(defaultY)) + val from = if (hasHistory) "history_location" else "default_location" + config.fxLog.d("fxView -> initLocation: x:$defaultX,y:$defaultY,from:$from") } - private fun getX(min: Float, max: Float): Float { + fun getDefaultEdgeXY(): Pair? { return if (config.enableEdgeAdsorption) { - if (isNearestLeft) min else max + if (config.adsorbDirection == FxAdsorbDirection.LEFT_OR_RIGHT) { + val moveX = if (isNearestLeft(x)) minWBoundary else maxWBoundary + val moveY = y + moveX to moveY + } else { + val moveX = x + val moveY = if (isNearestTop(y)) minHBoundary else maxHBoundary + moveX to moveY + } + } else if (config.enableEdgeRebound) { + x to y } else { - x.coerceInFx(min, max) + null } } - private fun getY(min: Float, max: Float): Float { - return y.coerceInFx(min, max) + fun updateViewSize() { + val view = basicView ?: return + val (pW, pH) = view.parentSize() + val viewH = view.height.toFloat() + val viewW = view.width.toFloat() + this.parentW = pW + this.parentH = pH + this.viewW = viewW + this.viewH = viewH + updateBoundary() + config.fxLog.d("fxView -> updateViewSize: parentW:$parentW,parentH:$parentH,viewW:$viewW,viewH:$viewH") + } + + fun safeX(x: Float) = x.coerceInFx(minWBoundary, maxWBoundary) + fun safeY(y: Float) = y.coerceInFx(minHBoundary, maxHBoundary) + fun checkOrSaveLocation(x: Float, y: Float) { + if (this.x == x && this.y == y) return + config.fxLog.d("saveLocation -> x:$x,y:$y") + } + + private fun isNearestLeft(x: Float): Boolean { + val middle = parentW / 2 + return x < middle + } + + private fun isNearestTop(y: Float): Boolean { + val middle = parentH / 2 + return y < middle + } + + private fun getHistoryXY(): Pair { + return config.run { + val configX = iFxConfigStorage?.getX() ?: 0f + val configY = iFxConfigStorage?.getY() ?: 0f + configX to configY + } + } + + private fun getDefaultXY( + width: Float, + height: Float, + viewW: Float, + viewH: Float + ): Pair { + return config.run { + val l = offsetX + safeEdgeOffSet + fxBorderMargin.l + val r = offsetX + safeEdgeOffSet + fxBorderMargin.r + val b = offsetY + safeEdgeOffSet + fxBorderMargin.b + val t = offsetY + safeEdgeOffSet + fxBorderMargin.t + when (gravity) { + FxGravity.DEFAULT, + FxGravity.LEFT_OR_TOP -> l to t + + FxGravity.LEFT_OR_CENTER -> l to (height - viewH).shr(1) + + FxGravity.LEFT_OR_BOTTOM -> 0f to height - viewH - b + + FxGravity.RIGHT_OR_TOP -> width - viewW - r to t + + FxGravity.RIGHT_OR_CENTER -> width - viewW - r to (height - viewH).shr(1) + + FxGravity.RIGHT_OR_BOTTOM -> width - viewW - r to height - viewH - b + + FxGravity.TOP_OR_CENTER -> (width - viewW).shr(1) to t + + FxGravity.BOTTOM_OR_CENTER -> (width - viewW).shr(1) to height - viewH - b + + else -> (width - viewW).shr(1) to (height - viewH).shr(1) + } + } + } + + private fun updateBoundary() { + config.apply { + if (enableEdgeRebound) { + val edgeOffset = edgeOffset + val marginTop = fxBorderMargin.t + edgeOffset + val marginBto = fxBorderMargin.b + edgeOffset + val marginLef = fxBorderMargin.l + edgeOffset + val marginRig = fxBorderMargin.r + edgeOffset + minWBoundary = marginLef + maxWBoundary = parentW - viewW - marginRig + minHBoundary = statsBarHeight.toFloat() + marginTop + maxHBoundary = parentH - viewH - navigationBarHeight - marginBto + } else { + minWBoundary = fxBorderMargin.l + maxWBoundary = parentW - viewW - fxBorderMargin.r + minHBoundary = statsBarHeight + fxBorderMargin.t + maxHBoundary = parentH - viewH - navigationBarHeight - fxBorderMargin.b + } + } } } diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewTouchHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewTouchHelper.kt index 3bac95cb..ff3aadef 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewTouchHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewTouchHelper.kt @@ -5,7 +5,6 @@ import android.view.MotionEvent import android.view.View import android.view.ViewConfiguration import androidx.annotation.Keep -import com.petterp.floatingx.assist.helper.FxBasisHelper import com.petterp.floatingx.util.INVALID_TOUCH_ID import com.petterp.floatingx.util.TOUCH_TIME_THRESHOLD import com.petterp.floatingx.util.pointerId @@ -15,7 +14,7 @@ import kotlin.math.abs * 手势事件辅助类,处理点击事件 * @author petterp */ -class FxViewTouchHelper { +class FxViewTouchHelper : FxBasicViewHelper() { private var initX = 0f private var initY = 0f private var scaledTouchSlop = 0F @@ -23,16 +22,13 @@ class FxViewTouchHelper { private var clickEnable = true private var mLastTouchDownTime = 0L private var touchDownId = INVALID_TOUCH_ID - private lateinit var helper: FxBasisHelper - private var basicView: FxBasicParentView? = null @SuppressLint("ClickableViewAccessibility") - fun initConfig(view: FxBasicParentView) { + override fun initConfig(parentView: FxBasicParentView) { + super.initConfig(parentView) reset() - this.basicView = view - this.helper = view.helper - scaledTouchSlop = ViewConfiguration.get(view.context).scaledTouchSlop.toFloat() - view.setOnTouchListener { _, event -> + scaledTouchSlop = ViewConfiguration.get(parentView.context).scaledTouchSlop.toFloat() + parentView.setOnTouchListener { _, event -> when (event.actionMasked) { MotionEvent.ACTION_DOWN -> initTouchDown(event) MotionEvent.ACTION_MOVE -> touchToMove(event) @@ -49,14 +45,14 @@ class FxViewTouchHelper { @Keep fun touchCancel(view: View) { if (isClickEffective()) { - helper.iFxClickListener?.onClick(view) - if (helper.clickTime > 0) { + config.iFxClickListener?.onClick(view) + if (config.clickTime > 0) { clickEnable = false - view.postDelayed({ clickEnable = true }, helper.clickTime) + view.postDelayed({ clickEnable = true }, config.clickTime) } else { clickEnable = true } - helper.fxLog?.d("fxView -> click") + config.fxLog.d("fxView -> click") } reset() } @@ -66,11 +62,11 @@ class FxViewTouchHelper { initClickConfig(event) touchDownId = event.pointerId basicView?.onTouchDown(event) - helper.fxLog?.d("fxView->initTouchDown---id:$touchDownId->") + config.fxLog.d("fxView -> initDownTouch,mainTouchId:$touchDownId") } private fun initClickConfig(event: MotionEvent) { - if (!helper.enableClickListener || helper.iFxClickListener == null) return + if (!config.enableClickListener || config.iFxClickListener == null) return isClickEvent = true this.initX = event.rawX this.initY = event.rawY @@ -78,7 +74,15 @@ class FxViewTouchHelper { } private fun touchToPointerDown(event: MotionEvent) { - if (hasMainPointerId()) return + if (hasMainPointerId()) { + config.fxLog.d("fxView -> touchToPointerDown: currentId:${event.pointerId}, mainTouchId:$touchDownId exist,return") + return + } + // Before the event starts, check first + if (basicView?.preCheckPointerDownTouch(event) != true) { + config.fxLog.d("fxView -> touchToPointerDown: current touch location error,return") + return + } initTouchDown(event) } @@ -86,21 +90,22 @@ class FxViewTouchHelper { if (!isCurrentPointerId(event)) return checkClickState(event) basicView?.onTouchMove(event) - helper.fxLog?.d("fxView---onTouchEvent---onTouchMove->") + config.fxLog.v("fxView -> touchMove,rawX:${event.rawX},rawY:${event.rawY}") } private fun touchCancel(event: MotionEvent) { if (!isCurrentPointerId(event)) return performClick() reset() + basicView?.moveToEdge() basicView?.onTouchCancel(event) - helper.fxLog?.d("fxView---onTouchEvent---MainTouchCancel->") + config.fxLog.d("fxView -> mainTouchUp") } private fun performClick() { if (isClickEffective()) { clickEnable = false - helper.iFxClickListener?.onClick(basicView) + config.iFxClickListener?.onClick(basicView) basicView?.postDelayed({ clickEnable = true }, 1000) @@ -128,8 +133,8 @@ class FxViewTouchHelper { private fun isClickEffective(): Boolean { // 当前是点击事件&&点击事件目前可启用&&回调存在&&点击时间小于阈值 - return isClickEvent && clickEnable && helper.enableClickListener && - helper.iFxClickListener != null && + return isClickEvent && clickEnable && config.enableClickListener && + config.iFxClickListener != null && System.currentTimeMillis() - mLastTouchDownTime < TOUCH_TIME_THRESHOLD } } diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/default/FxDefaultContainerView.kt b/floatingx/src/main/java/com/petterp/floatingx/view/default/FxDefaultContainerView.kt index 86dbf882..53f96cfe 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/default/FxDefaultContainerView.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/default/FxDefaultContainerView.kt @@ -21,7 +21,7 @@ import com.petterp.floatingx.util.pointerId import com.petterp.floatingx.util.withIn import com.petterp.floatingx.view.FxViewHolder import com.petterp.floatingx.view.IFxInternalView -import com.petterp.floatingx.view.basic.FxLocationHelper +import com.petterp.floatingx.view.basic.FxViewLocationHelper import com.petterp.floatingx.view.basic.FxViewTouchHelper /** 基础悬浮窗View */ @@ -33,7 +33,7 @@ class FxDefaultContainerView @JvmOverloads constructor( private lateinit var helper: FxBasisHelper private val clickHelper = FxViewTouchHelper() - private val locationHelper = FxLocationHelper() + private val locationHelper = FxViewLocationHelper() private val configHelper = FxViewConfigHelper() private var _viewHolder: FxViewHolder? = null @@ -58,7 +58,7 @@ class FxDefaultContainerView @JvmOverloads constructor( private fun initView() { _childFxView = inflateLayoutView() ?: inflateLayoutId() // clickHelper.initConfig(context, helper) - locationHelper.initConfig(helper) +// locationHelper.initConfig(this) configHelper.initConfig(context, helper) checkNotNull(_childFxView) { "initFxView -> Error,check your layoutId or layoutView." } initLocation() @@ -69,7 +69,7 @@ class FxDefaultContainerView @JvmOverloads constructor( private fun inflateLayoutView(): View? { val view = helper.layoutView ?: return null - helper.fxLog?.d("fxView-->init, way:[layoutView]") + helper.fxLog.d("fxView-->init, way:[layoutView]") val lp = view.layoutParams ?: LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, @@ -80,7 +80,7 @@ class FxDefaultContainerView @JvmOverloads constructor( private fun inflateLayoutId(): View? { if (helper.layoutId == INVALID_LAYOUT_ID) return null - helper.fxLog?.d("fxView-->init, way:[layoutId]") + helper.fxLog.d("fxView-->init, way:[layoutId]") val view = LayoutInflater.from(context).inflate(helper.layoutId, this, false) addView(view) return view @@ -106,13 +106,13 @@ class FxDefaultContainerView @JvmOverloads constructor( } if (initX != -1F) x = initX if (initY != -1F) y = initY - helper.fxLog?.d("fxView->initLocation,isHasConfig-($hasConfig),defaultX-($initX),defaultY-($initY)") + helper.fxLog.d("fxView -> initLocation,isHasConfig-($hasConfig),defaultX-($initX),defaultY-($initY)") } private fun initDefaultXY(): Pair { // 非辅助定位&&非默认位置,此时x,y不可信 if (!helper.enableAssistLocation && !helper.gravity.isDefault()) { - helper.fxLog?.e( + helper.fxLog.e( "fxView--默认坐标可能初始化异常,如果显示位置异常,请检查您的gravity是否为默认配置,当前gravity:${helper.gravity}。\n" + "如果您要配置gravity,建议您启用辅助定位setEnableAssistDirection(),此方法将更便于定位。", ) @@ -136,12 +136,12 @@ class FxDefaultContainerView @JvmOverloads constructor( when (ev.actionMasked) { MotionEvent.ACTION_DOWN -> { initTouchDown(ev) - helper.fxLog?.d("fxView---onInterceptTouchEvent-[down]") + helper.fxLog.d("fxView---onInterceptTouchEvent-[down]") } MotionEvent.ACTION_MOVE -> { intercepted = configHelper.checkInterceptedEvent(ev) - helper.fxLog?.d("fxView---onInterceptTouchEvent-[move], interceptedTouch-$intercepted") + helper.fxLog.d("fxView---onInterceptTouchEvent-[move], interceptedTouch-$intercepted") } } return intercepted @@ -164,32 +164,32 @@ class FxDefaultContainerView @JvmOverloads constructor( super.onAttachedToWindow() helper.iFxViewLifecycle?.attach() (parent as? ViewGroup)?.addOnLayoutChangeListener(this) - helper.fxLog?.d("fxView-lifecycle-> onAttachedToWindow") + helper.fxLog.d("fxView-lifecycle-> onAttachedToWindow") } override fun onDetachedFromWindow() { super.onDetachedFromWindow() helper.iFxViewLifecycle?.detached() (parent as? ViewGroup)?.removeOnLayoutChangeListener(this) - helper.fxLog?.d("fxView-lifecycle-> onDetachedFromWindow") + helper.fxLog.d("fxView-lifecycle-> onDetachedFromWindow") } override fun onWindowVisibilityChanged(visibility: Int) { super.onWindowVisibilityChanged(visibility) helper.iFxViewLifecycle?.windowsVisibility(visibility) - helper.fxLog?.d("fxView-lifecycle-> onWindowVisibilityChanged") + helper.fxLog.d("fxView-lifecycle-> onWindowVisibilityChanged") } override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) - helper.fxLog?.d("fxView--lifecycle-> onConfigurationChanged--->") + helper.fxLog.d("fxView--lifecycle-> onConfigurationChanged--->") // use the configuration in Configuration first - val isScreenChanged = locationHelper.updateConfig(newConfig) - if (!isScreenChanged) return +// val isScreenChanged = locationHelper.updateConfig(newConfig) +// if (!isScreenChanged) return val x = x val y = y - locationHelper.saveLocation(x, y, configHelper) - helper.fxLog?.d("fxView--lifecycle-> saveLocation:[x:$x,y:$y]") +// locationHelper.saveLocation(x, y, configHelper) + helper.fxLog.d("fxView--lifecycle-> saveLocation:[x:$x,y:$y]") } override fun setOnClickListener(l: OnClickListener?) { @@ -249,26 +249,26 @@ class FxDefaultContainerView @JvmOverloads constructor( private fun moveToLocation(moveX: Float, moveY: Float) { if (moveX == x && moveY == y) return - helper.fxLog?.d("fxView-->moveToEdge---x-($x),y-($y) -> moveX-($moveX),moveY-($moveY)") + helper.fxLog.d("fxView-->moveToEdge---x-($x),y-($y) -> moveX-($moveX),moveY-($moveY)") animate().x(moveX).y(moveY).setDuration(DEFAULT_MOVE_ANIMATOR_DURATION).start() } private fun saveLocationToStorage(moveX: Float, moveY: Float) { if (!helper.enableSaveDirection) return if (helper.iFxConfigStorage == null) { - helper.fxLog?.e("fxView-->saveDirection---iFxConfigStorageImpl does not exist, save failed!") + helper.fxLog.e("fxView-->saveDirection---iFxConfigStorageImpl does not exist, save failed!") return } helper.iFxConfigStorage?.update(moveX, moveY) - helper.fxLog?.d("fxView-->saveDirection---x-($moveX),y-($moveY)") + helper.fxLog.d("fxView-->saveDirection---x-($moveX),y-($moveY)") } private fun restoreLocation() { - val (x, y) = locationHelper.getLocation(configHelper) - this.x = x - this.y = y +// val (x, y) = locationHelper.getLocation(configHelper) +// this.x = x +// this.y = y saveLocationToStorage(x, y) - helper.fxLog?.d("fxView--lifecycle-> restoreLocation:[x:$x,y:$y]") + helper.fxLog.d("fxView--lifecycle-> restoreLocation:[x:$x,y:$y]") } private fun touchToMove(event: MotionEvent) { @@ -281,12 +281,12 @@ class FxDefaultContainerView @JvmOverloads constructor( if (configHelper.isCurrentPointerId(event)) { touchToCancel() } else { - helper.fxLog?.d("fxView---onTouchEvent--ACTION_POINTER_UP---id:${event.pointerId}->") + helper.fxLog.d("fxView---onTouchEvent--ACTION_POINTER_UP---id:${event.pointerId}->") } } private fun touchToPointerDown(event: MotionEvent) { - helper.fxLog?.d("fxView---onTouchEvent--touchToPointerDown--id:${event.getPointerId(event.actionIndex)}->") + helper.fxLog.d("fxView---onTouchEvent--touchToPointerDown--id:${event.getPointerId(event.actionIndex)}->") if (configHelper.hasMainPointerId()) return // Here you can realize the multi-finger cooperative pulling 😆 if (event.x.withIn(0, width) && event.y.withIn(0, height)) { @@ -299,7 +299,7 @@ class FxDefaultContainerView @JvmOverloads constructor( helper.iFxScrollListener?.up() configHelper.touchDownId = INVALID_TOUCH_ID clickHelper.touchCancel(this) - helper.fxLog?.d("fxView---onTouchEvent---MainTouchCancel->") + helper.fxLog.d("fxView---onTouchEvent---MainTouchCancel->") } private fun refreshLocation(w: Int, h: Int) { @@ -329,7 +329,7 @@ class FxDefaultContainerView @JvmOverloads constructor( y = disY // clickHelper.touchMove(event) helper.iFxScrollListener?.dragIng(event, disX, disY) - helper.fxLog?.v("fxView---scrollListener--drag-event--x($disX)-y($disY)") + helper.fxLog.v("fxView---scrollListener--drag-event--x($disX)-y($disY)") } override fun onLayoutChange( diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/default/FxViewConfigHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/view/default/FxViewConfigHelper.kt index af823439..78b108f6 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/default/FxViewConfigHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/default/FxViewConfigHelper.kt @@ -50,7 +50,7 @@ class FxViewConfigHelper { touchDownId = ev.pointerId downTouchX = ev.x downTouchY = ev.y - helper.fxLog?.d("fxView---newTouchDown:$touchDownId") + helper.fxLog.d("fxView---newTouchDown:$touchDownId") } fun updateWidgetSize(view: ViewGroup): Boolean { @@ -63,7 +63,7 @@ class FxViewConfigHelper { val parentWidth = (parentW - view.width).toFloat() val parentHeight = (parentH - view.height).toFloat() if (mParentHeight != parentHeight || mParentWidth != parentWidth) { - helper.fxLog?.d("fxView->updateContainerSize: oldW-($mParentWidth),oldH-($mParentHeight),newW-($parentWidth),newH-($parentHeight)") + helper.fxLog.d("fxView -> updateContainerSize: oldW-($mParentWidth),oldH-($mParentHeight),newW-($parentWidth),newH-($parentHeight)") mParentWidth = parentWidth mParentHeight = parentHeight updateBoundary(false) @@ -72,12 +72,12 @@ class FxViewConfigHelper { return false } - fun isNearestLeft(x: Float): Boolean { + private fun isNearestLeft(x: Float): Boolean { val middle = mParentWidth / 2 return x < middle } - fun isNearestTop(y: Float): Boolean { + private fun isNearestTop(y: Float): Boolean { val middle = mParentHeight / 2 return y < middle } diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt b/floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt index 0c91fb26..7c264977 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt @@ -40,21 +40,25 @@ class FxSystemContainerView @JvmOverloads constructor( wm.addView(this, wl) } - override fun moveLocation(x: Float, y: Float, useAnimation: Boolean) { - wl.x = x.toInt() - wl.y = y.toInt() - wm.updateViewLayout(this, wl) + override fun currentX(): Float { + return wl.x.toFloat() } - override fun onLayoutInit() { - val width = helper.context.screenWidth - val height = helper.context.screenHeight - val viewH = this.height - val viewW = this.width - val (defaultX, defaultY) = helper.defaultXY(width, height, viewW, viewH) - wl.x = defaultX - wl.y = defaultY - wm.updateViewLayout(this, wl) + override fun currentY(): Float { + return wl.y.toFloat() + } + + override fun preCheckPointerDownTouch(event: MotionEvent): Boolean { + // 当前屏幕存在手指时,check当前手势是否真的在浮窗之上 + val x = event.rawX + val y = event.rawY + val location = IntArray(2) + getLocationOnScreen(location) + val left = location[0] + val top = location[1] + val right = left + this.width + val bottom = top + this.height + return x >= left && x <= right && y >= top && y <= bottom } override fun onTouchDown(event: MotionEvent) { @@ -69,9 +73,7 @@ class FxSystemContainerView @JvmOverloads constructor( val movedY = nowY - cY cX = nowX cY = nowY - wl.x += movedX.toInt() - wl.y += movedY.toInt() - wm.updateViewLayout(this, wl) + updateXY(wl.x + movedX, wl.y + movedY) } override fun onTouchCancel(event: MotionEvent) { @@ -83,6 +85,16 @@ class FxSystemContainerView @JvmOverloads constructor( return false } + override fun updateXY(x: Float, y: Float) { + wl.x = x.toInt() + wl.y = y.toInt() + wm.updateViewLayout(this, wl) + } + + override fun parentSize(): Pair { + return helper.context.screenWidth.toFloat() to helper.context.screenHeight.toFloat() + } + private fun initWLParams() { wl = WindowManager.LayoutParams().apply { width = WindowManager.LayoutParams.WRAP_CONTENT From e53b3e64653b297a3324515b0d76f00d8dd9c3c8 Mon Sep 17 00:00:00 2001 From: petterp Date: Mon, 1 Jan 2024 13:04:41 +0800 Subject: [PATCH 7/8] =?UTF-8?q?perf:=E4=BC=98=E5=8C=96fx=20view=E7=9A=84?= =?UTF-8?q?=E6=BB=91=E5=8A=A8=E8=BE=B9=E7=95=8C=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../floatingx/view/basic/FxBasicParentView.kt | 15 ++++- .../view/basic/FxViewBoundaryConfig.kt | 20 +++++++ .../view/basic/FxViewLocationHelper.kt | 58 +++++++++++-------- .../view/system/FxSystemContainerView.kt | 23 ++++---- 4 files changed, 76 insertions(+), 40 deletions(-) create mode 100644 floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewBoundaryConfig.kt diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxBasicParentView.kt b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxBasicParentView.kt index 4e455ec4..338c00bd 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxBasicParentView.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxBasicParentView.kt @@ -25,7 +25,7 @@ abstract class FxBasicParentView @JvmOverloads constructor( private var _viewHolder: FxViewHolder? = null private val touchHelper = FxViewTouchHelper() private val animateHelper = FxViewAnimationHelper() - internal val locationHelper = FxViewLocationHelper() + private val locationHelper = FxViewLocationHelper() abstract fun currentX(): Float abstract fun currentY(): Float @@ -90,6 +90,12 @@ abstract class FxBasicParentView @JvmOverloads constructor( return interceptTouchEvent(event) || super.onInterceptTouchEvent(event) } + protected fun safeUpdateXY(x: Float, y: Float) { + val safeX = locationHelper.safeX(x, true) + val safeY = locationHelper.safeY(y, true) + updateXY(safeX, safeY) + } + protected fun initChildView(): View? { _childView = inflateLayoutView() ?: inflateLayoutId() return _childView @@ -117,13 +123,18 @@ abstract class FxBasicParentView @JvmOverloads constructor( private fun moveToXY(x: Float, y: Float, useAnimation: Boolean) { val endX = locationHelper.safeX(x) val endY = locationHelper.safeY(y) + if (currentX() == endX && currentY() == endY) return + internalMoveToXY(useAnimation, endX, endY) locationHelper.checkOrSaveLocation(endX, endY) + helper.fxLog.d("fxView -> moveToXY: start(${currentX()},${currentY()}),end($endX,$endY)") + } + + private fun internalMoveToXY(useAnimation: Boolean, endX: Float, endY: Float) { if (useAnimation) { animateHelper.start(endX, endY) } else { updateXY(endX, endY) } - helper.fxLog.d("moveToXY: start(${currentX()},${currentY()}),end($endX,$endY)") } private fun checkOrInitLayout() { diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewBoundaryConfig.kt b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewBoundaryConfig.kt new file mode 100644 index 00000000..cb2a1962 --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewBoundaryConfig.kt @@ -0,0 +1,20 @@ +package com.petterp.floatingx.view.basic + +/** + * FxView 边界配置 + * @author petterp + */ +class FxViewBoundaryConfig( + var minW: Float = 0f, + var maxW: Float = 0f, + var minH: Float = 0f, + var maxH: Float = 0f +) { + fun copy(other: FxViewBoundaryConfig): FxViewBoundaryConfig { + this.minW = other.minW + this.maxW = other.maxW + this.minH = other.minH + this.maxH = other.maxH + return this + } +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewLocationHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewLocationHelper.kt index a5643b6a..43a8758a 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewLocationHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewLocationHelper.kt @@ -19,10 +19,9 @@ class FxViewLocationHelper : FxBasicViewHelper() { private var viewW = 0f private var viewH = 0f - private var minHBoundary = 0f - private var maxHBoundary = 0f - private var minWBoundary = 0f - private var maxWBoundary = 0f + private val moveIngBoundary = FxViewBoundaryConfig() + private val moveBoundary = FxViewBoundaryConfig() + private val x: Float get() = basicView?.currentX() ?: 0f private val y: Float @@ -66,12 +65,12 @@ class FxViewLocationHelper : FxBasicViewHelper() { fun getDefaultEdgeXY(): Pair? { return if (config.enableEdgeAdsorption) { if (config.adsorbDirection == FxAdsorbDirection.LEFT_OR_RIGHT) { - val moveX = if (isNearestLeft(x)) minWBoundary else maxWBoundary + val moveX = if (isNearestLeft(x)) moveBoundary.minW else moveBoundary.maxW val moveY = y moveX to moveY } else { val moveX = x - val moveY = if (isNearestTop(y)) minHBoundary else maxHBoundary + val moveY = if (isNearestTop(y)) moveBoundary.minH else moveBoundary.maxH moveX to moveY } } else if (config.enableEdgeRebound) { @@ -81,7 +80,7 @@ class FxViewLocationHelper : FxBasicViewHelper() { } } - fun updateViewSize() { + private fun updateViewSize() { val view = basicView ?: return val (pW, pH) = view.parentSize() val viewH = view.height.toFloat() @@ -94,10 +93,23 @@ class FxViewLocationHelper : FxBasicViewHelper() { config.fxLog.d("fxView -> updateViewSize: parentW:$parentW,parentH:$parentH,viewW:$viewW,viewH:$viewH") } - fun safeX(x: Float) = x.coerceInFx(minWBoundary, maxWBoundary) - fun safeY(y: Float) = y.coerceInFx(minHBoundary, maxHBoundary) + fun safeX(x: Float, isMoveIng: Boolean = false): Float { + val enableBound = isMoveIng && config.enableEdgeRebound + val minW = if (enableBound) moveIngBoundary.minW else moveBoundary.minW + val maxW = if (enableBound) moveIngBoundary.maxW else moveBoundary.maxW + return x.coerceInFx(minW, maxW) + } + + fun safeY(y: Float, isMoveIng: Boolean = false): Float { + val enableBound = isMoveIng && config.enableEdgeRebound + val minH = if (enableBound) moveIngBoundary.minH else moveBoundary.minH + val maxH = if (enableBound) moveIngBoundary.maxH else moveBoundary.maxH + return y.coerceInFx(minH, maxH) + } + fun checkOrSaveLocation(x: Float, y: Float) { - if (this.x == x && this.y == y) return + if (config.iFxConfigStorage == null || !config.enableSaveDirection) return + config.iFxConfigStorage!!.update(x, y) config.fxLog.d("saveLocation -> x:$x,y:$y") } @@ -155,21 +167,17 @@ class FxViewLocationHelper : FxBasicViewHelper() { private fun updateBoundary() { config.apply { - if (enableEdgeRebound) { - val edgeOffset = edgeOffset - val marginTop = fxBorderMargin.t + edgeOffset - val marginBto = fxBorderMargin.b + edgeOffset - val marginLef = fxBorderMargin.l + edgeOffset - val marginRig = fxBorderMargin.r + edgeOffset - minWBoundary = marginLef - maxWBoundary = parentW - viewW - marginRig - minHBoundary = statsBarHeight.toFloat() + marginTop - maxHBoundary = parentH - viewH - navigationBarHeight - marginBto - } else { - minWBoundary = fxBorderMargin.l - maxWBoundary = parentW - viewW - fxBorderMargin.r - minHBoundary = statsBarHeight + fxBorderMargin.t - maxHBoundary = parentH - viewH - navigationBarHeight - fxBorderMargin.b + moveIngBoundary.apply { + minW = 0f + maxW = parentW - viewW + minH = statsBarHeight.toFloat() + maxH = parentH - viewH - navigationBarHeight + } + moveBoundary.copy(moveIngBoundary).apply { + minW += fxBorderMargin.l + edgeOffset + maxW -= fxBorderMargin.r + edgeOffset + minH += fxBorderMargin.t + edgeOffset + maxH -= fxBorderMargin.b + edgeOffset } } } diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt b/floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt index 7c264977..baa89017 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt @@ -23,8 +23,9 @@ class FxSystemContainerView @JvmOverloads constructor( ) : FxBasicParentView(helper, context, attrs) { private lateinit var wl: WindowManager.LayoutParams - private var cX = 0f - private var cY = 0f + + private var downTouchX = 0f + private var downTouchY = 0f val isAttachToWM: Boolean get() = windowToken != null @@ -62,23 +63,19 @@ class FxSystemContainerView @JvmOverloads constructor( } override fun onTouchDown(event: MotionEvent) { - cX = event.rawX - cY = event.rawY + downTouchX = wl.x.minus(event.rawX) + downTouchY = wl.y.minus(event.rawY) } override fun onTouchMove(event: MotionEvent) { - val nowX = event.rawX - val nowY = event.rawY - val movedX = nowX - cX - val movedY = nowY - cY - cX = nowX - cY = nowY - updateXY(wl.x + movedX, wl.y + movedY) + val x = downTouchX.plus(event.rawX) + val y = downTouchY.plus(event.rawY) + safeUpdateXY(x, y) } override fun onTouchCancel(event: MotionEvent) { - cX = 0f - cY = 0f + downTouchX = 0f + downTouchY = 0f } override fun interceptTouchEvent(ev: MotionEvent): Boolean { From 03db53753b737e69a39b6f6032ed0d3c1528d9b0 Mon Sep 17 00:00:00 2001 From: petterp Date: Mon, 1 Jan 2024 20:40:51 +0800 Subject: [PATCH 8/8] =?UTF-8?q?perf:=E9=87=8D=E6=9E=84fx=E9=BB=98=E8=AE=A4?= =?UTF-8?q?view=E7=9A=84=E5=BA=95=E5=B1=82=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/kotlin/CustomKtApplication.kt | 5 +- .../provider/app/FxAppPlatformProvider.kt | 5 +- .../provider/scope/FxScopePlatFromProvider.kt | 12 ++-- .../system/FxSystemPlatformProvider.kt | 2 +- .../floatingx/view/FxDefaultContainerView.kt | 72 +++++++++++++++++++ .../{system => }/FxSystemContainerView.kt | 12 ++-- .../floatingx/view/basic/FxBasicParentView.kt | 23 +++--- .../view/basic/FxViewLocationHelper.kt | 6 +- .../floatingx/view/basic/FxViewTouchHelper.kt | 22 +++++- 9 files changed, 119 insertions(+), 40 deletions(-) create mode 100644 floatingx/src/main/java/com/petterp/floatingx/view/FxDefaultContainerView.kt rename floatingx/src/main/java/com/petterp/floatingx/view/{system => }/FxSystemContainerView.kt (90%) diff --git a/app/src/main/java/com/petterp/floatingx/app/kotlin/CustomKtApplication.kt b/app/src/main/java/com/petterp/floatingx/app/kotlin/CustomKtApplication.kt index 3caf9031..a5ec2b2f 100644 --- a/app/src/main/java/com/petterp/floatingx/app/kotlin/CustomKtApplication.kt +++ b/app/src/main/java/com/petterp/floatingx/app/kotlin/CustomKtApplication.kt @@ -14,6 +14,7 @@ import androidx.cardview.widget.CardView import com.petterp.floatingx.FloatingX import com.petterp.floatingx.app.* import com.petterp.floatingx.app.simple.FxAnimationImpl +import com.petterp.floatingx.app.simple.FxConfigStorageToSpImpl import com.petterp.floatingx.app.test.BlackActivity import com.petterp.floatingx.app.test.MultipleFxActivity import com.petterp.floatingx.assist.FxDisplayMode @@ -76,7 +77,7 @@ class CustomKtApplication : Application() { // 设置启用悬浮窗可屏幕外回弹 setEnableScrollOutsideScreen(true) // 开启历史位置缓存 -// setSaveDirectionImpl(FxConfigStorageToSpImpl(context)) + setSaveDirectionImpl(FxConfigStorageToSpImpl(context)) // 设置启用动画 setEnableAnimation(true) // 设置启用动画实现 @@ -163,6 +164,8 @@ class CustomKtApplication : Application() { ) setTag(MultipleFxActivity.TAG_2) setEnableLog(true) + setEdgeOffset(20f) + setEnableEdgeAdsorption(true) enableFx() } } diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/app/FxAppPlatformProvider.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/app/FxAppPlatformProvider.kt index 0f322256..9cf6ba23 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/app/FxAppPlatformProvider.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/app/FxAppPlatformProvider.kt @@ -13,8 +13,8 @@ import com.petterp.floatingx.impl.lifecycle.FxTempAppLifecycleImp import com.petterp.floatingx.listener.provider.IFxPlatformProvider import com.petterp.floatingx.util.decorView import com.petterp.floatingx.util.topActivity +import com.petterp.floatingx.view.FxDefaultContainerView import com.petterp.floatingx.view.IFxInternalView -import com.petterp.floatingx.view.default.FxDefaultContainerView import java.lang.ref.WeakReference /** @@ -58,7 +58,8 @@ class FxAppPlatformProvider( initWindowsInsetsListener() helper.updateNavigationBar(act) helper.updateStatsBar(act) - _internalView = FxDefaultContainerView(helper.context).init(helper) + _internalView = FxDefaultContainerView(helper, helper.context) + _internalView?.initView() checkRegisterAppLifecycle() attach(act) } diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/scope/FxScopePlatFromProvider.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/scope/FxScopePlatFromProvider.kt index 53d8112c..b479cfe2 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/scope/FxScopePlatFromProvider.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/scope/FxScopePlatFromProvider.kt @@ -5,9 +5,8 @@ import android.view.View import android.view.ViewGroup import com.petterp.floatingx.assist.helper.FxScopeHelper import com.petterp.floatingx.listener.provider.IFxPlatformProvider -import com.petterp.floatingx.view.FxViewHolder import com.petterp.floatingx.view.IFxInternalView -import com.petterp.floatingx.view.default.FxDefaultContainerView +import com.petterp.floatingx.view.FxDefaultContainerView import java.lang.ref.WeakReference /** @@ -18,7 +17,6 @@ class FxScopePlatFromProvider( override val helper: FxScopeHelper, ) : IFxPlatformProvider { - private var _holder: FxViewHolder? = null private var _internalView: FxDefaultContainerView? = null private var _containerGroup: WeakReference? = null @@ -44,10 +42,10 @@ class FxScopePlatFromProvider( override fun checkOrInit(): Boolean { if (_internalView == null) { - val containerGroupView = containerGroupView ?: return false - _internalView = FxDefaultContainerView(containerGroupView.context).init(helper) - _holder = FxViewHolder(_internalView?.containerView) - containerGroupView.addView(_internalView) + val parentView = containerGroupView ?: return false + _internalView = FxDefaultContainerView(helper, parentView.context) + _internalView?.initView() + parentView.addView(_internalView) } return true } diff --git a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/system/FxSystemPlatformProvider.kt b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/system/FxSystemPlatformProvider.kt index f14c4f14..6565bd38 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/impl/provider/system/FxSystemPlatformProvider.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/impl/provider/system/FxSystemPlatformProvider.kt @@ -7,7 +7,7 @@ import com.petterp.floatingx.assist.helper.FxAppHelper import com.petterp.floatingx.listener.provider.IFxPlatformProvider import com.petterp.floatingx.util.isVisibility import com.petterp.floatingx.view.IFxInternalView -import com.petterp.floatingx.view.system.FxSystemContainerView +import com.petterp.floatingx.view.FxSystemContainerView /** * diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/FxDefaultContainerView.kt b/floatingx/src/main/java/com/petterp/floatingx/view/FxDefaultContainerView.kt new file mode 100644 index 00000000..a5605e26 --- /dev/null +++ b/floatingx/src/main/java/com/petterp/floatingx/view/FxDefaultContainerView.kt @@ -0,0 +1,72 @@ +package com.petterp.floatingx.view + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.util.AttributeSet +import android.view.Gravity +import android.view.MotionEvent +import android.view.ViewGroup +import com.petterp.floatingx.assist.helper.FxBasisHelper +import com.petterp.floatingx.view.basic.FxBasicParentView + +/** + * FxDefault View + * @author petterp + */ +@SuppressLint("ViewConstructor") +class FxDefaultContainerView(helper: FxBasisHelper, context: Context, attrs: AttributeSet? = null) : + FxBasicParentView(helper, context, attrs) { + + private var downTouchX = 0f + private var downTouchY = 0f + + override fun initView() { + super.initView() + isClickable = true + initLayoutParams() + installChildView() + setBackgroundColor(Color.TRANSPARENT) + } + + private fun initLayoutParams() { + val lp = helper.layoutParams ?: LayoutParams( + LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT, + ).apply { + gravity = Gravity.START or Gravity.TOP + } + layoutParams = lp + } + + override fun currentX(): Float = x + + override fun currentY(): Float = y + + override fun updateXY(x: Float, y: Float) { + this.x = x + this.y = y + } + + override fun parentSize(): Pair? { + val parentGroup = (parent as? ViewGroup) ?: return null + return parentGroup.width to parentGroup.height + } + + override fun onTouchDown(event: MotionEvent) { + downTouchX = event.x + downTouchY = event.y + } + + // 计算方式的不同,故与system逻辑有区别 + override fun onTouchMove(event: MotionEvent) { + val x = x.minus(downTouchX).plus(event.x) + val y = y.minus(downTouchY).plus(event.y) + safeUpdateXY(x, y) + } + + override fun onTouchCancel(event: MotionEvent) { + downTouchX = 0f + downTouchY = 0f + } +} diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt b/floatingx/src/main/java/com/petterp/floatingx/view/FxSystemContainerView.kt similarity index 90% rename from floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt rename to floatingx/src/main/java/com/petterp/floatingx/view/FxSystemContainerView.kt index baa89017..9b8fed1f 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/system/FxSystemContainerView.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/FxSystemContainerView.kt @@ -1,4 +1,4 @@ -package com.petterp.floatingx.view.system +package com.petterp.floatingx.view import android.annotation.SuppressLint import android.content.Context @@ -32,7 +32,7 @@ class FxSystemContainerView @JvmOverloads constructor( override fun initView() { super.initView() - initChildView() ?: return + installChildView() ?: return initWLParams() } @@ -78,18 +78,14 @@ class FxSystemContainerView @JvmOverloads constructor( downTouchY = 0f } - override fun interceptTouchEvent(ev: MotionEvent): Boolean { - return false - } - override fun updateXY(x: Float, y: Float) { wl.x = x.toInt() wl.y = y.toInt() wm.updateViewLayout(this, wl) } - override fun parentSize(): Pair { - return helper.context.screenWidth.toFloat() to helper.context.screenHeight.toFloat() + override fun parentSize(): Pair { + return helper.context.screenWidth to helper.context.screenHeight } private fun initWLParams() { diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxBasicParentView.kt b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxBasicParentView.kt index 338c00bd..9f4f4f94 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxBasicParentView.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxBasicParentView.kt @@ -30,24 +30,17 @@ abstract class FxBasicParentView @JvmOverloads constructor( abstract fun currentX(): Float abstract fun currentY(): Float abstract fun updateXY(x: Float, y: Float) - abstract fun parentSize(): Pair + abstract fun parentSize(): Pair? abstract fun onTouchDown(event: MotionEvent) abstract fun onTouchMove(event: MotionEvent) abstract fun onTouchCancel(event: MotionEvent) - abstract fun interceptTouchEvent(ev: MotionEvent): Boolean open fun preCheckPointerDownTouch(event: MotionEvent): Boolean = true open fun onLayoutInit() {} - override val childView: View? - get() = _childView - override val containerView: FrameLayout - get() = this - override val viewHolder: FxViewHolder? - get() { - if (_viewHolder == null) _viewHolder = FxViewHolder(this) - return _viewHolder - } + override val childView: View? get() = _childView + override val containerView: FrameLayout get() = this + override val viewHolder: FxViewHolder? get() = _viewHolder open fun initView() { touchHelper.initConfig(this) @@ -72,7 +65,7 @@ abstract class FxBasicParentView @JvmOverloads constructor( helper.fxLog.d("fxView -> updateView") locationHelper.updateLocationStatus() removeView(_childView) - initChildView() + installChildView() } override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { @@ -86,8 +79,7 @@ abstract class FxBasicParentView @JvmOverloads constructor( } override fun onInterceptTouchEvent(event: MotionEvent): Boolean { - if (touchHelper.hasMainPointerId()) return super.onInterceptTouchEvent(event) - return interceptTouchEvent(event) || super.onInterceptTouchEvent(event) + return touchHelper.interceptTouchEvent(event) || super.onInterceptTouchEvent(event) } protected fun safeUpdateXY(x: Float, y: Float) { @@ -96,8 +88,9 @@ abstract class FxBasicParentView @JvmOverloads constructor( updateXY(safeX, safeY) } - protected fun initChildView(): View? { + protected fun installChildView(): View? { _childView = inflateLayoutView() ?: inflateLayoutId() + if (_childView != null) _viewHolder = FxViewHolder(_childView) return _childView } diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewLocationHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewLocationHelper.kt index 43a8758a..81e6a1fc 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewLocationHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewLocationHelper.kt @@ -82,11 +82,11 @@ class FxViewLocationHelper : FxBasicViewHelper() { private fun updateViewSize() { val view = basicView ?: return - val (pW, pH) = view.parentSize() + val (pW, pH) = view.parentSize() ?: return val viewH = view.height.toFloat() val viewW = view.width.toFloat() - this.parentW = pW - this.parentH = pH + this.parentW = pW.toFloat() + this.parentH = pH.toFloat() this.viewW = viewW this.viewH = viewH updateBoundary() diff --git a/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewTouchHelper.kt b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewTouchHelper.kt index ff3aadef..1b000fb2 100644 --- a/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewTouchHelper.kt +++ b/floatingx/src/main/java/com/petterp/floatingx/view/basic/FxViewTouchHelper.kt @@ -40,7 +40,21 @@ class FxViewTouchHelper : FxBasicViewHelper() { } } - fun hasMainPointerId() = touchDownId != INVALID_TOUCH_ID + fun interceptTouchEvent(event: MotionEvent): Boolean { + when (event.action) { + MotionEvent.ACTION_DOWN -> { + if (hasMainPointerId()) return false + initTouchDown(event) + } + + MotionEvent.ACTION_MOVE -> { + if (!isCurrentPointerId(event)) return false + return abs(event.x - initX) >= scaledTouchSlop || + abs(event.y - initY) >= scaledTouchSlop + } + } + return false + } @Keep fun touchCancel(view: View) { @@ -66,10 +80,10 @@ class FxViewTouchHelper : FxBasicViewHelper() { } private fun initClickConfig(event: MotionEvent) { - if (!config.enableClickListener || config.iFxClickListener == null) return - isClickEvent = true this.initX = event.rawX this.initY = event.rawY + if (!config.enableClickListener || config.iFxClickListener == null) return + isClickEvent = true mLastTouchDownTime = System.currentTimeMillis() } @@ -131,6 +145,8 @@ class FxViewTouchHelper : FxBasicViewHelper() { touchDownId = INVALID_TOUCH_ID } + private fun hasMainPointerId() = touchDownId != INVALID_TOUCH_ID + private fun isClickEffective(): Boolean { // 当前是点击事件&&点击事件目前可启用&&回调存在&&点击时间小于阈值 return isClickEvent && clickEnable && config.enableClickListener &&