简体   繁体   中英

Flutter: How to know if my widget is inside another widget of a specific type?

I am writing a Widget called TopBar , and associated with it is another Widget called TopBarAction . I need to know if TopBarAction is being used inside TopBar or not in order to use an Align or Positioned widget in its build method:

class TopBar extends StatelessWidget {

  final List<Widget> actions;
  final EdgeInsets padding;
  final Alignment actionsAlignment;

  ...

  @override
  Widget build(BuildContext context) {
    final MediaQueryData moc = MediaQuery.of(context);
    return LimitedBox(
      maxWidth: moc.size.width,
      maxHeight: moc.size.height,
      child: Stack(
        alignment: actionsAlignment,
        children: actions,
      ),
    );
  }
}

class TopBarAction extends StatelessWidget {

  final Widget title;
  final VoidCallback onTap;
  final EdgeInsets? padding;
  final Alignment? actionAlignment;

  ...

  @override
  Widget build(BuildContext context) {
    bool isParentTopBar = false;
    context.visitAncestorElements((element) { <-------- Is this the right way to do it??
      if (element.widget is TopBar) {
        isParentTopBar = true;
      }
      return false; // return false to stop visiting other widgets. Only visit the direct parent.
    });
    late Widget child;
    child = Padding(
      padding: padding ?? EdgeInsets.zero,
      child: InkWell(
        onTap: onTap,
        child: title,
      ),
    );
    if (actionAlignment != null && isParentTopBar) {
      child = Align(
        alignment: actionAlignment!,
        child: child,
      );
    }
    return child;
  }
}

visitAncestorElements may get very expensive but in your case you're just adding an additional visit to the parent node, and that might be ok.

But I'd suggest the following to simplify your code and to prevent the use of visitAncestorElements .


class TopBar extends StatelessWidget {
  const TopBar({
    required this.actions,
    required this.padding,
    required this.actionsAlignment,
    super.key,
  });

  final List<Widget> actions;
  final EdgeInsets padding;
  final Alignment actionsAlignment;

  @override
  Widget build(BuildContext context) {
    final moc = MediaQuery.of(context);
    return LimitedBox(
      maxWidth: moc.size.width,
      maxHeight: moc.size.height,
      child: Stack(
        alignment: actionsAlignment,
        children: [
          for (final a in actions)
            if (a is TopBarAction)
              Align(
                alignment: actionsAlignment,
                child: a,
              )
            else
              Padding(padding: padding, child: a)
        ],
      ),
    );
  }
}

class TopBarAction extends StatelessWidget {
  const TopBarAction({
    required this.title,
    required this.onTap,
    super.key,
  });

  final Widget title;
  final VoidCallback onTap;

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: onTap,
      child: title,
    );
  }
}

Let me know if i've understood what you need.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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