From ad7e43e932cc78cdb9573ba83919b36964ed2712 Mon Sep 17 00:00:00 2001 From: zhangyang Date: Wed, 27 Oct 2021 20:52:31 +0800 Subject: [PATCH] feat: [Android] support floating-icon edge pinned --- .../doraemondemo/MainDebugActivityOkhttpV3.kt | 94 +++--- .../com/didichuxing/doraemonkit/DoKitEnv.kt | 3 + .../DokitActivityLifecycleCallbacks.kt | 19 +- .../doraemonkit/kit/core/AbsDokitView.kt | 290 +++++++++++------- .../doraemonkit/kit/main/MainIconDoKitView.kt | 9 +- 5 files changed, 248 insertions(+), 167 deletions(-) diff --git a/Android/app/src/main/java/com/didichuxing/doraemondemo/MainDebugActivityOkhttpV3.kt b/Android/app/src/main/java/com/didichuxing/doraemondemo/MainDebugActivityOkhttpV3.kt index e5f822eaa..18dbb6f79 100644 --- a/Android/app/src/main/java/com/didichuxing/doraemondemo/MainDebugActivityOkhttpV3.kt +++ b/Android/app/src/main/java/com/didichuxing/doraemondemo/MainDebugActivityOkhttpV3.kt @@ -17,11 +17,9 @@ import android.text.format.Formatter import android.util.Log import android.view.View import android.widget.ImageView -import android.widget.TextView import android.widget.Toast import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView import coil.imageLoader import coil.request.CachePolicy import coil.transform.CircleCropTransformation @@ -29,15 +27,16 @@ import com.amap.api.location.AMapLocationListener import com.blankj.utilcode.util.ConvertUtils import com.blankj.utilcode.util.ThreadUtils import com.bumptech.glide.Glide +import com.bumptech.glide.RequestBuilder import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.resource.bitmap.CircleCrop import com.didichuxing.doraemondemo.amap.AMapRouterFragment import com.didichuxing.doraemondemo.comm.CommLauncher +import com.didichuxing.doraemondemo.databinding.ActivityMainBinding import com.didichuxing.doraemondemo.mc.MCActivity import com.didichuxing.doraemondemo.retrofit.GithubService import com.didichuxing.doraemonkit.DoKit import com.facebook.drawee.backends.pipeline.Fresco -import com.facebook.drawee.view.SimpleDraweeView import com.lzy.okgo.OkGo import com.lzy.okgo.callback.StringCallback import com.lzy.okgo.model.Response @@ -45,6 +44,7 @@ import com.nostra13.universalimageloader.core.ImageLoader import com.nostra13.universalimageloader.core.ImageLoaderConfiguration import com.squareup.picasso.MemoryPolicy import com.squareup.picasso.Picasso +import com.squareup.picasso.RequestCreator import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.* import okhttp3.* @@ -61,8 +61,8 @@ import kotlin.coroutines.resume /** * @author jintai */ -class MainDebugActivityOkhttpV3 : BaseActivity(), View.OnClickListener, - CoroutineScope by MainScope() { +class MainDebugActivityOkhttpV3 : BaseActivity(), View.OnClickListener, CoroutineScope by MainScope() { + private var okHttpClient: OkHttpClient? = null private var mLocationManager: LocationManager? = null private val UPDATE_UI = 100 @@ -79,19 +79,20 @@ class MainDebugActivityOkhttpV3 : BaseActivity(), View.OnClickListener, */ private var githubService: GithubService? = null + private var _binding: ActivityMainBinding? = null + @SuppressLint("HandlerLeak") private val mHandler: Handler = object : Handler() { override fun handleMessage(msg: Message) { super.handleMessage(msg) when (msg.what) { - 100 -> (findViewById(R.id.iv_picasso) as ImageView).setImageBitmap(msg.obj as Bitmap) + 100 -> _binding?.ivPicasso?.setImageBitmap(msg.obj as Bitmap) else -> { } } } } - val datas = mutableListOf( "测试", "显示/隐藏Dokit入口", @@ -119,7 +120,6 @@ class MainDebugActivityOkhttpV3 : BaseActivity(), View.OnClickListener, it.resume("sleep 1000ms") } - fun sleep2(): String { Thread.sleep(5000) return "sleep 1000ms" @@ -127,17 +127,14 @@ class MainDebugActivityOkhttpV3 : BaseActivity(), View.OnClickListener, override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) - val tvEnv = findViewById(R.id.tv_env) - tvEnv.text = "${getString(R.string.app_build_types)}:Debug" - val rv = findViewById(R.id.rv) - rv.layoutManager = LinearLayoutManager(this) - mAdapter = MainAdapter(R.layout.item_main_rv, datas) - rv.adapter = mAdapter + _binding = ActivityMainBinding.inflate(layoutInflater).also { + setContentView(it.root) + mAdapter = MainAdapter(R.layout.item_main_rv, datas) + it.initView(this) + } mAdapter.setOnItemClickListener { _, _, position -> when (datas[position]) { "测试" -> { - lifecycleScope // lifecycleScope.launch { // val helloworld = async { // "Hello world!!" @@ -180,7 +177,10 @@ class MainDebugActivityOkhttpV3 : BaseActivity(), View.OnClickListener, DoKit.showToolPanel() } "获取已安装的app" -> { - packageManager.getInstalledApplications(PackageManager.MATCH_UNINSTALLED_PACKAGES) + packageManager.getInstalledApplications( + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) PackageManager.MATCH_UNINSTALLED_PACKAGES + else PackageManager.GET_UNINSTALLED_PACKAGES + ) } "跳转其他Activity" -> { startActivity(Intent(this, SecondActivity::class.java)) @@ -274,7 +274,7 @@ class MainDebugActivityOkhttpV3 : BaseActivity(), View.OnClickListener, ) } "模拟Crash" -> { - testCrash()!!.length + checkNotNull(testCrash()) } "创建数据库" -> { val dbHelper = MyDatabaseHelper(this, "BookStore.db", null, 1) @@ -291,7 +291,6 @@ class MainDebugActivityOkhttpV3 : BaseActivity(), View.OnClickListener, } } } - findViewById(R.id.btn_load_img).setOnClickListener(this) okHttpClient = OkHttpClient().newBuilder().build() //获取定位服务 @@ -312,8 +311,13 @@ class MainDebugActivityOkhttpV3 : BaseActivity(), View.OnClickListener, ImageLoader.getInstance().init(config) githubService = retrofit.create(GithubService::class.java) + } - + private fun ActivityMainBinding.initView(context: Context) { + tvEnv.text = "${getString(R.string.app_build_types)}:Debug" + rv.layoutManager = LinearLayoutManager(context) + rv.adapter = mAdapter + btnLoadImg.setOnClickListener(this@MainDebugActivityOkhttpV3) } private fun test1() { @@ -387,7 +391,6 @@ class MainDebugActivityOkhttpV3 : BaseActivity(), View.OnClickListener, ) } - @SuppressLint("MissingPermission") override fun onClick(v: View) { when (v.id) { @@ -408,7 +411,7 @@ class MainDebugActivityOkhttpV3 : BaseActivity(), View.OnClickListener, .memoryPolicy(MemoryPolicy.NO_CACHE) .placeholder(R.mipmap.cat) .error(R.mipmap.cat) - .into(findViewById(R.id.iv_picasso) as ImageView) + .intoOrCancel(_binding?.ivPicasso) Glide.with(this@MainDebugActivityOkhttpV3) .asBitmap() .load(glideImageUrl) @@ -417,9 +420,9 @@ class MainDebugActivityOkhttpV3 : BaseActivity(), View.OnClickListener, .diskCacheStrategy(DiskCacheStrategy.NONE) .skipMemoryCache(true) .transform(CircleCrop()) - .into((findViewById(R.id.iv_glide) as ImageView)) + .intoOrCancel(_binding?.ivGlide) //coil - findViewById(R.id.iv_coil).apply { + _binding?.ivCoil?.apply { val request = coil.request.ImageRequest.Builder(this.context) .memoryCachePolicy(CachePolicy.DISABLED) .transformations(CircleCropTransformation()) @@ -431,13 +434,9 @@ class MainDebugActivityOkhttpV3 : BaseActivity(), View.OnClickListener, } //imageLoader val imageLoader = ImageLoader.getInstance() - imageLoader.displayImage( - imageLoaderImageUrl, - findViewById(R.id.iv_imageloader) as ImageView - ) + imageLoader.displayImageOrNot(imageLoaderImageUrl, _binding?.ivImageloader) //fresco - val frescoImageView = findViewById(R.id.iv_fresco) - frescoImageView.setImageURI(Uri.parse(frescoImageUrl)) + _binding?.ivFresco?.setImageURI(Uri.parse(frescoImageUrl)) val imagePipeline = Fresco.getImagePipeline() // combines above two lines imagePipeline.clearCaches() @@ -567,18 +566,16 @@ class MainDebugActivityOkhttpV3 : BaseActivity(), View.OnClickListener, } private fun inputStream2File(`is`: InputStream, saveFile: File) { - try { - var len: Int - val buf = ByteArray(2048) - val fos = FileOutputStream(saveFile) - while (`is`.read(buf).also { len = it } != -1) { - fos.write(buf, 0, len) + var len: Int + val buf = ByteArray(2048) + val fos = FileOutputStream(saveFile) + `is`.use { input -> + fos.use { output -> + while (input.read(buf).also { len = it } != -1) { + output.write(buf, 0, len) + } + output.flush() } - fos.flush() - fos.close() - `is`.close() - } catch (e: Exception) { - e.printStackTrace() } } @@ -612,12 +609,19 @@ class MainDebugActivityOkhttpV3 : BaseActivity(), View.OnClickListener, } } - override fun onWindowFocusChanged(hasFocus: Boolean) { - super.onWindowFocusChanged(hasFocus) + private fun RequestCreator.intoOrCancel(target: ImageView?) { + target?.also { into(it) } + } + + private fun RequestBuilder<*>.intoOrCancel(target: ImageView?) { + target?.also { into(it) } + } + + private fun ImageLoader.displayImageOrNot(url: String, target: ImageView?) { + target?.also { displayImage(url, it) } } companion object { const val TAG = "MainDebugActivity" - } -} \ No newline at end of file +} diff --git a/Android/dokit/src/main/java/com/didichuxing/doraemonkit/DoKitEnv.kt b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/DoKitEnv.kt index 9d31b758a..e1a636ebe 100644 --- a/Android/dokit/src/main/java/com/didichuxing/doraemonkit/DoKitEnv.kt +++ b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/DoKitEnv.kt @@ -1,6 +1,7 @@ package com.didichuxing.doraemonkit import android.app.Application +import android.graphics.Point /** * Created by alvince on 2021/9/29 @@ -12,6 +13,8 @@ internal object DoKitEnv { @Volatile var app: Application? = null + val windowSize: Point= Point() + @JvmStatic fun requireApp(): Application { return app ?: throw IllegalStateException("Dokit app no set") diff --git a/Android/dokit/src/main/java/com/didichuxing/doraemonkit/DokitActivityLifecycleCallbacks.kt b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/DokitActivityLifecycleCallbacks.kt index 85cac7d71..f070836a9 100644 --- a/Android/dokit/src/main/java/com/didichuxing/doraemonkit/DokitActivityLifecycleCallbacks.kt +++ b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/DokitActivityLifecycleCallbacks.kt @@ -4,6 +4,7 @@ import android.app.Activity import android.app.Application import android.content.Context import android.os.Bundle +import android.view.View import android.widget.Toast import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentManager @@ -173,17 +174,21 @@ class DokitActivityLifecycleCallbacks : Application.ActivityLifecycleCallbacks { * @param activity */ private fun dispatchOnActivityResumed(activity: Activity) { + activity.window.decorView.also { + it.post { DoKitEnv.windowSize.set(it.width, it.height) } + } if (DoKitManager.IS_NORMAL_FLOAT_MODE) { //显示内置dokitView icon DokitViewManager.INSTANCE.dispatchOnActivityResumed(activity) + return + } + // FIXME: consider handle permission down to activity-layer, just dispatch resumed-event here + //悬浮窗权限 vivo 华为可以不需要动态权限 小米需要 + if (DoKitPermissionUtil.canDrawOverlays(activity)) { + DokitViewManager.INSTANCE.dispatchOnActivityResumed(activity) } else { - //悬浮窗权限 vivo 华为可以不需要动态权限 小米需要 - if (DoKitPermissionUtil.canDrawOverlays(activity)) { - DokitViewManager.INSTANCE.dispatchOnActivityResumed(activity) - } else { - //请求悬浮窗权限 - requestPermission(activity) - } + //请求悬浮窗权限 + requestPermission(activity) } } diff --git a/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/core/AbsDokitView.kt b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/core/AbsDokitView.kt index 8badd7a8c..bee3a9e96 100644 --- a/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/core/AbsDokitView.kt +++ b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/core/AbsDokitView.kt @@ -1,5 +1,8 @@ package com.didichuxing.doraemonkit.kit.core +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.animation.ValueAnimator import android.annotation.SuppressLint import android.app.Activity import android.content.BroadcastReceiver @@ -18,15 +21,19 @@ import android.view.ViewTreeObserver.OnGlobalLayoutListener import android.widget.FrameLayout import androidx.annotation.IdRes import androidx.annotation.StringRes +import androidx.core.view.GravityCompat import com.didichuxing.doraemonkit.DoKit +import com.didichuxing.doraemonkit.DoKitEnv import com.didichuxing.doraemonkit.config.FloatIconConfig import com.didichuxing.doraemonkit.extension.tagName import com.didichuxing.doraemonkit.kit.main.MainIconDoKitView import com.didichuxing.doraemonkit.util.ActivityUtils import com.didichuxing.doraemonkit.util.LogHelper import com.didichuxing.doraemonkit.util.ScreenUtils -import kotlinx.coroutines.* -import java.lang.Runnable +import kotlinx.coroutines.CoroutineName +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.cancel +import kotlinx.coroutines.plus import java.lang.ref.WeakReference /** @@ -38,20 +45,28 @@ import java.lang.ref.WeakReference * 修订历史: * ================================================ */ -abstract class AbsDokitView : DokitView, TouchProxy.OnTouchEventListener, - DokitViewManager.DokitViewAttachedListener { +abstract class AbsDokitView : DokitView, TouchProxy.OnTouchEventListener, DokitViewManager.DokitViewAttachedListener { - val doKitViewScope = MainScope() + CoroutineName(this.toString()) + class ViewArgs { + var mode: DoKitViewLaunchMode = DoKitViewLaunchMode.SINGLE_INSTANCE + var normalMode = DoKitManager.IS_NORMAL_FLOAT_MODE + var edgePinned = false + } + val doKitViewScope = MainScope() + CoroutineName(this.toString()) val TAG = this.tagName /** * 页面启动模式 */ - var mode: DoKitViewLaunchMode = DoKitViewLaunchMode.SINGLE_INSTANCE + var mode: DoKitViewLaunchMode + get() = viewProps.mode + set(value) { + viewProps.mode = value + } - val isNormalMode = DoKitManager.IS_NORMAL_FLOAT_MODE + val isNormalMode get() = viewProps.normalMode /** * 手势代理 @@ -59,6 +74,8 @@ abstract class AbsDokitView : DokitView, TouchProxy.OnTouchEventListener, @JvmField var mTouchProxy = TouchProxy(this) + protected val viewProps = ViewArgs() + @JvmField protected var mWindowManager = DokitViewManager.INSTANCE.windowManager @@ -66,11 +83,13 @@ abstract class AbsDokitView : DokitView, TouchProxy.OnTouchEventListener, * 创建FrameLayout#LayoutParams 内置悬浮窗调用 */ var normalLayoutParams: FrameLayout.LayoutParams? = null + private set /** * 创建FrameLayout#LayoutParams 系统悬浮窗调用 */ var systemLayoutParams: WindowManager.LayoutParams? = null + private set private var mHandler: Handler? = Handler(Looper.myLooper()) @@ -119,7 +138,6 @@ abstract class AbsDokitView : DokitView, TouchProxy.OnTouchEventListener, mRootView!!.parent as DokitFrameLayout } else null - /** * 用来保存rootview的LayoutParams */ @@ -136,7 +154,6 @@ abstract class AbsDokitView : DokitView, TouchProxy.OnTouchEventListener, } else { DokitViewManager.INSTANCE.getLastDokitViewPosInfo(tag)!! } - } /** @@ -158,10 +175,8 @@ abstract class AbsDokitView : DokitView, TouchProxy.OnTouchEventListener, mLastDokitViewPosInfo.dokitViewWidth = mDokitViewWidth mLastDokitViewPosInfo.dokitViewHeight = mDokitViewHeight } - } - /** * 执行floatPage create * @@ -205,12 +220,11 @@ abstract class AbsDokitView : DokitView, TouchProxy.OnTouchEventListener, mDokitViewLayoutParams = DokitViewLayoutParams() //分别创建对应的LayoutParams if (isNormalMode) { - normalLayoutParams = FrameLayout.LayoutParams( - FrameLayout.LayoutParams.WRAP_CONTENT, - FrameLayout.LayoutParams.WRAP_CONTENT - ) - normalLayoutParams?.gravity = Gravity.LEFT or Gravity.TOP - mDokitViewLayoutParams.gravity = Gravity.LEFT or Gravity.TOP + normalLayoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT) + .apply { + gravity = GravityCompat.START or Gravity.TOP + } + mDokitViewLayoutParams.gravity = GravityCompat.START or Gravity.TOP } else { systemLayoutParams = WindowManager.LayoutParams() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { @@ -236,11 +250,11 @@ abstract class AbsDokitView : DokitView, TouchProxy.OnTouchEventListener, } systemLayoutParams?.apply { format = PixelFormat.TRANSPARENT - gravity = Gravity.LEFT or Gravity.TOP + gravity = GravityCompat.START or Gravity.TOP } - mDokitViewLayoutParams.gravity = Gravity.LEFT or Gravity.TOP + mDokitViewLayoutParams.gravity = GravityCompat.START or Gravity.TOP //动态注册关闭系统弹窗的广播 val intentFilter = IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS) context.registerReceiver(mInnerReceiver, intentFilter) @@ -298,22 +312,30 @@ abstract class AbsDokitView : DokitView, TouchProxy.OnTouchEventListener, */ private fun onNormalLayoutParamsCreated() { //如果有上一个页面的位置记录 这更新位置 - normalLayoutParams?.width = mDokitViewLayoutParams.width - normalLayoutParams?.height = mDokitViewLayoutParams.height - normalLayoutParams?.gravity = mDokitViewLayoutParams.gravity + normalLayoutParams?.apply { + width = mDokitViewLayoutParams.width + height = mDokitViewLayoutParams.height + gravity = mDokitViewLayoutParams.gravity + } val doKitViewInfo = DokitViewManager.INSTANCE.getDoKitViewPos(tag) if (doKitViewInfo != null) { //竖向 if (doKitViewInfo.orientation == Configuration.ORIENTATION_PORTRAIT) { - normalLayoutParams?.leftMargin = doKitViewInfo.portraitPoint.x - normalLayoutParams?.topMargin = doKitViewInfo.portraitPoint.y + normalLayoutParams?.apply { + leftMargin = doKitViewInfo.portraitPoint.x + topMargin = doKitViewInfo.portraitPoint.y + } } else if (doKitViewInfo.orientation == Configuration.ORIENTATION_LANDSCAPE) { - normalLayoutParams?.leftMargin = doKitViewInfo.landscapePoint.x - normalLayoutParams?.topMargin = doKitViewInfo.landscapePoint.y + normalLayoutParams?.apply { + leftMargin = doKitViewInfo.landscapePoint.x + topMargin = doKitViewInfo.landscapePoint.y + } } } else { - normalLayoutParams?.leftMargin = mDokitViewLayoutParams.x - normalLayoutParams?.topMargin = mDokitViewLayoutParams.y + normalLayoutParams?.apply { + leftMargin = mDokitViewLayoutParams.x + topMargin = mDokitViewLayoutParams.y + } } portraitOrLandscape() } @@ -322,82 +344,85 @@ abstract class AbsDokitView : DokitView, TouchProxy.OnTouchEventListener, * 用于普通模式下的横竖屏切换 */ private fun portraitOrLandscape() { - val doKitViewInfo = DokitViewManager.INSTANCE.getDoKitViewPos(tag) - if (doKitViewInfo != null) { - //横竖屏切换兼容 - if (ScreenUtils.isPortrait()) { - if (mLastDokitViewPosInfo.isPortrait) { - normalLayoutParams?.leftMargin = doKitViewInfo.portraitPoint.x - normalLayoutParams?.topMargin = doKitViewInfo.portraitPoint.y - } else { - normalLayoutParams?.leftMargin = - (doKitViewInfo.landscapePoint.x * mLastDokitViewPosInfo.leftMarginPercent).toInt() - normalLayoutParams?.topMargin = - (doKitViewInfo.landscapePoint.y * mLastDokitViewPosInfo.topMarginPercent).toInt() - } - } else { - if (mLastDokitViewPosInfo.isPortrait) { - normalLayoutParams?.leftMargin = - (doKitViewInfo.portraitPoint.x * mLastDokitViewPosInfo.leftMarginPercent).toInt() - normalLayoutParams?.topMargin = - (doKitViewInfo.portraitPoint.y * mLastDokitViewPosInfo.topMarginPercent).toInt() + DokitViewManager.INSTANCE.getDoKitViewPos(tag) + ?.also { doKitViewInfo -> + //横竖屏切换兼容 + if (ScreenUtils.isPortrait()) { + if (mLastDokitViewPosInfo.isPortrait) { + normalLayoutParams?.apply { + leftMargin = doKitViewInfo.portraitPoint.x + topMargin = doKitViewInfo.portraitPoint.y + } + } else { + normalLayoutParams?.apply { + leftMargin = (doKitViewInfo.landscapePoint.x * mLastDokitViewPosInfo.leftMarginPercent).toInt() + topMargin = (doKitViewInfo.landscapePoint.y * mLastDokitViewPosInfo.topMarginPercent).toInt() + } + } } else { - normalLayoutParams?.leftMargin = doKitViewInfo.landscapePoint.x - normalLayoutParams?.topMargin = doKitViewInfo.landscapePoint.y + if (mLastDokitViewPosInfo.isPortrait) { + normalLayoutParams?.apply { + leftMargin = (doKitViewInfo.portraitPoint.x * mLastDokitViewPosInfo.leftMarginPercent).toInt() + topMargin = (doKitViewInfo.portraitPoint.y * mLastDokitViewPosInfo.topMarginPercent).toInt() + } + } else { + normalLayoutParams?.apply { + leftMargin = doKitViewInfo.landscapePoint.x + topMargin = doKitViewInfo.landscapePoint.y + } + } } } - } else { - //横竖屏切换兼容 - if (ScreenUtils.isPortrait()) { - if (mLastDokitViewPosInfo.isPortrait) { - normalLayoutParams?.leftMargin = mDokitViewLayoutParams.x - normalLayoutParams?.topMargin = mDokitViewLayoutParams.y - } else { - normalLayoutParams?.leftMargin = - (mDokitViewLayoutParams.x * mLastDokitViewPosInfo.leftMarginPercent).toInt() - normalLayoutParams?.topMargin = - (mDokitViewLayoutParams.y * mLastDokitViewPosInfo.topMarginPercent).toInt() - } - } else { - if (mLastDokitViewPosInfo.isPortrait) { - normalLayoutParams?.leftMargin = - (mDokitViewLayoutParams.x * mLastDokitViewPosInfo.leftMarginPercent).toInt() - normalLayoutParams?.topMargin = - (mDokitViewLayoutParams.y * mLastDokitViewPosInfo.topMarginPercent).toInt() + ?: run { + //横竖屏切换兼容 + if (ScreenUtils.isPortrait()) { + if (mLastDokitViewPosInfo.isPortrait) { + normalLayoutParams?.apply { + leftMargin = mDokitViewLayoutParams.x + topMargin = mDokitViewLayoutParams.y + } + } else { + normalLayoutParams?.apply { + leftMargin = (mDokitViewLayoutParams.x * mLastDokitViewPosInfo.leftMarginPercent).toInt() + topMargin = (mDokitViewLayoutParams.y * mLastDokitViewPosInfo.topMarginPercent).toInt() + } + } } else { - normalLayoutParams?.leftMargin = mDokitViewLayoutParams.x - normalLayoutParams?.topMargin = mDokitViewLayoutParams.y + if (mLastDokitViewPosInfo.isPortrait) { + normalLayoutParams?.apply { + leftMargin = (mDokitViewLayoutParams.x * mLastDokitViewPosInfo.leftMarginPercent).toInt() + topMargin = (mDokitViewLayoutParams.y * mLastDokitViewPosInfo.topMarginPercent).toInt() + } + } else { + normalLayoutParams?.apply { + leftMargin = mDokitViewLayoutParams.x + topMargin = mDokitViewLayoutParams.y + } + } } } - } mLastDokitViewPosInfo.setPortrait() - normalLayoutParams?.let { + normalLayoutParams?.also { mLastDokitViewPosInfo.setLeftMargin(it.leftMargin) mLastDokitViewPosInfo.setTopMargin(it.topMargin) } if (tag == MainIconDoKitView::class.tagName) { if (isNormalMode) { - normalLayoutParams?.let { + normalLayoutParams?.also { FloatIconConfig.saveLastPosX(it.leftMargin) FloatIconConfig.saveLastPosY(it.topMargin) } } else { - systemLayoutParams?.let { + systemLayoutParams?.also { FloatIconConfig.saveLastPosX(it.x) FloatIconConfig.saveLastPosY(it.y) } - } } - DokitViewManager.INSTANCE.saveDokitViewPos( - tag, - normalLayoutParams?.leftMargin ?: 0, - normalLayoutParams?.topMargin ?: 0 - ) + DokitViewManager.INSTANCE.saveDokitViewPos(tag, normalLayoutParams?.leftMargin ?: 0, normalLayoutParams?.topMargin ?: 0) } - /** * 确定系统浮标的初始位置 * LayoutParams创建完以后调用 @@ -475,7 +500,6 @@ abstract class AbsDokitView : DokitView, TouchProxy.OnTouchEventListener, it.visibility = View.GONE } } - } override fun onEnterForeground() { @@ -484,7 +508,6 @@ abstract class AbsDokitView : DokitView, TouchProxy.OnTouchEventListener, it.visibility = View.VISIBLE } } - } override fun onMove(x: Int, y: Int, dx: Int, dy: Int) { @@ -520,29 +543,11 @@ abstract class AbsDokitView : DokitView, TouchProxy.OnTouchEventListener, if (!canDrag()) { return } - if (tag == MainIconDoKitView::class.tagName) { - if (isNormalMode) { - normalLayoutParams?.let { - FloatIconConfig.saveLastPosX(it.leftMargin) - FloatIconConfig.saveLastPosY(it.topMargin) - } - } else { - systemLayoutParams?.let { - FloatIconConfig.saveLastPosX(it.x) - FloatIconConfig.saveLastPosY(it.y) - } - } - } - //保存在内存中 - if (isNormalMode) { - normalLayoutParams?.let { - DokitViewManager.INSTANCE.saveDokitViewPos(tag, it.leftMargin, it.topMargin) - } - } else { - systemLayoutParams?.let { - DokitViewManager.INSTANCE.saveDokitViewPos(tag, it.x, it.y) - } + if (!viewProps.edgePinned) { + endMoveAndRecord() + return } + animatedMoveToEdge() } /** @@ -638,7 +643,6 @@ abstract class AbsDokitView : DokitView, TouchProxy.OnTouchEventListener, return mRootView?.findViewById(id) } - /** * 将当前dokitView于activity解绑 */ @@ -655,7 +659,7 @@ abstract class AbsDokitView : DokitView, TouchProxy.OnTouchEventListener, if (decorRootView == null) { return } - } + } // FIXME: useless code, what that intention? @jtsky } /** @@ -707,7 +711,6 @@ abstract class AbsDokitView : DokitView, TouchProxy.OnTouchEventListener, resetBorderline(this, systemLayoutParams) mRootView?.layoutParams = this } - } /** @@ -798,7 +801,6 @@ abstract class AbsDokitView : DokitView, TouchProxy.OnTouchEventListener, return true } - fun post(run: Runnable) { mHandler?.post(run) } @@ -808,13 +810,13 @@ abstract class AbsDokitView : DokitView, TouchProxy.OnTouchEventListener, } /** - * 设置当前kitView不响应触摸事件 + * 设置当前 kitView 不响应触摸事件 * 控件默认响应触摸事件 - * 需要在子view的onViewCreated中调用 + * 需要在子 view 的 onViewCreated 中调用 */ fun setDoKitViewNotResponseTouchEvent(view: View?) { if (isNormalMode) { - view?.setOnTouchListener { v, event -> false } + view?.setOnTouchListener { _, _ -> false } } else { view?.setOnTouchListener(null) } @@ -852,4 +854,70 @@ abstract class AbsDokitView : DokitView, TouchProxy.OnTouchEventListener, open fun immInvalidate() { mRootView?.requestLayout() } + + private fun animatedMoveToEdge() { + val viewSize = mRootView?.width ?: return + if (isNormalMode) { + val parent = (mRootView?.parent as? ViewGroup) ?: return + normalLayoutParams?.also { layoutAttrs -> + makeAnimator(layoutAttrs.leftMargin, viewSize, parent.width) { + addUpdateListener { v -> + layoutAttrs.leftMargin = v.animatedValue as Int + updateViewLayout(tag, false) + } + addListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator?) { + endMoveAndRecord() + } + }) + } + } + return + } + systemLayoutParams?.also { layoutAttrs -> + makeAnimator(layoutAttrs.x, viewSize, DoKitEnv.windowSize.x) { + addUpdateListener { v -> + layoutAttrs.x = v.animatedValue as Int + mWindowManager.updateViewLayout(mRootView, layoutAttrs) + } + addListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator?) { + endMoveAndRecord() + } + }) + } + } + } + + private fun endMoveAndRecord() { + if (tag == MainIconDoKitView::class.tagName) { + if (isNormalMode) { + normalLayoutParams?.also { + FloatIconConfig.saveLastPosX(it.leftMargin) + FloatIconConfig.saveLastPosY(it.topMargin) + } + } else { + systemLayoutParams?.also { + FloatIconConfig.saveLastPosX(it.x) + FloatIconConfig.saveLastPosY(it.y) + } + } + } + // 保存在内存中 + if (isNormalMode) { + normalLayoutParams?.also { DokitViewManager.INSTANCE.saveDokitViewPos(tag, it.leftMargin, it.topMargin) } + } else { + systemLayoutParams?.also { DokitViewManager.INSTANCE.saveDokitViewPos(tag, it.x, it.y) } + } + } + + private inline fun makeAnimator(from: Int, size: Int, containerSize: Int, setup: ValueAnimator.() -> Unit) { + if (size <= 0 || containerSize <= 0) return + ValueAnimator.ofInt(from, if (from <= (containerSize - size) / 2) 0 else (containerSize - size)) + .apply { + duration = 150L + setup() + } + .start() + } } diff --git a/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/main/MainIconDoKitView.kt b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/main/MainIconDoKitView.kt index a2cc2f979..a862b77c2 100644 --- a/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/main/MainIconDoKitView.kt +++ b/Android/dokit/src/main/java/com/didichuxing/doraemonkit/kit/main/MainIconDoKitView.kt @@ -16,8 +16,11 @@ import com.didichuxing.doraemonkit.kit.core.DokitViewLayoutParams * Created by jintai on 2019/09/26. */ class MainIconDoKitView : AbsDokitView() { - //public static int FLOAT_SIZE = 174; - //public static int FLOAT_SIZE = 58; + + init { + viewProps.edgePinned = true + } + override fun onCreate(context: Context) {} override fun onViewCreated(view: FrameLayout) { @@ -39,8 +42,6 @@ class MainIconDoKitView : AbsDokitView() { params.y = FloatIconConfig.getLastPosY() params.width = DokitViewLayoutParams.WRAP_CONTENT params.height = DokitViewLayoutParams.WRAP_CONTENT - // params.width = ConvertUtils.dp2px(FLOAT_SIZE); -// params.height = ConvertUtils.dp2px(FLOAT_SIZE); } override fun onResume() {