android 创建无界面程序,如何在Android中创建一个悬浮的界面

关键词: WindowManager , Activity属性 , uses-permission

前言:

最近在项目开发中碰到了一个问题,需要在android界面上显示一个悬浮的图标用于提示用户我的一个已经隐藏掉的Activity的一个内部的逻辑状态,同时开发的Android系统经过了第三方的深度定制,删除了系统的状态条。这就意味着我不得不:

1、显示一个可以无论在什么界面都能悬浮于窗口最顶端的一个图标——暂时定位为一个图标吧。

2、这个图标可支持一些基础的控制,比如拖动。

3、可以在应用程序中动态的控制这个图标,比如切换图片。

4、这个图标可以对应用程序进行一些基础的操作,比如唤起我的Activity。

如果你是一位不想拘泥于android状态栏的局限,或者想做一个恶心无比的程序(请自由联想)的程序猿,那么我的这篇文章可能能帮助到你。

正文:

其实在度娘的怀中我们可以摸到很多关于一个悬浮窗口的有用的demo,其基本是基于以下的一种方法:

WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);

WindowManager.LayoutParams params = StatusBarView.params;

params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT

| WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;

params.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL

| LayoutParams.FLAG_NOT_FOCUSABLE;

params.width = WindowManager.LayoutParams.WRAP_CONTENT;

params.height = WindowManager.LayoutParams.WRAP_CONTENT;

params.alpha = 1.0f;

//设置透明

params.format = PixelFormat.TRANSPARENT;

params.gravity=Gravity.LEFT|Gravity.TOP;

//以屏幕左上角为原点,设置x、y初始值

params.x = 0;

params.y = 0;

if(mStatusBar != null && mStatusBar.isShown()){

wm.removeView(mStatusBar);

}

if(mStatusBar == null){

mStatusBar = new StatusBarView(this);

}

//根据应用程序的状态更换图标

if(mModeManager.isMode1()) {

mStatusBar.setBackgroundResource(R.drawable.status_bar_1);

}else if(mModeManager.isMode2()) {

mStatusBar.setBackgroundResource(R.drawable.status_bar_2);

}else if(mInputModeManager.isDigitMode()){

mStatusBar.setBackgroundResource(R.drawable.status_bar_3);

}

wm.addView(mStatusBar, params);

如以上代码所示,其实简单的只是在windowManager中添加了一个我们自己写得界面,这里我的界面叫StatusBarView。具体的StatusBarView中的细节如下。

public class StatusBarView extends Button {

private static final String TAG = "MyStatusBarView";

private float x, y, startX, startY;

//用于在计算新坐标的时候的偏移量,与系统候选栏的高度有关。不是重点

public static int TOOL_BAR_HIGH = 0;

WindowManager wm = (WindowManager)getContext().getApplicationContext().

getSystemService(Context.WINDOW_SERVICE);

public static WindowManager.LayoutParams params = new WindowManager.LayoutParams();

public StatusBarView(Context context) {

super(context);

}

@Override

public boolean onTouchEvent(MotionEvent event) {

// 触摸点相对于屏幕左上角坐标

x = event.getRawX();

y = event.getRawY();

// Log.d(TAG, "------X: " + x + "------Y:" + y);

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

startX = event.getX();

startY = event.getY();

break;

case MotionEvent.ACTION_MOVE:

updatePosition();

break;

case MotionEvent.ACTION_UP:

updatePosition();

startX = startY = 0;

break;

}

return super.onTouchEvent(event);

}

// 更新状态栏位置参数

private void updatePosition() {

// View的当前位置

params.x = (int) (x - startX);

params.y = (int) (y - startY) - TOOL_BAR_HIGH;

wm.updateViewLayout(this, params);

}

}在我的StatusBarView我只继承自Button,其实如果有想法的话可以继承LinearLayout,然后inflate自己写得XML布局文件简单例如:

LayoutInflater inflater = (LayoutInflater) context

.getSystemService(FlyIME.LAYOUT_INFLATER_SERVICE);

View view = inflater.inflate(R.layout.status_bar_to_show, null);

this.addView(view);通过LinerLayout,很多东西,比如响应按键消息,就可以自由发挥了,这里我就暂不发散了。

需要注意重点是:

1、

这里我给我的View设定了一个这样的Type

params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT

| WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;这里需要你给你的程序加上一个

的权限,不然当你启动这个悬浮界面的时候你也许会在LogCat中抓住

Unable to add window android.view.ViewRoot$W@40645d80 -- permission denied for this window type

这样的错误。

2、

另外一个需要注意的问题是,如果各位在利用getApplicationContext()来getSystemService而不是用this时,将可能会抓到

Unable to add window -- token null is no for a application

的错误。其实this和getApplicationContext()是不一样的,具体的大家可以在度娘的怀中摸一下,应该容易摸到相关的东西。

