詳解Flutter如何在單個(gè)屏幕上實(shí)現(xiàn)多個(gè)列表
前言
今天,我將提供一個(gè)實(shí)際的示例,演示如何在單個(gè)頁面上實(shí)現(xiàn)多個(gè)列表,這些列表可以水平排列、網(wǎng)格格式、垂直排列,甚至是這些常用布局的組合。
下面是要做的:

實(shí)現(xiàn)
讓我們從創(chuàng)建一個(gè)包含產(chǎn)品所有屬性的產(chǎn)品模型開始。
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'],
);
}
}現(xiàn)在,我們將設(shè)計(jì)我們的小部件以支持水平、垂直和網(wǎng)格視圖。
創(chuàng)建一個(gè)名為 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)),
],
),
],
),
),
)
],
),
),
);
}
}設(shè)計(jì)一個(gè)名為 GridViewRawWidget 的小部件類,定義單個(gè)網(wǎng)格視圖的用戶界面。
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,
),
),
)
],
),
);
}
}最后,讓我們?yōu)榇怪币晥D創(chuàng)建一個(gè)小部件類。
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)),
],
),
)
],
),
);
}
}現(xiàn)在是時(shí)候把所有的小部件合并到一個(gè)屏幕中了,我們先創(chuàng)建一個(gè)名為“home_page.dart”的頁面,在這個(gè)頁面中,我們將使用一個(gè)橫向的 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],
);
}),
],
),
),
),
);
}
}我使用了一個(gè) SingleChildScrollView widget 作為代碼中的頂部根 widget,考慮到我整合了多個(gè)布局,如水平列表、網(wǎng)格視圖和垂直列表,我將所有這些 widget 包裝在一個(gè) Column widget 中。
挑戰(zhàn)在于如何處理多個(gè)滾動(dòng)部件,因?yàn)樵谏鲜鍪纠杏袃蓚€(gè)垂直滾動(dòng)部件:一個(gè)網(wǎng)格視圖和一個(gè)垂直列表視圖。為了禁用單個(gè)部件的滾動(dòng)行為, physics 屬性被設(shè)置為 const NeverScrollableScrollPhysics()。取而代之的是,使用頂層根 SingleChildScrollView` 來啟用整個(gè)內(nèi)容的滾動(dòng)。此外, SingleChildScrollView上的shrinkWrap屬性被設(shè)置為true,以確保它能緊緊包裹其內(nèi)容,只占用其子控件所需的空間。
Github 鏈接:https://github.com/tarunaronno005/flutter-multiple-listview
到此這篇關(guān)于詳解Flutter如何在單個(gè)屏幕上實(shí)現(xiàn)多個(gè)列表的文章就介紹到這了,更多相關(guān)Flutter單個(gè)屏幕實(shí)現(xiàn)多個(gè)列表內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android實(shí)現(xiàn)繪制LocationMarkerView圖的示例代碼
LocationMarker是運(yùn)動(dòng)軌跡上Start、End, 以及整公里點(diǎn)上筆者自定義繪制的一個(gè)MarkerView。這篇文章主要介紹了Android實(shí)現(xiàn)繪制LocationMarkerView圖的示例代碼,希望對(duì)大家有所幫助2023-02-02
基于Android中手勢(shì)交互的實(shí)現(xiàn)方法
本篇文章是對(duì)Android中手勢(shì)交互的實(shí)現(xiàn)進(jìn)行了詳細(xì)的分析介紹。需要的朋友參考下2013-05-05
Android Activity啟動(dòng)模式全面解析
這篇文章主要介紹了Android Activity啟動(dòng)模式全面解析的相關(guān)資料,需要的朋友可以參考下2016-02-02
完美解決客戶端webview持有的頁面緩存,不會(huì)立即釋放的問題
下面小編就為大家?guī)硪黄昝澜鉀Q客戶端webview持有的頁面緩存,不會(huì)立即釋放的問題。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-12-12
Android自定義控件實(shí)現(xiàn)通用驗(yàn)證碼輸入框
這篇文章主要為大家詳細(xì)介紹了Android自定義控件實(shí)現(xiàn)通用驗(yàn)證碼輸入框,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-01-01
Android InputMethodManager輸入法簡(jiǎn)介
這篇文章主要介紹了Android InputMethodManager輸入法框架的使用,具有參考價(jià)值,需要的朋友可以參考下。2016-06-06
Android 屬性動(dòng)畫ValueAnimator與插值器詳解
這篇文章主要介紹了Android 屬性動(dòng)畫ValueAnimator與插值器詳解的相關(guān)資料,需要的朋友可以參考下2017-05-05
關(guān)于Android 6.0權(quán)限的動(dòng)態(tài)適配詳解
Android 6.0版本(Api 23)推出了很多新的特性, 大幅提升了用戶體驗(yàn), 同時(shí)也為程序員帶來新的負(fù)擔(dān). 動(dòng)態(tài)權(quán)限管理就是這樣, 一方面讓用戶更加容易的控制自己的隱私, 一方面需要重新適配應(yīng)用權(quán)限,本文介紹了關(guān)于Android 6.0權(quán)限動(dòng)態(tài)適配的相關(guān)資料,需要的朋友可以參考下。2017-11-11
學(xué)習(xí)Android自定義Spinner適配器
這篇文章主要為大家詳細(xì)介紹了學(xué)習(xí)Android自定義Spinner適配器的相關(guān)資料,感興趣的小伙伴們可以參考一下2016-05-05
Android使用WindowManager構(gòu)造懸浮view
這篇文章主要為大家詳細(xì)介紹了Android使用WindowManager構(gòu)造懸浮view的具體方法,感興趣的小伙伴們可以參考一下2016-05-05

