Flutter弹性头部效果插件stretchy_header的使用

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

Flutter弹性头部效果插件 stretchy_header 的使用

stretchy_header 是一个用于创建弹性头部效果的 Flutter 插件。当用户滚动页面时,头部会有一个弹性效果,提供良好的用户体验。

示例效果

示例 1

Sample 1

示例 2

Sample 2

开始使用

首先,确保在你的 Flutter 项目中添加该插件作为依赖项:

dependencies:
  stretchy_header: "^1.0.8"

然后运行 flutter packages upgrade 或者在 IntelliJ 中更新你的包。

使用示例

示例 1:带有列表视图的弹性头部

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

class SampleListView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: StretchyHeader.listViewBuilder(
        headerData: HeaderData(
          headerHeight: 250,
          header: Image.asset(
            "images/chichen.jpg",
            fit: BoxFit.cover,
          ),
        ),
        itemCount: 15,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text("item $index"),
            onTap: () {
              final snackBar = SnackBar(
                content: Text('item $index tapped'),
              );
              ScaffoldMessenger.of(context).showSnackBar(snackBar);
            },
          );
        },
      ),
    );
  }
}

示例 2:自定义头部和覆盖层

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

class SampleCustomHeader extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: StretchyHeader.singleChild(
        headerData: HeaderData(
          headerHeight: 200,
          backgroundColor: Colors.black54,
          blurColor: Colors.yellow,
          header: UserAccountsDrawerHeader(
            accountName: Text("Diego"),
            accountEmail: Text("twitter [@diegoveloper](/user/diegoveloper)"),
            currentAccountPicture: CircleAvatar(
              backgroundColor: Colors.red,
              child: Text("DV"),
            ),
            margin: EdgeInsets.zero,
          ),
          overlay: Align(
            alignment: Alignment.bottomRight,
            child: Material(
              color: Colors.transparent,
              child: Builder(
                builder: (newContext) {
                  return InkResponse(
                    onTap: () {
                      ScaffoldMessenger.of(newContext).showSnackBar(
                        SnackBar(
                          content: Text('onTap'),
                        ),
                      );
                    },
                    child: Padding(
                      padding: EdgeInsets.all(12),
                      child: Icon(
                        Icons.fullscreen,
                        color: Colors.white,
                      ),
                    ),
                  );
                },
              ),
            ),
          ),
        ),
        child: Padding(
          padding: const EdgeInsets.all(15),
          child: Text(
            "Hello World!",
            style: TextStyle(fontSize: 45, color: Colors.white),
          ),
        ),
      ),
    );
  }
}

示例 3:底部标签

class SampleBottomLabel extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: StretchyHeader.singleChild(
        headerData: HeaderData(
          headerHeight: 250,
          header: Image.asset(
            "images/machu.jpg",
            fit: BoxFit.cover,
          ),
          highlightHeaderAlignment: HighlightHeaderAlignment.bottom,
          highlightHeader: Container(
            width: MediaQuery.of(context).size.width,
            decoration: BoxDecoration(
              gradient: LinearGradient(
                colors: [
                  Colors.black54,
                  Colors.black54,
                  Colors.black26,
                  Colors.black12,
                  Colors.black12,
                ],
                begin: Alignment.bottomCenter,
                end: Alignment.topCenter,
              ),
            ),
            child: Padding(
              padding: const EdgeInsets.all(15),
              child: Text(
                "Machu Picchu",
                style: TextStyle(color: Colors.white, fontSize: 22),
              ),
            ),
          ),
        ),
        child: Padding(
          padding: const EdgeInsets.all(15),
          child: Text(LONG_DESCRIPTION),
        ),
      ),
    );
  }
}

示例 4:中心部件

class SampleCenterWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: StretchyHeader.singleChild(
        headerData: HeaderData(
          headerHeight: 250,
          header: Image.asset(
            "images/machu.jpg",
            fit: BoxFit.cover,
          ),
          highlightHeaderAlignment: HighlightHeaderAlignment.center,
          highlightHeader: SizedBox(
            width: MediaQuery.of(context).size.width,
            child: GestureDetector(
              onTap: () {
                print("tap highlightHeader");
              },
              child: CircleAvatar(
                backgroundColor: Colors.red,
                child: Text("M"),
              ),
            ),
          ),
        ),
        child: Padding(
          padding: const EdgeInsets.all(15),
          child: Text(LONG_DESCRIPTION),
        ),
      ),
    );
  }
}

示例 5:刷新指示器

class SampleRefreshIndicator extends StatefulWidget {
  @override
  _SampleRefreshIndicatorState createState() => _SampleRefreshIndicatorState();
}

class _SampleRefreshIndicatorState extends State<SampleRefreshIndicator> {
  bool isLoading = false;
  bool numbers = true;

