悬浮窗适配

简单记录下悬浮窗的显示,各种适配就不管了,下边帖子有介绍,可以参考
https://www.jianshu.com/p/2229d4a12269

下边是点击按钮,弹出一个悬浮窗,默认显示在右边中间,可以手指触摸移动位置。
ShowFloatingWindow().showView()

import android.app.AppOpsManager
import android.content.Context
import android.graphics.Point
import android.os.Binder
import android.os.Build
import android.provider.Settings
import android.view.*
import com.charliesong.demo0327.R
import android.view.Gravity
import android.widget.OverScroller
import android.widget.Toast
import android.content.Intent
import android.net.Uri
import android.support.annotation.RequiresApi
import com.charliesong.demo0327.base.MyApplication


class ShowFloatingWindow(){

   private var context:Context= MyApplication.getInstance()
    private  var windowManager:WindowManager= MyApplication.getInstance().getSystemService(Context.WINDOW_SERVICE) as WindowManager
    companion object {
        var showView:View?=null
    }
    var params=WindowManager.LayoutParams()
    val point=Point()//记录手指down的时候params的 x和y值
    //权限检查,不检查的话会崩掉的。
    private fun checkPermission():Boolean{
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            return Settings.canDrawOverlays(context);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            //AppOpsManager添加于API 19
            return checkOps();
        } else {
            //4.4以下一般都可以直接添加悬浮窗
            return true;
        }
    }
    @RequiresApi(Build.VERSION_CODES.KITKAT)
    private  fun  checkOps():Boolean {
        try {
            val obj = context.getSystemService(Context.APP_OPS_SERVICE);
            if (obj == null) {
                return false;
            }
            val localClass = obj.javaClass
            val method = localClass.getMethod("checkOp", Integer.TYPE,Integer.TYPE, String::class.java);
            if (method == null) {
                return false;
            }
            val m = method.invoke(obj, 24,Binder.getCallingUid(),context.getPackageName()) as Int
            //4.4至6.0之间的非国产手机,例如samsung,sony一般都可以直接添加悬浮窗
            return m == AppOpsManager.MODE_ALLOWED ;
        } catch ( e:Exception) {
            e.printStackTrace()
        }
        return false;
    }

    private fun applyCommonPermission(context: Context) {
        try {
            val clazz = Settings::class.java
            val field = clazz.getDeclaredField("ACTION_MANAGE_OVERLAY_PERMISSION")
            val intent = Intent(field.get(null).toString())
            intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
            intent.data = Uri.parse("package:" + context.packageName)
            context.startActivity(intent)
        } catch (e: Exception) {
            Toast.makeText(context, "进入设置页面失败,请手动设置", Toast.LENGTH_LONG).show()
        }

    }

    fun showView(){
        if(!checkPermission()){
            applyCommonPermission(context)
            return
        }
        showView?.apply {
            if(this.parent!=null)
                windowManager.removeViewImmediate(showView)
        }
        showView=LayoutInflater.from(context).inflate(R.layout.floating_view,null).apply {
            findViewById(R.id.btn_close).setOnClickListener {
              windowManager.removeView(showView)
                showView=null
            }
            handleTouch(this)
        }

        var tp=WindowManager.LayoutParams.TYPE_TOAST
        if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
            tp=WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
        }
         params=WindowManager.LayoutParams().apply {
            x=110
            y=0
            flags=WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
            gravity= Gravity.END or Gravity.CENTER;
            width=WindowManager.LayoutParams.WRAP_CONTENT
            height=WindowManager.LayoutParams.WRAP_CONTENT
            type=tp
        }

        windowManager.addView(showView,params)

    }


    private fun handleTouch(view: View){
        val listener=object :GestureDetector.SimpleOnGestureListener(){
            override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean {
//                println("=======onScroll=========$distanceX===$distanceY=======${params.y}===${e1.rawX}==${e2.rawX}")
                params.x=point.x+(e1.rawX-e2.rawX).toInt()
                params.y=point.y-(e1.rawY-e2.rawY).toInt()
                windowManager.updateViewLayout(view,params)
                return true
            }

            override fun onDown(e: MotionEvent?): Boolean {
                point.x=params.x
                point.y=params.y
                return super.onDown(e)
            }
            override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
                val overScroller=OverScroller(view.context)
                overScroller.fling(e2.rawX.toInt(),e2.rawY.toInt(),velocityX.toInt(),velocityY.toInt(),-10000,10000,-10000,10000)
                overScroller.abortAnimation()
                params.x=point.x+(e1.rawX-overScroller.currX).toInt()
                params.y=point.y-(e1.rawY-overScroller.currY).toInt()
                windowManager.updateViewLayout(view,params)
                return super.onFling(e1, e2, velocityX, velocityY)
            }
        }
        val guesture=GestureDetector(context,listener)
        view.setOnTouchListener { v, event ->
            guesture.onTouchEvent(event)
            return@setOnTouchListener true
        }
    }
}

悬浮窗的添加,删除,修改就3个方法

    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);

你可能感兴趣的:(悬浮窗适配)