# uni.startGyroscope(options?)

开始监听陀螺仪数据。

# startGyroscope 兼容性

Web 微信小程序 Android iOS HarmonyOS HarmonyOS(Vapor)
x 4.41 5.08 5.08 5.08 5.08

# 参数

名称 类型 必填 默认值 兼容性 描述
options StartGyroscopeOptions
开始监听陀螺仪数据的参数
名称 类型 必备 默认值 兼容性 描述
interval string
监听陀螺仪数据回调函数的执行频率
合法值 兼容性 描述
game
适用于更新游戏的回调频率,约 20ms/次 左右
ui
适用于更新 UI 的回调频率,在 60ms/次 左右
normal
普通的回调频率,在 200ms/次 左右
success (res: StartGyroscopeSuccess) => void
接口调用成功的回调函数
fail (res: StartGyroscopeFail) => void
接口调用失败的回调函数
complete (res: StartGyroscopeSuccess | StartGyroscopeFail) => void
接口调用结束的回调函数(调用成功、失败都会执行)

# StartGyroscopeSuccess 的属性值

名称 类型 必备 默认值 兼容性 描述
errMsg string

# StartGyroscopeFail 的属性值

名称 类型 必备 默认值 兼容性 描述
errCode number
合法值 兼容性 描述
501
502
503
504
601
602
603
604
701
702
703
704
801
802
803
804
901
errSubject string
统一错误主题(模块)名称
data any
错误信息中包含的数据
cause Error 源错误信息,可以包含多个错误,详见SourceError
errMsg string

# 参见

# 注意

  • 鸿蒙平台权限设置 此接口需要权限 ohos.permission.GYROSCOPE。具体配置方法请参考鸿蒙权限配置指南

# uni.stopGyroscope(options?)

停止监听陀螺仪数据变化事件。

# stopGyroscope 兼容性

Web 微信小程序 Android iOS HarmonyOS HarmonyOS(Vapor)
x 4.41 5.08 5.08 5.08 5.08

# 参数

名称 类型 必填 默认值 兼容性 描述
options StopGyroscopeOptions
停止监听陀螺仪数据的参数
名称 类型 必备 默认值 兼容性 描述
success (res: StopGyroscopeSuccess) => void
接口调用成功的回调函数
fail (res: StopGyroscopeFail) => void
接口调用失败的回调函数
complete (res: StopGyroscopeSuccess | StopGyroscopeFail) => void
接口调用结束的回调函数(调用成功、失败都会执行)

# StopGyroscopeSuccess 的属性值

名称 类型 必备 默认值 兼容性 描述
errMsg string

# StopGyroscopeFail 的属性值

名称 类型 必备 默认值 兼容性 描述
errCode number
合法值 兼容性 描述
501
502
503
504
601
602
603
604
701
702
703
704
801
802
803
804
901
errSubject string
统一错误主题(模块)名称
data any
错误信息中包含的数据
cause Error 源错误信息,可以包含多个错误,详见SourceError
errMsg string

# 参见

# uni.onGyroscopeChange(callback)

监听陀螺仪数据变化事件 支付宝小程序频率为 500ms/次,微信小程序频率根据 uni.startGyroscope 的 interval 参数设置。事件只有在调用 uni.startGyroscope 后才会开始监听,使用 uni.stopGyroscope 可以停止监听。

# onGyroscopeChange 兼容性

Web 微信小程序 Android iOS iOS uni-app x UTS 插件 HarmonyOS HarmonyOS(Vapor)
x 4.41 5.08 5.08 x 5.08 5.08

# 参数

名称 类型 必填 默认值 兼容性 描述
callback (result: OnGyroscopeChangeCallbackResult) => void
陀螺仪数据事件的监听函数

# OnGyroscopeChangeCallbackResult 的属性值

名称 类型 必备 默认值 兼容性 描述
x number
x 轴的角速度
y number
y 轴的角速度
z number
z 轴的角速度

# 参见

# 注意

  • 鸿蒙平台权限设置 此接口需要如下权限:具体配置方法请参考鸿蒙权限配置指南
    • ohos.permission.GYROSCOPE: 注册监听时如果当前未启动,会自动调用 startGyroscope(),因此间接触发权限申请和传感器启动。

