背景
懸浮視圖或者窗體,在Android和iOS兩大移動平臺均有使用,HarmonyOS 也實現(xiàn)了此功能,如下為大家分享一下效果
準(zhǔn)備
- 熟讀HarmonyOS 懸浮窗口指導(dǎo)
- 熟讀HarmonyOS 手勢指導(dǎo)
- 熟讀ALC簽名指導(dǎo),用于可以申請 “ohos.permission.SYSTEM_FLOAT_WINDOW” 權(quán)限。
- 熟悉的文檔在下方
|
實踐代碼
- 如果開啟了懸浮窗口,任何界面的物理返回鍵事件都會被懸浮窗口攔截掉,即 手勢返回廢了
- 參數(shù)類型易混淆, 拖動 PanGesture 中的onActionUpdate接口,數(shù)據(jù)單位為 vp ,window中的 moveWindowTo接口參數(shù),數(shù)據(jù)單位為px
- 采用moveWindowTo實現(xiàn)的窗口拖動效果十分不平滑
- 通過 requestPermissionsFromUser 申請 ohos.permission.SYSTEM_FLOAT_WINDOW 權(quán)限時,無法彈出系統(tǒng)權(quán)限提示框
片段代碼
配置module.json5
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
"phone",
"tablet"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"abilities": [
......
{
"name": "FloatWindowAbility",
"srcEntry": "./ets/myentryability/FloatWindowAbility.ts",
"description": "$string:FloatWindowAbility_desc",
"icon": "$media:icon",
"label": "$string:FloatWindowAbility_label",
"startWindowIcon": "$media:icon",
"startWindowBackground": "$color:start_window_background",
},
],
"requestPermissions": [
{
"name": "ohos.permission.SYSTEM_FLOAT_WINDOW",
"usedScene": {
"abilities": [
"FloatWindowAbility"
],
"when": "always"
}
}
]
}
}
懸浮窗口UIAbility
import window from '@ohos.window';
import BaseUIAbility from '../baseuiability/BaseUIAbility';
import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
import bundleManager from '@ohos.bundle.bundleManager';
const permissions: Array< Permissions > = ['ohos.permission.SYSTEM_FLOAT_WINDOW'];
export default class FloatWindowAbility extends BaseUIAbility {
onWindowStageCreate(windowStage: window.WindowStage) {
// Main window is created, set main page for this ability
let context = this.context;
let atManager = abilityAccessCtrl.createAtManager();
checkPermissions().then((result)= >{
if(result){
// requestPermissionsFromUser會判斷權(quán)限的授權(quán)狀態(tài)來決定是否喚起彈窗
atManager.requestPermissionsFromUser(context, permissions).then((data) = > {
let grantStatus: Array< number > = data.authResults;
let length: number = grantStatus.length;
for (let i = 0; i < length; i++) {
if (grantStatus[i] === 0) {
// 用戶授權(quán),可以繼續(xù)訪問目標(biāo)操作
console.log('用戶授權(quán),可以繼續(xù)訪問目標(biāo)操作')
} else {
// 用戶拒絕授權(quán),提示用戶必須授權(quán)才能訪問當(dāng)前頁面的功能,并引導(dǎo)用戶到系統(tǒng)設(shè)置中打開相應(yīng)的權(quán)限
console.log('用戶拒絕授權(quán),提示用戶必須授權(quán)才能訪問當(dāng)前頁面的功能,并引導(dǎo)用戶到系統(tǒng)設(shè)置中打開相應(yīng)的權(quán)限')
return;
}
}
// 授權(quán)成功
// 1.創(chuàng)建懸浮窗。
let windowClass = null;
let config = {name: "floatWindow", windowType: window.WindowType.TYPE_FLOAT, ctx: this.context};
window.createWindow(config, (err, data) = > {
if (err.code) {
console.error('Failed to create the floatWindow. Cause: ' + JSON.stringify(err));
return;
}
console.info('Succeeded in creating the floatWindow. Data: ' + JSON.stringify(data));
windowClass = data;
// 2.懸浮窗窗口創(chuàng)建成功后,設(shè)置懸浮窗的位置、大小及相關(guān)屬性等。
windowClass.moveWindowTo(0, 200, (err) = > {
if (err.code) {
console.error('Failed to move the window. Cause:' + JSON.stringify(err));
return;
}
console.info('Succeeded in moving the window.');
});
windowClass.resize(1080, 151, (err) = > {
if (err.code) {
console.error('Failed to change the window size. Cause:' + JSON.stringify(err));
return;
}
console.info('Succeeded in changing the window size.');
});
// 3.為懸浮窗加載對應(yīng)的目標(biāo)頁面。
windowClass.setUIContent("custompages/FloatPage", (err) = > {
if (err.code) {
console.error('Failed to load the content. Cause:' + JSON.stringify(err));
return;
}
console.info('Succeeded in loading the content.');
// 3.顯示懸浮窗。
windowClass.showWindow((err) = > {
if (err.code) {
console.error('Failed to show the window. Cause: ' + JSON.stringify(err));
return;
}
console.info('Succeeded in showing the window.');
});
try {
windowClass.setWindowBackgroundColor('#00000000')
} catch (exception) {
console.error('Failed to set the background color. Cause: ' + JSON.stringify(exception));
}
});
})
}).catch((err) = > {
console.error(`requestPermissionsFromUser failed, code is ${err.code}, message is ${err.message}`);
})
}
})
}
}
async function checkAccessToken(permission: Permissions): Promise< abilityAccessCtrl.GrantStatus > {
let atManager = abilityAccessCtrl.createAtManager();
let grantStatus: abilityAccessCtrl.GrantStatus;
// 獲取應(yīng)用程序的accessTokenID
let tokenId: number;
try {
let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;
tokenId = appInfo.accessTokenId;
} catch (err) {
console.error(`getBundleInfoForSelf failed, code is ${err.code}, message is ${err.message}`);
}
// 校驗應(yīng)用是否被授予權(quán)限
try {
grantStatus = await atManager.checkAccessToken(tokenId, permission);
} catch (err) {
console.error(`checkAccessToken failed, code is ${err.code}, message is ${err.message}`);
}
return grantStatus;
}
async function checkPermissions(): Promise< boolean > {
const permissions: Array< Permissions > = ['ohos.permission.SYSTEM_FLOAT_WINDOW'];
let grantStatus: abilityAccessCtrl.GrantStatus = await checkAccessToken(permissions[0]);
if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
// 已經(jīng)授權(quán),可以繼續(xù)訪問目標(biāo)操作
console.log('沒有授權(quán)')
return true
} else {
// 申請日歷權(quán)限
console.log('已授權(quán)')
return false
}
}
懸浮窗口頁面
import common from '@ohos.app.ability.common';
import window from '@ohos.window';
@Entry
@Component
struct Index {
@State lasttime: number = 0
@State message: string = '懸浮窗'
@State foldStatus: boolean = false
@State idleName: string = '收起'
@State floatWindowWidth: number = 0
@State offsetX: number = 0
@State offsetY: number = 0
@State positionX: number = 0
@State positionY: number = 0
@State windowPosition: Position = { x: 0, y: 0 };
private context = getContext(this) as common.UIAbilityContext;
private panOption: PanGestureOptions = new PanGestureOptions({ direction: PanDirection.All });
floatWindow: window.Window
aboutToAppear(){
this.eventHubFunc()
this.floatWindow = window.findWindow("floatWindow")
this.floatWindowWidth = 1080
this.panOption.setDistance(1)
}
onBackPress(){
console.log('返回')
}
build() {
Row() {
Text('X').width(px2vp(140))
.textAlign(TextAlign.Center)
.fontColor(Color.Red).onClick(()= >{
//關(guān)閉所依賴的UIAbility
this.context.terminateSelf()
//銷毀懸浮窗。當(dāng)不再需要懸浮窗時,可根據(jù)具體實現(xiàn)邏輯,使用destroy對其進行銷毀。
this.floatWindow.destroyWindow((err) = > {
if (err.code) {
console.error('Failed to destroy the window. Cause: ' + JSON.stringify(err));
return;
}
console.info('Succeeded in destroying the window.');
});
})
Text(this.idleName)
.width(px2vp(140))
.height('100%')
.fontSize(18)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.backgroundColor(Color.Gray)
.onClick(()= >{
this.foldStatus = !this.foldStatus
if(this.foldStatus){
this.idleName = "展開"
this.floatWindowWidth = 280
} else {
this.idleName = "收起"
this.floatWindowWidth = 1080
}
})
Divider().vertical(true).color(Color.Red)
if(!this.foldStatus) {
Text(this.message)
.width(px2vp(800))
.fontSize(18)
.fontColor(Color.White)
.padding('12vp')
}
}
.width(px2vp(this.floatWindowWidth))
.height(px2vp(150))
.borderRadius('12vp')
.backgroundColor(Color.Green)
.gesture(
// 綁定PanGesture事件,監(jiān)聽拖拽動作
PanGesture(this.panOption)
.onActionStart((event: GestureEvent) = > {
console.info('Pan start');
})
// 發(fā)生拖拽時,獲取到觸摸點的位置,并將位置信息傳遞給windowPosition
.onActionUpdate((event: GestureEvent) = > {
console.log(event.offsetX +' ' + event.offsetY)
this.offsetX = this.positionX + event.offsetX
this.offsetY = this.positionY + event.offsetY
this.floatWindow.moveWindowTo(vp2px(this.offsetX), vp2px(this.offsetY));
})
.onActionEnd(() = > {
this.positionX = this.offsetX
this.positionY = this.offsetY
console.info('Pan end');
})
)
}
eventHubFunc() {
this.context.eventHub.on('info', (data) = > {
this.message = data
});
}
}
審核編輯 黃宇
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。
舉報投訴
-
鴻蒙
+關(guān)注
關(guān)注
57文章
2302瀏覽量
42689 -
HarmonyOS
+關(guān)注
關(guān)注
79文章
1966瀏覽量
29962 -
鴻蒙OS
+關(guān)注
關(guān)注
0文章
188瀏覽量
4359
發(fā)布評論請先 登錄
相關(guān)推薦
鴻蒙OS元服務(wù)開發(fā):【(Stage模型)設(shè)置懸浮窗】
懸浮窗可以在已有的任務(wù)基礎(chǔ)上,創(chuàng)建一個始終在前臺顯示的窗口。即使創(chuàng)建懸浮窗的任務(wù)退至后臺,懸浮窗仍然可以在前臺顯示。通常懸浮窗位于所有應(yīng)用
鴻蒙實戰(zhàn)基礎(chǔ)(ArkTS)-窗口管理
(CommonConstants.HOME_PAGE_ACTION);
}, CommonConstants.LOGIN_WAIT_TIME);
}
本文主要是對基于窗口能力,實現(xiàn)驗證碼登錄的場景。有關(guān)鴻蒙的進階技能大家可以前往主頁查看更多
發(fā)表于 01-12 17:51
鴻蒙應(yīng)用/元服務(wù)開發(fā)-窗口(Stage模型)設(shè)置懸浮窗
一、設(shè)置懸浮窗說明
懸浮窗可以在已有的任務(wù)基礎(chǔ)上,創(chuàng)建一個始終在前臺顯示的窗口。即使創(chuàng)建懸浮窗的任務(wù)退至后臺,懸浮窗仍然可以在前臺顯示。通常
發(fā)表于 02-04 14:05
鴻蒙實戰(zhàn)項目開發(fā):【短信服務(wù)】
數(shù)據(jù)管理
電話服務(wù)
分布式應(yīng)用開發(fā)
通知與窗口管理
多媒體技術(shù)
安全技能
任務(wù)管理
WebGL
國際化開發(fā)
應(yīng)用測試
DFX面向未來設(shè)計
鴻蒙系統(tǒng)移植和裁剪定制
……
?
《
發(fā)表于 03-03 21:29
鴻蒙OS崛起,鴻蒙應(yīng)用開發(fā)工程師成市場新寵
應(yīng)用的形態(tài)也在發(fā)生著翻天覆地的變化。作為全球領(lǐng)先的移動操作系統(tǒng)和智能終端制造商,華為公司自主研發(fā)的鴻蒙OS應(yīng)運而生,致力于構(gòu)建一個統(tǒng)一的分布式操作系統(tǒng),為各行各業(yè)的應(yīng)用開發(fā)帶來全新的可能性。
一、
發(fā)表于 04-29 17:32
OpenHarmony實戰(zhàn)開發(fā)-如何實現(xiàn)窗口開發(fā)概述
],單位為vp。
系統(tǒng)窗口存在大小限制,寬度范圍:[0, 2560],高度范圍:[0, 2560],單位為vp。
最后
如果大家覺得這篇內(nèi)容對學(xué)習(xí)鴻蒙開發(fā)有幫助,我想邀請大家?guī)臀胰齻€小忙:
點贊,轉(zhuǎn)發(fā),有
發(fā)表于 05-06 14:29
鴻蒙Flutter實戰(zhàn):07混合開發(fā)
# 鴻蒙Flutter實戰(zhàn):混合開發(fā)
鴻蒙Flutter混合開發(fā)主要有兩種形式。
## 1.基于har
將flutter module
發(fā)表于 10-23 16:00
鴻蒙OS應(yīng)用程序開發(fā)
這份學(xué)習(xí)文檔主要是帶領(lǐng)大家在鴻蒙OS上學(xué)習(xí)開發(fā)一個應(yīng)用程序,主要知識點如下:1、U-Boot引導(dǎo)文件燒寫方式;2、內(nèi)核鏡像燒寫方式;3、鏡像運行。
發(fā)表于 09-11 14:39
鴻蒙 OS 應(yīng)用開發(fā)初體驗
的操作系統(tǒng)平臺和開發(fā)框架。HarmonyOS 的目標(biāo)是實現(xiàn)跨設(shè)備的無縫協(xié)同和高性能。
DevEco Studio
對標(biāo) Android Studio,開發(fā)鴻蒙 OS 應(yīng)用的 IDE。
發(fā)表于 11-02 19:38
鴻蒙OS 2.0手機開發(fā)者Beta版發(fā)布會在京舉辦
三個月前,鴻蒙OS 2.0正式在華為開發(fā)者大會2020亮相。12月16日,鴻蒙OS 2.0手機開發(fā)
華為發(fā)布鴻蒙OS Beta版
昨天華為發(fā)布鴻蒙OS Beta版了?鴻蒙系統(tǒng)一直在按照既有步伐前進,現(xiàn)在華為發(fā)布鴻蒙OS Beta版,而且一些生態(tài)
鴻蒙os怎么升級
6月2日,華為正式發(fā)布了鴻蒙armonyOS 2系統(tǒng),那么鴻蒙os如何升級?現(xiàn)將鴻蒙os升級方式告知如下。
華為開發(fā)者大會2021鴻蒙os在哪場
華為開發(fā)者大會2021將在10月22日-24日舉辦,地點為東莞松山湖,鴻蒙os 3.0或?qū)⑴c我們見面,那么華為開發(fā)者大會2021鴻蒙
鴻蒙實戰(zhàn)開發(fā):【實現(xiàn)應(yīng)用懸浮窗】
如果你要做的是系統(tǒng)級別的懸浮窗,就需要判斷是否具備懸浮窗權(quán)限。然而這又不是一個標(biāo)準(zhǔn)的動態(tài)權(quán)限,你需要兼容各種奇葩機型的懸浮窗權(quán)限判斷。
評論