Flutter布局协调插件coordinator_layout的使用

发布于 1周前 作者 htzhanglong 来自 Flutter

Flutter布局协调插件coordinator_layout的使用

pub package

coordinator_layout是一个包含处理折叠头部行为的控件和布局库。

示例

示例代码

CoordinatorLayout(
    headerMaxHeight: 200,
    headerMinHeight: kToolbarHeight + MediaQuery.of(context).padding.top,
    headers: [
        SliverCollapsingHeader(
            builder: (context, offset, diff) {
                return ...;
            },
        ),
    ],
    body: Container(height: null, child: buildBody(context)),
),

自适应内容高度

CoordinatorLayout(
    headerMaxHeight: 200,
    headerMinHeight: kToolbarHeight + MediaQuery.of(context).padding.top,
    headers:[ 
        Builder(builder: (context) {
            return SliverOverlapAbsorber(
            handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
            sliver: SliverSafeArea(
                top: false,
                sliver: SliverCollapsingHeader(
                builder: (context, offset, diff) {
                    return ...;
                },
                ),
            ),
            );
        }),
    ],
    body: Container(height: null, child: buildBody(context)),
),

完整示例代码

import 'package:coordinator_layout/coordinator_layout.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // 这个小部件是你应用的根节点。
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        useMaterial3: false,
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({super.key, required this.title});

  // 这个小部件是你的应用的主页。它是有状态的,意味着
  // 它有一个状态对象(定义在下面),这个对象包含影响其外观的字段。
  // 这个类是状态的配置。它保存了由父组件(在这个例子中是App小部件)提供的值(例如标题),
  // 并且被状态的小部件构建方法使用。小部件子类中的字段总是标记为"final"。

  final String title;

  [@override](/user/override)
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      // 这次对setState的调用告诉Flutter框架某些事情发生了改变,
      // 因此它会重新运行构建方法,以便屏幕能够反映更新后的值。
      // 如果我们不调用setState而直接改变了_counter,那么构建方法将不会再次运行,
      // 所以看起来好像什么都没有发生。
      _counter++;
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    double headerMinHeight = kToolbarHeight + MediaQuery.of(context).padding.top;
    return Scaffold(
      body: CoordinatorLayout(
        headerMaxHeight: headerMinHeight + 80,
        headerMinHeight: headerMinHeight,
        headers: [
          Builder(builder: (context) {
            return SliverOverlapAbsorber(
              handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
              sliver: SliverSafeArea(
                top: false,
                sliver: SliverCollapsingHeader(
                  builder: (context, offset, diff) {
                    return Card(
                      margin: EdgeInsets.only(bottom: 0),
                      child: SingleChildScrollView(
                        physics: NeverScrollableScrollPhysics(),
                        child: Stack(
                          children: <Widget>[
                            Opacity(
                              opacity: offset,
                              child: Container(
                                margin: EdgeInsets.only(top: headerMinHeight * (offset)),
                                padding: EdgeInsets.symmetric(horizontal: 32, vertical: 8),
                                child: Row(
                                  children: <Widget>[
                                    Expanded(
                                      flex: 1,
                                      child: Text("Point : 30,200"),
                                    ),
                                    FloatingActionButton.extended(
                                      backgroundColor: Colors.green,
                                      onPressed: () {},
                                      label: Text("View"),
                                    ),
                                  ],
                                ),
                              ),
                            ),
                            AppBar(
                              title: Text("Home"),
                            ),
                          ],
                        ),
                      ),
                    );
                  },
                ),
              ),
            );
          })
        ],
        body: ListView.builder(
            itemCount: 1, itemBuilder: (context, index) => Container(height: null, child: buildBody(context))),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // 这个尾随的逗号使自动格式化更美观。
    );
  }

  Center buildBody(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.start,
        children: <Widget>[
          Text(
            '你已经按下了按钮这么多次:',
          ),
          Text(
            '$_counter',
            style: Theme.of(context).textTheme.headline4,
          ),
        ],
      ),
    );
  }
}

更多关于Flutter布局协调插件coordinator_layout的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter布局协调插件coordinator_layout的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中,虽然没有一个直接对应于Android中CoordinatorLayout的官方插件,但我们可以通过组合Flutter中的现有布局和组件来实现类似的功能。CoordinatorLayout在Android中主要用于协调子视图之间的行为,比如处理滚动事件和视图的交互。在Flutter中,这通常可以通过NestedScrollViewSliverAppBarCustomScrollView等组件来实现。

下面是一个使用CustomScrollViewSliverAppBar来实现类似CoordinatorLayout功能的示例代码。这个例子展示了如何创建一个带有可折叠工具栏(类似于Google Keep应用的布局)的页面。

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter CoordinatorLayout Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        body: NestedScrollView(
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            return <Widget>[
              SliverAppBar(
                expandedHeight: 200.0,
                floating: true,
                pinned: true,
                flexibleSpace: FlexibleSpaceBar(
                  centerTitle: true,
                  title: Text('CoordinatorLayout Equivalent in Flutter'),
                  background: Image.network(
                    'https://via.placeholder.com/1500x500',
                    fit: BoxFit.cover,
                  ),
                ),
              ),
            ];
          },
          body: Builder(
            builder: (BuildContext context) {
              return Column(
                children: <Widget>[
                  Container(
                    color: Colors.white,
                    child: Padding(
                      padding: const EdgeInsets.all(16.0),
                      child: Text(
                        'This is a scrollable content area below the SliverAppBar.',
                        style: TextStyle(fontSize: 20),
                      ),
                    ),
                  ),
                  // Add more widgets here as needed
                  // ...
                ],
              );
            },
          ),
        ),
      ),
    );
  }
}

解释

  1. NestedScrollView: 这个组件允许内部的滚动视图(在这个例子中是Column)与外部的头部(SliverAppBar)进行协调。

  2. SliverAppBar: 这是一个特殊的sliver,可以用作NestedScrollView的头部。它支持多种配置,包括expandedHeight(扩展高度)、floating(是否浮动)、pinned(是否固定)等。

  3. FlexibleSpaceBar: 这个组件用于SliverAppBarflexibleSpace属性,允许我们自定义当SliverAppBar展开时的背景和内容。

  4. Column: 在这个例子中,Column用于表示滚动内容区域。你可以根据需要向其中添加更多的widget。

通过这种方式,我们可以在Flutter中实现类似于Android中CoordinatorLayout的布局效果,尤其是在处理复杂的滚动和头部折叠行为时。这个示例只是一个开始,你可以根据具体需求进一步自定义和扩展这个布局。

回到顶部