• Lv0
    粉丝1

积分23 / 贡献0

提问0答案被采纳0文章3

[经验分享] 妙用Sensor Server Kit开发感知光影效果

hellokun 显示全部楼层 发表于 2024-9-18 17:57:09

1 简介

传感器在APP较为常用,例如开屏摇一摇广告是结合陀螺仪实现的。本篇文章将讲解Sensor Service Kit(传感器服务),通过本篇文章你将学到:

  • 如何获取光线、加速度、陀螺仪数据。
  • 如何实现丰富的震动效果
  • 如何将UI基础组件与光线、陀螺仪传感器数据联动,实现感知光影效果
  • 注:开发者手机不支持光线、陀螺仪传感器 ![sensor2.gif](

)

2 环境搭建

我们首先需要完成OpenHarmony应用开发环境搭建,可参考(开发一个BLE低功耗蓝牙调试助手(一)连接蓝牙服务设备-华为开发者论坛)中的第二章进行操作。

3 代码结构解读

本篇文档只对**核心代码**进行讲解,全部代码可看仓库地址HelloKun - Gitee.com

```c . entry/src |-- common // 常用工具库 | |-- CommonConstants.ets | |-- Logger.ets | `-- PermissionUtil.ets |-- entryability | `-- EntryAbility.ets // 入口,设置全屏 |-- pages | |-- ControlBox.ets // 蓝牙体感手柄页面 | |-- IconModel.ets // 图标类 | |-- Index.ets // 首页 | `-- LingDongIcon.ets // 感知光影页面 `-- services // 蓝牙服务 |-- BLEGattClientManager.ets `-- BLEScanManager.ets ```

4 构建应用主界面

首页面使用Navigation组件实现布局,先将需要展示页面单独存放在首页列表中,页面的title与icon在IconModel.ets进行定义。

```js // IconModel.ets 定义需要的跳转页面title与icon const SensorSources: IconItem[] = [ { title: '灵动光影', image: \$r('app.media.calendar') }, { title: '灵动手柄', image: \$r('app.media.xbox') }, // ... ] ```

首页的布局使用Navigation组件实现,具体可参考该系列教程。只需要在PageMap中新增需要跳转的页面即可。

```js // Index.ets // ... // 1. 导航页面列表 PageMap(name: string) { if (name === "LingDongIcon") { LingDongIcon(); } else if (name === "ControlBox") { ControlBox(); } // ... } ```

实现的效果如下:

![sensor1.png](

?x-oss-process=image/resize,w_307,h_627)

5 使用Sensor服务

使用传感器主要步骤如下:

  • 1)导入模块

```js import { sensor } from '@kit.SensorServiceKit'; ```

  • 2)获取相应权限,本篇文章涉及的、需要向用户声请的权限有:

```js export const permissions: Array<Permissions> = ['ohos.permission.ACCESS_BLUETOOTH', "ohos.permission.ACCELEROMETER", "ohos.permission.GYROSCOPE", "ohos.permission.VIBRATE"]; ```

需要在module.json中声明的权限有:

```json "requestPermissions": [ { "name": " ohos.permission.ACCESS_BLUETOOTH", "reason": "\$string:app_name", "usedScene": { "abilities": [ "EntryAbility" ], "when": "always" } }, { "name": "ohos.permission.ACCELEROMETER", // ... }, { "name": "ohos.permission.GYROSCOPE", // ... }, { "name": "ohos.permission.ORIENTATION", // ... }, { "name": "ohos.permission.VIBRATE", // ... }, { "name": "ohos.permission.AMBIENT_LIGHT", // ... } ] ```

  • 3)了解传感器及其ID

每个传感器都有对应的ID,其定义在@ohos.sensor.d.ts中

```c enum SensorId { ACCELEROMETER = 1, GYROSCOPE = 2, AMBIENT_LIGHT = 5, MAGNETIC_FIELD = 6, BAROMETER = 8, HALL = 10, PROXIMITY = 12, HUMIDITY = 13, ORIENTATION = 256, GRAVITY = 257, LINEAR_ACCELEROMETER = 258, ROTATION_VECTOR = 259, // ... } ```

设备并非具备全部传感器能力,在使用传感器前,可以先扫描确定当前设备拥有的传感器列表,实现如下:

```js sensor.getSensorList((error: BusinessError, data: Array<sensor.Sensor>) => { if (error) { console.info('getSensorList failed'); } else { console.info('getSensorList success'); for (let i = 0; i < data.length; i++) { console.info(JSON.stringify(data*)); } } }); ```

![](C:\Users\jingwen liang\Downloads\sensor2.png)

  • 4)注册监听与结束监听。可以通过on()和once()两种接口监听传感器的调用结果。

通过on()接口,实现对传感器的持续监听,传感器上报周期interval设置为100000000纳秒。

```typescript sensor.on(sensor.SensorId.ACCELEROMETER, (data: sensor.AccelerometerResponse) => { console.info("Succeeded in obtaining data. x: " + data.x + " y: " + data.y + " z: " + data.z);}, { interval: 100000000 }); ```

