Column child PageView interaction through the whole screen

560 Views Asked by At

I'm trying to create a screen as follows:

enter image description here

The bottom part is PageView.builder. I want it to be interactable through the whole screen.

The first thing I came up with was wrapping them in a stack, creating an invisible PageView on the top, and synchronizing the bottom and invisible(top) PageViews' controllers. But, in this case, the button doesn't receive input.

PS: Wrapping the top PageView by a listener with HitTestBehavior.translucent didn't work. I think PageView doesn't let tap events propagate.

How can I aproach this screen?

class Test extends StatelessWidget {
  Test({Key? key}) : super(key: key);
  final pageController = PageController();
  final infoPages = [
    Container(
      color: Colors.blue[200],
      child: Text("info 1"),
    ),
    Container(
      color: Colors.blue[400],
      child: Text("info 2"),
    ),
    Container(
      color: Colors.blue[600],
      child: Text("info 3"),
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Expanded(
            flex: 2,
            child: Container(
              color: Colors.grey,
              child: Text("this is a static image"),
            )),
        Expanded(
          child: TextButton(
            onPressed: () {
              print("button pressed");
            },
            child: const Text("This is a static button"),
          ),
        ),
        Expanded(
          flex: 2,
          child: PageView.builder(
            controller: pageController,
            itemCount: infoPages.length,
            itemBuilder: ((context, index) {
              return infoPages[index];
            }),
          ),
        ),
      ],
    );
  }
}
1

There are 1 best solutions below

0
On

Dear parallel universe me; I solved it by wrapping it with a stack, disabling the PageView interaction, and controlling it with a GestureDetector.

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

  @override
  State<Test> createState() => _TestState();
}

class _TestState extends State<Test> {
  final pageController = PageController();

  final infoPages = [
    Container(
      color: Colors.blue[200],
      child: Text("info 1"),
    ),
    Container(
      color: Colors.blue[400],
      child: Text("info 2"),
    ),
    Container(
      color: Colors.blue[600],
      child: Text("info 3"),
    ),
  ];

  late double offset;
  late double start;
  bool snap = true;

  @override
  Widget build(BuildContext context) {
    return Stack(children: [
      Column(
        children: [
          Expanded(
            flex: 2,
            child: Container(
              color: Colors.grey,
              child: Text("this is a static image"),
            ),
          ),
          Expanded(
            child: TextButton(
              onPressed: () {
                print("button pressed");
              },
              child: const Text("This is a static button"),
            ),
          ),
          Expanded(
            flex: 2,
            child: PageView.builder(
              pageSnapping: snap,
              physics: const NeverScrollableScrollPhysics(),
              controller: pageController,
              itemCount: infoPages.length,
              itemBuilder: ((context, index) {
                return infoPages[index];
              }),
            ),
          ),
        ],
      ),
      GestureDetector(
        onHorizontalDragStart: (details) {
          offset = pageController.offset;
          start = details.globalPosition.dx;
          setState(() {
            snap = false;
          });
        },
        onHorizontalDragUpdate: (details) {
          final dx = details.globalPosition.dx - start;
          double temp = offset - dx;
          pageController.jumpTo(temp);
        },
        onHorizontalDragEnd: (details) {
          setState(() {
            snap = true;
          });
        },
      )
    ]);
  }
}