@@ -49,6 +49,14 @@ class _RemoteTouchViewState extends State<RemoteTouchView> {
bool _isLongPressed = false ;
Timer ? _longPressTimer ;
// 缓存 RenderBox 信息以优化坐标换算开销
RenderBox ? _cachedRenderBox ;
Size ? _cachedSize ;
// 采样率限制:控制 ACTION_MOVE 的发送频率(例如每 16ms 发送一次,约 60fps)
int _lastMoveTimestamp = 0 ;
static const int _sampleIntervalMs = 16 ;
/// 长按触发阈值,对应 Android GestureDetector 默认的 LONG_PRESS_TIMEOUT( 400ms) 。
static const _longPressTimeout = Duration ( milliseconds: 400 ) ;
@@ -76,14 +84,11 @@ class _RemoteTouchViewState extends State<RemoteTouchView> {
Widget build ( BuildContext context ) {
return Focus (
autofocus: true ,
// 捕获物理按键(外接键盘 / 遥控器等)。
onKeyEvent: ( node , event ) {
if ( event is KeyDownEvent ) {
debugPrint ( ' RemoteTouchView: KeyDown - ${ event . logicalKey . debugName } ( ${ event . logicalKey . keyId } ) ' ) ;
widget . onKey ( event . logicalKey . keyId , 0 ) ;
return KeyEventResult . handled ;
} else if ( event is KeyUpEvent ) {
debugPrint ( ' RemoteTouchView: KeyUp - ${ event . logicalKey . debugName } ( ${ event . logicalKey . keyId } ) ' ) ;
widget . onKey ( event . logicalKey . keyId , 1 ) ;
return KeyEventResult . handled ;
}
@@ -97,41 +102,42 @@ class _RemoteTouchViewState extends State<RemoteTouchView> {
_startPosition = event . localPosition ;
_currentPosition = event . localPosition ;
_startTime = DateTime . now ( ) ;
_lastMoveTimestamp = 0 ; // 重置采样计时
final size = context . size ;
if ( size ! = null ) {
final rx = _toRelativeX ( event . localPosition , size ) ;
final ry = _toRelativeY ( event . localPosition , size ) ;
debugPrint ( ' RemoteTouchView: PointerDown - relX: ${ rx . toStringAsFixed ( 3 ) } , relY: ${ ry . toStringAsFixed ( 3 ) } ' ) ;
widget . onMotionEvent ( 0 , rx , ry ) ;
// 开始触摸时缓存 RenderBox 和 Size
_cachedRenderBox = context . findRenderObject ( ) as RenderBox ? ;
_cachedSize = _cachedRenderBox ? . size ;
if ( _cachedSize ! = null ) {
final rx = _toRelativeX ( event . localPosition , _cachedSize ! ) ;
final ry = _toRelativeY ( event . localPosition , _cachedSize ! ) ;
widget . onMotionEvent ( 0 , rx , ry ) ; // ACTION_DOWN
}
_longPressTimer = Timer ( _longPressTimeout , ( ) {
final size = context . size ;
if ( _currentPosition = = null | | size = = null ) return ;
if ( _currentPosition = = null | | _cachedSize = = null ) return ;
_isLongPressed = true ;
final x = _toRelativeX ( _currentPosition ! , size ) ;
final y = _toRelativeY ( _currentPosition ! , size ) ;
debugPrint ( ' RemoteTouchView: LongPress - relX: ${ x . toStringAsFixed ( 3 ) } , relY: ${ y . toStringAsFixed ( 3 ) } ' ) ;
final x = _toRelativeX ( _currentPosition ! , _cachedSize ! ) ;
final y = _toRelativeY ( _currentPosition ! , _cachedSize ! ) ;
widget . onLongPress ( x , y ) ;
} ) ;
} ,
onPointerMove: ( event ) {
_currentPosition = event . localPosition ;
final s ize = context . size ;
if ( size ! = null ) {
final rx = _toRelativeX ( event . localPosition , size ) ;
final ry = _toRelativeY ( event . localPosition , size ) ;
// Move 事件较多,可以考虑控制日志频率,这里直接打印
debugPrint ( ' RemoteTouchView: PointerMove - relX: ${ rx . toStringAsFixed ( 3 ) } , relY: ${ ry . toStringAsFixed ( 3 ) } ' ) ;
widget . onMotionEvent ( 2 , rx , ry ) ;
if ( _cachedS ize ! = null ) {
final now = DateTime . now ( ) . millisecondsSinceEpoch ;
// 采样率限制逻辑
if ( now - _lastMoveTimestamp > = _sampleIntervalMs ) {
_lastMoveTimestamp = now ;
final rx = _toRelativeX ( event . localPosition , _cachedSize ! ) ;
final ry = _toRelativeY ( event . localPosition , _cachedSize ! ) ;
widget . onMotionEvent ( 2 , rx , ry ) ; // ACTION_MOVE
}
}
if ( _longPressTimer ! = null & & _startPosition ! = null ) {
final dx = ( event . localPosition . dx - _startPosition ! . dx ). abs ( ) ;
final dy = ( event . localPosition . dy - _startPosition ! . dy ) . abs ( ) ;
if ( dx > _touchSlop | | dy > _touchSlop ) {
if ( ( event . localPosition - _startPosition ! ) . distance > _touchSlop ) {
_cancelLongPress ( ) ;
}
}
@@ -139,43 +145,32 @@ class _RemoteTouchViewState extends State<RemoteTouchView> {
onPointerUp: ( event ) {
_cancelLongPress ( ) ;
final s ize = context . size ;
if ( s ize ! = null ) {
final rx = _toRelativeX ( event . localPosition , size ) ;
final ry = _toRelativeY ( event . localPosition , size ) ;
debugPrint ( ' RemoteTouchView: PointerUp - relX: ${ rx . toStringAsFixed ( 3 ) } , relY: ${ ry . toStringAsFixed ( 3 ) } ' ) ;
widget . onMotionEvent ( 1 , rx , ry ) ;
if ( _cachedS ize ! = null ) {
final rx = _toRelativeX ( event . localPosition , _cachedS ize ! ) ;
final ry = _toRelativeY ( event . localPosition , _cachedSize ! ) ;
widget . onMotionEvent ( 1 , rx , ry ) ; // ACTION_UP
if ( ! _isLongPressed & & _startPosition ! = null & & _startTime ! = null ) {
final startX = _toRelativeX ( _startPosition ! , _cachedSize ! ) ;
final startY = _toRelativeY ( _startPosition ! , _cachedSize ! ) ;
final duration = DateTime . now ( ) . difference ( _startTime ! ) . inMilliseconds ;
final dx = ( rx - startX ) . abs ( ) ;
final dy = ( ry - startY ) . abs ( ) ;
if ( duration < 200 & & dx < 0.02 & & dy < 0.02 ) {
widget . onTouch ( startX , startY ) ;
} else {
widget . onSwipe ( startX , startY , rx , ry , max ( duration , 1 ) ) ;
}
}
}
// 长按已触发则不再派发单击 / 滑动事件(对应 Android 端 isLongPressed 逻辑)。
if ( _isLongPressed ) {
_startPosition = null ;
_currentPosition = null ;
_startTime = null ;
return ;
}
if ( _startPosition = = null | | size = = null | | _startTime = = null ) {
return ;
}
final startX = _toRelativeX ( _startPosition ! , size ) ;
final startY = _toRelativeY ( _startPosition ! , size ) ;
final endX = _toRelativeX ( event . localPosition , size ) ;
final endY = _toRelativeY ( event . localPosition , size ) ;
final duration = DateTime . now ( ) . difference ( _startTime ! ) . inMilliseconds ;
final dx = ( endX - startX ) . abs ( ) ;
final dy = ( endY - startY ) . abs ( ) ;
if ( duration < 200 & & dx < 0.02 & & dy < 0.02 ) {
debugPrint ( ' RemoteTouchView: Detected Touch - x: ${ startX . toStringAsFixed ( 3 ) } , y: ${ startY . toStringAsFixed ( 3 ) } ' ) ;
widget . onTouch ( startX , startY ) ;
} else {
debugPrint ( ' RemoteTouchView: Detected Swipe - from ( ${ startX . toStringAsFixed ( 3 ) } , ${ startY . toStringAsFixed ( 3 ) } ) to ( ${ endX . toStringAsFixed ( 3 ) } , ${ endY . toStringAsFixed ( 3 ) } ), duration: ${ max ( duration , 1 ) } ms ' ) ;
widget . onSwipe ( startX , startY , endX , endY , max ( duration , 1 ) ) ;
}
// 清理状态
_startPosition = null ;
_currentPosition = null ;
_startTime = null ;
_cachedRenderBox = null ;
_cachedSize = null ;
} ,
child: const ColoredBox (
color: Colors . transparent ,
@@ -185,3 +180,5 @@ class _RemoteTouchViewState extends State<RemoteTouchView> {
) ;
}
}