前言

这章主要介绍 悬浮窗口
主要分为2种
1:悬浮在所有窗口上
2:悬浮在当前窗口上
这章讲述 悬浮在所有窗口上

1 准备
Android studio 4.1.1 或以上
win7 或以上

2 悬浮在所有窗口上
1> 需要注册个service

AndroidManifest.xml 如下

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.testfloatallwindow"><uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /><!--uses-permission android:name="android.permission.CAMERA" /--><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.Testfloatallwindow"><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><service android:name=".FloatingVideoService"></service></application></manifest>

2> 布局
activity_main.xml

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical">
<TextViewandroid:id="@+id/show_text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello World!" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="start"android:onClick="startbtn"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="close"android:onClick="closebtn"/></LinearLayout>

video_display.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><!--androidx.camera.view.PreviewViewandroid:id="@+id/video_display_surfaceview"android:layout_width="wrap_content"android:layout_height="wrap_content" /--><SurfaceViewandroid:id="@+id/video_display_surfaceview"android:layout_width="wrap_content"android:layout_height="wrap_content" /></LinearLayout>app下的build.gradle```clike
plugins {id 'com.android.application'
}android {compileSdkVersion 33buildToolsVersion "33.0.0"defaultConfig {applicationId "com.example.testfloatallwindow"minSdkVersion 23targetSdkVersion 33versionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}compileOptions {sourceCompatibility JavaVersion.VERSION_1_8targetCompatibility JavaVersion.VERSION_1_8}
}dependencies {implementation 'androidx.appcompat:appcompat:1.1.0'implementation 'com.google.android.material:material:1.1.0'implementation 'androidx.constraintlayout:constraintlayout:1.1.3'testImplementation 'junit:junit:4.+'androidTestImplementation 'androidx.test.ext:junit:1.1.1'androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'//附加的implementation 'org.apache.commons:commons-pool2:2.9.0'def camerax_version = "1.1.0-beta03"
// CameraX core libraryimplementation "androidx.camera:camera-core:$camerax_version"
// CameraX Camera2 extensions[可选]拓展库可实现人像、HDR、夜间和美颜、滤镜但依赖于OEMimplementation "androidx.camera:camera-camera2:$camerax_version"
// CameraX Lifecycle library[可选]避免手动在生命周期释放和销毁数据implementation "androidx.camera:camera-lifecycle:$camerax_version"
// CameraX View class[可选]最佳实践,最好用里面的PreviewView,它会自行判断用SurfaceView还是TextureView来实现implementation "androidx.camera:camera-view:$camerax_version"implementation "androidx.camera:camera-extensions:${camerax_version}"
}

app 下的 build.gradle

plugins {id 'com.android.application'
}android {compileSdkVersion 33buildToolsVersion "33.0.0"defaultConfig {applicationId "com.example.testcamerax"minSdkVersion 23targetSdkVersion 30versionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}compileOptions {sourceCompatibility JavaVersion.VERSION_1_8targetCompatibility JavaVersion.VERSION_1_8}
}dependencies {implementation 'androidx.appcompat:appcompat:1.1.0'implementation 'com.google.android.material:material:1.1.0'implementation 'androidx.constraintlayout:constraintlayout:1.1.3'testImplementation 'junit:junit:4.+'androidTestImplementation 'androidx.test.ext:junit:1.1.1'androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'def camerax_version = "1.2.0"    //"1.1.0-beta03"
// CameraX core libraryimplementation "androidx.camera:camera-core:$camerax_version"
// CameraX Camera2 extensions[可选]拓展库可实现人像、HDR、夜间和美颜、滤镜但依赖于OEMimplementation "androidx.camera:camera-camera2:$camerax_version"
// CameraX Lifecycle library[可选]避免手动在生命周期释放和销毁数据implementation "androidx.camera:camera-lifecycle:$camerax_version"
// CameraX View class[可选]最佳实践,最好用里面的PreviewView,它会自行判断用SurfaceView还是TextureView来实现implementation "androidx.camera:camera-view:$camerax_version"implementation "androidx.camera:camera-extensions:${camerax_version}"// If you want to additionally use the CameraX VideoCapture libraryimplementation "androidx.camera:camera-video:${camerax_version}"// CameraX core library using the camera2 implementation//  def camerax_version = "1.2.0-alpha02" //1.2.0-alpha02
// The following line is optional, as the core library is included indirectly by camera-camera2/*   implementation "androidx.camera:camera-core:${camerax_version}"implementation "androidx.camera:camera-camera2:${camerax_version}"
// If you want to additionally use the CameraX Lifecycle libraryimplementation "androidx.camera:camera-lifecycle:${camerax_version}"
// If you want to additionally use the CameraX VideoCapture libraryimplementation "androidx.camera:camera-video:${camerax_version}"
// If you want to additionally use the CameraX View classimplementation "androidx.camera:camera-view:${camerax_version}"
// If you want to additionally add CameraX ML Kit Vision Integrationimplementation "androidx.camera:camera-mlkit-vision:${camerax_version}"
// If you want to additionally use the CameraX Extensions libraryimplementation "androidx.camera:camera-extensions:${camerax_version}"*/
}
3>代码MainActivity.java```clike
package com.example.testfloatallwindow;import androidx.appcompat.app.AppCompatActivity;import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.Toast;public class MainActivity extends AppCompatActivity {//绑定方式 启动
//    private FloatingVideoService service = null;
//    private boolean isBound = false;
//
//    private ServiceConnection conn = new ServiceConnection() {
//        @Override
//        public void onServiceConnected(ComponentName name, IBinder binder) {
//            isBound = true;
//            FloatingVideoService.MyBinder myBinder = (FloatingVideoService.MyBinder)binder;
//            service = myBinder.getService();
//            Log.i("DemoLog", "ActivityA onServiceConnected");
//            //  int num = service.getRandomNumber();
//            //  Log.i("DemoLog", "ActivityA 中调用 TestService的getRandomNumber方法, 结果: " + num);
//        }
//
//        @Override
//        public void onServiceDisconnected(ComponentName name) {
//            isBound = false;
//            Log.i("DemoLog", "ActivityA onServiceDisconnected");
//        }
//    };@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void startbtn(View view) {if (FloatingVideoService.isStarted) {return;}if (!Settings.canDrawOverlays(this)) {Toast.makeText(this, "当前无权限,请授权", Toast.LENGTH_SHORT);startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), 2);} else {startService(new Intent(MainActivity.this, FloatingVideoService.class));}}public  void closebtn(View view){//unbindService(conn);stopService(new Intent(MainActivity.this,FloatingVideoService.class));}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (requestCode == 0) {if (!Settings.canDrawOverlays(this)) {Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show();} else {Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();startService(new Intent(MainActivity.this, FloatingVideoService.class));}} else if (requestCode == 1) {if (!Settings.canDrawOverlays(this)) {Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show();} else {Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();startService(new Intent(MainActivity.this, FloatingVideoService.class));}} else if (requestCode == 2) {if (!Settings.canDrawOverlays(this)) {Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show();} else {Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();startService(new Intent(MainActivity.this, FloatingVideoService.class));}}}
}

