浏览代码

v1.0.0开发:浮标开发

#Suyghur 3 年之前
父节点
当前提交
a21d68e306

+ 0 - 4
demo/src/main/java/com/yyxxgame/columbus/DemoActivity.kt

@@ -12,9 +12,7 @@ import android.widget.*
 import cn.yyxx.eyuangame.base.EYuanGame
 import cn.yyxx.eyuangame.base.internal.ICallback
 import cn.yyxx.eyuangame.base.utils.Logger
-import cn.yyxx.eyuangame.core.entity.FloatFeature
 import cn.yyxx.eyuangame.core.impl.SdkDrive
-import cn.yyxx.eyuangame.core.impl.floating.FloatCenterItem
 import cn.yyxx.support.hawkeye.LogUtils
 import kotlin.system.exitProcess
 
@@ -71,8 +69,6 @@ class DemoActivity : Activity(), View.OnClickListener {
             text = ""
             this@DemoActivity.layout.addView(this)
         }
-        val itemView = FloatCenterItem(this, "", FloatFeature.FEATURE_MEMBER)
-        layout.addView(itemView)
         val scrollView = ScrollView(this)
         scrollView.addView(layout)
         setContentView(scrollView)

+ 1 - 1
library_core/src/main/AndroidManifest.xml

@@ -27,7 +27,7 @@
 
 
         <service
-            android:name=".impl.floating.FloatCenterService"
+            android:name=".impl.floatball.FloatCenterService"
             android:exported="true" />
     </application>
 

+ 1 - 1
library_core/src/main/java/cn/yyxx/eyuangame/core/impl/SdkBridgeImpl.kt

@@ -14,7 +14,7 @@ import cn.yyxx.eyuangame.base.utils.ParamsUtils
 import cn.yyxx.eyuangame.core.entity.ResultInfo
 import cn.yyxx.eyuangame.core.entity.SdkBackLoginInfo
 import cn.yyxx.eyuangame.core.entity.bean.init.InitBean
-import cn.yyxx.eyuangame.core.impl.floating.FloatCenterServiceManager
+import cn.yyxx.eyuangame.core.impl.floatball.FloatCenterServiceManager
 import cn.yyxx.eyuangame.core.impl.iab.ChargeImpl
 import cn.yyxx.eyuangame.core.impl.login.LoginActivity
 import cn.yyxx.eyuangame.core.internal.IImplCallback

+ 95 - 0
library_core/src/main/java/cn/yyxx/eyuangame/core/impl/floatball/FloatCenterService.kt

@@ -0,0 +1,95 @@
+package cn.yyxx.eyuangame.core.impl.floatball
+
+import android.app.Activity
+import android.app.Service
+import android.content.Intent
+import android.os.Binder
+import android.os.IBinder
+import android.widget.ImageView
+import cn.yyxx.eyuangame.base.utils.Logger
+import cn.yyxx.eyuangame.core.entity.FloatFeature
+import cn.yyxx.eyuangame.core.impl.SdkBridgeImpl
+import cn.yyxx.eyuangame.core.ui.floatview.FloatingBall
+import cn.yyxx.eyuangame.core.ui.floatview.FloatingBallMenu
+import cn.yyxx.support.ResUtils
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/06/28
+ */
+class FloatCenterService : Service() {
+
+//    private var floatCenter: FloatLogoMenu? = null
+
+    private var floatingBall: FloatingBall? = null
+    private var mActivity: Activity? = null
+
+    private val callback = object : FloatingBall.FloatingBallCallback {
+        override fun onUpdateBallView(ballView: ImageView, isLeftLocation: Boolean, isHide: Boolean) {
+            ballView.setBackgroundResource(ResUtils.getResId(mActivity, "yyxx_float_logo_img", "drawable"))
+        }
+
+        override fun onInitMenuData(): MutableList<FloatingBallMenu.FloatingBallMenuItem> {
+            return mutableListOf(
+                FloatingBallMenu.FloatingBallMenuItem(FloatFeature.FEATURE_MEMBER, "", ""),
+                FloatingBallMenu.FloatingBallMenuItem(FloatFeature.FEATURE_GIF, "", ""),
+                FloatingBallMenu.FloatingBallMenuItem(FloatFeature.FEATURE_GM, "", ""),
+                FloatingBallMenu.FloatingBallMenuItem(FloatFeature.FEATURE_CHARGE, "", ""),
+                FloatingBallMenu.FloatingBallMenuItem(FloatFeature.FEATURE_INVITE, "", "")
+            )
+        }
+
+        override fun onMenuItemClick(item: FloatingBallMenu.FloatingBallMenuItem, pos: Int) {
+            Logger.d("onMenuItemClick , ${item.type.name}")
+        }
+
+        override fun onExpandMenu(hasRedDot: Boolean) {
+            Logger.d("onExpandMenu")
+        }
+
+        override fun onDismissMenu() {
+            floatingBall?.dismissMenu()
+        }
+
+    }
+
+    override fun onCreate() {
+        super.onCreate()
+    }
+
+    fun initService(activity: Activity) {
+        this.mActivity = activity
+    }
+
+    fun show() {
+        if (mActivity == null) {
+            return
+        }
+
+        if (floatingBall == null) {
+            floatingBall = FloatingBall(mActivity!!, SdkBridgeImpl.isLand, callback)
+        }
+        floatingBall?.attach()
+    }
+
+    fun hide() {
+        floatingBall?.detach()
+    }
+
+    fun release() {
+        floatingBall?.release()
+    }
+
+    override fun onBind(intent: Intent?): IBinder {
+        return FloatCenterServiceBinder()
+    }
+
+    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+        return super.onStartCommand(intent, flags, startId)
+    }
+
+    inner class FloatCenterServiceBinder : Binder() {
+        val service: FloatCenterService = this@FloatCenterService
+    }
+
+}

