Flutter PageView+GridView实现菜单横屏滚动

PageView实现页面横向滑动,GwridView实现单个页面内的菜单展示,横向ListView实现指示器,展示效果如下:

 

具体实现如下:

import 'package:flutter/material.dart';

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

  @override
  State<MenusPage> createState() => _MenusPageState();
}

class _MenusPageState extends State<MenusPage> {
  final List<Map<String, dynamic>> _menuData = [
    {"name": "菜单0", "img": "images/testimg/ic_launcher.png"},
    {"name": "菜单1", "img": "images/testimg/ic_launcher.png"},
    {"name": "菜单2", "img": "images/testimg/ic_launcher.png"},
    {"name": "菜单3", "img": "images/testimg/ic_launcher.png"},
    {"name": "菜单4", "img": "images/testimg/ic_launcher.png"},
    {"name": "菜单5", "img": "images/testimg/ic_launcher.png"},
    {"name": "菜单6", "img": "images/testimg/ic_launcher.png"},
  ];

  int _pageIndex = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          leading: IconButton(
            icon: const Icon(Icons.arrow_back_ios, color: Colors.white),
            onPressed: () => Navigator.of(context).pop(),
          ),
          backgroundColor: Colors.greenAccent,
          title: const Text(
            '菜单',
            style: TextStyle(fontSize: 18.0, color: Colors.white),
          ),
          centerTitle: true,
          elevation: 0,
        ),
        body: Container(
            height: 100,
            margin: const EdgeInsets.only(top: 30, left: 10, right: 10),
            padding: const EdgeInsets.all(10),
            decoration: BoxDecoration(
              color: Colors.white,
              border: Border.all(width: 1, color: Colors.black),
              borderRadius: BorderRadius.circular(5),
            ),
            child: Column(
              children: [
                Expanded(child: getPageBody()),
                Container(
                  height: 15,
                  alignment: Alignment.center,
                  child: ListView.builder(
                      shrinkWrap: true,
                      physics: const NeverScrollableScrollPhysics(),
                      scrollDirection: Axis.horizontal,
                      itemCount: (_menuData.length % 4) > 0
                          ? (_menuData.length ~/ 4) + 1
                          : (_menuData.length ~/ 4),
                      itemBuilder: (context, index) {
                        return Container(
                          alignment: const Alignment(0, .5),
                          height: 15,
                          width: 15,
                          child: CircleAvatar(
                            radius: 5,
                            backgroundColor: _pageIndex == index
                                ? Colors.greenAccent
                                : Colors.grey,
                            child: Container(
                              alignment: const Alignment(0, .5),
                              width: 10,
                              height: 10,
                            ),
                          ),
                        );
                      }),
                )
              ],
            )));
  }

  Widget getPageBody() {
    return PageView.builder(
      itemCount: (_menuData.length % 4) > 0
          ? (_menuData.length ~/ 4) + 1
          : (_menuData.length ~/ 4),
      onPageChanged: (index) {
        _pageIndex = index;
        setState(() {});
      },
      itemBuilder: (BuildContext context, int index) {
        return ScrollConfiguration(
            behavior: const ScrollBehavior(),
            child: GridView.builder(
              shrinkWrap: true,
              physics: const NeverScrollableScrollPhysics(),
              itemCount: (index < (_menuData.length ~/ 4))
                  ? 4
                  : (_menuData.length % 4),
              gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 4,
                mainAxisSpacing: 0,
                crossAxisSpacing: 0,
                childAspectRatio: 1,
              ),
              itemBuilder: (context, position) {
                return Container(
                  alignment: Alignment.center,
                  child: Column(
                    children: [
                      Image.asset(
                        _menuData[index * 4 + position]['img'].toString(),
                        width: 40,
                        height: 40,
                      ),
                      Text(
                        _menuData[index * 4 + position]['name'].toString(),
                        style: const TextStyle(fontSize: 12),
                      ),
                    ],
                  ),
                );
              },
            ));
      },
    );
  }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值