#flutter #dart
#флаттер #dart
Вопрос:
Я бы хотел, чтобы изображение, которое я масштабирую, возвращалось к исходному значению масштаба (1.0), когда оно будет выпущено.
onInteractionEnd кажется подходящим свойством для этого, но я не уверен, как получить доступ к свойству scale для создания функции, которая это делает.
child: InteractiveViewer(
boundaryMargin: EdgeInsets.all(0.0),
minScale: 1.0,
maxScale: 2.5,
onInteractionEnd: //scale = 1.0,
Ответ №1:
Вы можете скопировать вставить запустить полный код ниже
, это модификация официального примера transformationController
https://api.flutter.dev/flutter/widgets/InteractiveViewer/transformationController.html
Всякий раз, когда дочерний элемент преобразуется, Matrix4
значение обновляется, и все listeners
получают уведомление. Если значение установлено, InteractiveViewer
будет обновляться с учетом нового значения.
Вы можете в onInteractionEnd
анимации сброса в качестве официальной демонстрации выполнить
фрагмент кода
void _animateResetInitialize() {
_controllerReset.reset();
_animationReset = Matrix4Tween(
begin: _transformationController.value,
end: Matrix4.identity(),
).animate(_controllerReset);
_animationReset.addListener(_onAnimateReset);
_controllerReset.forward();
}
void _onInteractionEnd(ScaleEndDetails details) {
_animateResetInitialize();
}
рабочая демонстрация
полный код
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
/// This is the stateful widget that the main application instantiates.
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({Key key}) : super(key: key);
@override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
/// This is the private State class that goes with MyStatefulWidget.
/// AnimationControllers can be created with `vsync: this` because of TickerProviderStateMixin.
class _MyStatefulWidgetState extends State<MyStatefulWidget>
with TickerProviderStateMixin {
final TransformationController _transformationController =
TransformationController();
Animation<Matrix4> _animationReset;
AnimationController _controllerReset;
void _onAnimateReset() {
_transformationController.value = _animationReset.value;
if (!_controllerReset.isAnimating) {
_animationReset?.removeListener(_onAnimateReset);
_animationReset = null;
_controllerReset.reset();
}
}
void _animateResetInitialize() {
_controllerReset.reset();
_animationReset = Matrix4Tween(
begin: _transformationController.value,
end: Matrix4.identity(),
).animate(_controllerReset);
_animationReset.addListener(_onAnimateReset);
_controllerReset.forward();
}
// Stop a running reset to home transform animation.
void _animateResetStop() {
_controllerReset.stop();
_animationReset?.removeListener(_onAnimateReset);
_animationReset = null;
_controllerReset.reset();
}
void _onInteractionStart(ScaleStartDetails details) {
// If the user tries to cause a transformation while the reset animation is
// running, cancel the reset animation.
if (_controllerReset.status == AnimationStatus.forward) {
_animateResetStop();
}
}
void _onInteractionEnd(ScaleEndDetails details) {
_animateResetInitialize();
}
@override
void initState() {
super.initState();
_controllerReset = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 400),
);
}
@override
void dispose() {
_controllerReset.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).colorScheme.primary,
appBar: AppBar(
automaticallyImplyLeading: false,
title: const Text('Controller demo'),
),
body: Center(
child: InteractiveViewer(
boundaryMargin: EdgeInsets.all(double.infinity),
transformationController: _transformationController,
minScale: 1.0,
maxScale: 2.5,
onInteractionStart: _onInteractionStart,
onInteractionEnd: _onInteractionEnd,
child: Image.network("https://picsum.photos/250?image=9")
),
),
persistentFooterButtons: [
IconButton(
onPressed: _animateResetInitialize,
tooltip: 'Reset',
color: Theme.of(context).colorScheme.surface,
icon: const Icon(Icons.replay),
),
],
);
}
}
Комментарии:
1. Спасибо! Отлично работает. Для нескольких изображений на одном экране вы бы делали все это повторно или часть этого кода может применяться к нескольким изображениям?
2. @chrisfavritz, не могли бы вы опубликовать свой код воспроизведения для нового вопроса. необходимо воспроизвести макет нескольких изображений. Спасибо.
3. @chunhunghan Просто потрясающе!
Ответ №2:
Я придумал простое решение.
Просто сохраните начальное значение контроллера в начале взаимодействия, а затем вернитесь к этому значению, когда взаимодействие закончится.
TransformationController controllerT = TransformationController();
var initialControllerValue;
InteractiveViewer(
minScale: 1.0,
maxScale: 100.0,
transformationController: controllerT,
onInteractionStart: (details){
initialControllerValue = controllerT.value;
},
onInteractionEnd: (details){
controllerT.value = initialControllerValue;
},
...
Если вы хотите это в виде таблицы или списка, просто объявите контроллер в itemBuilder:
ListView.builder(
itemCount: widget.types.length,
itemBuilder: (context, index) {
TransformationController controllerT = TransformationController();
var initialControllerValue;