+ 1 - 1
library_core/src/main/java/cn/yyxx/eyuangame/core/impl/floating/FloatCenterServiceManager.kt → library_core/src/main/java/cn/yyxx/eyuangame/core/impl/floatball/FloatCenterServiceManager.kt

@@ -1,4 +1,4 @@
-package cn.yyxx.eyuangame.core.impl.floating
+package cn.yyxx.eyuangame.core.impl.floatball
 
 import android.app.Activity
 import android.content.ComponentName

+ 0 - 192
library_core/src/main/java/cn/yyxx/eyuangame/core/impl/floating/FloatCenter.kt

@@ -1,192 +0,0 @@
-package cn.yyxx.eyuangame.core.impl.floating
-
-import android.app.Activity
-import android.content.Context
-import android.view.View
-import android.widget.ImageView
-import android.widget.LinearLayout
-import cn.yyxx.eyuangame.base.utils.Logger
-import cn.yyxx.support.DensityUtils
-import cn.yyxx.support.ResUtils
-import cn.yyxx.support.ui.DragViewLayout
-
-/**
- * @author #Suyghur.
- * Created on 2021/06/28
- */
-class FloatCenter(val activity: Activity, private val features: MutableList<FloatCenterItem>) : DragViewLayout(activity), View.OnClickListener {
-
-    private lateinit var view: LinearLayout
-
-    //    private lateinit var leftView: View
-//    private lateinit var rightView: View
-//    private lateinit var leftMenu: LinearLayout
-//    private lateinit var rightMenu: LinearLayout
-    private lateinit var menu: LinearLayout
-    private lateinit var icon: ImageView
-    private var menuWidth = 0
-    private var menuHeight = 0
-    private var iconWidth = 0
-    private var iconHeight = 0
-    private var isShowMenu = false
-
-    init {
-        isClickable = true
-//        val params = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
-//        params.height = DensityUtils.dip2px(activity, 40.0f)
-//        params.width = DensityUtils.dip2px(activity, 40.0f)
-        initView(activity)
-    }
-
-
-    private fun initView(context: Context) {
-//        view = LayoutInflater.from(context).inflate(ResUtils.getResId(context, "yyxx_float_menu", "layout"), null)
-//        rightView = LayoutInflater.from(context).inflate(ResUtils.getResId(context, "yyxx_float_right_menu", "layout"), null)
-
-//        val imageView = ImageView(activity)
-//        imageView.setImageResource(ResUtils.getResId(activity, "yyxx_float_icon_img", "drawable"))
-//        imageView.setOnClickListener(this)
-        iconWidth = DensityUtils.dip2px(context, 40f)
-        iconHeight = DensityUtils.dip2px(context, 40f)
-        Logger.d("width : ${features[0].width}")
-        menuWidth = DensityUtils.dip2px(context, 30f) * features.size + iconWidth / 2
-        menuHeight = iconHeight
-
-        view = LinearLayout(context)
-        view.apply {
-            orientation = LinearLayout.HORIZONTAL
-            val params = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
-            layoutParams = params
-        }
-
-        icon = ImageView(context)
-        icon.apply {
-            setBackgroundResource(ResUtils.getResId(context, "yyxx_float_logo_img", "drawable"))
-            val params = LayoutParams(iconWidth, iconHeight)
-            layoutParams = params
-            setOnClickListener(this@FloatCenter)
-        }
-
-        menu = LinearLayout(context)
-        menu.apply {
-            orientation = LinearLayout.HORIZONTAL
-//            setBackgroundColor(Color.TRANSPARENT)
-            val params = LayoutParams(menuWidth, menuHeight)
-            layoutParams = params
-        }
-
-//        leftMenu = view.findViewById(ResUtils.getResId(context, "yyxx_left_menu", "id"))
-//        leftMenu.layoutParams = LayoutParams(menuWidth, menuHeight)
-//        leftVview.visibility = View.GONE
-
-//        rightMenu = view.findViewById(ResUtils.getResId(context, "yyxx_right_menu", "id"))
-//        rightMenu.layoutParams = LayoutParams(menuWidth, menuHeight)
-//        rightView.visibility = View.GONE
-
-//        icon = view.findViewById(ResUtils.getResId(context, "yyxx_iv_icon", "id"))
-////        icon = ImageView(context)
-//        icon.apply {
-//            setBackgroundResource(ResUtils.getResId(context, "yyxx_float_logo_img", "drawable"))
-//            val params = LayoutParams(iconWidth, iconHeight)
-//            layoutParams = params
-//            setOnClickListener(this@FloatCenter)
-//        }
-//        removeAllViews()
-//        addView(leftView)
-//        addView(rightView)
-        view.addView(icon)
-        addView(view)
-
-//        setDragViewLayoutListener(object :DragViewLayoutListener {
-//
-//        })
-//        setDragViewLayoutListener(object :Drag)
-    }
-
-    override fun updateFloatPosition(p0: Boolean) {
-        super.updateFloatPosition(p0)
-//        if (!isDrag) {
-//            Logger.d("updateFloatPosition isRight : $isRightFloat")
-//            if (isRightFloat) {
-//                val params = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
-//                params.marginEnd = DensityUtils.dip2px(activity, 65f)
-//                icon.layoutParams = params
-//                rightMenu.visibility = View.VISIBLE
-//            }
-//        }
-    }
-
-    override fun startAnim() {
-        super.startAnim()
-//        Logger.d("startAnim mWidth $mWidth")
-//        mWidth = iconWidth
-//        if (isShowMenu) {
-//            icon.apply {
-//                val params = LayoutParams(iconWidth, iconHeight)
-//                layoutParams = params
-//            }
-//            leftMenu.visibility = View.GONE
-//            leftMenu.visibility = View.GONE
-//            updateFloatPosition(false)
-//            isShowMenu = false
-//        }
-    }
-
-
-    override fun onClick(v: View?) {
-        v?.apply {
-            Logger.d("FloatCenter onClick , isRight : $isRightFloat")
-            if (isDrag) {
-                return
-            }
-//            mWidth = iconWidth
-//            icon.apply {
-//                val params = LayoutParams(iconWidth, iconHeight)
-//                layoutParams = params
-//            }
-//            updateFloatPosition(false)
-            if (isShowMenu) {
-//                leftMenu.visibility = View.GONE
-//                rightMenu.visibility = View.GONE
-                mWidth = iconWidth
-                view.removeAllViews()
-                view.addView(icon)
-                updateViewLayout(view, LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT))
-                isShowMenu = false
-                updateFloatPosition(false)
-                return
-            }
-            if (isRightFloat) {
-//                leftMenu.visibility = View.GONE
-//                rightMenu.visibility = View.VISIBLE
-//                val rootParam = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
-                mWidth = iconWidth
-                view.removeAllViews()
-                removeAllViews()
-                view.addView(menu)
-                view.addView(icon)
-                addView(view)
-                updateViewLayout(view, LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT))
-                isShowMenu = true
-                updateFloatPosition(false)
-            } else {
-                mWidth = menuWidth
-                view.removeAllViews()
-                removeAllViews()
-                view.addView(icon)
-                view.addView(menu)
-                addView(view)
-                updateViewLayout(view, LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT))
-//                val params = LayoutParams(iconWidth, iconWidth)
-//                icon.layoutParams = params
-//                val menuParams = LayoutParams(menuWidth, menuHeight)
-//                leftMenu.layoutParams = menuParams
-//                leftMenu.visibility = View.VISIBLE
-//                rightMenu.visibility = View.GONE
-//                val rootParam = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
-                isShowMenu = true
-                updateFloatPosition(false)
-            }
-        }
-    }
-}

+ 0 - 83
library_core/src/main/java/cn/yyxx/eyuangame/core/impl/floating/FloatCenterItem.kt

@@ -1,83 +0,0 @@
-package cn.yyxx.eyuangame.core.impl.floating
-
-import android.content.Context
-import android.text.TextUtils
-import android.view.LayoutInflater
-import android.view.View
-import android.widget.ImageView
-import android.widget.LinearLayout
-import android.widget.TextView
-import cn.yyxx.eyuangame.core.entity.FloatFeature
-import cn.yyxx.support.ResUtils
-
-/**
- * @author #Suyghur.
- * Created on 2021/06/28
- */
-class FloatCenterItem constructor(context: Context, url: String, feature: FloatFeature) : LinearLayout(context) {
-
-    private lateinit var root: View
-    private lateinit var icon: ImageView
-    private lateinit var desc: TextView
-
-    init {
-        initView(context, url, feature)
-    }
-
-    private fun initView(context: Context, url: String, feature: FloatFeature) {
-        root = LayoutInflater.from(context).inflate(ResUtils.getResId(context, "yyxx_float_item", "layout"), null)
-        icon = root.findViewById(ResUtils.getResId(context, "yyxx_iv_float_icon", "id"))
-        desc = root.findViewById(ResUtils.getResId(context, "yyxx_tv_float_desc", "id"))
-
-
-        when (feature) {
-            FloatFeature.FEATURE_MEMBER -> {
-                if (TextUtils.isEmpty(url)) {
-                    icon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_member_img", "drawable"))
-                } else {
-                    icon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_member_img", "drawable"))
-                }
-                desc.text = ResUtils.getResString(context, "yyxx_tv_float_member_desc")
-            }
-
-            FloatFeature.FEATURE_GIF -> {
-                if (TextUtils.isEmpty(url)) {
-                    icon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_gif_img", "drawable"))
-                } else {
-                    icon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_gif_img", "drawable"))
-                }
-                desc.text = ResUtils.getResString(context, "yyxx_tv_float_gif_desc")
-            }
-
-            FloatFeature.FEATURE_GM -> {
-                if (TextUtils.isEmpty(url)) {
-                    icon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_gm_img", "drawable"))
-                } else {
-                    icon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_gm_img", "drawable"))
-                }
-                desc.text = ResUtils.getResString(context, "yyxx_tv_float_gm_desc")
-            }
-
-            FloatFeature.FEATURE_CHARGE -> {
-                if (TextUtils.isEmpty(url)) {
-                    icon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_charge_img", "drawable"))
-                } else {
-                    icon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_charge_img", "drawable"))
-                }
-                desc.text = ResUtils.getResString(context, "yyxx_tv_float_charge_desc")
-            }
-
-            FloatFeature.FEATURE_INVITE -> {
-                if (TextUtils.isEmpty(url)) {
-                    icon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_invite_img", "drawable"))
-                } else {
-                    icon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_invite_img", "drawable"))
-                }
-                desc.text = ResUtils.getResString(context, "yyxx_tv_float_invite_desc")
-            }
-        }
-
-        addView(root)
-//        icon = view
-    }
-}

