Player_Flutter
Player_Flutter copied to clipboard
TXPlayerVideo 中双指放大5-7倍,播放器会卡,画面会糊,甚至停止播放。
flutter 中双指放大5-7倍,播放器会卡,甚至停止播放,画面会糊。
使用flutter 推荐的包 video_player 就很流畅,不会卡。
@Downey-Tang 辛苦帮忙确认下,放大是什么什么组件和逻辑放大的,我们看看能否优化
import 'dart:math';
import 'package:flutter/material.dart';
class ZoomableWidget extends StatefulWidget {
final Widget child;
final double minScale;
final double maxScale;
const ZoomableWidget({
super.key,
required this.child,
this.minScale = 0.2,
this.maxScale = 7.0,
});
@override
State createState() => _ZoomableWidgetState();
}
class _ZoomableWidgetState extends State with TickerProviderStateMixin {
double _scale = 1.0;
Offset _translate = Offset.zero;
final Map _pointers = {};
Size _containerSize = Size.zero;
Offset? _previousCenter;
double? _previousDistance;
late AnimationController _animationController;
late Animation _scaleAnimation;
late Animation _translateAnimation;
@override
void initState() {
super.initState();
_animationController = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
);
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
void _handleZoom(List points) {
final currentCenter = (points[0] + points[1]) / 2;
final currentDistance = (points[0] - points[1]).distance;
if (_previousCenter != null && _previousDistance != null) {
final scaleFactor = (currentDistance / _previousDistance!) - 1.0;
final limitedScaleFactor = scaleFactor.clamp(-0.5, 0.5);
final targetScale = _scale * (1 + limitedScaleFactor);
final newScale = targetScale.clamp(widget.minScale, widget.maxScale);
final localPoint = (currentCenter -
Offset(
_containerSize.width / 2,
_containerSize.height / 2,
)) /
_scale;
final matrix = Matrix4.identity()
..translate(localPoint.dx, localPoint.dy)
..scale(newScale / _scale)
..translate(-localPoint.dx, -localPoint.dy);
final updatedTransform = matrix
..multiply(Matrix4.identity()
..translate(_translate.dx, _translate.dy)
..scale(_scale));
setState(() {
_scale = newScale;
_translate = Offset(
updatedTransform.getTranslation().x,
updatedTransform.getTranslation().y,
);
_setOffsetLimits();
});
}
_previousCenter = currentCenter;
_previousDistance = currentDistance;
}
void _setOffsetLimits() {
final size = _containerSize;
final double maxX = max(0, size.width * (_scale - 1) / 2);
final double maxY = max(0, size.height * (_scale - 1) / 2);
final dx = _translate.dx.clamp(-maxX, maxX);
final dy = _translate.dy.clamp(-maxY, maxY);
_translate = Offset(dx, dy);
}
void _resetZoomState() {
_previousCenter = null;
_previousDistance = null;
if (_scale != 1.0) {
_animateReset();
} else {
setState(() {
_scale = 1.0;
_translate = Offset.zero;
});
}
}
void _animateReset() {
_animationController.reset();
double curScale = _scale;
Offset curTranslate = _translate;
_scaleAnimation = Tween(
begin: curScale,
end: 1.0,
).animate(CurvedAnimation(
parent: _animationController,
curve: Curves.easeInOut,
));
_translateAnimation = Tween(
begin: curTranslate,
end: Offset.zero,
).animate(CurvedAnimation(
parent: _animationController,
curve: Curves.easeInOut,
));
void updateState() {
if (mounted) {
setState(() {
_scale = _scaleAnimation.value;
_translate = _translateAnimation.value;
});
}
}
_animationController.addListener(updateState);
_animationController.forward().whenCompleteOrCancel(() {
_animationController.removeListener(updateState);
setState(() {
_scale = 1.0;
_translate = Offset.zero;
});
});
}
Widget _buildScaleWidget() {
return Listener(
onPointerDown: (event) {
_pointers[event.pointer] = event.position;
},
onPointerMove: (event) {
if (_pointers.containsKey(event.pointer)) {
_pointers[event.pointer] = event.position;
if (_pointers.length == 2) {
_handleZoom(_pointers.values.toList());
}
}
},
onPointerUp: (event) {
_pointers.remove(event.pointer);
if (_pointers.isEmpty) {
_resetZoomState();
}
setState(() {});
},
onPointerCancel: (event) {
_pointers.remove(event.pointer);
if (_pointers.isEmpty) {
_resetZoomState();
}
setState(() {});
},
child: RepaintBoundary(
child: Transform(
alignment: Alignment.center,
transform: Matrix4.identity()
..translate(_translate.dx, _translate.dy)
..scale(_scale),
child: widget.child,
),
),
);
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
_containerSize = Size(constraints.maxWidth, constraints.maxHeight);
return _buildScaleWidget();
},
);
}
}
使用:
ZoomableWidget(
child: Image.asset('assets/your_image.png'),
)
上面是去除业务逻辑的缩放代码实现; 包装 TXPlayerVideo 和 flutter 推荐的包 video_player,设置循环播放 ,对比 双指放大效果(不要松手),
video_player 很丝滑 , TXPlayerVideo 会糊,会卡,会停止播放
@Downey-Tang 感谢提供复现代码,这里是系统或者 flutter 对 TextureView 做了限制,放大后,view 超出屏幕的不可见部分到一定程度,纹理的更新就会停掉,来优化性能,这里可以将 renderType 切为 SurfaceView 试试