通过once()接口,实现对传感器的一次监听。

```typescript sensor.once(sensor.SensorId.ACCELEROMETER, (data: sensor.AccelerometerResponse) => { console.info("Succeeded in obtaining data. x: " + data.x + " y: " + data.y + " z: " + data.z);}); ```

通过off()接口,实现取消持续监听传感器数据。适当使用传感器,能更好的控制设备功耗。

```typescript sensor.off(sensor.SensorId.ACCELEROMETER); ```

5.1 获取加速度数据

加速度传感器数据有两类,分别是校准数据(ACCELEROMETER)和原始数据(ACCELEROMETER_UNCALIBRATED)。示例中使用校准数据,数据说明如下:

传感器类型 描述 说明 主要用途
ACCELEROMETER 加速度传感器 测量三个物理轴(x、y 和 z)上,施加在设备上的加速度(包括重力加速度),单位 : m/s² 检测运动状态。

设置了一个定时器,每隔一段时间就持续监听x轴的加速度(其他传感器同样处理)数据,并给赋值给变量angle_X,后续进行使用。

```js @State accelerometer_X:number = 0; setInterval(()=>{ try { sensor.on(sensor.SensorId.ACCELEROMETER, (data: sensor.AccelerometerResponse) => { this.accelerometer_X = data.x; // data.y data.z包含其他两个轴的加速度 }, { interval: 100000000 });

  } catch (error) {
    let e: BusinessError = error as BusinessError;
    console.error(\`Failed to invoke on. Code: \${e.code}, message: \${e.message}\`);
  }
 console.info(TAG,'accelerometer\_X:'+this.accelerometer\_X.toString())
},500)

```

5.2 获取陀螺仪数据

1)角速度获取

陀螺仪传感器角速度数据分为是否校准两类,这里获取校准的GYROSCOPE数据,数据说明如下:

传感器类型 描述 说明 主要用途
GYROSCOPE 陀螺仪传感器 测量三个物理轴(x、y 和 z)上,设备的旋转角速度,单位 : rad/s。 测量旋转的角速度。

继续在定时器中补充获取y轴角速度的监听程序:

```js @State gyroscope_Y:number = 0; setInterval(()=>{ try { //... sensor.on(sensor.SensorId.GYROSCOPE, (data: sensor.GyroscopeResponse) => { this.gyroscope_Y = data.y * 10 }, { interval: 100000000 });

  } catch (error) {
    let e: BusinessError = error as BusinessError;
    console.error(\`Failed to invoke on. Code: \${e.code}, message: \${e.message}\`);
  }
  // ...
  console.info(TAG,'gyroscope\_Y:'+this.gyroscope\_Y.toString())
},500)

```

2)获取角度

陀螺仪传感器可以计算出设备在三个轴的旋转角度,在应用层我们可以直接获取到旋转角度。

传感器类型 描述 说明 主要用途
ORIENTATION 方向传感器 测量设备围绕所有三个物理轴(z、x、y)旋转的角度值,单位:rad。 用于测量屏幕旋转的3个角度值。

监听到的三个物理轴(z、x、y)旋转的角度值分别为alpha、beta、gamma,获取角度的程序如下:

```js @State orientation_X:number = 0; @State orientation_Y:number = 0; @State orientation_Z:number = 0; setInterval(()=>{ try { //... sensor.on(sensor.SensorId.ORIENTATION, (data: sensor.OrientationResponse) => { this.orientation_X = data.beta this.orientation_Y = data.gamma this.orientation_Z = data.alpha }, { interval: 100000000 });

  } catch (error) {
    let e: BusinessError = error as BusinessError;
    console.error(\`Failed to invoke on. Code: \${e.code}, message: \${e.message}\`);
  }
  // ...
  console.info(TAG,'beta:'+this.orientation\_X.toString())
  console.info(TAG,'gamma:'+this.orientation\_Y.toString())
  console.info(TAG,'alpha:'+this.orientation\_Z.toString())
},500)

```

5.4 获取光线传感器

光线传感器通常用来调节亮度,不过我们可以监听其数值,用于应用程序组件属性控制。

传感器类型 描述 说明 主要用途
AMBIENT_LIGHT 环境光传感器 测量设备周围光线强度,单位:lux。 自动调节屏幕亮度,检测屏幕上方是否有遮挡。

光线传感器返回的数据类型为LightResponse, 包含强读、色温、红外强度(可以用来做出行建议),完整定义如下:

```js interface LightResponse extends Response { /** * Indicates light intensity, in lux. * @type { number } * @syscap SystemCapability.Sensors.Sensor * @since 8 */ intensity: number; /** * Indicates color temperature, in kelvin. * @type { ?number } * @syscap SystemCapability.Sensors.Sensor * @since 12 */ colorTemperature?: number; /** * Indicates infrared luminance, in cd/m2. * @type { ?number } * @syscap SystemCapability.Sensors.Sensor * @since 12 */ infraredLuminance?: number; } ```

继续在定时器中补充获取环境光线强度的监听程序:

```js @State Light_Lux:number = 0; setInterval(()=>{ try { // ... sensor.on(sensor.SensorId.AMBIENT_LIGHT, (data: sensor.LightResponse) => { this.Light_Lux = data.intensity/100; }, { interval: 100000000 });

  } catch (error) {
    let e: BusinessError = error as BusinessError;
    console.error(\`Failed to invoke on. Code: \${e.code}, message: \${e.message}\`);
  }
  // ...
  console.info(TAG,'Light\_Lux:'+this.Light\_Lux.toString())
},500)

```

5.5 震动控制

HarmonyOS NEXT提供了丰富的震动控制接口,不仅预设了丰富的预置震动效果,开发者还可以自定义震动。具体可参考:振动开发指导-振动-Sensor Service Kit(传感器服务)。我们使用预置的震动效果,开发步骤如下:

  • 1)引入模块

```js import { vibrator } from '@kit.SensorServiceKit'; ```

  • 2)安装预置震动效果开启震动,可先查询振动效果是否被支持,再调用振动接口,下面是开启一次震动的实现:

```js OpenPreSetVibrator() { try { // 查询是否支持'haptic.effect.soft' vibrator.isSupportEffect('haptic.effect.soft', (err: BusinessError, state: boolean) => { if (err) { console.error(`Failed to query effect. Code: \${err.code}, message: \${err.message}`); return; } console.info('Succeed in querying effect'); if (state) { try { // 触发马达振动 vibrator.startVibration({ type: 'preset', effectId: 'haptic.effect.soft', count: 1, intensity: 50, }, { usage: 'unknown' }, (error: BusinessError) => { if (error) { console.error(`Failed to start vibration. Code: \${error.code}, message: \${error.message}`); } else { console.info('Succeed in starting vibration'); } }); } catch (error) { let e: BusinessError = error as BusinessError; console.error(`An unexpected error occurred. Code: \${e.code}, message: \${e.message}`); } } }) } catch (error) { let e: BusinessError = error as BusinessError; console.error(`An unexpected error occurred. Code: \${e.code}, message: \${e.message}`); } } ```

6 感知光影

上一章节获取到了加速度、角速度、角度、光强度数据,接下来结合常用组件,实现光影感知的效果。

1)首先使用.shadow属性将图标和文字添加阴影效果:

  • 光的强度控制阴影的可变半径;
  • X轴加速度控制X轴可变偏移范围;
  • y轴转动角度控制Y轴可变偏移范围;

```js // LingDongIcon.ets // 光影标题 Text(this.message) .textShadow({radius:10-this.Light_Lux/2,type:ShadowType.COLOR,color:'#000000', offsetX:this.widthIcon/2+this.accelerometer_X,offsetY:40+this.gyroscope_Y}) // 光影图标 Image(service.image) .margin({top:'15%'}) .backgroundBlurStyle(BlurStyle.Thick) .height(this.widthIcon) .width(this.widthIcon) .borderRadius(this.widthIcon / 2) .borderWidth(0) .borderColor('#A8D18D') .shadow({ radius: 40 - this.Light_Lux / 2, type: ShadowType.COLOR, color: '#000000', offsetX: this.accelerometer_X, offsetY: 20 + this.gyroscope_Y / 2 }) ```

2)使用Grid模拟桌面布局,更直观的查看感知光影的效果。实现如下:

```js // LingDongIcon.ets @Component struct ShowIcon{ // ... build(){ Column() { Column() { Grid() { ForEach(IconSources, (service: IconItem, index: number) => { GridItem() { Column({ space: 15 }) { Image(service.image) .margin({top:'15%'}) // 光影图标 // ... Text(service.title) } } }) }.height('100%') .width('100%') .rowsTemplate(('1fr 1fr 1fr 1fr') as string) .columnsTemplate(('1fr 1fr 1fr 1fr') as string) .supportAnimation(true) }.height('100%') }.justifyContent(FlexAlign.Center) } } ```

实现效果演示:

  • 1)当手机静置时,图标和文字的阴影较大且位置固定
  • 2)当手机被拿起时,图标和文字的阴影会随着握持的姿势变动

sensor2.gif

  • 3)光线强度不同的环境中图标阴影会变淡或者变深

light.gif

总结

本篇综合介绍了如何使用光线、加速度、陀螺仪和震动等传感器,并实现感知光影的交互体验。我们可以发挥想象,如结合蓝牙、角度、震动、加速度可以将手机变为无线体感手柄!*

©著作权归作者所有,转载或内容合作请联系作者

您尚未登录,无法参与评论,登录后可以:
参与开源共建问题交流
认同或收藏高质量问答
获取积分成为开源共建先驱

Copyright   ©2023  OpenHarmony开发者论坛  京ICP备2020036654号-3 |技术支持 Discuz!

返回顶部