+ 0 - 118
library_core/src/main/java/cn/yyxx/eyuangame/core/impl/floating/FloatCenterService.kt

@@ -1,118 +0,0 @@
-package cn.yyxx.eyuangame.core.impl.floating
-
-import android.app.Activity
-import android.app.Service
-import android.content.Intent
-import android.graphics.BitmapFactory
-import android.os.Binder
-import android.os.IBinder
-import cn.yyxx.eyuangame.core.entity.FloatFeature
-import cn.yyxx.support.ResUtils
-import cn.yyxx.support.ui.floating.FloatItem
-import cn.yyxx.support.ui.floating.FloatLogoMenu
-import cn.yyxx.support.ui.floating.FloatMenuView
-
-/**
- * @author #Suyghur.
- * Created on 2021/06/28
- */
-class FloatCenterService : Service() {
-
-        private var floatCenter: FloatLogoMenu? = null
-//    private var floatCenter: FloatCenter? = null
-    private var mActivity: Activity? = null
-
-    override fun onCreate() {
-        super.onCreate()
-    }
-
-    fun initService(activity: Activity) {
-        this.mActivity = activity
-    }
-
-    fun show() {
-        if (floatCenter == null && mActivity != null) {
-//            val features = mutableListOf(
-//                FloatCenterItem(mActivity!!, "", FloatFeature.FEATURE_MEMBER),
-//                FloatCenterItem(mActivity!!, "", FloatFeature.FEATURE_GIF),
-//                FloatCenterItem(mActivity!!, "", FloatFeature.FEATURE_GM),
-//                FloatCenterItem(mActivity!!, "", FloatFeature.FEATURE_CHARGE),
-//                FloatCenterItem(mActivity!!, "", FloatFeature.FEATURE_INVITE),
-//            )
-            val features = mutableListOf(
-                FloatItem(
-                    ResUtils.getResString(mActivity, "yyxx_tv_float_member_desc"),
-                    "#1DB1AD",
-                    "#000000",
-                    BitmapFactory.decodeResource(mActivity!!.resources, ResUtils.getResId(mActivity, "yyxx_float_member_img", "drawable"))
-                ),
-                FloatItem(
-                    ResUtils.getResString(mActivity, "yyxx_tv_float_gif_desc"),
-                    "#1DB1AD",
-                    "#000000",
-                    BitmapFactory.decodeResource(mActivity!!.resources, ResUtils.getResId(mActivity, "yyxx_float_gif_img", "drawable"))
-                ),
-                FloatItem(
-                    ResUtils.getResString(mActivity, "yyxx_tv_float_gm_desc"),
-                    "#1DB1AD",
-                    "#000000",
-                    BitmapFactory.decodeResource(mActivity!!.resources, ResUtils.getResId(mActivity, "yyxx_float_gm_img", "drawable"))
-                ),
-                FloatItem(
-                    ResUtils.getResString(mActivity, "yyxx_tv_float_charge_desc"),
-                    "#1DB1AD",
-                    "#000000",
-                    BitmapFactory.decodeResource(mActivity!!.resources, ResUtils.getResId(mActivity, "yyxx_float_charge_img", "drawable"))
-                ),
-                FloatItem(
-                    ResUtils.getResString(mActivity, "yyxx_tv_float_invite_desc"),
-                    "#1DB1AD",
-                    "#000000",
-                    BitmapFactory.decodeResource(mActivity!!.resources, ResUtils.getResId(mActivity, "yyxx_float_invite_img", "drawable"))
-                ),
-            )
-
-            floatCenter = FloatLogoMenu.Builder()
-                .withActivity(mActivity)
-                .logo(BitmapFactory.decodeResource(mActivity!!.resources, ResUtils.getResId(mActivity, "yyxx_float_logo_img", "drawable")))
-                .drawCicleMenuBg(true)
-                .backMenuColor("#FFFFFF")
-                .setBgDrawable(mActivity!!.resources.getDrawable(ResUtils.getResId(mActivity, "yyxx_float_menu_bg", "drawable")))
-                //这个背景色需要和logo的背景色一致
-                .setFloatItems(features)
-                .defaultLocation(FloatLogoMenu.LEFT)
-                .drawRedPointNum(false)
-                .showWithListener(object : FloatMenuView.OnMenuClickListener {
-                    override fun onItemClick(p0: Int, p1: String?) {
-                    }
-
-                    override fun dismiss() {
-                    }
-
-                })
-//            floatCenter = FloatCenter(mActivity!!, features)
-        }
-        floatCenter?.show()
-    }
-
-    fun hide() {
-        floatCenter?.hide()
-    }
-
-    fun release() {
-        floatCenter?.release()
-    }
-
-    override fun onBind(intent: Intent?): IBinder {
-        return FloatCenterServiceBinder()
-    }
-
-    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
-        return super.onStartCommand(intent, flags, startId)
-    }
-
-    inner class FloatCenterServiceBinder : Binder() {
-        val service: FloatCenterService = this@FloatCenterService
-    }
-
-}