  void _loadFakeData() async {
    setState(() {
      isLoading = true;
    });

    await Future.delayed(Duration(seconds: 3));
    numbers = !numbers;
    setState(() {
      isLoading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          StretchyHeader.listViewBuilder(
            onRefresh: () {
              _loadFakeData();
            },
            headerData: HeaderData(
              headerHeight: 250,
              header: Image.asset(
                "images/machu.jpg",
                fit: BoxFit.cover,
              ),
            ),
            itemCount: 15,
            itemBuilder: (context, index) {
              return ListTile(
                title: numbers
                    ? Text("item $index")
                    : Container(
                        height: 10,
                        width: 10,
                        color: Colors.primaries[index % Colors.primaries.length],
                      ),
                onTap: () {
                  final snackBar = SnackBar(
                    content: Text('item $index tapped'),
                  );
                  ScaffoldMessenger.of(context).showSnackBar(snackBar);
                },
              );
            },
          ),
          if (isLoading) _buildLoadingWidget()
        ],
      ),
    );
  }

  Widget _buildLoadingWidget() {
    return Container(
      color: Colors.black54,
      child: Center(
        child: CircularProgressIndicator(),
      ),
    );
  }
}

主程序入口

以下是一个完整的主程序入口文件,它包含了上述所有示例的导航按钮:

import 'package:example/long_description.dart';
import 'package:flutter/material.dart';
import 'package:stretchy_header/stretchy_header.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Stretchy',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Samples(),
    );
  }
}

class Samples extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            MaterialButton(
              onPressed: () {
                Navigator.of(context).push(MaterialPageRoute(
                  builder: (context) => SampleListView(),
                ));
              },
              child: Text("ListView"),
              color: Colors.red,
            ),
            MaterialButton(
              onPressed: () {
                Navigator.of(context).push(MaterialPageRoute(
                  builder: (context) => SampleCustomHeader(),
                ));
              },
              child: Text("Custom header"),
              color: Colors.red,
            ),
            MaterialButton(
              onPressed: () {
                Navigator.of(context).push(MaterialPageRoute(
                  builder: (context) => SampleBottomLabel(),
                ));
              },
              child: Text("Bottom label"),
              color: Colors.red,
            ),
            MaterialButton(
              onPressed: () {
                Navigator.of(context).push(MaterialPageRoute(
                  builder: (context) => SampleCenterWidget(),
                ));
              },
              child: Text("Center widget"),
              color: Colors.red,
            ),
            MaterialButton(
              onPressed: () {
                Navigator.of(context).push(MaterialPageRoute(
                  builder: (context) => SampleRefreshIndicator(),
                ));
              },
              child: Text("Refresh Indicator"),
              color: Colors.red,
            ),
          ],
        ),
      ),
    );
  }
}

通过这些示例,你可以轻松地在自己的 Flutter 应用中实现弹性头部效果。如果有任何问题或需要进一步的帮助,请随时联系开发者 @diegoveloper


更多关于Flutter弹性头部效果插件stretchy_header的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter弹性头部效果插件stretchy_header的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter中使用stretchy_header插件来实现弹性头部效果的代码案例。这个插件允许你创建一个可拉伸的头部,当用户滚动页面时,头部会相应地拉伸或压缩。

首先,你需要在你的pubspec.yaml文件中添加stretchy_header依赖:

dependencies:
  flutter:
    sdk: flutter
  stretchy_header: ^x.y.z  # 请替换为最新版本号

然后运行flutter pub get来安装依赖。

接下来是一个简单的示例代码,展示如何使用stretchy_header

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Stretchy Header Example'),
        ),
        body: StretchyHeader(
          header: Container(
            height: 200.0,
            color: Colors.blue,
            child: Center(
              child: Text(
                'Stretch Me!',
                style: TextStyle(color: Colors.white, fontSize: 24),
              ),
            ),
          ),
          headerBuilder: (context, shrinkPercent, overlayPercent) {
            return Container(
              decoration: BoxDecoration(
                color: Color.lerp(Colors.blue, Colors.grey, shrinkPercent)!,
              ),
              child: Center(
                child: Text(
                  'Shrink Percent: $shrinkPercent\nOverlay Percent: $overlayPercent',
                  style: TextStyle(color: Colors.white),
                ),
              ),
            );
          },
          content: ListView.builder(
            itemCount: 50,
            itemBuilder: (context, index) {
              return ListTile(
                title: Text('Item $index'),
              );
            },
          ),
        ),
      ),
    );
  }
}

代码说明:

  1. StretchyHeader:

    • header: 定义了头部的基本内容。这里是一个高度为200的蓝色容器,中央有一个白色文本。
    • headerBuilder: 一个回调函数,它根据头部的拉伸比例(shrinkPercent)和覆盖比例(overlayPercent)来动态构建头部。这里我们简单地根据shrinkPercent改变了头部的颜色,并显示了当前的拉伸和覆盖比例。
    • content: 定义了头部下方的内容。这里我们使用ListView.builder来生成一个包含50个条目的列表。
  2. shrinkPercent 和 overlayPercent:

    • shrinkPercent 是头部被拉伸或压缩的比例,范围是0到1。0表示头部未被拉伸(完全展开),1表示头部被完全压缩。
    • overlayPercent 是头部覆盖内容的比例,也是0到1的范围。当头部拉伸时,这个值会增加,表示头部覆盖了多少比例的内容。

通过这种方式,你可以很容易地在Flutter应用中实现一个弹性头部效果,并根据用户的滚动行为动态调整头部的外观。

回到顶部