软件编程
位置:首页>> 软件编程>> Android编程>> Android 实现可任意拖动的悬浮窗功能(类似悬浮球)

Android 实现可任意拖动的悬浮窗功能(类似悬浮球)

作者:爱码士_yan  发布时间:2023-08-07 10:19:05 

标签:android,悬浮窗

最近开发项目中,有个在屏幕上任意拖动的悬浮窗功能,其实就是利用 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() - mOffsetToParent);
             mLayoutParams.y = (int) (event.getRawY() - mOffsetToParentY);
             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>

来源:https://blog.csdn.net/baidu_41666295/article/details/106384621

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com