最近开发项目中,有个在屏幕上任意拖动的悬浮窗功能,其实就是利用 WindowManager的api来完成这个需求,具体的实现的功能如下:
1.自定义view

import android.content.Context;import android.content.Intent;import android.os.Handler;import android.os.Message;import android.util.Log;import android.util.TypedValue;import android.view.MotionEvent;import android.view.View;import android.view.ViewConfiguration;import android.view.WindowManager;import android.widget.LinearLayout;import com.xinrui.recordscreen.R;import java.lang.reflect.Field;/** * */public class RecordScreenView extends LinearLayout implements View.OnClickListener{    private WindowManager mWindowManager;    private WindowManager.LayoutParams mLayoutParams;    private long mLastDownTime;    private float mLastDownX;    private float mLastDownY;    private boolean mIsLongTouch;    private boolean mIsTouching;    private float mTouchSlop;    private final static long LONG_CLICK_LIMIT = 20;    private final static int TIME_COUNT = 0;    private int mStatusBarHeight;    private int mCurrentMode,time=0;    private final static int MODE_NONE = 0x000;    private final static int MODE_MOVE = 0x001;    private int mOffsetToParent;    private int mOffsetToParentY;    private Context mContext;    public RecordScreenView(Context context) {        super(context);        this.mContext=context;        mWindowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);        initView();    }    private void initView() {        View view = inflate(getContext(), R.layout.layout_ball, this);        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();        mCurrentMode = MODE_NONE;        recordtime(0);        mStatusBarHeight = getStatusBarHeight();        mOffsetToParent = dip2px(25);        mOffsetToParentY = mStatusBarHeight + mOffsetToParent;        view.setOnTouchListener(new OnTouchListener() {            @Override            public boolean onTouch(View v, final MotionEvent event) {                switch (event.getAction()) {                    case MotionEvent.ACTION_DOWN:                        mIsTouching = true;                        mLastDownTime = System.currentTimeMillis();                        mLastDownX = event.getX();                        mLastDownY = event.getY();                        postDelayed(new Runnable() {                            @Override                            public void run() {                                if (isLongTouch()) {                                    mIsLongTouch = true;                                }                            }                        }, LONG_CLICK_LIMIT);                        break;                    case MotionEvent.ACTION_MOVE:                        if (!mIsLongTouch && isTouchSlop(event)) {                            return true;                        }                        if (mIsLongTouch && (mCurrentMode == MODE_NONE || mCurrentMode == MODE_MOVE)) {                            mLayoutParams.x = (int) (event.getRawX() - mLastDownX);                            mLayoutParams.y = (int) (event.getRawY() - mLastDownY);                            mWindowManager.updateViewLayout(RecordScreenView.this, mLayoutParams);//不断刷新悬浮窗的位置                            mCurrentMode = MODE_MOVE;                        }                        break;                    case MotionEvent.ACTION_CANCEL:                    case MotionEvent.ACTION_UP:                        mIsTouching = false;                        if (mIsLongTouch) {                            mIsLongTouch = false;                        }                        mCurrentMode = MODE_NONE;                        break;                }                return true;            }        });    }    private boolean isLongTouch() {        long time = System.currentTimeMillis();        if (mIsTouching && mCurrentMode == MODE_NONE && (time - mLastDownTime >= LONG_CLICK_LIMIT)) {            return true;        }        return false;    }    /**     * 判断是否是轻微滑动     *     * @param event     * @return     */    private boolean isTouchSlop(MotionEvent event) {        float x = event.getX();        float y = event.getY();        if (Math.abs(x - mLastDownX) < mTouchSlop && Math.abs(y - mLastDownY) < mTouchSlop) {            return true;        }        return false;    }    public void setLayoutParams(WindowManager.LayoutParams params) {        mLayoutParams = params;    }    /**     * 获取通知栏高度     *     * @return     */    private int getStatusBarHeight() {        int statusBarHeight = 0;        try {            Class<?> c = Class.forName("com.android.internal.R$dimen");            Object o = c.newInstance();            Field field = c.getField("status_bar_height");            int x = (Integer) field.get(o);            statusBarHeight = getResources().getDimensionPixelSize(x);        } catch (Exception e) {            e.printStackTrace();        }        return statusBarHeight;    }    public int dip2px(float dip) {        return (int) TypedValue.applyDimension(                TypedValue.COMPLEX_UNIT_DIP, dip, getContext().getResources().getDisplayMetrics()        );    }}

2.添加windowManager添加view

import android.content.Context;import android.graphics.PixelFormat;import android.view.Gravity;import android.view.WindowManager;import android.view.WindowManager.LayoutParams;/** * Created by wangxiandeng on 2016/11/25. */public class FloatWindowManager {    private static RecordScreenView mBallView;    private static WindowManager mWindowManager;    public static void addBallView(Context context) {        if (mBallView == null) {            WindowManager windowManager = getWindowManager(context);            int screenWidth = windowManager.getDefaultDisplay().getWidth();            int screenHeight = windowManager.getDefaultDisplay().getHeight();            mBallView = new RecordScreenView(context);            LayoutParams params = new LayoutParams();            params.x = screenWidth/2;            params.y = screenHeight/2+150;            params.width = LayoutParams.WRAP_CONTENT;            params.height = LayoutParams.WRAP_CONTENT;            params.gravity = Gravity.LEFT | Gravity.TOP;            params.type = LayoutParams.TYPE_APPLICATION_OVERLAY;            params.format = PixelFormat.RGBA_8888;            params.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL                    | LayoutParams.FLAG_NOT_FOCUSABLE;            mBallView.setLayoutParams(params);            windowManager.addView(mBallView, params);        }    }    public static void removeBallView(Context context) {        if (mBallView != null) {            WindowManager windowManager = getWindowManager(context);            windowManager.removeView(mBallView);            mBallView = null;        }    }    private static WindowManager getWindowManager(Context context) {        if (mWindowManager == null) {            mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);        }        return mWindowManager;    }}

3.Acitivity中调用

import android.app.Activity;import android.content.Intent;import android.os.Build;import android.os.Bundle;import android.provider.Settings;import android.util.Log;import android.widget.Toast;import com.xinrui.recordscreen.view.FloatWindowManager;public class MainActivity extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        if (Build.VERSION.SDK_INT >= 23) {        //设置中请求开启悬浮窗权限            if (!Settings.canDrawOverlays(this)) {                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);                startActivity(intent);                Toast.makeText(this, MainActivity.this.getResources().getString(R.string.open_float), Toast.LENGTH_SHORT).show();            }else{                initView();            }        }    }    private void initView() {        FloatWindowManager.addBallView(MainActivity.this);        finish();    }}

5.AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.xinrui.recordscreen">    <uses-permission android:name="android.permission.INTERNET"/>    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>//悬浮窗权限    <application        android:allowBackup="true"        android:icon="@drawable/recording_screen_nor"        android:label="@string/app_name"        android:supportsRtl="true">        <activity android:name="com.xinrui.recordscreen.MainActivity">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity></manifest>

更多相关文章

  1. 访问自己创建的Contentprovider 抛异常 提示Permission Denial:
  2. Ubuntu 将adb加入环境变量 及adb shell 无法启动
  3. Android热点、WiFi、蓝牙等功能开启和关闭
  4. Android(安卓)Camera应用初探二
  5. VMware View Client for iPAD、Android发布了!
  6. Android(安卓)语音通话模块介绍(一) 开源的SIP协议栈
  7. Android(安卓)9.0模拟器root权限获取
  8. Android(安卓)监听Home键
  9. Android(安卓)Launcher3 禁止用户拖动图标创建文件夹,控制拖动图

随机推荐

  1. Android Permission check的一点认知更新
  2. 有用链接
  3. 转:[Android]实现静默安装APK的两种方法
  4. 第十一篇 ANDROID 系统网络连接和管理机
  5. [安卓基础] 003.建立你的第一个App
  6. 【30篇突击 android】源码统计 十八
  7. Android动态加载Dex技术基础
  8. Android(安卓)Studio1.5使用和学习记录
  9. 【译】使用Kotlin从零开始写一个现代Andr
  10. Android之Goldfish