Flutter 中在单个屏幕上实现多个列表

今天,我将提供一个实际的示例,演示如何在单个页面上实现多个列表,这些列表可以水平排列、网格格式、垂直排列,甚至是这些常用布局的组合。

下面是要做的:

实现

让我们从创建一个包含产品所有属性的产品模型开始。

dart 复制代码
class Product {
  final String id;
  final String name;
  final double price;
  final String image;

  const Product({
    required this.id,
    required this.name,
    required this.price,
    required this.image,
  });

  factory Product.fromJson(Map json) {
    return Product(
      id: json['id'],
      name: json['name'],
      price: json['price'],
      image: json['image'],
    );
  }
}

现在,我们将设计我们的小部件以支持水平、垂直和网格视图。

创建一个名为 HorizontalRawWidget 的新窗口小部件类,定义水平列表的用户界面。

dart 复制代码
import 'package:flutter/material.dart';
import 'package:multiple_listview_example/models/product.dart';

class HorizontalRawWidget extends StatelessWidget {
  final Product product;

  const HorizontalRawWidget({Key? key, required this.product})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(
        left: 15,
      ),
      child: Container(
        width: 125,
        decoration: BoxDecoration(
            color: Colors.white, borderRadius: BorderRadius.circular(12)),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Padding(
              padding: const EdgeInsets.fromLTRB(5, 5, 5, 0),
              child: ClipRRect(
                borderRadius: BorderRadius.circular(12),
                child: Image.network(
                  product.image,
                  height: 130,
                  fit: BoxFit.contain,
                ),
              ),
            ),
            Expanded(
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Expanded(
                      child: Text(product.name,
                          maxLines: 2,
                          overflow: TextOverflow.ellipsis,
                          style: const TextStyle(
                              color: Colors.black,
                              fontSize: 12,
                              fontWeight: FontWeight.bold)),
                    ),
                    Row(
                      crossAxisAlignment: CrossAxisAlignment.end,
                      children: [
                        Text("\$${product.price}",
                            style: const TextStyle(
                                color: Colors.black, fontSize: 12)),
                      ],
                    ),
                  ],
                ),
              ),
            )
          ],
        ),
      ),
    );
  }
}

设计一个名为 GridViewRawWidget 的小部件类,定义单个网格视图的用户界面。

dart 复制代码
import 'package:flutter/material.dart';
import 'package:multiple_listview_example/models/product.dart';

class GridViewRawWidget extends StatelessWidget {
  final Product product;

  const GridViewRawWidget({Key? key, required this.product}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(5),
      decoration: BoxDecoration(
          color: Colors.white, borderRadius: BorderRadius.circular(10)),
      child: Column(
        children: [
          AspectRatio(
            aspectRatio: 1,
            child: ClipRRect(
              borderRadius: BorderRadius.circular(10),
              child: Image.network(
                product.image,
                fit: BoxFit.fill,
              ),
            ),
          )
        ],
      ),
    );
  }
}

最后,让我们为垂直视图创建一个小部件类。

dart 复制代码
import 'package:flutter/material.dart';
import 'package:multiple_listview_example/models/product.dart';

class VerticalRawWidget extends StatelessWidget {
  final Product product;

  const VerticalRawWidget({Key? key, required this.product}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.symmetric(horizontal: 15, vertical: 5),
      padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
      color: Colors.white,
      child: Row(
        children: [
          Image.network(
            product.image,
            width: 78,
            height: 88,
          ),
          const SizedBox(
            width: 15,
          ),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  product.name,
                  style: const TextStyle(fontSize: 12, color: Colors.black, fontWeight: FontWeight.bold),
                ),
                SizedBox(
                  height: 5,
                ),
                Text("\$${product.price}",
                    style: const TextStyle(color: Colors.black, fontSize: 12)),
              ],
            ),
          )
        ],
      ),
    );
  }
}

现在是时候把所有的小部件合并到一个屏幕中了,我们先创建一个名为"home_page.dart"的页面,在这个页面中,我们将使用一个横向的 ListView、纵向的 ListView 和 GridView。

