1

given the code below

import 'package:flutter/material.dart';

Future<void> _showMyDialog(BuildContext context) async => showDialog<void>(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Success'),
        content: const Text('nice job!'),
        actions: <Widget>[
          TextButton(
            child: const Text('done'),
            onPressed: Navigator.of(context).pop,
          ),
        ],
      ),
    );

void main() => runApp(
      const MaterialApp(
        home: SafeArea(
          child: MyHomePage(),
        ),
      ),
    );

class MyHomePage extends StatelessWidget {
  const MyHomePage({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) => Material(
        child: Stack(
          fit: StackFit.expand,
          children: [
            Positioned(
              bottom: 25,
              right: 25,
              child: FloatingActionButton(
                child: const Icon(Icons.message),
                onPressed: () => _showMyDialog(context),
              ),
            ),
            PageView.builder(
              itemBuilder: (context, index) => Center(
                child: SizedBox(
                  height: MediaQuery.of(context).size.height,
                  width: MediaQuery.of(context).size.width / 2,
                  child: const ColoredBox(
                    color: Color.fromRGBO(60, 30, 10, .5),
                  ),
                ),
              ),
            ),
          ],
        ),
      );
}


how do I make the button clickable without changing the order of the children in the stack and keeping the scroll view scrollable?

I have tried wrapping the PageView in a GestureDetector without results

  GestureDetector(
              behavior: HitTestBehavior.translucent,
              onTap: null,
              child: PageView.builder(
                itemBuilder: (context, index) => ...
              ),
            ),

flutter issue

aoatmon
  • 507
  • 4
  • 13

1 Answers1

1

Updated Answer

The problem is PageView takes up the whole screen. There is no visible part of FloatingActionButton regarding gesture events.

If you don't want to change the order of your stack children's widgets, you have to change the PageView area.

Below is the updated code snippet. The PageView is scrollable but only in its area. The FloatingActionButton is clickable.

import 'package:flutter/material.dart';

Future<void> _showMyDialog(BuildContext context) async => showDialog<void>(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Success'),
        content: const Text('nice job!'),
        actions: <Widget>[
          TextButton(
            child: const Text('done'),
            onPressed: Navigator.of(context).pop,
          ),
        ],
      ),
    );

void main() => runApp(
      const MaterialApp(
        home: SafeArea(
          child: MyHomePage(),
        ),
      ),
    );

class MyHomePage extends StatelessWidget {
  const MyHomePage({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) => Material(
        child: Stack(
          children: [
            Positioned(
              bottom: 25,
              right: 25,
              child: FloatingActionButton(
                child: const Icon(Icons.message),
                onPressed: () => _showMyDialog(context),
              ),
            ),
    
            Positioned(     //// <------  
 //// The page ends before it can cover the floating action button.
 /// But if the screen size changes, you might have to see how to make it work.

              left: MediaQuery.of(context).size.width / 4,
              top: 0,
              bottom: 0,
              width: MediaQuery.of(context).size.width / 2,
              child: PageView.builder(
                itemCount: 3,
                itemBuilder: (context, index) => ColoredBox(
                  color: Color.fromRGBO(60, 30, index * 100, .5),
                ),
              ),
            ),
          ],
        ),
      );
}

You can have a global PageView controller to set the scrollable functionality outside of the pageview area.


Old Answer

Wrap the PageView (the top widget which must be transparent to any tap) with IgnorePointer and set the ignoring field to true.

This will make the FloatingActionButton (the down widget) listen to tap events.

Here is the code snippet with change:

...
              child: FloatingActionButton(
                child: const Icon(Icons.message),
                onPressed: () => _showMyDialog(context),
              ),
            ),


            IgnorePointer(    /// <---------- Wrap with IgnorePointer
              ignoring: true,

              child: PageView.builder(
                itemBuilder: (context, index) => Center(
                  child: SizedBox(
                    height: MediaQuery.of(context).size.height,
                    width: MediaQuery.of(context).size.width / 2,
                    child: const ColoredBox(
                      color: Color.fromRGBO(60, 30, 10, .5),
                    ),
                  ),
...

See this for reference.

nicks101
  • 1,065
  • 11
  • 20