Android 悬浮窗口(一)
前言
这章主要介绍 悬浮窗口
主要分为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 悬浮窗口(一)相关推荐
- Android 悬浮窗口
Android 悬浮窗口 一.创建悬浮窗口步骤 1.实现一个ViewGroup类,作为悬浮窗口的界面类,以便在里面重写onInterceptTouchEvent和onTouchEvent方法, ...
- android 悬浮窗口和主界面同时显示,Android 悬浮窗口(及解决6.0以上无法显示问题)...
思路实现 通过WindowManager添加一个View,创建一个系统顶级的窗口,实现悬浮窗口的效果. 本篇思路,来源于郭霖大神的悬浮窗口教程. 大致介绍WindowManager 类 创建的对象: ...
- Android 悬浮窗口(及解决6.0以上无法显示问题)
思路实现 通过WindowManager添加一个View,创建一个系统顶级的窗口,实现悬浮窗口的效果. 本篇思路,来源于郭霖大神的悬浮窗口教程. 大致介绍WindowManager 类 创建的对象: ...
- android悬浮窗口的实现
当我们在手机上使用360安全卫士时,手机屏幕上时刻都会出现一个小浮动窗口,点击该浮动窗口可跳转到安全卫士的操作界面,而且该浮动窗口不受其他activity的覆盖影响仍然可见(多米音乐也有相关的和主界面 ...
- Android悬浮窗口开发
注意: 1. 需要Context上下文,在绝大多数非原生系统上,context上下文会影响悬浮窗的显示范围.在MIUI和华为等国产系统上,使用Activity的Context只能显示在Activity ...
- Android悬浮窗口
随时随地技术实战干货,获取项目源码.学习资料,请关注源代码社区公众号(ydmsq666) FloatService: package com.home.floatwindow;import andro ...
- android 悬浮窗口禁止横屏显示,悬浮窗强制设置屏幕方向|App开发交流区|研发交流|雨滴科技技术论坛 - Powered by Discuz!...
最近在做平板上的一个程序,需要配合中通的app来控制扫描与分拣机的转动.然后中通的程序在平板上运行有一个问题, 就是app里设置了强制竖屏,不能跟随系统旋转应用屏幕方向,然后把系统里的屏幕方向写死,虽 ...
- android 悬浮窗口透明,悬浮视频窗口可调透明度_LG Optimus G Pro_手机Android频道-中关村在线...
在多媒体方面,由于LG-E985T配备的高通骁龙600有着强劲的CPU.GPU.多媒体支持,所以理论上来说,LG-E985T的多媒体实力理论上来讲自然是不俗.接下来我们实际测试一下它对于高清视频播放的 ...
- android悬浮窗口 关闭,Android悬浮窗的创建及关闭
最近有看到直播类App在退出房间的时候会生成小的悬浮窗,继续播放,甚至当App界面全部关闭之后,还可以悬浮到手机桌面播放.虽然我此功能感觉很流氓,但还是研究了下怎么实现这种效果.查阅相关资料后,发现这 ...
最新文章
- 大话设计模式之简单的工厂模式
- 台3岁女童疑把玩风枪致死案疑点多 警方将调查厘清
- Android 4.4 中 WebView 使用注意事项
- MyBatis-02 MyBatis XML方式概述及配置步骤
- nacos 怎么配置 里的配置ip_Nacos-服务注册地址为内网IP的解决办法
- Freemarker静态化ActiveMQ实现
- MySQL索引下推(5.6版本+)
- 【Linux】一步一步学Linux——exit命令(207)
- Docker介绍与安装使用(一)
- python高阶函数闭包装饰器_Python自学从入门到就业之高阶函数、嵌套函数、闭包、装饰器...
- mac java 版本_Mac 下 Java 多版本切换
- 一步步实现SDDC-NSX MGR安装和主机准备
- vs解决方案中添加文件夹
- const的理解、const指针、指向const的指针
- 四十五.加密与解密 AIDE入侵检测系统 扫描与抓包
- 头文件不应该含有非inline函数或对象的定义
- 简单的反编译class文件并重新编译的方法
- rabbitmq遇到的一些坑
- WinCE快捷方式浅析
- 【渝粤教育】国家开放大学2018年秋季 2408T中国当代文学 参考试题
热门文章
- cesium mars3d天地图标注置顶
- 华为手机创建文件夹失败
- JavaScript系列-02 HTML嵌入js代码的第二种方式
- 武邑中学2021高考成绩查询,拼百日酬壮志 誓圆梦铸辉煌——河北武邑中学2021年高三年级决胜高考誓师大会...
- 剑指offer 动画图解 | 变态跳台阶
- 抖音短视频APP——视频编辑改版产品设计
- SQL 注入攻击介绍
- 配置Clion+OpenOCD+Stm32CubeMX进行优雅的嵌入式开发
- Continuous collision detection (CCD) 连续式碰撞检测 Physics物理系列之三
- 如何使用python把json文件转换为csv文件