+ 335 - 0
library_core/src/main/java/cn/yyxx/eyuangame/core/ui/floatview/FloatingBall.kt

@@ -0,0 +1,335 @@
+package cn.yyxx.eyuangame.core.ui.floatview
+
+import android.app.Activity
+import android.content.Context
+import android.graphics.PixelFormat
+import android.graphics.drawable.ColorDrawable
+import android.os.Build
+import android.os.Handler
+import android.os.Looper
+import android.os.Message
+import android.view.*
+import android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN
+import android.widget.FrameLayout
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.PopupWindow
+import cn.yyxx.eyuangame.base.utils.Logger
+import cn.yyxx.support.DensityUtils
+import cn.yyxx.support.scheduler.ScheduledWorker
+import java.util.concurrent.TimeUnit
+import kotlin.math.abs
+
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/06/30
+ */
+class FloatingBall(val activity: Activity, private val isLandscape: Boolean, private val callback: FloatingBallCallback) : FrameLayout(activity),
+    View.OnTouchListener {
+
+    private lateinit var wm: WindowManager
+    private lateinit var wlp: WindowManager.LayoutParams
+
+    private lateinit var rootLinearLayout: LinearLayout
+    private lateinit var frameLayout: FrameLayout
+    private lateinit var ballView: ImageView
+    private lateinit var ballMenu: FloatingBallMenu
+    private lateinit var menu: PopupWindow
+
+    //浮标是否移动
+    private var isMove = false
+
+    //手指按下时坐标
+    private var mTouchStartX = 0f
+    private var mTouchStartY = 0f
+
+    //是否展开
+    private var hasShowContent = false
+
+    //默认吸附在左边
+    private var isLeftLocation = true
+
+    //菜单menu的长度
+    private var mSize = 0
+
+    private var hasStatusBar = false
+
+    private var displayWorker: ScheduledWorker? = null
+//    private var displayWorker: ScheduledWorker? = null
+
+
+    private val timerHandler = object : Handler(Looper.getMainLooper()) {
+        override fun handleMessage(msg: Message) {
+
+        }
+    }
+
+    init {
+        hasStatusBar = activity.window.attributes.flags and FLAG_FULLSCREEN != FLAG_FULLSCREEN
+        createWM()
+        createView()
+        addView(rootLinearLayout)
+        wm.addView(this, wlp)
+        displayWorker = ScheduledWorker(1)
+        invokeDisplayTimerWork()
+    }
+
+    private fun createWM() {
+        wm = activity.windowManager
+        wlp = WindowManager.LayoutParams()
+        wlp.apply {
+            //总是出现在应用程序窗口之上
+            type = WindowManager.LayoutParams.LAST_APPLICATION_WINDOW
+            format = PixelFormat.RGBA_8888
+            flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+            wlp.gravity = Gravity.TOP or Gravity.LEFT
+            //默认左边居中
+            wlp.x = 0
+            wlp.y = DensityUtils.getHeigthAndWidth(activity)[1] / 2
+            width = WindowManager.LayoutParams.WRAP_CONTENT
+            height = WindowManager.LayoutParams.WRAP_CONTENT
+        }
+    }
+
+    private fun createView() {
+        rootLinearLayout = LinearLayout(activity)
+        rootLinearLayout.layoutParams = ViewGroup.LayoutParams(DensityUtils.dip2px(activity, 40f), DensityUtils.dip2px(activity, 40f))
+
+        frameLayout = FrameLayout(activity)
+        frameLayout.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+
+        ballView = ImageView(activity)
+        ballView.apply {
+            layoutParams = ViewGroup.LayoutParams(DensityUtils.dip2px(activity, 40f), DensityUtils.dip2px(activity, 40f))
+            invokeUpdateBallView()
+            scaleType = ImageView.ScaleType.FIT_XY
+            //TODO onClickListener ?
+            setOnTouchListener(this@FloatingBall)
+//            ballView.setOnClickListener {
+//                invokeMenuShowOrDismiss()
+//            }
+            frameLayout.addView(this)
+        }
+
+        ballMenu = FloatingBallMenu(activity, object : FloatingBallMenu.FloatingBallMenuCallback {
+            override fun onInitMenuData(): MutableList<FloatingBallMenu.FloatingBallMenuItem> {
+                mSize = callback.onInitMenuData().size
+                return callback.onInitMenuData()
+            }
+
+            override fun onDismissMenu() {
+                callback.onDismissMenu()
+            }
+
+            override fun onMenuItemClick(item: FloatingBallMenu.FloatingBallMenuItem, pos: Int) {
+                callback.onMenuItemClick(item, pos)
+            }
+        })
+
+        menu = PopupWindow(activity)
+        menu.apply {
+            contentView = ballMenu.contentView
+            width = DensityUtils.dip2px(activity, 40f + mSize * 40f)
+            height = DensityUtils.dip2px(activity, 40f)
+            isFocusable = true
+            setBackgroundDrawable(ColorDrawable())
+            isOutsideTouchable = true
+            setOnDismissListener {
+                invokeDisplayTimerWork()
+            }
+        }
+
+        if (isLandscape) {
+            handleFullScreenModel()
+        }
+        rootLinearLayout.addView(frameLayout)
+    }
+
+    fun dismissMenu() {
+        hasShowContent = false
+        menu.dismiss()
+        invokeUpdateBallView()
+    }
+
+    private fun invokeMenuShowOrDismiss() {
+        Logger.d("invokeMenuShowOrDismiss")
+        if (hasShowContent) {
+            menu.dismiss()
+            hasShowContent = false
+        } else {
+            hasShowContent = true
+            callback.onExpandMenu(false)
+            ballMenu.updateLayout(isLeftLocation)
+            if (hasStatusBar) {
+                menu.showAtLocation(ballMenu.contentView, Gravity.NO_GRAVITY, wlp.x + 10, wlp.y + getStatusBarHeight(activity))
+            } else {
+                when {
+                    isNotch() -> {
+                        menu.showAtLocation(ballMenu.contentView, Gravity.NO_GRAVITY, wlp.x + 10, wlp.y + getStatusBarHeight(activity))
+                    }
+                    isDisplayCutout(activity) -> {
+                        menu.showAtLocation(ballMenu.contentView, Gravity.NO_GRAVITY, wlp.x + 10, wlp.y + getStatusBarHeight(activity))
+                    }
+                    else -> {
+                        menu.showAtLocation(ballMenu.contentView, Gravity.NO_GRAVITY, wlp.x + 10, wlp.y)
+                    }
+                }
+            }
+        }
+    }
+
+    private fun invokeUpdateBallView() {
+        callback.onUpdateBallView(ballView, isLeftLocation, false)
+    }
+
+    private fun invokeDisplayTimerWork() {
+        displayWorker?.invokeAtFixedRate({
+            timerHandler.sendEmptyMessage(1000)
+        }, 10, 3, TimeUnit.SECONDS)
+    }
+
+
+    fun attach() {
+        if (visibility == View.GONE) {
+            visibility = View.VISIBLE
+        }
+    }
+
+    fun detach() {
+        if (visibility == View.VISIBLE) {
+            visibility = View.GONE
+        }
+    }
+
+    fun release() {
+        displayWorker?.apply {
+            cancel()
+            displayWorker = null
+        }
+
+        wm.removeView(rootLinearLayout)
+    }
+
+    /**
+     * 解决PopupWindow无法在状态栏上显示
+     *
+     */
+    private fun handleFullScreenModel() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            try {
+                val mLayoutInScreen = PopupWindow::class.java.getDeclaredField("mLayoutInScreen")
+                mLayoutInScreen.isAccessible = true
+                mLayoutInScreen.set(menu, true)
+            } catch (e: Exception) {
+                e.printStackTrace()
+            }
+        }
+    }
+
+    private fun getStatusBarHeight(context: Context): Int {
+        val id = context.resources.getIdentifier("status_bar_height", "dimen", "android")
+        return context.resources.getDimensionPixelSize(id)
+    }
+
+    /**
+     * 适配小米Android O设备 判断是否是刘海屏
+     */
+    private fun isNotch(): Boolean {
+        try {
+            val method = Class.forName("android.os.SystemProperties").getMethod("getInt", String::class.java, Int::class.java)
+            return (method.invoke(null, "ro.miui.notch", 0) as Int == 1)
+        } catch (e: Exception) {
+            e.printStackTrace()
+        }
+        return false
+    }
+
+    /**
+     * 判断是否为挖孔屏幕
+     */
+    private fun isDisplayCutout(activity: Activity): Boolean {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+            try {
+                return activity.window.decorView.rootWindowInsets?.displayCutout != null
+            } catch (e: Exception) {
+                e.printStackTrace()
+            }
+        }
+        return false
+    }
+
+    override fun onTouch(v: View, event: MotionEvent): Boolean {
+        displayWorker?.cancel()
+        //获取相对屏幕的坐标
+        val x = event.rawX
+        val y = event.rawY
+        //下面的这些事件,跟图标的移动无关,为了区分开拖动和点击事件
+        when (event.action) {
+            MotionEvent.ACTION_DOWN -> {
+                isMove = false
+                mTouchStartX = event.x
+                mTouchStartY = event.y
+            }
+            MotionEvent.ACTION_MOVE -> {
+                //图标移动的逻辑在这里
+                val moveStartX = event.x
+                val moveStartY = event.y
+                //移动量大于3才判定移动
+                if (abs(mTouchStartX - moveStartX) > 3 && abs(mTouchStartY - moveStartY) > 3) {
+                    wlp.x = (x - mTouchStartX).toInt()
+                    wlp.y = (y - mTouchStartY).toInt()
+                    wm.updateViewLayout(this, wlp)
+                    isMove = true
+                    if (menu.isShowing) {
+                        menu.dismiss()
+                        hasShowContent = false
+                    }
+                    return false
+                }
+            }
+
+            MotionEvent.ACTION_UP -> {
+                //大于屏幕宽度的一半吸附在左边
+                v.performClick()
+                if (wlp.x <= DensityUtils.getHeigthAndWidth(activity)[0] / 2) {
+                    wlp.x = 0
+                    isLeftLocation = true
+                } else {
+                    wlp.x = DensityUtils.getHeigthAndWidth(activity)[0]
+                    isLeftLocation = false
+                }
+
+                wm.updateViewLayout(this, wlp)
+
+                invokeMenuShowOrDismiss()
+
+                if (isMove) {
+                    invokeDisplayTimerWork()
+                } else {
+                    invokeUpdateBallView()
+                }
+            }
+        }
+
+        return true
+
+    }
+
+    interface FloatingBallCallback {
+
+        fun onUpdateBallView(ballView: ImageView, isLeftLocation: Boolean, isHide: Boolean)
+
+        //fun onUpdateRedDotView(redDotView: ImageView)
+
+        fun onInitMenuData(): MutableList<FloatingBallMenu.FloatingBallMenuItem>
+
+        fun onMenuItemClick(item: FloatingBallMenu.FloatingBallMenuItem, pos: Int)
+
+        fun onExpandMenu(hasRedDot: Boolean)
+
+        fun onDismissMenu()
+    }
+
+
+}

