简体   繁体   English

如何在数据表小部件中制作英雄 animation?

[英]how to make hero animation in a datatable widget?

Hello everybody I have a datatable in which I filled with some data I want to add hero tag to each row in the datatable so when I click on that row it will open another MaterialPageRoute which contains a widget with the same hero tag of that particular row.大家好我有一个数据表,我在其中填充了一些数据我想将英雄标签添加到数据表中的每一行,所以当我单击该行时,它将打开另一个 MaterialPageRoute,其中包含一个具有与该特定行相同的英雄标签的小部件. The problem is that the hero animation is not working properly it shows the MaterialPageRoute normally without animation.问题是英雄 animation 无法正常工作,它在没有 animation 的情况下正常显示 MaterialPageRoute。

import 'package:art_sweetalert/art_sweetalert.dart';
import 'package:flutter/material.dart';
import 'package:global_flutter_lib/I18n-Helper.dart';
import 'package:provider/provider.dart';
import 'package:shopping_cart_data/Data/Models/Setting.dart';
import 'package:shopping_cart_project/App-Widgets/App-Colors.dart';
import 'package:shopping_cart_project/Helpers/App-UI-Helper.dart';
import 'package:shopping_cart_project/States/States.dart';

import 'CustomRect-Tween.dart';
import 'hero-tags.dart';

class SettingTableWidget extends StatefulWidget {
  const SettingTableWidget({Key? key}) : super(key: key);

  @override
  State<SettingTableWidget> createState() => _SettingTableWidgetState();
}

class _SettingTableWidgetState extends State<SettingTableWidget> {
  GlobalKey<ArtDialogState>? _artDialogKey;

  final Map<int, GlobalKey> _buttonMapKeys = {};

  Setting? _selectedSetting;
  String? companyHeaderText;

  String? nameArabicHeaderText;
  String? nameEnglishHeaderText;
  String? yearHeaderText;
  String? ipHeaderText;
  String? portHeaderText;

  String? defaultHeaderText;

  String? addSettingText;

  @override
  void initState() {
    super.initState();
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();

    companyHeaderText ??= I18nHelper.t(context, "setting.company");

    nameArabicHeaderText ??= I18nHelper.t(context, "setting.nameArabic");
    nameEnglishHeaderText ??= I18nHelper.t(context, "setting.nameEnglish");
    yearHeaderText ??= I18nHelper.t(context, "setting.year");
    ipHeaderText ??= I18nHelper.t(context, "setting.ip");
    portHeaderText ??= I18nHelper.t(context, "setting.port");

    defaultHeaderText ??= I18nHelper.t(context, "setting.default");

    addSettingText ??= I18nHelper.t(context, "global.add");
  }

  @override
  Widget build(BuildContext context) {
    SettingState settingState = Provider.of<SettingState>(context);

    return Column(
      children: [
        Row(
          children: [
            Padding(
              padding: const EdgeInsets.symmetric(vertical: 8.0),
              child: ElevatedButton(
                  style:
                      ElevatedButton.styleFrom(primary: AppColors.primaryColor),
                  onPressed: _addNewRow,
                  child: Text(addSettingText!)),
            )
          ],
        ),
        const SizedBox(
          height: 10,
        ),
        Expanded(
          child: DataTable(
              headingRowColor: MaterialStateColor.resolveWith(
                  (states) => Colors.grey.shade300),
              showBottomBorder: true,
              showCheckboxColumn: false,
              columns: _createColumns(),
              rows: _createRows()),
        ),
      ],
    );
  }

  final TextStyle _columnHeaderStyle =
      const TextStyle(fontWeight: FontWeight.bold);

  _createColumns() {
    List<DataColumn> colList = [];
    colList.add(const DataColumn(label: Text("")));
    colList.add(DataColumn(
        label: Text(
      companyHeaderText!,
      // I18nHelper.t(context, "setting.company"),
      style: _columnHeaderStyle,
    )));
    colList.add(DataColumn(
        label: Text(
      nameArabicHeaderText!,
      style: _columnHeaderStyle,
    )));
    colList.add(DataColumn(
        label: Text(
      nameEnglishHeaderText!,
      style: _columnHeaderStyle,
    )));
    colList.add(DataColumn(
        label: Text(
      yearHeaderText!,
      style: _columnHeaderStyle,
    )));
    colList.add(DataColumn(
        label: Text(
      ipHeaderText!,
      style: _columnHeaderStyle,
    )));
    colList.add(DataColumn(
        label: Text(
      portHeaderText!,
      style: _columnHeaderStyle,
    )));

    colList.add(const DataColumn(
        label: SizedBox(
      width: 0,
      height: 0,
    )));
    return colList;
  }

  _createRows() {
    SettingState settingState =
        Provider.of<SettingState>(context, listen: false);
    List<DataRow> rowList = [];
    for (Setting s in settingState.list) {
      rowList.add(DataRow(
          color: settingState.current == s
              ? MaterialStateProperty.all(Colors.grey.shade300)
              : MaterialStateProperty.all(Colors.white),
          onSelectChanged: (selected) => _onSelectChanged(s, selected),
          cells: [
            DataCell(_createActions(s)),
            DataCell(Text(s.company ?? "")),
            DataCell(Text(s.nameArabic ?? "")),
            DataCell(Text(s.nameEnglish ?? "")),
            DataCell(Text(s.year.toString())),
            DataCell(Text(s.ip.toString())),
            DataCell(Text(s.port.toString())),
            DataCell(Row(
              children: [
                settingState.defaultSetting?.id == s.id
                    ? Icon(
                        Icons.check,
                        color: AppColors.primaryColor,
                      )
                    : Container(),
                ElevatedButton(
                    onPressed: () async {
                      // I18nHelper.setLocale(context, SessionVariables.language!);
                      await settingState.setSettingAsDefault(setting: s);
                    },
                    child: Text(defaultHeaderText!))
              ],
            )),
          ]));
    }
    return rowList;
  }

  _onSelectChanged(Setting s, bool? selected) {
    //=================
    // print("_onSelectChanged Selected ;$selected - Setting: ${s.nameArabic}");
    SettingState settingState =
        Provider.of<SettingState>(context, listen: false);
    settingState.setCurrent(s);
    // _selectedSetting = s;
  }

  _createActions(Setting setting) {
    if (_buttonMapKeys.containsKey(setting.id) == false) {
      _buttonMapKeys[setting.id as int] = GlobalKey();
    }
    return Row(children: [
      Hero(
        tag:setting.id,
        createRectTween: (begin, end) {
          return CustomRectTween(begin: begin!, end: end!);
        },
        child: IconButton(
          key: _buttonMapKeys[setting.id],
          color: AppColors.primaryColor,
          onPressed: () => _editRow(setting),
          icon: const Icon(Icons.edit),
        ),
      ),
      IconButton(
        color: AppColors.primaryColor,
        onPressed: () => _deleteRow(setting),
        icon: const Icon(Icons.delete),
      )
    ]);
  }

  _addNewRow() {
    Setting s = Setting.create();
    AppUIHelper.showSettingFormDialog(context, s);
  }

  void _editRow(Setting s) async {
    RenderBox? renderBox =
        _buttonMapKeys[s.id]?.currentContext?.findRenderObject() as RenderBox?;

    SettingState settingState =
        Provider.of<SettingState>(context, listen: false);

    settingState.setCurrent(s);

    // AppUIHelper.showSettingFormDialog(context, s,
    //     offset: renderBox?.localToGlobal(const Offset(0, 0)) as Offset);

    showSettingFormDialog(
      context,
      s,
    );
  }

  void _deleteRow(Setting s) async {
    SettingState settingState =
        Provider.of<SettingState>(context, listen: false);

    settingState.setCurrent(s);
    AppUIHelper.showConfirmDelete(context, onConfirm: () async {
      await settingState.deleteRow();
    });
  }

   showSettingFormDialog(){
        showSettingFormDialog(BuildContext context, Setting setting,
      {String title = ""}) {
    Navigator.push(
        context,
        HeroDialogRoute(
            horizPadding: 370,
            tag: setting.id,
            title: title,
            builder: (_) => SettingFormWidget(
                  setting: setting,
                )));
  }   
    }
}

//======================HeroTagDialog

/// {@template hero_dialog_route}
/// Custom [PageRoute] that creates an overlay dialog (popup effect).
///
/// Best used with a [Hero] animation.
/// {@endtemplate}
class HeroDialogRoute<T> extends PageRoute<T> {
  final double? vertPadding;
  final double? horizPadding;

  final String? tag;
  final String? title;

  /// {@macro hero_dialog_route}
  HeroDialogRoute(
      {required WidgetBuilder builder,
      RouteSettings? settings,
      bool fullscreenDialog = false,
      this.vertPadding = 80,
      this.horizPadding = 80,
      this.tag,
      this.title})
      : _builder = builder,
        super(settings: settings, fullscreenDialog: fullscreenDialog);

  final WidgetBuilder _builder;

  @override
  bool get opaque => false;

  @override
  bool get barrierDismissible => false;

  @override
  Duration get transitionDuration => const Duration(milliseconds: 600);

  @override
  Duration get reverseTransitionDuration => const Duration(milliseconds: 900);

  @override
  bool get maintainState => true;

  @override
  Color get barrierColor => Colors.black54;

  @override
  Widget buildTransitions(BuildContext context, Animation<double> animation,
      Animation<double> secondaryAnimation, Widget child) {
    return ScaleTransition(scale: animation, child: child);
  }

  @override
  Widget buildPage(BuildContext context, Animation<double> animation,
      Animation<double> secondaryAnimation) {
    return Center(
      child: Padding(
        padding: EdgeInsets.symmetric(
            vertical: vertPadding ?? 80.0, horizontal: horizPadding ?? 80.0),
        child: Hero(
          tag: tag ?? "HeroTag",
          createRectTween: (begin, end) {
            return CustomRectTween(begin: begin!, end: end!);
          },
          child: Container(
            decoration: BoxDecoration(
                borderRadius: const BorderRadius.all(Radius.circular(20)),
                border: Border.all(color: AppColors.primaryColor, width: 4)),
            child: ClipRRect(
              clipBehavior: Clip.antiAliasWithSaveLayer,
              borderRadius: const BorderRadius.all(Radius.circular(20)),
              child: Scaffold(
                appBar: AppBar(
                    backgroundColor: AppColors.primaryColor,
                    title: AppUIHelper.dialogTitle(title: title ?? "No Title")),
                body: _builder(context),
              ),
            ),
          ),
        ),
      ),
    );
  }

  @override
  String get barrierLabel => 'Popup dialog open';
}




I found out the problem I wrapped the SettingTableWidget with AlertDialog and any child widgets inside the AlertDialog does not support the hero tag so instead of using showDialog method I used我发现了我用 AlertDialog 包装 SettingTableWidget 的问题,并且 AlertDialog 内的任何子小部件都不支持 hero 标记,所以我没有使用 showDialog 方法

Navigator.of(context).push(MaterialPageRoute(builder(_)=>SettingTableWidget()))

and it works like charm,thanks.它就像魅力一样,谢谢。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM