Флаттер: Переопределите жест прокрутки «Просмотр страницы» с помощью детектора жестов ребенка

#flutter #dart

Вопрос:

Я использую комбинацию «BottomNavigationBar» и «Просмотр страниц» для навигации в моем приложении. Пользователь может либо перейти на следующую страницу, либо воспользоваться панелью навигации.

На одной из моих страниц я хотел бы использовать детектор жестов, который обрабатывает жесты панорамирования как по вертикали, так и по горизонтали.

Я не могу найти способ переопределить обнаружение жестов в просмотре страницы с помощью вложенного детектора жестов. Это означает, что обрабатываются только вертикальные жесты панорамирования, так как горизонтальные заняты просмотром страницы.

Как я могу отключить / переопределить обнаружение жестов просмотра страниц только для этой страницы или только для виджета, не полностью отключая физику прокрутки просмотров страниц?

Я создал упрощенную версию своего приложения, чтобы изолировать проблему, и прикрепил видео проблемы ниже.

Любая помощь будет очень признательна!

quot;Детектор жестовquot; получает только жесты вертикального перетаскивания...

Вот код внутри моего main.dart:

 import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: GestureIssueExample(),
    );
  }
}

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

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

class _GestureIssueExampleState extends State<GestureIssueExample> {
  int _navigationIndex;
  double _xLocalValue;
  double _yLocalValue;
  PageController _pageController;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: null,
      bottomNavigationBar: _buildBottomNavigationBar(),
      backgroundColor: Colors.white,
      body: PageView(
        controller: _pageController,
        onPageChanged: _onNavigationPageChanged,
        children: [
          //Just a placeholder to represent a page to the left of the "swipe cards" widget
          _buildSamplePage("Home"),

          //Center child of 'PageView', contains a GestureDetector that handles Pan Gestures
          //Thanks to the page view however, only vertical pan gestures are detected, while both horizontal and vertical gestures
          //need to be handled...
          Container(
            width: MediaQuery.of(context).size.width,
            height: MediaQuery.of(context).size.height,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Text(
                    "Local X: ${_xLocalValue.toString()}nLocal Y: ${_yLocalValue.toString()}"),
                GestureDetector(
                  onPanStart: (details) => setState(
                    () {
                      this._xLocalValue = details.localPosition.dx;
                      this._yLocalValue = details.localPosition.dy;
                    },
                  ),
                  onPanUpdate: (details) => setState(
                    () {
                      this._xLocalValue = details.localPosition.dx;
                      this._yLocalValue = details.localPosition.dy;
                    },
                  ),
                  child: Container(
                    width: MediaQuery.of(context).size.width * 0.9,
                    height: 100.0,
                    color: Colors.red,
                    alignment: Alignment.center,
                    child: Text("Slidable Surface",
                        style: TextStyle(color: Colors.white)),
                  ),
                ),
              ],
            ),
          ),

          //Just a placeholder to represent a page to the right of the "swipe cards" widget
          _buildSamplePage("Settings"),
        ],
      ),
    );
  }

  @override
  void initState() {
    super.initState();
    this._navigationIndex = 0;
    this._pageController = PageController(
      initialPage: _navigationIndex,
    );
  }

  Widget _buildSamplePage(String text) {
    // This simply returns a container that fills the page,
    // with a text widget in its center.

    return Container(
      width: MediaQuery.of(context).size.width,
      height: MediaQuery.of(context).size.height,
      color: Colors.grey[900],
      alignment: Alignment.center,
      child: Text(
        text,
        style: TextStyle(
            color: Colors.white, fontSize: 30.0, fontWeight: FontWeight.bold),
      ),
    );
  }

  Widget _buildBottomNavigationBar() {
    //Returns the bottom navigation bar for the scaffold
    return BottomNavigationBar(
      backgroundColor: Colors.grey[900],
      selectedItemColor: Colors.redAccent,
      unselectedItemColor: Colors.white,
      items: [
        BottomNavigationBarItem(icon: Icon(Icons.home_outlined), label: "Home"),
        BottomNavigationBarItem(
            icon: Icon(Icons.check_box_outline_blank), label: "Cards"),
        BottomNavigationBarItem(
            icon: Icon(Icons.settings_outlined), label: "Settings"),
      ],
      currentIndex: _navigationIndex,
      onTap: _onNavigationPageChanged,
    );
  }

  void _onNavigationPageChanged(int newIndex) {
    //Set the new navigation index for the nav bar
    setState(() => this._navigationIndex = newIndex);

    //Animate to the selected page
    _pageController.animateToPage(
      newIndex,
      curve: Curves.easeInOut,
      duration: Duration(microseconds: 100),
    );
  }
}
 

Ответ №1:

Можете ли вы попробовать что-то подобное:

Добавьте эту строку в свой PageView :

 PageView(
...
physics: _navigationIndex == 1 ? NeverScrollableScrollPhysics() : AlwaysScrollableScrollPhysics(),
...
)
 

Примечание: номер 1 указан потому, что страница с GestureDetector индексом 1 находится в списке .

Комментарии:

1. Здравствуйте, Андрей, спасибо вам за ваш ответ! Я пробовал это решение, но, к сожалению, оно вызывает другую проблему. Просмотры страниц «currentIndex» обновляются, когда новая страница попадает в центр экрана. Это приводит к остановке перехода на центральную страницу (индекс 1), как только страница проходит центр экрана, в результате чего пользовательский интерфейс застревает между двумя страницами. Пожалуйста, дайте мне знать, если я смогу предоставить дополнительную информацию!

2. Я просто попробовал это на своем телефоне, и это сработало нормально. Пожалуйста, ознакомьтесь с записью: screencast.com/t/U9J0dXSYib , можете ли вы добавить еще одну запись экрана нового выпуска?

3. Эй, Андрей, в этом нет необходимости.. Я только что понял, что причина, по которой предложенное вами решение не работало, заключалась в том, что просмотр страниц в моем исходном приложении использовал другую переменную индекса, которая неправильно обновлялась, когда я устанавливал состояние. Я попробовал ваше решение как в моем тестовом приложении, так и в реальной версии, и оба они теперь работают нормально. Большое вам спасибо за вашу помощь!

4. Нет проблем! Я рад, что помог тебе. Хорошего вам дня. 🙂