+ 141 - 0
library_core/src/main/java/cn/yyxx/eyuangame/core/ui/floatview/FloatingBallMenu.kt

@@ -0,0 +1,141 @@
+package cn.yyxx.eyuangame.core.ui.floatview
+
+import android.content.Context
+import android.text.TextUtils
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.*
+import cn.yyxx.eyuangame.core.entity.FloatFeature
+import cn.yyxx.support.DensityUtils
+import cn.yyxx.support.ResUtils
+
+/**
+ * @author #Suyghur.
+ * Created on 2021/06/30
+ */
+class FloatingBallMenu(val context: Context, private val callback: FloatingBallMenuCallback) {
+
+    lateinit var contentView: View
+    private lateinit var containerLayout: LinearLayout
+    private lateinit var menuView: GridView
+    private var items = mutableListOf<FloatingBallMenuItem>()
+
+    init {
+        initView()
+        initData()
+    }
+
+    private fun initView() {
+        contentView = LayoutInflater.from(context).inflate(ResUtils.getResId(context, "yyxx_floating_ball_menu", "layout"), null)
+
+        containerLayout = contentView.findViewById(ResUtils.getResId(context, "yyxx_ll_container", "id"))
+        containerLayout.gravity = Gravity.CENTER_VERTICAL or Gravity.RIGHT
+
+        menuView = contentView.findViewById(ResUtils.getResId(context, "yyxx_gv_menu", "id"))
+        //重新设置menuView宽高
+        val menuWidth = DensityUtils.dip2px(context, callback.onInitMenuData().size * 40f)
+        menuView.layoutParams = LinearLayout.LayoutParams(menuWidth, LinearLayout.LayoutParams.WRAP_CONTENT)
+    }
+
+    private fun initData() {
+        items = callback.onInitMenuData()
+        menuView.numColumns = items.size
+        menuView.adapter = FloatingBallMenuAdapter(context, items)
+    }
+
+    fun updateLayout(isLeftLocation: Boolean) {
+        menuView.bringToFront()
+        if (isLeftLocation) {
+            containerLayout.gravity = Gravity.CENTER_VERTICAL or Gravity.RIGHT
+        } else {
+            containerLayout.gravity = Gravity.CENTER_VERTICAL or Gravity.LEFT
+        }
+//        updateViewBackground(isLeftLocation)
+    }
+
+    interface FloatingBallMenuCallback {
+
+        fun onInitMenuData(): MutableList<FloatingBallMenuItem>
+
+        fun onDismissMenu()
+
+        fun onMenuItemClick(item: FloatingBallMenuItem, pos: Int)
+    }
+
+    data class FloatingBallMenuItem(val type: FloatFeature, val iconUrl: String, val url: String)
+
+    private inner class FloatingBallMenuAdapter(val context: Context, val items: MutableList<FloatingBallMenuItem>) : BaseAdapter() {
+
+        override fun getCount(): Int {
+            return items.size
+        }
+
+        override fun getItem(position: Int): Any {
+            return items[position]
+        }
+
+        override fun getItemId(position: Int): Long {
+            return position.toLong()
+        }
+
+        override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
+            val item = items[position]
+            val view = View.inflate(context, ResUtils.getResId(context, "yyxx_floating_ball_item", "layout"), null)
+            val ivIcon = view.findViewById<ImageView>(ResUtils.getResId(context, "yyxx_iv_icon", "id"))
+            val tvDesc = view.findViewById<TextView>(ResUtils.getResId(context, "yyxx_tv_desc", "id"))
+            when (item.type) {
+                FloatFeature.FEATURE_MEMBER -> {
+                    if (TextUtils.isEmpty(item.iconUrl)) {
+                        ivIcon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_member_img", "drawable"))
+                    } else {
+                        ivIcon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_member_img", "drawable"))
+                    }
+                    tvDesc.text = ResUtils.getResString(context, "yyxx_tv_float_member_desc")
+                }
+
+                FloatFeature.FEATURE_GIF -> {
+                    if (TextUtils.isEmpty(item.iconUrl)) {
+                        ivIcon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_gif_img", "drawable"))
+                    } else {
+                        ivIcon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_gif_img", "drawable"))
+                    }
+                    tvDesc.text = ResUtils.getResString(context, "yyxx_tv_float_gif_desc")
+                }
+
+                FloatFeature.FEATURE_GM -> {
+                    if (TextUtils.isEmpty(item.iconUrl)) {
+                        ivIcon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_gm_img", "drawable"))
+                    } else {
+                        ivIcon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_gm_img", "drawable"))
+                    }
+                    tvDesc.text = ResUtils.getResString(context, "yyxx_tv_float_gm_desc")
+                }
+
+                FloatFeature.FEATURE_CHARGE -> {
+                    if (TextUtils.isEmpty(item.iconUrl)) {
+                        ivIcon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_charge_img", "drawable"))
+                    } else {
+                        ivIcon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_charge_img", "drawable"))
+                    }
+                    tvDesc.text = ResUtils.getResString(context, "yyxx_tv_float_charge_desc")
+                }
+
+                FloatFeature.FEATURE_INVITE -> {
+                    if (TextUtils.isEmpty(item.iconUrl)) {
+                        ivIcon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_invite_img", "drawable"))
+                    } else {
+                        ivIcon.setBackgroundResource(ResUtils.getResId(context, "yyxx_float_invite_img", "drawable"))
+                    }
+                    tvDesc.text = ResUtils.getResString(context, "yyxx_tv_float_invite_desc")
+                }
+            }
+            view.setOnClickListener {
+                callback.onMenuItemClick(item, position)
+            }
+            return view
+        }
+
+    }
+}