# uni.offGyroscopeChange(callback?)

停止监听陀螺仪数据变化事件

# offGyroscopeChange 兼容性

Web 微信小程序 Android iOS iOS uni-app x UTS 插件 HarmonyOS HarmonyOS(Vapor)
x 4.41 5.08 5.08 x 5.08 5.08

# 参数

名称 类型 必填 默认值 兼容性 描述
callback (result: OnGyroscopeChangeCallbackResult) => void
onGyroscopeChange 传入的监听函数。不传此参数则移除所有监听函数。

# OnGyroscopeChangeCallbackResult 的属性值

名称 类型 必备 默认值 兼容性 描述
x number
x 轴的角速度
y number
y 轴的角速度
z number
z 轴的角速度

# 参见

# 示例

示例为hello uni-app x alpha分支,与最新HBuilderX Alpha版同步。与最新正式版同步的master分支示例另见

该 API 不支持 Web,请运行 hello uni-app x 到 App 平台体验

扫码体验(手机浏览器跳转到App直达页)
<template>
	<!-- #ifdef APP -->
	<scroll-view style="flex: 1;padding: 6px;">
	<!-- #endif -->
		<text class="uni-h2">陀螺仪 API</text>
		<text class="margin-v">演示 `uni.startGyroscope`、`uni.stopGyroscope`、`uni.onGyroscopeChange`、`uni.offGyroscopeChange` 的完整用法。</text>
		<text class="margin-v">`x / y / z` 表示各轴角速度。</text>

		<text class="uni-h3">实时状态</text>
		<view class="log-list">
			<text class="log-item" v-for="item in statusItems" :key="item.label">{{ item.label }}:{{ item.value }}</text>
			<text class="log-item" v-for="item in axisItems" :key="item.label">{{ item.label }}:{{ item.value }}</text>
		</view>

		<text class="uni-h3">调用结果</text>
		<view class="log-list">
			<text class="log-item" v-for="item in resultItems" :key="item.label">{{ item.label }}:{{ item.value }}</text>
		</view>

		<text class="uni-h3">开始 / 停止</text>
		<text class="margin-v">先注册监听函数,再按不同 interval 启动;停止后会继续保留已绑定监听,直到显式 off。</text>
		<radio-group class="option-group" @change="handleIntervalChange">
			<view class="option-item" v-for="item in intervalOptions" :key="item.value">
				<radio :value="item.value" :checked="activeInterval == item.value">
					<text class="option-text">{{ item.label }}</text>
				</radio>
			</view>
		</radio-group>
		<button id="btn-start-gyroscope" class="margin-v" type="primary" @tap="startListening">开始监听</button>
		<button id="btn-stop-gyroscope" class="margin-v" @tap="stopListening">停止监听</button>
		<button id="btn-bind-primary-listener" class="margin-v" @tap="registerSingleListener">绑定主监听</button>
		<button id="btn-bind-extra-listener" class="margin-v" @tap="registerExtraListener">再绑一个监听</button>
		<button id="btn-remove-primary-listener" class="margin-v" @tap="removeSingleListener">off 指定监听</button>
		<button id="btn-remove-all-listeners" class="margin-v" @tap="removeAllListeners">off 全部监听</button>
		<button id="btn-open-panorama" class="margin-v" @tap="navigateToPanorama">跳转全景示例</button>

		<text class="uni-h3">监听日志</text>
		<view class="log-list">
			<text class="log-item" v-for="item in logItems" :key="item">{{ item }}</text>
		</view>
	<!-- #ifdef APP -->
	</scroll-view>
	<!-- #endif -->
</template>

