holding 0.0.1
holding: ^0.0.1 copied to clipboard
Flutter 握持手感知插件,支持 HarmonyOS/OpenHarmony,订阅握持手状态变化(未握持/左手/右手/双手/未识别)。
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:holding/holding.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final _holding = Holding();
HoldingHandStatus _holdingStatus = HoldingHandStatus.none;
bool _isHoldingSubscribed = false;
final List<String> _holdingLog = [];
void _subscribeHoldingHand() {
_holding.subscribeHoldingHand(
SubscribeHoldingHandOptions(
onChange: (HoldingHandStatus status) {
if (!mounted) return;
setState(() {
_holdingStatus = status;
_holdingLog.insert(
0,
'${DateTime.now().toString().substring(11, 19)} ${_holdingLabel(status)}',
);
if (_holdingLog.length > 20) _holdingLog.removeLast();
});
},
success: () {
if (!mounted) return;
setState(() => _isHoldingSubscribed = true);
},
fail: (String msg) {
if (!mounted) return;
setState(() => _isHoldingSubscribed = false);
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('握持手订阅失败: $msg')));
},
),
);
}
void _unsubscribeHoldingHand() {
_holding.unsubscribeHoldingHand(
UnsubscribeHoldingHandOptions(
success: () {
if (!mounted) return;
setState(() => _isHoldingSubscribed = false);
},
fail: (String msg) {
if (!mounted) return;
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('握持手取消订阅失败: $msg')));
},
),
);
}
String _holdingLabel(HoldingHandStatus s) {
switch (s) {
case HoldingHandStatus.none:
return '未握持';
case HoldingHandStatus.left:
return '左手握持';
case HoldingHandStatus.right:
return '右手握持';
case HoldingHandStatus.both:
return '双手握持';
case HoldingHandStatus.unknown:
return '未识别';
}
}
Widget _buildStatusCard({
required String title,
required String statusText,
required bool isSubscribed,
}) {
return Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Icon(
isSubscribed ? Icons.check_circle : Icons.radio_button_unchecked,
color: isSubscribed ? Colors.green : Colors.grey,
size: 28,
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(fontSize: 12, color: Colors.grey),
),
const SizedBox(height: 2),
Text(
statusText,
style: Theme.of(context).textTheme.titleLarge,
),
Text(
isSubscribed ? '已订阅' : '未订阅',
style: TextStyle(color: Colors.grey[600], fontSize: 12),
),
],
),
),
],
),
),
);
}
Widget _buildLogCard(List<String> log) {
if (log.isEmpty) return const SizedBox.shrink();
return Card(
child: ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 160),
child: ListView.builder(
shrinkWrap: true,
itemCount: log.length,
itemBuilder: (_, i) => Padding(
padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 12),
child: Text(
log[i],
style: const TextStyle(fontFamily: 'monospace', fontSize: 12),
),
),
),
),
);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Holding 插件示例')),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(height: 16),
const Text(
'握持手状态',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
_buildStatusCard(
title: '握持手',
statusText: _holdingLabel(_holdingStatus),
isSubscribed: _isHoldingSubscribed,
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: FilledButton.icon(
onPressed: _isHoldingSubscribed
? null
: _subscribeHoldingHand,
icon: const Icon(Icons.play_arrow),
label: const Text('订阅'),
),
),
const SizedBox(width: 12),
Expanded(
child: OutlinedButton.icon(
onPressed: _isHoldingSubscribed
? _unsubscribeHoldingHand
: null,
icon: const Icon(Icons.stop),
label: const Text('取消'),
),
),
],
),
if (_holdingLog.isNotEmpty) ...[
const SizedBox(height: 8),
_buildLogCard(_holdingLog),
],
],
),
),
),
);
}
}