From 31259fe6b1284cff8f4ceafb7ffa545708a33158 Mon Sep 17 00:00:00 2001 From: Lewis Date: Tue, 9 Mar 2021 16:40:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=8B=96=E6=8B=BD=E8=BE=B9?= =?UTF-8?q?=E7=95=8C=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/lzf/easyfloat/EasyFloat.kt | 29 ++ .../easyfloat/core/FloatingWindowHelper.kt | 15 + .../java/com/lzf/easyfloat/core/TouchUtils.kt | 107 ++++-- .../com/lzf/easyfloat/data/FloatConfig.kt | 6 + .../lzf/easyfloat/permission/rom/RomUtils.kt | 4 +- example/src/main/AndroidManifest.xml | 1 + .../example/activity/BorderTestActivity.kt | 60 ++++ .../example/activity/MainActivity.kt | 2 + .../main/res/layout/activity_border_test.xml | 33 ++ example/src/main/res/layout/activity_main.xml | 325 +++++++++--------- .../src/main/res/layout/float_border_test.xml | 25 ++ 11 files changed, 426 insertions(+), 181 deletions(-) create mode 100644 example/src/main/java/com/lzf/easyfloat/example/activity/BorderTestActivity.kt create mode 100644 example/src/main/res/layout/activity_border_test.xml create mode 100644 example/src/main/res/layout/float_border_test.xml diff --git a/easyfloat/src/main/java/com/lzf/easyfloat/EasyFloat.kt b/easyfloat/src/main/java/com/lzf/easyfloat/EasyFloat.kt index 86835aa..cc87ead 100644 --- a/easyfloat/src/main/java/com/lzf/easyfloat/EasyFloat.kt +++ b/easyfloat/src/main/java/com/lzf/easyfloat/EasyFloat.kt @@ -12,6 +12,7 @@ import com.lzf.easyfloat.interfaces.OnPermissionResult import com.lzf.easyfloat.permission.PermissionUtils import com.lzf.easyfloat.utils.LifecycleUtils import com.lzf.easyfloat.interfaces.FloatCallbacks +import com.lzf.easyfloat.utils.DisplayUtils import com.lzf.easyfloat.utils.Logger import java.lang.Exception @@ -87,6 +88,15 @@ class EasyFloat { @JvmOverloads fun getFloatView(tag: String? = null): View? = getConfig(tag)?.layoutView + /** + * 更新浮窗坐标,未指定坐标执行吸附动画 + * @param tag 浮窗标签 + * @param x 更新后的X轴坐标 + * @param y 更新后的Y轴坐标 + */ + fun updateFloat(tag: String? = null, x: Int = -1, y: Int = -1) = + FloatingWindowManager.getHelper(tag)?.updateFloat(x, y) + // 以下几个方法为:系统浮窗过滤页面的添加、移除、清空 /** * 为当前浮窗过滤,设置需要过滤的Activity @@ -200,6 +210,25 @@ class EasyFloat { */ fun setLocation(x: Int, y: Int) = apply { config.locationPair = Pair(x, y) } + /** + * 设置浮窗的拖拽边距值 + * @param left 浮窗左侧边距 + * @param top 浮窗顶部边距 + * @param right 浮窗右侧边距 + * @param bottom 浮窗底部边距 + */ + fun setBorder( + left: Int = 0, + top: Int = -DisplayUtils.getStatusBarHeight(activity), + right: Int = DisplayUtils.getScreenWidth(activity), + bottom: Int = DisplayUtils.getScreenHeight(activity) + ) = apply { + config.leftBorder = left + config.topBorder = top + config.rightBorder = right + config.bottomBorder = bottom + } + /** * 设置浮窗的标签:只有一个浮窗时,可以不设置; * 有多个浮窗必须设置不容的浮窗,不然没法管理,所以禁止创建相同标签的浮窗 diff --git a/easyfloat/src/main/java/com/lzf/easyfloat/core/FloatingWindowHelper.kt b/easyfloat/src/main/java/com/lzf/easyfloat/core/FloatingWindowHelper.kt index 6e00437..436bfcb 100644 --- a/easyfloat/src/main/java/com/lzf/easyfloat/core/FloatingWindowHelper.kt +++ b/easyfloat/src/main/java/com/lzf/easyfloat/core/FloatingWindowHelper.kt @@ -319,4 +319,19 @@ internal class FloatingWindowHelper(val context: Context, var config: FloatConfi Logger.e("浮窗关闭出现异常:$e") } + /** + * 更新浮窗坐标 + */ + fun updateFloat(x: Int, y: Int) { + frameLayout?.let { + if (x == -1 && y == -1) { + // 未指定具体坐标,执行吸附动画 + it.postDelayed({ touchUtils.updateFloat(it, params, windowManager) }, 200) + } else { + params.x = x + params.y = y + windowManager.updateViewLayout(it, params) + } + } + } } \ No newline at end of file diff --git a/easyfloat/src/main/java/com/lzf/easyfloat/core/TouchUtils.kt b/easyfloat/src/main/java/com/lzf/easyfloat/core/TouchUtils.kt index 8bbf92c..42f5529 100644 --- a/easyfloat/src/main/java/com/lzf/easyfloat/core/TouchUtils.kt +++ b/easyfloat/src/main/java/com/lzf/easyfloat/core/TouchUtils.kt @@ -12,6 +12,7 @@ import com.lzf.easyfloat.data.FloatConfig import com.lzf.easyfloat.enums.ShowPattern import com.lzf.easyfloat.enums.SidePattern import com.lzf.easyfloat.utils.DisplayUtils +import kotlin.math.max import kotlin.math.min /** @@ -28,6 +29,12 @@ internal class TouchUtils(val context: Context, val config: FloatConfig) { private var parentHeight = 0 private var parentWidth = 0 + // 四周坐标边界值 + private var leftBorder = 0 + private var topBorder = 0 + private var rightBorder = 0 + private var bottomBorder = 0 + // 起点坐标 private var lastX = 0f private var lastY = 0f @@ -70,17 +77,16 @@ internal class TouchUtils(val context: Context, val config: FloatConfig) { // 记录触摸点的位置 lastX = event.rawX lastY = event.rawY - // 屏幕宽高需要每次获取,可能会有屏幕旋转、虚拟导航栏的状态变化 - parentWidth = DisplayUtils.getScreenWidth(context) - parentHeight = config.displayHeight.getDisplayRealHeight(context) - // 获取在整个屏幕内的绝对坐标 - view.getLocationOnScreen(location) - // 通过绝对高度和相对高度比较,判断包含顶部状态栏 - statusBarHeight = if (location[1] > params.y) statusBarHeight(view) else 0 - emptyHeight = parentHeight - view.height - statusBarHeight + // 初始化一些边界数据 + initBoarderValue(view, params) } MotionEvent.ACTION_MOVE -> { + // 过滤边界值之外的拖拽 + if (event.rawX < leftBorder || event.rawX > rightBorder + view.width + || event.rawY < topBorder || event.rawY > bottomBorder + view.width + ) return + // 移动值 = 本次触摸值 - 上次触摸值 val dx = event.rawX - lastX val dy = event.rawY - lastY @@ -92,8 +98,8 @@ internal class TouchUtils(val context: Context, val config: FloatConfig) { var y = params.y + dy.toInt() // 检测浮窗是否到达边缘 x = when { - x < 0 -> 0 - x > parentWidth - view.width -> parentWidth - view.width + x < leftBorder -> leftBorder + x > rightBorder -> rightBorder else -> x } @@ -104,11 +110,12 @@ internal class TouchUtils(val context: Context, val config: FloatConfig) { } y = when { + y < topBorder -> topBorder // 状态栏沉浸时,最小高度为-statusBarHeight,反之最小高度为0 y < 0 -> if (config.immersionStatusBar) { if (y < -statusBarHeight) -statusBarHeight else y } else 0 - y > emptyHeight -> emptyHeight + y > bottomBorder -> bottomBorder else -> y } @@ -154,7 +161,7 @@ internal class TouchUtils(val context: Context, val config: FloatConfig) { lastY = event.rawY } - MotionEvent.ACTION_UP -> { + MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { if (!config.isDrag) return // 回调拖拽事件的ACTION_UP config.callbacks?.drag(view, event) @@ -178,17 +185,67 @@ internal class TouchUtils(val context: Context, val config: FloatConfig) { } } + /** + * 根据吸附类别,更新浮窗位置 + */ + fun updateFloat( + view: View, + params: LayoutParams, + windowManager: WindowManager + ) { + initBoarderValue(view, params) + sideAnim(view, params, windowManager) + } + + /** + * 初始化边界值等数据 + */ + private fun initBoarderValue(view: View, params: LayoutParams) { + // 屏幕宽高需要每次获取,可能会有屏幕旋转、虚拟导航栏的状态变化 + parentWidth = DisplayUtils.getScreenWidth(context) + parentHeight = config.displayHeight.getDisplayRealHeight(context) + // 获取在整个屏幕内的绝对坐标 + view.getLocationOnScreen(location) + // 通过绝对高度和相对高度比较,判断包含顶部状态栏 + statusBarHeight = if (location[1] > params.y) statusBarHeight(view) else 0 + emptyHeight = parentHeight - view.height - statusBarHeight + + leftBorder = max(0, config.leftBorder) + rightBorder = min(parentWidth, config.rightBorder) - view.width + topBorder = if (config.showPattern == ShowPattern.CURRENT_ACTIVITY) { + // 单页面浮窗,坐标屏幕顶部计算 + if (config.immersionStatusBar) config.topBorder + else config.topBorder + statusBarHeight(view) + } else { + // 系统浮窗,坐标从状态栏底部开始,沉浸时坐标为负 + if (config.immersionStatusBar) config.topBorder - statusBarHeight(view) else config.topBorder + } + bottomBorder = if (config.showPattern == ShowPattern.CURRENT_ACTIVITY) { + // 单页面浮窗,坐标屏幕顶部计算 + if (config.immersionStatusBar) + min(emptyHeight, config.bottomBorder - view.height) + else + min(emptyHeight, config.bottomBorder + statusBarHeight(view) - view.height) + } else { + // 系统浮窗,坐标从状态栏底部开始,沉浸时坐标为负 + if (config.immersionStatusBar) + min(emptyHeight, config.bottomBorder - statusBarHeight(view) - view.height) + else + min(emptyHeight, config.bottomBorder - view.height) + } + } + private fun sideAnim( view: View, params: LayoutParams, windowManager: WindowManager ) { - initDistanceValue(params, view) + initDistanceValue(params) val isX: Boolean val end = when (config.sidePattern) { SidePattern.RESULT_LEFT -> { isX = true - 0 + leftBorder } SidePattern.RESULT_RIGHT -> { isX = true @@ -196,30 +253,30 @@ internal class TouchUtils(val context: Context, val config: FloatConfig) { } SidePattern.RESULT_HORIZONTAL -> { isX = true - if (leftDistance < rightDistance) 0 else params.x + rightDistance + if (leftDistance < rightDistance) leftBorder else params.x + rightDistance } SidePattern.RESULT_TOP -> { isX = false - if (config.immersionStatusBar) -statusBarHeight else 0 + topBorder } SidePattern.RESULT_BOTTOM -> { isX = false // 不要轻易使用此相关模式,需要考虑虚拟导航栏的情况 - emptyHeight + bottomBorder } SidePattern.RESULT_VERTICAL -> { isX = false - if (topDistance < bottomDistance) 0 else emptyHeight + if (topDistance < bottomDistance) topBorder else bottomBorder } SidePattern.RESULT_SIDE -> { if (minX < minY) { isX = true - if (leftDistance < rightDistance) 0 else params.x + rightDistance + if (leftDistance < rightDistance) leftBorder else params.x + rightDistance } else { isX = false - if (topDistance < bottomDistance) if (config.immersionStatusBar) -statusBarHeight else 0 else emptyHeight + if (topDistance < bottomDistance) topBorder else bottomBorder } } else -> return @@ -262,11 +319,11 @@ internal class TouchUtils(val context: Context, val config: FloatConfig) { /** * 计算一些边界距离数据 */ - private fun initDistanceValue(params: LayoutParams, view: View) { - leftDistance = params.x - rightDistance = parentWidth - (leftDistance + view.right) - topDistance = params.y - bottomDistance = emptyHeight - topDistance + private fun initDistanceValue(params: LayoutParams) { + leftDistance = params.x - leftBorder + rightDistance = rightBorder - params.x + topDistance = params.y - topBorder + bottomDistance = bottomBorder - params.y minX = min(leftDistance, rightDistance) minY = min(topDistance, bottomDistance) diff --git a/easyfloat/src/main/java/com/lzf/easyfloat/data/FloatConfig.kt b/easyfloat/src/main/java/com/lzf/easyfloat/data/FloatConfig.kt index b7fd641..0392856 100644 --- a/easyfloat/src/main/java/com/lzf/easyfloat/data/FloatConfig.kt +++ b/easyfloat/src/main/java/com/lzf/easyfloat/data/FloatConfig.kt @@ -52,6 +52,12 @@ data class FloatConfig( var locationPair: Pair = Pair(0, 0), // ps:优先使用固定坐标,若固定坐标不为原点坐标,gravity属性和offset属性无效 + // 四周边界值 + var leftBorder: Int = 0, + var topBorder: Int = -999, + var rightBorder: Int = 9999, + var bottomBorder: Int = 9999, + // Callbacks var invokeView: OnInvokeView? = null, var callbacks: OnFloatCallbacks? = null, diff --git a/easyfloat/src/main/java/com/lzf/easyfloat/permission/rom/RomUtils.kt b/easyfloat/src/main/java/com/lzf/easyfloat/permission/rom/RomUtils.kt index cb7459d..9ca218d 100644 --- a/easyfloat/src/main/java/com/lzf/easyfloat/permission/rom/RomUtils.kt +++ b/easyfloat/src/main/java/com/lzf/easyfloat/permission/rom/RomUtils.kt @@ -9,7 +9,7 @@ import java.io.InputStreamReader /** * @author: liuzhenfeng - * @github:https://github.com/princekin-f/EasyHttp + * @github:https://github.com/princekin-f/EasyFloat * @function: 判断手机ROM * @date: 2020-01-07 22:30 */ @@ -40,7 +40,7 @@ object RomUtils { input = BufferedReader(InputStreamReader(p.inputStream), 1024) line = input.readLine() input.close() - } catch (ex: IOException) { + } catch (ex: Exception) { Log.e(TAG, "Unable to read sysprop $propName", ex) return null } finally { diff --git a/example/src/main/AndroidManifest.xml b/example/src/main/AndroidManifest.xml index daa7eb7..70bcd1b 100644 --- a/example/src/main/AndroidManifest.xml +++ b/example/src/main/AndroidManifest.xml @@ -31,6 +31,7 @@ + diff --git a/example/src/main/java/com/lzf/easyfloat/example/activity/BorderTestActivity.kt b/example/src/main/java/com/lzf/easyfloat/example/activity/BorderTestActivity.kt new file mode 100644 index 0000000..82cc9bb --- /dev/null +++ b/example/src/main/java/com/lzf/easyfloat/example/activity/BorderTestActivity.kt @@ -0,0 +1,60 @@ +package com.lzf.easyfloat.example.activity + +import android.os.Bundle +import android.view.Gravity +import android.view.View +import android.widget.ImageView +import com.lzf.easyfloat.EasyFloat +import com.lzf.easyfloat.enums.SidePattern +import com.lzf.easyfloat.example.R +import com.lzf.easyfloat.utils.DisplayUtils +import kotlinx.android.synthetic.main.activity_border_test.* + +/** + * @author: liuzhenfeng + * @date: 3/9/21 11:27 + * @Package: com.lzf.easyfloat.example.activity + * @Description: + */ +class BorderTestActivity : BaseActivity() { + + private val tag = "borderTest" + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_border_test) + + tv_show.setOnClickListener { showBorderTest() } + tv_dismiss.setOnClickListener { EasyFloat.dismiss(tag) } + } + + private fun showBorderTest() { + EasyFloat.with(this) + .setTag(tag) + .setLayout(R.layout.float_border_test) { + val ivLogo = it.findViewById(R.id.iv_logo) + val ivLogo2 = it.findViewById(R.id.iv_logo2) + ivLogo.setOnClickListener { + ivLogo2.visibility = + if (ivLogo2.visibility == View.VISIBLE) View.GONE else View.VISIBLE + EasyFloat.updateFloat(tag) + } + ivLogo2.setOnClickListener { + ivLogo.visibility = + if (ivLogo.visibility == View.VISIBLE) View.GONE else View.VISIBLE + EasyFloat.updateFloat(tag) + } + } + .setBorder( + 30f.dp2px(), 50f.dp2px(), + DisplayUtils.getScreenWidth(this) - 30f.dp2px(), + DisplayUtils.getScreenHeight(this) - 180f.dp2px() + ) + .setGravity(Gravity.CENTER) + .setSidePattern(SidePattern.RESULT_SIDE) + .show() + } + + private fun Float.dp2px() = DisplayUtils.dp2px(this@BorderTestActivity, this) + +} \ No newline at end of file diff --git a/example/src/main/java/com/lzf/easyfloat/example/activity/MainActivity.kt b/example/src/main/java/com/lzf/easyfloat/example/activity/MainActivity.kt index 0e83cf8..84034cc 100644 --- a/example/src/main/java/com/lzf/easyfloat/example/activity/MainActivity.kt +++ b/example/src/main/java/com/lzf/easyfloat/example/activity/MainActivity.kt @@ -52,6 +52,7 @@ class MainActivity : BaseActivity(), View.OnClickListener { openSecond.setOnClickListener(this) openSwipeTest.setOnClickListener(this) + openBorderTest.setOnClickListener(this) } override fun onClick(v: View?) { @@ -79,6 +80,7 @@ class MainActivity : BaseActivity(), View.OnClickListener { openSecond -> startActivity(this) openSwipeTest -> startActivity(this) + openBorderTest -> startActivity(this) else -> return } diff --git a/example/src/main/res/layout/activity_border_test.xml b/example/src/main/res/layout/activity_border_test.xml new file mode 100644 index 0000000..1d41ddb --- /dev/null +++ b/example/src/main/res/layout/activity_border_test.xml @@ -0,0 +1,33 @@ + + + + + + + + + + \ No newline at end of file diff --git a/example/src/main/res/layout/activity_main.xml b/example/src/main/res/layout/activity_main.xml index 231cf96..1305cb1 100644 --- a/example/src/main/res/layout/activity_main.xml +++ b/example/src/main/res/layout/activity_main.xml @@ -9,159 +9,176 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:layout_height="wrap_content" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/example/src/main/res/layout/float_border_test.xml b/example/src/main/res/layout/float_border_test.xml new file mode 100644 index 0000000..e09fa89 --- /dev/null +++ b/example/src/main/res/layout/float_border_test.xml @@ -0,0 +1,25 @@ + + + + + + + + \ No newline at end of file