结语:

总结了实现方法和可能出错的地方,祝各位顺利的实现自己的浮动窗口。

如果您有任何相关方面的补充,有趣的发现,或者实践过程中的问题,欢迎与我联系

### UniApp 中自定义相机权限获取方式及 Package.json 依赖分析 #### 自定义相机权限获取方法 在 UniApp 应用中,可以通过 `plus.runtime.isApplicationExist` 和 `plus.android.requestPermissions` 等 API 来实现更精细的权限管理。然而,考虑到跨平台兼容性和简化开发流程,通常推荐使用内置的 `uni.authorize` 方法来请求权限。 以下是基于 Android 平台的相机权限获取示例代码: ```javascript function checkAndRequestCameraPermission() { return new Promise((resolve, reject) => { uni.getSetting({ success(res) { if (!res.authSetting['scope.camera']) { // 如果未授权,则发起授权请求 uni.authorize({ scope: 'scope.camera', success() { resolve(true); // 授权成功 }, fail(err) { reject(new Error('用户拒绝授予相机权限')); // 授权失败 } }); } else { resolve(true); // 已经拥有相机权限 } }, fail(err) { reject(new Error('无法获取当前权限状态')); } }); }); } // 调用函数 checkAndRequestCameraPermission() .then(() => console.log('相机权限已获取')) .catch(err => console.error(`相机权限获取失败: ${err.message}`)); ``` 此代码片段展示了如何通过 `uni.getSetting` 和 `uni.authorize` 动态检查并请求相机权限[^1]。需要注意的是,在某些特殊场景下(如 Android 13 及更高版本),还需要额外考虑运行时权限的动态申请逻辑。 对于 Android 设备上的高级需求,可借助 `plus.android.requestPermissions` 进一步增强控制能力。例如: ```javascript if (window.plus && window.plus.os.name === 'Android') { let permissions = ['android.permission.CAMERA']; plus.android.requestPermissions( permissions, function (result) { if (result.granted.length > 0) { console.log('相机权限已被授予'); } else { console.warn('相机权限被拒绝'); } }, function () { console.error('请求权限失败'); } ); } ``` 这段代码适用于需要针对 Android 特定功能进行扩展的情况[^1]。 --- #### Package.json 文件中的依赖关系分析 假设我们有一个典型的 UniApp 项目结构,其 `package.json` 文件可能如下所示: ```json { "name": "my-uniapp-project", "version": "1.0.0", "description": "A simple UniApp project with custom camera functionality.", "scripts": { "dev": "vue-cli-service serve", "build:h5": "vue-cli-service build --mode production", "preview": "hbuilderx preview" }, "dependencies": { "@dcloudio/uni-app-plus": "^3.7.0", "@dcloudio/uni-h5": "^3.7.0", "@dcloudio/vue-cli-plugin-uni": "^3.7.0", "axios": "^0.27.2", "dayjs": "^1.10.8" }, "devDependencies": { "@babel/core": "^7.20.12", "@babel/eslint-parser": "^7.20.3", "@types/node": "^16.11.45", "eslint": "^8.26.0", "eslint-config-standard-with-typescript": "^24.0.0", "eslint-plugin-vue": "^9.7.0", "typescript": "^4.9.4", "vue-template-compiler": "^2.7.14" } } ``` ##### 主要依赖解析 1. **核心框架** - `@dcloudio/uni-app-plus`: 提供了完整的 UniApp 开发生态支持,包括但不限于 HBuilderX 集成工具链以及底层 SDK 的封装[^3]。 - `@dcloudio/uni-h5`: 支持将 UniApp 应用编译为目标 HTML5 页面,便于部署至 Web 浏览器环境中[^3]。 2. **第三方库** - `axios`: HTTP 客户端用于数据交互,适合处理 RESTful API 请求[^3]。 - `dayjs`: 替代 Moment.js 的轻量级日期时间处理库,能够有效减少打包体积[^3]。 3. **开发辅助工具** - Babel 相关包 (`@babel/core`, `@babel/eslint-parser`):JavaScript 编译器及其插件集合,帮助转换现代 JavaScript 语法以适配旧版浏览器或运行环境[^3]。 - ESLint 插件系列 (`eslint`, `eslint-config-standard-with-typescript`, `eslint-plugin-vue`):静态代码分析工具集,保障代码质量与一致性。 - TypeScript 类型声明文件及相关构建工具 (`typescript`, `vue-template-compiler`):引入强类型系统提升开发效率的同时保持灵活性[^3]。 --- ### 总结 UniApp 提供了一套简单易用但又不失强大的 API 来满足开发者关于相机权限及其他资源访问的需求。与此同时,合理规划项目的依赖项有助于提高性能表现、降低维护成本,并最终带来更好的用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值