+ 0 - 34
library_core/src/main/res/layout/yyxx_float_menu.xml

@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:orientation="horizontal"
-    android:background="@drawable/yyxx_float_menu_bg">
-
-
-    <ImageView
-        android:id="@+id/yyxx_iv_icon"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:background="@drawable/yyxx_float_logo_img" />
-
-
-
-    <LinearLayout
-        android:id="@+id/yyxx_left_menu"
-        android:layout_width="100dp"
-        android:layout_height="35dp"
-        android:background="@drawable/yyxx_float_menu_bg"
-        android:orientation="horizontal"
-        android:visibility="visible" />
-
-<!--    <LinearLayout-->
-<!--        android:id="@+id/yyxx_right_menu"-->
-<!--        android:layout_width="100dp"-->
-<!--        android:layout_height="35dp"-->
-<!--        android:background="@drawable/yyxx_float_menu_bg"-->
-<!--        android:orientation="horizontal"-->
-<!--        android:visibility="visible" />-->
-
-
-</LinearLayout>

+ 0 - 22
library_core/src/main/res/layout/yyxx_float_right_menu.xml

@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content">
-
-
-    <LinearLayout
-        android:id="@+id/yyxx_right_menu"
-        android:layout_width="100dp"
-        android:layout_height="35dp"
-        android:background="@drawable/yyxx_float_menu_bg"
-        android:orientation="horizontal"
-        android:visibility="visible" />
-
-    <ImageView
-        android:id="@+id/yyxx_iv_icon"
-        android:layout_width="35dp"
-        android:layout_height="35dp"
-        android:layout_marginStart="65dp"
-        android:background="@drawable/yyxx_float_logo_img" />
-
-</FrameLayout>