<script setup lang="uts">
	type GyroscopeErrorItem = {
		code : number
		title : string
		description : string
	}

	type IntervalOption = {
		value : GyroscopeInterval
		label : string
	}

	type DisplayItem = {
		label : string
		value : string
	}

	const activeInterval = ref<GyroscopeInterval>('normal')
	const statusText = ref('未启动')
	const axisX = ref('0.0000')
	const axisY = ref('0.0000')
	const axisZ = ref('0.0000')
	const lastAction = ref('等待调用')
	const lastStatus = ref('未执行')
	const lastPayload = ref('请先绑定监听后开始')
	const logItems = ref<Array<string>>([])
	const primaryBound = ref(false)
	const extraBound = ref(false)
	const intervalOptions : Array<IntervalOption> = [
		{ value: 'game', label: 'game' },
		{ value: 'ui', label: 'ui' },
		{ value: 'normal', label: 'normal' }
	]
	const statusItems = computed((): Array<DisplayItem> => {
		return [
			{ label: '监听状态', value: statusText.value },
			{ label: '当前频率', value: activeInterval.value }
		]
	})
	const axisItems = computed((): Array<DisplayItem> => {
		return [
			{ label: 'X', value: axisX.value },
			{ label: 'Y', value: axisY.value },
			{ label: 'Z', value: axisZ.value }
		]
	})
	const resultItems = computed((): Array<DisplayItem> => {
		return [
			{ label: '最近动作', value: lastAction.value },
			{ label: '状态', value: lastStatus.value },
			{ label: '说明', value: lastPayload.value }
		]
	})

	const errorItems : Array<GyroscopeErrorItem> = [
		{ code: 601, title: '不支持', description: '设备或平台没有陀螺仪能力。' },
		{ code: 602, title: '启动失败', description: '权限、初始化或浏览器授权被拒。' },
		{ code: 603, title: '停止失败', description: '停止订阅或销毁资源失败。' },
		{ code: 604, title: '内部错误', description: '插件内部出现未分类异常。' },
		{ code: 701, title: 'Android SensorManager 不可用', description: 'Android 无法获取传感器服务。' },
		{ code: 702, title: 'Android 陀螺仪不存在', description: 'Android 设备不含 TYPE_GYROSCOPE。' },
		{ code: 703, title: 'Android 注册失败', description: 'Android 注册监听器失败。' },
		{ code: 704, title: 'Android 数据异常', description: 'Android 原生数据回调不完整。' },
		{ code: 801, title: 'iOS 不支持', description: 'iOS 设备没有 gyro 能力。' },
		{ code: 802, title: 'iOS 初始化失败', description: 'iOS MotionManager 创建失败。' },
		{ code: 803, title: 'iOS 启动失败', description: 'iOS startGyroUpdates 未成功激活。' },
		{ code: 804, title: 'iOS 停止失败', description: 'iOS stopGyroUpdates 后状态异常。' },
		{ code: 501, title: 'Harmony 不支持', description: '鸿蒙设备无法获取 gyroscope 传感器。' },
		{ code: 502, title: 'Harmony 订阅失败', description: '鸿蒙订阅传感器失败。' },
		{ code: 503, title: 'Harmony 取消订阅失败', description: '鸿蒙停止监听失败。' },
		{ code: 504, title: 'Harmony 数据异常', description: '鸿蒙传感器数据内容异常。' },
		{ code: 901, title: 'Web 不支持', description: '浏览器没有真实 gyroscope / rotationRate。' }
	]

	function pushLog(line : string) : void {
		logItems.value.unshift(line)
		if (logItems.value.length > 10) {
			logItems.value.splice(10)
		}
    console.log('logItems.value.length', logItems.value.length)
	}

	function updateResult(action : string, status : string, payload : string) : void {
		lastAction.value = action
		lastStatus.value = status
		lastPayload.value = payload
		pushLog(`${action} -> ${status}`)
	}

	function formatAxisValue(value : number) : string {
		return value.toFixed(4)
	}

	const primaryListener : OnGyroscopeChangeCallback = (result) => {
		axisX.value = formatAxisValue(result.x)
		axisY.value = formatAxisValue(result.y)
		axisZ.value = formatAxisValue(result.z)
		statusText.value = `监听中 (${activeInterval.value})`
	}

	const extraListener : OnGyroscopeChangeCallback = (result) => {
		pushLog(`额外监听 -> ${formatAxisValue(result.x)}, ${formatAxisValue(result.y)}, ${formatAxisValue(result.z)}`)
	}

	function selectInterval(interval : GyroscopeInterval) : void {
		activeInterval.value = interval
		updateResult('selectInterval', '已切换', interval)
	}

	function handleIntervalChange(event : UniRadioGroupChangeEvent) : void {
		selectInterval(event.detail.value as GyroscopeInterval)
	}

	function registerSingleListener() : void {
		if (!primaryBound.value) {
			uni.onGyroscopeChange(primaryListener)
			primaryBound.value = true
		}
		updateResult('onGyroscopeChange(primary)', '已绑定', '主监听已注册')
	}

	function registerExtraListener() : void {
		if (!extraBound.value) {
			uni.onGyroscopeChange(extraListener)
			extraBound.value = true
		}
		updateResult('onGyroscopeChange(extra)', '已绑定', '额外监听已注册')
	}

	function removeSingleListener() : void {
		uni.offGyroscopeChange(primaryListener)
		primaryBound.value = false
		updateResult('offGyroscopeChange(listener)', '已解绑', '仅移除主监听')
	}

	function removeAllListeners() : void {
		uni.offGyroscopeChange()
		primaryBound.value = false
		extraBound.value = false
		updateResult('offGyroscopeChange()', '已解绑', '所有监听函数已移除')
	}

	function navigateToPanorama() {
		uni.navigateTo({
			url: '/pages/API/gyroscope/panorama'
		})
	}

	function startListening() : void {
		if (!primaryBound.value) {
			registerSingleListener()
		}
		uni.startGyroscope({
			interval: activeInterval.value,
			success: (res) => {
				const errMsg : string = res.errMsg != null ? res.errMsg as string : 'startGyroscope:ok'
				statusText.value = `监听中 (${activeInterval.value})`
				updateResult('startGyroscope', '成功', errMsg)
			},
			fail: (error) => {
				statusText.value = '启动失败'
				updateResult('startGyroscope', `失败 (${error.errCode})`, error.errMsg != null ? error.errMsg : 'startGyroscope:fail')
			}
		})
	}

	function stopListening() : void {
		uni.stopGyroscope({
			success: (res) => {
				const errMsg : string = res.errMsg != null ? res.errMsg as string : 'stopGyroscope:ok'
				statusText.value = '已停止'
				updateResult('stopGyroscope', '成功', errMsg)
			},
			fail: (error) => {
				updateResult('stopGyroscope', `失败 (${error.errCode})`, error.errMsg != null ? error.errMsg : 'stopGyroscope:fail')
			}
		})
	}

	onUnload(() => {
		uni.offGyroscopeChange()
		uni.stopGyroscope()
	})
