Android Window窗口案例实录

Android窗口应用的真实案例

Android window窗口应用介绍

当前应用实现的是一个悬浮球的功能;主要功能如下:

  1. 小球浮在界面上可移动;
  2. 点击小球可展开五个入口功能;
  3. 点击入口进行各自业务;
  4. 点击展开小球中心可隐藏入口恢复到小球状态

下面就来上代码了:

  1. 先给一个WindowManager管理的工具类
package com.floating.qihang.utils;


import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Build;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.RelativeLayout;

import com.floating.qihang.R;

/**
 * 管理window窗应用的界面和事件
 */
public class ProgressWindowManager {

    private static WindowManager windowManager;
    private static WindowManager.LayoutParams standardParams;
    public static View floatView;
    /**
     *添加view到屏幕上
     */
    private static void windowAddView(Context context,int locationX,int locationY){

        windowManagerInstance(context);

        /**
         * 注意每个View必须用自己的LayoutParams,不可以复用同一个;
         */
        standardParams = new WindowManager.LayoutParams();
        //窗口类型
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) {
            //Android 8.0以上的系统必须使用这个新的type类型TYPE_APPLICATION_OVERLAY
            standardParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            standardParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
        }
        standardParams.format = PixelFormat.RGBA_8888;
        standardParams.setTitle("ist_floatball");
        // 设置标志,这个两个标志为了让就算出现了悬浮窗,不影响其他区域,只在悬浮窗的区域受干扰
        standardParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
                WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH |
                WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
        standardParams.x=locationX;
        standardParams.y = locationY;//初始的位置
        //坐标原点定位属性值(以屏幕左边正中间为坐标原点,往上坐标为负值,往下坐标为正值;例如要初始化view在屏幕左上角(standardParams.x=0;standardParams.y =-(1080/2)))
        standardParams.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;

    }

    /**
     * 具体添加那个view
     * 设置添加的view具体的信息(位置,尺寸等)
     *
     * @param context
     * @param layoutId
     */
    public static View windowAddFixedSizeView(Context context, int layoutId, int locationX, int locationY){
        windowAddView(context,locationX,locationY);
        standardParams.width = context.getResources().getDimensionPixelSize(R.dimen.dpi_390px);
        standardParams.height = context.getResources().getDimensionPixelSize(R.dimen.dpi_390px);
        View view  = LayoutInflater.from(context).inflate(layoutId, null);
        windowManager.addView(view, standardParams);
        return view;
    }

    /**
     * 注意:RelativeLayout.LayoutParams
     * 不同的布局要给对应的LayoutParams
     * @param context
     * @param layoutId
     * @param locationX 初始的X坐标
     * @param locationY 初始的Y坐标
     * @return
     */
    public static View windowAddCommonView(Context context, int layoutId,int locationX, int locationY){
        windowAddView(context,locationX,locationY);
        standardParams.width = RelativeLayout.LayoutParams.WRAP_CONTENT;
        standardParams.height = RelativeLayout.LayoutParams.WRAP_CONTENT;
        View view  = LayoutInflater.from(context).inflate(layoutId, null);
        windowManager.addView(view, standardParams);
        floatView=view;
        return view;
    }

    /**
     * 获取屏幕尺寸
     * @return
     */
    public static int[] getDisplaySize(Context context){
        if (windowManager == null) {
            windowManager = (WindowManager)context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
        }
        DisplayMetrics dm = new DisplayMetrics();
        windowManager.getDefaultDisplay().getMetrics(dm);
       return new int[]{dm.widthPixels,dm.heightPixels};
    }


    /**
     * 获取当前view的坐标参数
     * @return
     */
    public static int[] getViewLocationParams(){
        if (standardParams == null) {
            standardParams = new WindowManager.LayoutParams();
        }
        return new int[]{standardParams.x,standardParams.y};
    }

    /**
     * 更新view在屏幕中的坐标
     * @param view
     * @param locationX
     * @param locationY
     */
    public static void updateViewLayoutLocationParams(View view,int locationX,int locationY){
        standardParams.x = locationX;
        standardParams.y = locationY;
        windowManager.updateViewLayout(view, standardParams);
    }
    /**
     * 更新view在屏幕中的坐标
     * @param view
     */
    public static void updateViewLayoutLocationParams(View view){
        windowManager.updateViewLayout(view, standardParams);
    }


    /**
     * 获取 WindowManager
     * @param context
     * @return
     */
    public static WindowManager windowManagerInstance(Context context){
        if (windowManager==null){
            windowManager = (WindowManager)context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
        }
        return windowManager;
    }
    public static WindowManager.LayoutParams paramsInstance(){
        if (standardParams == null) {
            standardParams = new WindowManager.LayoutParams();
        }
        return standardParams;
    }


}

**

window窗应用必须要注意的几个点

  • 权限
 <!--悬浮窗权限-->
            <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
  • 启动方式 ***务必用Service控制
/*动态申请权限*/
        if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.M) {
            if(!Settings.canDrawOverlays(getApplicationContext())) {
                //启动Activity让用户授权
                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                        Uri.parse("package:" + getPackageName()));
                startActivityForResult(intent,WINDOW_REQUEST_CODE);
            }
        }
        if (Settings.canDrawOverlays(getApplicationContext())){
            Intent intent = new Intent(this,FloatManagerService.class);
            startService(intent);
            finish();
        }
注意Android8.0以上版本的问题  type要用新的类型
 //窗口类型
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) {
            //Android 8.0以上的系统必须使用这个新的type类型TYPE_APPLICATION_OVERLAY
            standardParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            standardParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
        }

如果想要控制窗口应用程序结束的话就需要停止Service;这里需要说明一点的是一定要正确停止服务,
如果是异常关闭服务的话服务会自动重启。
写博客大家都知道是一件很耗时间和精力的事情,但为了学习互相进步,一定会坚持的;

项目GitHub连接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值