+ 7 - 5
library_core/src/main/res/layout/yyxx_float_item.xml → library_core/src/main/res/layout/yyxx_floating_ball_item.xml

@@ -2,21 +2,23 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
+    android:background="@color/yyxx_transparent"
     android:gravity="center"
     android:orientation="vertical">
 
     <ImageView
-        android:id="@+id/yyxx_iv_float_icon"
-        android:layout_width="25dp"
-        android:layout_height="25dp"
+        android:id="@+id/yyxx_iv_icon"
+        android:layout_width="18dp"
+        android:layout_height="18dp"
         android:background="@drawable/yyxx_float_logo_img" />
 
     <TextView
-        android:id="@+id/yyxx_tv_float_desc"
+        android:id="@+id/yyxx_tv_desc"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_marginTop="2dp"
         android:text="feature"
         android:textColor="@color/yyxx_color_green_blue"
-        android:textSize="10sp" />
+        android:textSize="8sp" />
 
 </LinearLayout>

+ 18 - 0
library_core/src/main/res/layout/yyxx_floating_ball_menu.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/yyxx_ll_container"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:background="@drawable/yyxx_float_menu_bg"
+    android:orientation="horizontal">
+
+    <GridView
+        android:id="@+id/yyxx_gv_menu"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:cacheColorHint="@color/yyxx_transparent"
+        android:fadingEdge="none"
+        android:listSelector="@color/yyxx_transparent"
+        android:padding="5dp" />
+
+</LinearLayout>

二进制
libs/yyxx_support_1.0.1.jar