</script>

<style>
	.margin-v {
		margin: 5px 0;
	}

	.notice {
		color: #550000;
		font-size: 14px;
		font-style: italic;
	}

	.option-group {
		margin: 5px 0;
		display: flex;
		flex-direction: row;
		flex-wrap: wrap;
	}

	.option-item {
		display: flex;
		flex-direction: row;
		align-items: center;
		margin-top: 8px;
		margin-right: 18px;
	}

	.option-text {
		font-size: 14px;
	}

	.error-list {
		margin: 5px 0;
		display: flex;
		flex-direction: column;
	}

	.error-item {
		margin: 5px 0;
		display: flex;
		flex-direction: row;
		flex-wrap: wrap;
	}

	.error-text {
		font-size: 14px;
	}

	.mini-button {
		margin-top: 5px;
	}

	.log-list {
		margin: 5px 0;
		padding: 10px;
		border: 1px solid #ccc;
		display: flex;
		flex-direction: column;
	}

	.log-item {
		font-size: 14px;
		margin: 4px 0;
	}
</style>

# 通用类型

# GeneralCallbackResult

名称 类型 必备 默认值 兼容性 描述
errMsg string
错误信息

# tips

  • 和微信小程序平台不同,app 平台调用 uni.onGyroscopeChange 时不会自动启动陀螺仪,需要调用 uni.startGyroscope() 才能正常启动陀螺仪。这个问题会在后续版本处理,app 平台在 5.09+ 版本中将和微信小程序行为保持一致。