luckysmg
luckysmg

Reputation: 369

In flutter How to make the inner widget with pan gesture will not conflict with PageView

I have a widget with pan gesture in PageView ,and the PageView can scoll horizontally,When I pan the widget horizontally,the PageView will move.

What I expect is that the pan gesture can move the widget in the pageview,instead of moving the PageView

Here is the picture.

enter image description here

Here is the demo code"

import 'package:flutter/material.dart';


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

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: PageView.builder(
        itemBuilder: (ctx, index) {
          return ChildPage(
            index: index,
          );
        },
        itemCount: 2,
      ),
    );
  }
}

class ChildPage extends StatefulWidget {
  final int index;

  const ChildPage({Key? key, required this.index}) : super(key: key);

  @override
  _ChildPageState createState() => _ChildPageState();
}

class _ChildPageState extends State<ChildPage> {
  Offset offset = Offset.zero;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        alignment: Alignment.center,
        children: [
          Positioned(
              top: offset.dy,
              left: offset.dx,
              child: GestureDetector(
                onPanUpdate: (details) {
                  print("hh");
                  offset = offset.translate(details.delta.dx, details.delta.dy);
                  setState(() {});
                },
                child: Container(
                  color: Colors.yellow,
                  width: 100,
                  height: 100,
                ),
              ))
        ],
      ),
    );
  }
}

Upvotes: 5

Views: 762

Answers (2)

Joe
Joe

Reputation: 1

I recently encountered the same problem and may be a bit late to answer, but I hope it will be helpful to others.

You can use Listener to listen to gestures to control the physics of PageView.

Code:


class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  bool _isWidgetDragging = false;

  void _setWidgetDragging(bool isDragging) {
    setState(() {
      _isWidgetDragging = isDragging;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: PageView.builder(
        physics:
            _isWidgetDragging ? const NeverScrollableScrollPhysics() : null,
        itemBuilder: (ctx, index) {
          return ChildPage(
            index: index,
            setWidgetDragging: _setWidgetDragging,
          );
        },
        itemCount: 2,
      ),
    );
  }
}

class ChildPage extends StatefulWidget {
  final int index;
  final Function(bool) setWidgetDragging;

  const ChildPage(
      {super.key, required this.index, required this.setWidgetDragging});

  @override
  _ChildPageState createState() => _ChildPageState();
}

class _ChildPageState extends State<ChildPage> {
  Offset offset = Offset.zero;
  bool isDragging = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          Center(child: Text('Page ${widget.index}')),
          Positioned(
            left: offset.dx,
            top: offset.dy,
            child: Listener(
              onPointerDown: (event) {
                isDragging = true;
                widget.setWidgetDragging(true);
              },
              onPointerUp: (event) {
                isDragging = false;
                widget.setWidgetDragging(false);
              },
              onPointerCancel: (event) {
                isDragging = false;
                widget.setWidgetDragging(false);
              },
              child: GestureDetector(
                behavior: HitTestBehavior.opaque,
                onPanUpdate: (details) {
                  if (isDragging) {
                    setState(() {
                      offset += details.delta;
                    });
                  }
                },
                child: Container(
                  width: 100,
                  height: 100,
                  color: Colors.yellow,
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

Upvotes: 0

luckysmg
luckysmg

Reputation: 369

Use RawGestureDectector,and use Horizontal and Vertical gestures to avoid this solution

Upvotes: 1

Related Questions