FloatingVideoService.java

package com.example.testfloatallwindow;import android.annotation.SuppressLint;
import android.app.Service;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.provider.Settings;
import android.util.Log;
import android.util.Size;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.Preview;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.content.ContextCompat;import com.google.common.util.concurrent.ListenableFuture;import java.io.IOException;
import java.util.concurrent.ExecutorService;public class FloatingVideoService extends Service {public static boolean isStarted = false;private WindowManager windowManager;private WindowManager.LayoutParams layoutParams;private MediaPlayer mediaPlayer;private View displayView;public static boolean bSetup = true;public static final int DMS_INPUT_IMG_W = 640;public static final int DMS_INPUT_IMG_H = 480;//private final String TAG = MainActivity.class.getName() ;private final int REQUEST_CODE_CONTACT = 1;private boolean isBackCamera =false;private ExecutorService cameraExecutor;private ProcessCameraProvider mCameraPRrovider = null;////下面的可以去掉,bind connect 方式 服务public class MyBinder extends Binder{public FloatingVideoService getService(){return FloatingVideoService.this;}}//通过binder实现调用者client与Service之间的通信private MyBinder binder = new MyBinder();public void methodInService() {Log.i("MyService", "执行服务钟的methodInService()方法");}@Overridepublic boolean onUnbind(Intent intent) {Log.i("MyService","jiebang ");return super.onUnbind(intent);}@Overridepublic IBinder onBind(Intent intent) {Log.i("MyService","绑定服务");return null; //new MyBinder();}@Overridepublic void onCreate() {super.onCreate();isStarted = true;windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);layoutParams = new WindowManager.LayoutParams();if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; //TYPE_APPLICATION_SUB_PANEL ; //TYPE_APPLICATION_OVERLAY;} else {layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;}layoutParams.format = PixelFormat.RGBA_8888;layoutParams.gravity = Gravity.LEFT | Gravity.TOP;layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;layoutParams.width = DMS_INPUT_IMG_W;layoutParams.height = DMS_INPUT_IMG_H;layoutParams.x = 300;layoutParams.y = 300;mediaPlayer = new MediaPlayer();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {showFloatingWindowVideo();return super.onStartCommand(intent, flags, startId);}private void showFloatingWindowVideo() {if (Settings.canDrawOverlays(this)) {LayoutInflater layoutInflater = LayoutInflater.from(this);displayView = layoutInflater.inflate(R.layout.video_display, null);displayView.setOnTouchListener(new FloatingOnTouchListener());mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);SurfaceView surfaceView = displayView.findViewById(R.id.video_display_surfaceview);final SurfaceHolder surfaceHolder = surfaceView.getHolder();surfaceHolder.addCallback(new SurfaceHolder.Callback() {@Overridepublic void surfaceCreated(SurfaceHolder holder) {mediaPlayer.setDisplay(surfaceHolder);}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {}});mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {@Overridepublic void onPrepared(MediaPlayer mp) {mediaPlayer.start();}});try {mediaPlayer.setDataSource(this, Uri.parse("视屏地址url"));mediaPlayer.prepareAsync();}catch (IOException e) {Toast.makeText(this, "打开失败", Toast.LENGTH_LONG).show();}windowManager.addView(displayView, layoutParams);bSetup = true ;}}private void showFloatingWindowCamera() {if (Settings.canDrawOverlays(this)) {LayoutInflater layoutInflater = LayoutInflater.from(this);displayView = layoutInflater.inflate(R.layout.video_display, null);displayView.setOnTouchListener(new FloatingOnTouchListener());SurfaceView surfaceView = displayView.findViewById(R.id.video_display_surfaceview);final SurfaceHolder surfaceHolder = surfaceView.getHolder();surfaceHolder.addCallback(new SurfaceHolder.Callback() {@Overridepublic void surfaceCreated(SurfaceHolder holder) {}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {}});windowManager.addView(displayView, layoutParams);bSetup = true ;}}private void setupCamera(){// 将Camera的生命周期和Activity绑定在一起(设定生命周期所有者),这样就不用手动控制相机的启动和关闭。ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this);cameraProviderFuture.addListener(() -> {try {// 将你的相机和当前生命周期的所有者绑定所需的对象ProcessCameraProvider mCameraPRrovider = cameraProviderFuture.get();////要预览开启下面3句 + processCameraProvider.bindToLifecycle(MainActivity.this, cameraSelector,//                        imageAnalysis,preview);  preview 加上,不要预览就去跳// 创建一个Preview 实例,并设置该实例的 surface 提供者(provider)。LayoutInflater layoutInflater = LayoutInflater.from(this);displayView = layoutInflater.inflate(R.layout.video_display, null);displayView.setOnTouchListener(new FloatingOnTouchListener());PreviewView viewFinder = displayView.findViewById(R.id.video_display_surfaceview);//   PreviewView viewFinder = (PreviewView)findViewById(R.id.viewFinder);Preview preview = new Preview.Builder().build();preview.setSurfaceProvider(viewFinder.getSurfaceProvider());windowManager.addView(displayView, layoutParams);///// 选择前置摄像头作为默认摄像头CameraSelector cameraSelector = isBackCamera?CameraSelector.DEFAULT_BACK_CAMERA:CameraSelector.DEFAULT_FRONT_CAMERA;// 创建拍照所需的实例//   imageCapture = new ImageCapture.Builder().build();// 设置预览帧分析
//                ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
//                        .build();//ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888ImageAnalysis imageAnalysis = new ImageAnalysis.Builder().setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888).setTargetResolution(new Size(DMS_INPUT_IMG_W, DMS_INPUT_IMG_H)) // 图片的建议尺寸.setOutputImageRotationEnabled(true) // 是否旋转分析器中得到的图片.setTargetRotation(Surface.ROTATION_0) // 允许旋转后 得到图片的旋转设置.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST).setImageQueueDepth(1).build();//  imageAnalysis.setAnalyzer(cameraExecutor, new MyAnalyzer());imageAnalysis.setAnalyzer(cameraExecutor, imageProxy -> {int picformat = imageProxy.getFormat();if(imageProxy.getFormat() == ImageFormat.YUV_420_888){//                        byte[] data = test2(imageProxy);
//                        onPreviewResult(data);//  byte[] data = bitmap.// byte[] data =  getUvData(imageProxy);// onPreviewResult(data);//  Image  image =  imageProxy.getImage();// ImageProxy.PlaneProxy[] mPlanes = imageProxy.getPlanes();//  byte[] data = YUV_420_888toNV21(mPlanes[0].getBuffer(),mPlanes[1].getBuffer(),mPlanes[2].getBuffer());//  byte[] data = BitmapUtils.yuv420ThreePlanesToNV21(image.getPlanes(),DMS_INPUT_IMG_W,DMS_INPUT_IMG_H);// onPreviewResult(data);
//                        ImageProxy.PlaneProxy mY = mPlanes[0];//Y分量
//                        ImageProxy.PlaneProxy mU = mPlanes[1];//U分量
//                        ImageProxy.PlaneProxy mV = mPlanes[2];//V风量
//                        Log.e(TAG, "planes0:" + mY.getPixelStride() + " planes1:" + mU.getPixelStride() + " planes2:" + mV.getPixelStride());}else if(imageProxy.getFormat() == ImageFormat.FLEX_RGBA_8888 || picformat == PixelFormat.RGBA_8888){//                        ImageProxy.PlaneProxy[] mPlanes = imageProxy.getPlanes();
//                        imageProxy.getPlanes()[0].getBuffer().get(0); //alpha透明度
//                        imageProxy.getPlanes()[0].getBuffer().get(1); //red红色
//                        imageProxy.getPlanes()[0].getBuffer().get(2); //green绿色
//                        imageProxy.getPlanes()[0].getBuffer().get(3); //blue蓝色
//                            @SuppressLint("UnsafeOptInUsageError") Bitmap bitmap = toBitmap(imageProxy.getImage());
//                            Bitmap bitmap1 = alterSizeBitmap(bitmap,DMS_INPUT_IMG_W,DMS_INPUT_IMG_H);
//                            byte[] data =  getNV21FromBitmap(bitmap1);
//                            onPreviewResult(data);}imageProxy.close(); // 最后要关闭这个});// 重新绑定用例前先解绑mCameraPRrovider.unbindAll();// 绑定用例至相机//需要LifecycleOwner view
//                    mCameraPRrovider.bindToLifecycle(this, cameraSelector,
//                            imageAnalysis,preview);} catch (Exception e) {Log.e(TAG, "用例绑定失败!" + e);}}, ContextCompat.getMainExecutor(this));}@Overridepublic void onDestroy() {if(windowManager !=null && layoutParams !=null) {if(bSetup){windowManager.removeView(displayView);bSetup = false ;isStarted = false;}}super.onDestroy();}private class FloatingOnTouchListener implements View.OnTouchListener {private int x;private int y;@Overridepublic boolean onTouch(View view, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:x = (int) event.getRawX();y = (int) event.getRawY();break;case MotionEvent.ACTION_MOVE:int nowX = (int) event.getRawX();int nowY = (int) event.getRawY();int movedX = nowX - x;int movedY = nowY - y;x = nowX;y = nowY;layoutParams.x = layoutParams.x + movedX;layoutParams.y = layoutParams.y + movedY;windowManager.updateViewLayout(view, layoutParams);break;default:break;}return true;}}
}//生命周期上的区别//执行startService时,Service会经历onCreate->onStartCommand。当执行stopService时,直接调用onDestroy方法。调用者如果没有stopService,Service会一直在后台运行,下次调用者再起来仍然可以stopService。//执行bindService时,Service会经历onCreate->onBind。这个时候调用者和Service绑定在一起。调用者调用unbindService方法或者调用者Context不存在了(如Activity被finish了),Service就会调用onUnbind->onDestroy。这里所谓的绑定在一起就是说两者共存亡了。**3 运行结果**
视屏地址自行修改,当前地址瞎写,所以播放不出
![在这里插入图片描述](https://img-blog.csdnimg.cn/bae22975ec154dd8ab728bffc5a28503.png)**4下章讲述悬浮在当前窗口上**

Android 悬浮窗口(一)相关推荐

  1. Android 悬浮窗口

    Android 悬浮窗口 一.创建悬浮窗口步骤     1.实现一个ViewGroup类,作为悬浮窗口的界面类,以便在里面重写onInterceptTouchEvent和onTouchEvent方法, ...

  2. android 悬浮窗口和主界面同时显示,Android 悬浮窗口(及解决6.0以上无法显示问题)...

    思路实现 通过WindowManager添加一个View,创建一个系统顶级的窗口,实现悬浮窗口的效果. 本篇思路,来源于郭霖大神的悬浮窗口教程. 大致介绍WindowManager 类 创建的对象: ...

  3. Android 悬浮窗口(及解决6.0以上无法显示问题)

    思路实现 通过WindowManager添加一个View,创建一个系统顶级的窗口,实现悬浮窗口的效果. 本篇思路,来源于郭霖大神的悬浮窗口教程. 大致介绍WindowManager 类 创建的对象: ...

  4. android悬浮窗口的实现

    当我们在手机上使用360安全卫士时,手机屏幕上时刻都会出现一个小浮动窗口,点击该浮动窗口可跳转到安全卫士的操作界面,而且该浮动窗口不受其他activity的覆盖影响仍然可见(多米音乐也有相关的和主界面 ...

  5. Android悬浮窗口开发

    注意: 1. 需要Context上下文,在绝大多数非原生系统上,context上下文会影响悬浮窗的显示范围.在MIUI和华为等国产系统上,使用Activity的Context只能显示在Activity ...

  6. Android悬浮窗口

    随时随地技术实战干货,获取项目源码.学习资料,请关注源代码社区公众号(ydmsq666) FloatService: package com.home.floatwindow;import andro ...

  7. android 悬浮窗口禁止横屏显示,悬浮窗强制设置屏幕方向|App开发交流区|研发交流|雨滴科技技术论坛 - Powered by Discuz!...

    最近在做平板上的一个程序,需要配合中通的app来控制扫描与分拣机的转动.然后中通的程序在平板上运行有一个问题, 就是app里设置了强制竖屏,不能跟随系统旋转应用屏幕方向,然后把系统里的屏幕方向写死,虽 ...

  8. android 悬浮窗口透明,悬浮视频窗口可调透明度_LG Optimus G Pro_手机Android频道-中关村在线...

    在多媒体方面,由于LG-E985T配备的高通骁龙600有着强劲的CPU.GPU.多媒体支持,所以理论上来说,LG-E985T的多媒体实力理论上来讲自然是不俗.接下来我们实际测试一下它对于高清视频播放的 ...

  9. android悬浮窗口 关闭,Android悬浮窗的创建及关闭

    最近有看到直播类App在退出房间的时候会生成小的悬浮窗,继续播放,甚至当App界面全部关闭之后,还可以悬浮到手机桌面播放.虽然我此功能感觉很流氓,但还是研究了下怎么实现这种效果.查阅相关资料后,发现这 ...

最新文章

  1. 大话设计模式之简单的工厂模式
  2. 台3岁女童疑把玩风枪致死案疑点多 警方将调查厘清
  3. Android 4.4 中 WebView 使用注意事项
  4. MyBatis-02 MyBatis XML方式概述及配置步骤
  5. nacos 怎么配置 里的配置ip_Nacos-服务注册地址为内网IP的解决办法
  6. Freemarker静态化ActiveMQ实现
  7. MySQL索引下推(5.6版本+)
  8. 【Linux】一步一步学Linux——exit命令(207)
  9. Docker介绍与安装使用(一)
  10. python高阶函数闭包装饰器_Python自学从入门到就业之高阶函数、嵌套函数、闭包、装饰器...
  11. mac java 版本_Mac 下 Java 多版本切换
  12. 一步步实现SDDC-NSX MGR安装和主机准备
  13. vs解决方案中添加文件夹
  14. const的理解、const指针、指向const的指针
  15. 四十五.加密与解密 AIDE入侵检测系统 扫描与抓包
  16. 头文件不应该含有非inline函数或对象的定义
  17. 简单的反编译class文件并重新编译的方法
  18. rabbitmq遇到的一些坑
  19. WinCE快捷方式浅析
  20. 【渝粤教育】国家开放大学2018年秋季 2408T中国当代文学 参考试题

热门文章

  1. cesium mars3d天地图标注置顶
  2. 华为手机创建文件夹失败
  3. JavaScript系列-02 HTML嵌入js代码的第二种方式
  4. 武邑中学2021高考成绩查询,拼百日酬壮志 誓圆梦铸辉煌——河北武邑中学2021年高三年级决胜高考誓师大会...
  5. 剑指offer 动画图解 | 变态跳台阶
  6. 抖音短视频APP——视频编辑改版产品设计
  7. SQL 注入攻击介绍
  8. 配置Clion+OpenOCD+Stm32CubeMX进行优雅的嵌入式开发
  9. Continuous collision detection (CCD) 连续式碰撞检测 Physics物理系列之三
  10. 如何使用python把json文件转换为csv文件