SuperAPI AI 工具集

flutter-master-detail-view

前端与建站

查看项目

更新于 10-16 02:01

技能介绍

用途

在 Flutter 中构建移动端、桌面端和 Web 应用时,常需要处理列表与选中内容之间的关系。根据数据不同,列表可能先渲染另一个列表,再进入详情视图。在平板或桌面上,可以通过多列布局实现主从视图;在手机上由于空间受限,仍需 push 到详情屏幕。该技能提供了实现这种响应式 Master-Detail 界面的方法。

主要能力

  • 响应式布局:通过 LayoutBuilder 获取可用宽度,当宽度大于 800 时判定为可显示详情(canShowDetails),采用 Row 并排展示列表与详情;否则仅展示列表。
  • 选中状态管理:使用 ValueNotifier<T?> 保存当前选中项,并通过 ValueListenableBuilder 驱动界面更新。
  • 窄屏跳转:当无法并排显示详情时,选中项会清空 selected 值并调用 onPush 回调,由外部执行页面跳转。
  • 可拖动分隔条:在可显示详情时,列表与详情之间渲染一个 5 像素宽的 VerticalDivider,配合 MouseRegion 与 GestureDetector 实现水平拖动调整详情宽度,并限制在 minWidth(350)与 maxWidth(可用宽度减去 minWidth)之间。
  • 空状态:未选中任何项时,详情区域显示 emptyBuilder 的内容,若未提供则显示默认文本“Select a item to view details”。
  • 可嵌套:组件会先按布局计算自身尺寸,尽量让列表小、详情占据剩余空间,便于后续嵌套多个此类组件以构建渐进式自适应布局。

使用方式

该组件以 StatefulWidget 形式提供,构造函数需要传入三个必需参数:listBuilder、detailBuilder、onPush,以及可选的 emptyBuilder。

  • listBuilder:类型为 Widget Function(BuildContext, ValueChanged<T?>, T?),用于构建列表区域,并接收选中项变更回调与当前选中值。
  • detailBuilder:类型为 Widget Function(BuildContext, T, bool),用于构建详情区域。
  • onPush:类型为 void Function(BuildContext, T),在窄屏选中项时调用,用于跳转到详情页。
  • emptyBuilder:类型为 WidgetBuilder?,可选,用于构建未选中时的占位内容。

使用示例代码(与资料一致):

import 'package:flutter/material.dart';

class MasterDetail extends StatefulWidget {
const MasterDetail({
Key? key,
required this.listBuilder,
required this.detailBuilder,
required this.onPush,
this.emptyBuilder,
}) : super(key: key);

final Widget Function(BuildContext, ValueChanged<T?>, T?) listBuilder;
final Widget Function(BuildContext, T, bool) detailBuilder;
final void Function(BuildContext, T) onPush;
final WidgetBuilder? emptyBuilder;

@override
State<MasterDetail> createState() => _MasterDetailState();
}

class _MasterDetailState extends State<MasterDetail> {
final selected = ValueNotifier<T?>(null);
double? detailsWidth;

@override
Widget build(BuildContext context) {
return Scaffold(
primary: false,
body: LayoutBuilder(
builder: (context, dimens) {
const double minWidth = 350;
final maxWidth = dimens.maxWidth - minWidth;
if (detailsWidth != null) {
if (detailsWidth! > maxWidth) {
detailsWidth = maxWidth;
}
if (detailsWidth! < minWidth) {
detailsWidth = minWidth;
}
}
return ValueListenableBuilder<T?>(
valueListenable: selected,
builder: (context, item, child) {
final canShowDetails = dimens.maxWidth > 800;
final showDetails = item != null && canShowDetails;
return Row(
children: [
Expanded(
child: widget.listBuilder(context, (item) {
if (canShowDetails) {
selected.value = item;
} else {
selected.value = null;
if (item != null) widget.onPush(context, item);
}
}, selected.value),
),
if (canShowDetails)
MouseRegion(
cursor: SystemMouseCursors.resizeLeftRight,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onHorizontalDragUpdate: (details) {
if (mounted) {
setState(() {
double w = detailsWidth ?? maxWidth;
w -= details.delta.dx;
// Check for min width
if (w < minWidth) {
w = minWidth;
}
// Check for max width
if (w > maxWidth) {
w = maxWidth;
}
detailsWidth = w;
});
}
},
child: const SizedBox(
width: 5,
height: double.infinity,
child: VerticalDivider(),
),
),
),
if (canShowDetails)
SizedBox(
width: detailsWidth ?? maxWidth,
height: double.infinity,
child: showDetails
? widget.detailBuilder(context, item, false)
: widget.emptyBuilder?.call(context) ??
const Center(
child: Text('Select a item to view details'),
),
),
],
);
},
);
},
),
);
}
}

适用场景

  • 需要在 Flutter 中同时支持移动端、桌面端和 Web 端的列表-详情界面。
  • 希望在宽屏上并排展示列表与详情,并允许用户调整详情区域宽度。
  • 需要构建可嵌套、渐进式自适应的多列布局。

限制

  • 资料未提供该组件的安装命令、包名或发布渠道。
  • 资料未提供收费、价格、平台兼容性、性能效果等额外信息。
  • 资料未提供除上述代码外的其他使用步骤或配置说明。