使可点击的页面在堆栈抖动下

时间:2018-09-04 21:47:02

标签: android dart flutter

我只有一个堆栈,其中包含断头台菜单和列表。但是下面的页面(列表和工厂)不可点击!第一个代码是主页,第二个代码是书籍(下页),第三个代码是断头台菜单。
如何使可点击的页面下方?

enter image description here

主页

import 'package:firebase_example/Ui/Books.dart';
import 'package:firebase_example/Ui/GuillotineMenu.dart';
import 'package:flutter/material.dart';

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  final GlobalKey<ScaffoldState> _drawerKey = new GlobalKey();

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      debugShowCheckedModeBanner: false,
      home: SafeArea(
        top: false,
        bottom: false,
        child: new Container(
          child: new Stack(
            alignment: Alignment.topLeft,
            children: <Widget>[
              Books(),
              GuillotineMenu(),
            ],
          ),
        ),
      ),
    );

3 个答案:

答案 0 :(得分:2)

您要寻找的是IgnorePointer。通过使用它,您应该能够将您的窗口小部件从点击测试中排除(因此可以触摸其下的内容)。

您将必须小心如何实现使断头台菜单打开/关闭的按钮。我建议将其作为堆栈中较低项的一部分,然后在断头台关闭时设置IgnorePointer的ignoring = true

请注意,使用PageRoutes实现断头台菜单可能会有“更好”的方式。这样,您只需要在现有导航器上推入/弹出一条新路线,而不必维护自己的堆栈。

代码如下:

class GuillotinePageRoute<T> extends PageRoute<T> {
  GuillotinePageRoute({
    @required this.builder,
    RouteSettings settings: const RouteSettings(),
    this.maintainState: true,
    bool fullscreenDialog: false,
  })  : assert(builder != null),
        super(settings: settings, fullscreenDialog: fullscreenDialog);

  final WidgetBuilder builder;

  @override
  final bool maintainState;

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

  @override
  Color get barrierColor => null;

  @override
  Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
    final Widget result = builder(context);
    assert(() {
      if (result == null) {
        throw new FlutterError('The builder for route "${settings.name}" returned null.\n'
            'Route builders must never be null.');
      }
      return true;
    }());
    return result;
  }

  @override
  Widget buildTransitions(
      BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
    MediaQueryData queryData = MediaQuery.of(context);

    var topInset = queryData.padding.top;

    Offset origin = Offset((kToolbarHeight / 2.0), topInset + (kToolbarHeight / 2.0));

    Curve curve = animation.status == AnimationStatus.forward ? Curves.bounceOut : Curves.bounceIn;
    var rotateTween = new Tween(begin: -pi / 2.0, end: 0.0);

    Cubic opacityCurve = Cubic(0.0, 1.0, 0.0, 1.0);

    return new AnimatedBuilder(
      animation: animation,
      child: child,
      builder: (context, child) {
        return Opacity(
          opacity: opacityCurve.transform(animation.value),
          child: Transform(
            transform: Matrix4.identity()..rotateZ(rotateTween.lerp(curve.transform(animation.value))),
            origin: origin,
            child: child,
          ),
        );
      },
    );
  }

  @override
  String get barrierLabel => null;
}

并在示例中使用它:

import 'dart:math';

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MenuPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(children: [
      AppBar(
        leading: new IconButton(icon: Icon(Icons.menu), onPressed: () => Navigator.pop(context)),
        elevation: 0.0,
      ),
      Expanded(
        child: Container(
          child: Center(
            child: Text(
              "Menu page!",
              style: TextStyle(color: Colors.white, decoration: TextDecoration.none),
            ),
          ),
          color: Colors.blue,
        ),
      ),
    ]);
  }
}

class MyHomePage extends StatelessWidget {
  void pushGuillotine(BuildContext context, WidgetBuilder builder) {
    Navigator.push(context, new GuillotinePageRoute(builder: builder));
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("This is a title"),
        leading: new RotatedBox(
          quarterTurns: -1,
          child: IconButton(icon: Icon(Icons.menu), onPressed: () => pushGuillotine(context, (context) => MenuPage())),
        ),
      ),
      body: Container(
        color: Colors.blueGrey,
        child: Center(
          child: new Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              new Text(
                'This is the home page.',
              ),
              new Text(
                'Hello world!',
                style: Theme.of(context).textTheme.display1,
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class GuillotinePageRoute<T> extends PageRoute<T> {
  GuillotinePageRoute({
    @required this.builder,
    RouteSettings settings: const RouteSettings(),
    this.maintainState: true,
    bool fullscreenDialog: false,
  })  : assert(builder != null),
        super(settings: settings, fullscreenDialog: fullscreenDialog);

  final WidgetBuilder builder;

  @override
  final bool maintainState;

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

  @override
  Color get barrierColor => null;

  @override
  Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
    final Widget result = builder(context);
    assert(() {
      if (result == null) {
        throw new FlutterError('The builder for route "${settings.name}" returned null.\n'
            'Route builders must never be null.');
      }
      return true;
    }());
    return result;
  }

  @override
  Widget buildTransitions(
      BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
    MediaQueryData queryData = MediaQuery.of(context);

    var topInset = queryData.padding.top;

    Offset origin = Offset((kToolbarHeight / 2.0), topInset + (kToolbarHeight / 2.0));

    Curve curve = animation.status == AnimationStatus.forward ? Curves.bounceOut : Curves.bounceIn;
    var rotateTween = new Tween(begin: -pi / 2.0, end: 0.0);

    Cubic opacityCurve = Cubic(0.0, 1.0, 0.0, 1.0);

    return new AnimatedBuilder(
      animation: animation,
      child: child,
      builder: (context, child) {
        return Opacity(
          opacity: opacityCurve.transform(animation.value),
          child: Transform(
            transform: Matrix4.identity()..rotateZ(rotateTween.lerp(curve.transform(animation.value))),
            origin: origin,
            child: child,
          ),
        );
      },
    );
  }

  @override
  String get barrierLabel => null;
}

答案 1 :(得分:0)

如果您有一个没有交互的窗口小部件,并且希望使用GestureDetector窗口小部件作为父级使其可单击,则可以在链接中查看示例。

---编辑

当您需要在不进行交互的情况下创建小部件时,此答案可以为您提供一些(并非完全是此问题的内容)诚实的错误,但是我可以帮助其他人。

答案 2 :(得分:0)

它是使用手势检测器的onTapDown的堆栈,该功能在浮动操作按钮中不可用