dart 复制代码
import 'package:flutter/material.dart';
import 'package:multiple_listview_example/models/product.dart';
import 'package:multiple_listview_example/utils/product_helper.dart';
import 'package:multiple_listview_example/views/widgets/gridview_raw_widget.dart';
import 'package:multiple_listview_example/views/widgets/horizontal_raw_widget.dart';
import 'package:multiple_listview_example/views/widgets/title_widget.dart';
import 'package:multiple_listview_example/views/widgets/vertical_raw_widget.dart';

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

  @override
  Widget build(BuildContext context) {
    List products = ProductHelper.getProductList();
    return Scaffold(
      backgroundColor: const Color(0xFFF6F5FA),
      appBar: AppBar(
        centerTitle: true,
        title: const Text("Home"),
      ),
      body: SingleChildScrollView(
        child: Container(
          padding: const EdgeInsets.symmetric(vertical: 20),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const TitleWidget(title: "Horizontal List"),
              const SizedBox(
                height: 10,
              ),
              SizedBox(
                height: 200,
                child: ListView.builder(
                    shrinkWrap: true,
                    scrollDirection: Axis.horizontal,
                    itemCount: products.length,
                    itemBuilder: (BuildContext context, int index) {
                      return HorizontalRawWidget(
                        product: products[index],
                      );
                    }),
              ),
              const SizedBox(
                height: 10,
              ),
              const TitleWidget(title: "Grid View"),
              Container(
                padding:
                    const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
                child: GridView.builder(
                    gridDelegate:
                        const SliverGridDelegateWithFixedCrossAxisCount(
                            crossAxisCount: 2,
                            crossAxisSpacing: 13,
                            mainAxisSpacing: 13,
                            childAspectRatio: 1),
                    itemCount: products.length,
                    shrinkWrap: true,
                    physics: const NeverScrollableScrollPhysics(),
                    itemBuilder: (BuildContext context, int index) {
                      return GridViewRawWidget(
                        product: products[index],
                      );
                    }),
              ),
              const TitleWidget(title: "Vertical List"),
              ListView.builder(
                  itemCount: products.length,
                  shrinkWrap: true,
                  physics: const NeverScrollableScrollPhysics(),
                  itemBuilder: (BuildContext context, int index) {
                    return VerticalRawWidget(
                      product: products[index],
                    );
                  }),
            ],
          ),
        ),
      ),
    );
  }
}

我使用了一个 SingleChildScrollView widget 作为代码中的顶部根 widget,考虑到我整合了多个布局,如水平列表、网格视图和垂直列表,我将所有这些 widget 包装在一个 Column widget 中。

挑战在于如何处理多个滚动部件,因为在上述示例中有两个垂直滚动部件:一个网格视图和一个垂直列表视图。为了禁用单个部件的滚动行为, physics 属性被设置为 const NeverScrollableScrollPhysics()。取而代之的是,使用顶层根 SingleChildScrollView`` 来启用整个内容的滚动。此外,SingleChildScrollView上的shrinkWrap属性被设置为true`,以确保它能紧紧包裹其内容,只占用其子控件所需的空间。

Github 链接github.com/tarunaronno...

相关推荐
Lanren的编程日记9 小时前
Flutter鸿蒙应用开发:生物识别(指纹/面容)功能集成实战
flutter·华为·harmonyos
Lanren的编程日记13 小时前
Flutter鸿蒙应用开发:基础UI组件库设计与实现实战
flutter·ui·harmonyos
西西学代码13 小时前
Flutter---波形动画
flutter
于慨16 小时前
flutter基础组件用法
开发语言·javascript·flutter
恋猫de小郭18 小时前
Android CLI ,谷歌为 Android 开发者专研的 AI Agent,提速三倍
android·前端·flutter
火柴就是我19 小时前
flutter pushAndRemoveUntil 的一次小疑惑
flutter
于慨20 小时前
flutter doctor问题解决
flutter
唔6620 小时前
flutter 图片加载类 图片的安全使用
安全·flutter
Nathan2024061621 小时前
Flutter - InheritedWidget
flutter·dart
恋猫de小郭21 小时前
JetBrains Amper 0.10 ,期待它未来替代 Gradle
android·前端·flutter