HarmonyOS 鸿蒙Next迷你栏适配智感握姿
HarmonyOS 鸿蒙Next迷你栏适配智感握姿 获取到手持状态后如何修改迷你栏左右位置,就像QQ音乐迷你栏目左右切换一样
开发者您好,您可以通过[@ohos.multimodalAwareness.motion (动作感知能力)](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-awareness-motion)获取握持手状态,参见获取握持手状态开发指导,需要添加权限: ohos.permission.DETECT_GESTURE,具体申请方式请参考声明权限:
"requestPermissions":[
{
"name" : "ohos.permission.DETECT_GESTURE"
}
]
对HdsTabs的barHeight设置为0,通过自定义tabbar和minibar实现窄屏的智感握姿,参考代码如下:
// 从6.0.2(22)版本开始,无需手动导入HdsTabsAttribute。具体请参考HdsTabs的导入模块说明。
import { HdsTabs, HdsTabsController } from '@kit.UIDesignKit';
import { motion } from '@kit.MultimodalAwarenessKit';
import { BusinessError } from '@kit.BasicServicesKit';
// Tab数据模型
interface TabItemData {
title: string;
icon: ResourceStr;
activeIcon: ResourceStr;
}
@Entry
@Component
struct Index {
// 初始化HdsTabs控制器
private controller: HdsTabsController = new HdsTabsController();
@State currentIndex: number = 0;
@State barReversed: boolean = false; // 是否交换MiniBar和TabBar的位置
// Tab数据源
private tabItems: TabItemData[] = [
{ title: '首页', icon: $r('sys.media.ohos_ic_public_clock'), activeIcon: $r('sys.media.ohos_ic_public_clock') }
];
callback: Callback<motion.HoldingHandStatus> = (data: motion.HoldingHandStatus) => {
// 1左手,2右手
console.info(`Succeeded in getting data:${data}.`);
if (data === 1) {
this.barReversed = true;
} else if (data === 2) {
this.barReversed = false;
}
};
onMotion() {
try {
motion.on('holdingHandChanged', this.callback);
console.info('Succeeded in holdingHandChang on.');
} catch (err) {
let error = err as BusinessError;
console.error('Failed on and err code is ' + error.code);
}
}
offMotion() {
try {
motion.off('holdingHandChanged');
console.info('Succeeded in holdingHandChanged off.');
} catch (err) {
let error = err as BusinessError;
console.error('Failed off and err code is ' + error.code);
}
}
// 单个Tab按钮
@Builder
TabItemBuilder(item: TabItemData, index: number) {
Column() {
Image(this.currentIndex === index ? item.activeIcon : item.icon)
.width(40)
.height(40)
.fillColor(this.currentIndex === index ? '#007DFF' : '#999999');
Text(item.title)
.fontSize(10)
.fontColor(this.currentIndex === index ? '#007DFF' : '#999999')
.margin({ top: 2 });
}
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
.onClick(() => {
this.currentIndex = index;
});
}
@Builder
TabBuilder() {
Stack() {
Column()
.height(60)
.width(60)
.borderRadius(30)
.foregroundBlurStyle(BlurStyle.Thin,
{
colorMode: ThemeColorMode.LIGHT,
adaptiveColor: AdaptiveColor.DEFAULT,
scale: 1.0
});
Row() {
ForEach(this.tabItems, (item: TabItemData, index: number) => {
this.TabItemBuilder(item, index);
});
};
}
.alignContent(Alignment.Center)
.height('60')
.width('60');
}
// MiniBar
@Builder
MiniBarBuilder() {
Stack() {
Column()
.height(50)
.width(200)
.borderRadius(25)
.foregroundBlurStyle(BlurStyle.Thin,
{
colorMode: ThemeColorMode.LIGHT,
adaptiveColor: AdaptiveColor.DEFAULT,
scale: 1.0
});
Row() {
Column() {
Image($r('app.media.startIcon'))
.width(40)
.height(40)
.borderRadius(40);
}.width(48).height(48).justifyContent(FlexAlign.Center).margin({ left: 4, right: 4 });
Text('Hello');
Column() {
Image($r('sys.media.ohos_ic_public_pause'))
.width(40)
.height(40)
.borderRadius(40);
}.width(48).height(48).justifyContent(FlexAlign.Center);
}
.justifyContent(FlexAlign.Start);
}
.alignContent(Alignment.Start)
.height(50)
.width(200);
}
// 自定义底部栏
@Builder
CustomBottomBar() {
Row() {
if (this.barReversed) {
// ====== 交换后:MiniBar 在左,TabBar 在右 ======
this.MiniBarBuilder();
this.TabBuilder();
} else {
// ====== 默认:TabBar 在左,MiniBar 在右 ======
this.TabBuilder();
this.MiniBarBuilder();
}
}
.padding({ left: 10, right: 10 })
.justifyContent(FlexAlign.SpaceBetween)
.width('100%')
.height(56)
.margin({ bottom: 20 });
}
aboutToAppear(): void {
this.onMotion();
}
aboutToDisappear(): void {
this.offMotion();
}
build() {
Stack({ alignContent: Alignment.Bottom }) {
HdsTabs({ controller: this.controller }) {
TabContent() {
Scroll() {
Column() {
Image($r('app.media.startIcon'));
Image($r('app.media.startIcon'));
Image($r('app.media.startIcon'));
Image($r('app.media.startIcon'));
};
};
}
.tabBar(new BottomTabBarStyle($r('sys.media.ohos_ic_public_clock'), 'Green'));
TabContent() {
Image($r('app.media.startIcon'));
}
.tabBar(new BottomTabBarStyle($r('sys.media.wifi_router_fill'), 'Blue'));
TabContent() {
Image($r('app.media.startIcon'));
}
.tabBar(new BottomTabBarStyle($r('sys.media.ohos_ic_public_clock'), 'Yellow'));
}
.barHeight(0)
// 设置barOverlap为true,vertical为false,barPosition为BarPosition.End
.barOverlap(true)
.barPosition(BarPosition.End)
.vertical(false);
this.CustomBottomBar();
};
}
}
更多关于HarmonyOS 鸿蒙Next迷你栏适配智感握姿的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
属性HdsTabsFloatingStyle不是有一个adaptToHandedness?,
同问
可以参考本联盟文章其他开发大佬的文章。
鸿蒙Next中迷你栏适配智感握姿需通过系统传感器接口获取握持数据(如压力、角度),利用ArkUI的布局监听或手势事件动态调整迷你栏位置/尺寸。在module.json5中声明握姿感知权限,通过@ohos.sensor或系统订阅接口实时响应姿态变化,确保迷你栏不遮挡交互区域。
在HarmonyOS Next中实现迷你栏根据手握姿态左/右适配,核心是通过 sensor 模块获取设备倾斜角度判断左/右手持握,再动态调整迷你栏组件的 margin 或 offset 实现移位。以下为关键代码示例:
import sensor from '@ohos.sensor';
import display from '@ohos.display';
@Entry
@Component
struct MiniBar {
@State marginLeft: number = 0; // 默认右对齐,实际可根据布局调整
private gravityCallback = (data: sensor.GravityData) => {
// 通过重力传感器X轴数据判断握姿:X > 2 为右倾(左手持握),X < -2 为左倾(右手持握)
const isLeftHand = data.x > 2;
const screenWidth = display.getDefaultDisplaySync().width;
// 假设迷你栏宽度为200vp,计算新的左/右位置
if (isLeftHand) {
this.marginLeft = 16; // 左手持握时迷你栏靠左
} else {
this.marginLeft = screenWidth - 216; // 右手持握时靠右,200宽度+16间距
}
}
aboutToAppear() {
sensor.on(sensor.SensorId.GRAVITY, this.gravityCallback, { interval: 100000000 }); // 100ms
}
aboutToDisappear() {
sensor.off(sensor.SensorId.GRAVITY, this.gravityCallback);
}
build() {
Column() {
// 迷你栏容器
Row() {
Text('♫ 歌曲名称')
.fontSize(14)
Progress({ value: 30, total: 100 })
.width(80)
}
.width(200)
.height(48)
.backgroundColor(Color.White)
.borderRadius(24)
.shadow(ShadowStyle.OUTER_DEFAULT_SM)
.margin({ left: this.marginLeft }) // 动态左边距实现左右切换
.animation({ duration: 300, curve: Curve.EaseInOut }) // 平滑移动
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.End) // 底部显示
}
}
说明:
- 重力传感器X轴值大于阈值(如2)判定为左手持握(手机右倾),迷你栏移到左侧;反之移到右侧。
- 使用
margin或offset动态改变组件水平位置,配合animation实现QQ音乐般的平滑切换效果。 - 阈值和位置数值需根据真实设备调试,也可结合历史数据进行防抖处理。

