简体   繁体   中英

how to make horizontal menu auto scroll with vertical product list in flutter

I have a Horizontal category menu on the top of the page and a long vertical scrollable list of product items. Currently I am looking for is to automate the horizontal menu on the top of the page as soon as I go down to the respective products.

So basically I am planning to have categories of items in a top horizontal menu and all the products containing these categories as part of their structure in one long list. So as soon as the user browses these products (vertically) the category in the horizontal menu is highlighted but as soon as he goes to another section of the product via browsing the item list down then the category on the top horizontal menu changes.

Categ 1 Categ 2 Categ 3 Categ 4 ------------->

Product 1
Product 2
Product 3
Product 4

I need help to achieve it in a flutter.

I am aware of the tab bar and nested scroll view but this is not what I am looking I need them to be on the same page and I don't want to differ the products as per the tabs. I want all products on the same page in one big list and just want categories to be highlighted automatically (depending on which product you are). I also need help in scrolling products to respective position as soon as I click on the category.

Thank You for helping me

You can set the itemExtent of the category and product list and use it to calculate the scroll offset to detect which is the current product list item.

Sample...

import 'dart:math';

import 'package:flutter/material.dart';

Future<void> main() async {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final Map<String, List<String>> _categories = <String, List<String>>{};
  final List<int> _categoryOffsets = <int>[];

  final ScrollController _categoriesController = ScrollController();
  final ScrollController _productsController = ScrollController();

  final int _categoryItemExtent = 150;
  final int _productItemExtent = 100;

  int _categoryIdx = 0;

  @override
  void initState() {
    super.initState();
    _productsController.addListener(_onProductsScroll);

    for (int i = 1; i <= 10; i++) {
      int productCnt = Random().nextInt(10);
      productCnt = productCnt == 0 ? 1 : productCnt;

      _categories['Category $i'] =
          List.generate(productCnt, (int j) => 'Product ${i * 10 + j}');

      final int prevOffset = i == 1 ? 0 : _categoryOffsets[i - 2];
      _categoryOffsets.add(prevOffset + (_productItemExtent * productCnt));
    }
  }

  @override
  Widget build(BuildContext context) {
    final List<String> allProducts = _categories.entries.fold<List<String>>(
      <String>[],
      (previousValue, element) {
        previousValue.addAll(element.value);
        return previousValue;
      },
    );

    return Scaffold(
      body: Column(
        children: <Widget>[
          Expanded(
            flex: 1,
            child: ListView.builder(
              controller: _categoriesController,
              scrollDirection: Axis.horizontal,
              itemExtent: _categoryItemExtent.toDouble(),
              itemCount: _categories.length,
              itemBuilder: (_, int i) => Card(
                color: _categoryIdx == i ? Colors.green : null,
                child: Text(_categories.keys.elementAt(i)),
              ),
            ),
          ),
          Expanded(
            flex: 3,
            child: ListView.builder(
              controller: _productsController,
              itemExtent: _productItemExtent.toDouble(),
              itemCount: allProducts.length,
              itemBuilder: (_, int i) {
                return Card(
                  child: Text(allProducts[i]),
                );
              },
            ),
          ),
        ],
      ),
    );
  }

  void _onProductsScroll() {
    final double offset = _productsController.offset;

    for (int i = 0; i < _categoryOffsets.length; i++) {
      if (offset <= _categoryOffsets[i]) {
        if (_categoryIdx != i) {
          print('Scroll to category $i');
          _categoriesController.animateTo(
            (i * _categoryItemExtent).toDouble(),
            duration: const Duration(milliseconds: 500),
            curve: Curves.easeInOut,
          );

          setState(() => _categoryIdx = i);
        }
        break;
      }
    }
  }

  @override
  void dispose() {
    _categoriesController.dispose();
    _productsController.removeListener(_onProductsScroll);
    _productsController.dispose();
    super.dispose();
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM