详解Flutter如何在单个屏幕上实现多个列表
作者:杭州程序员张张
前言
今天,我将提供一个实际的示例,演示如何在单个页面上实现多个列表,这些列表可以水平排列、网格格式、垂直排列,甚至是这些常用布局的组合。
下面是要做的:
实现
让我们从创建一个包含产品所有属性的产品模型开始。
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 的新窗口小部件类,定义水平列表的用户界面。
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 的小部件类,定义单个网格视图的用户界面。
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, ), ), ) ], ), ); } }
最后,让我们为垂直视图创建一个小部件类。
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。
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 链接:https://github.com/tarunaronno005/flutter-multiple-listview
到此这篇关于详解Flutter如何在单个屏幕上实现多个列表的文章就介绍到这了,更多相关Flutter单个屏幕实现多个列表内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!