Flutter 中的 Instagram 个人资料标题布局

Ted*_*nry 16 dart flutter flutter-layout customscrollview flutter-sliverappbar

我一直在研究 SliverAppBar、CustomScrollView、NestedScrollView、SliverPersistentHeader 等。我找不到一种方法来构建类似 Instagram 用户个人资料屏幕的标题,其中只有标签栏被固定。屏幕的主体是一个 TabBarView,每个窗格都有一个可滚动的列表。

使用 SliverAppBar,可以很容易地在底部参数中添加 TabBar。但我想在 TabBar 上方有一个未知/可变高度的额外小部件。当页面滚动时,额外的小部件应该滚动到一边,然后 TabBar 是固定在屏幕顶部的。

在此处输入图片说明

我所能管理的只是标签栏之前的固定内容和固定标签栏。我无法让标题向上滚动并将 贴TabBarAppBar.

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(home: MyApp()));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 2,
      child: Scaffold(
        appBar: AppBar(
          title: Text("pabloaleko"),
        ),
        body: CustomScrollView(
          physics: const BouncingScrollPhysics(),
          slivers: <Widget>[
            SliverToBoxAdapter(
              child: SafeArea(
                child: Text("an unknown\namount of content\n goes here in the header"),
              ),
            ),
            SliverToBoxAdapter(
              child: TabBar(
                tabs: [
                  Tab(child: Text('Days', style: TextStyle(color: Colors.black))),
                  Tab(child: Text('Months', style: TextStyle(color: Colors.black))),
                ],
              ),
            ),
            SliverFillRemaining(
              child: TabBarView(
                children: [
                  ListView(
                    children: <Widget>[
                      ListTile(title: Text('Sunday 1')),
                      ListTile(title: Text('Monday 2')),
                      ListTile(title: Text('Tuesday 3')),
                      ListTile(title: Text('Wednesday 4')),
                      ListTile(title: Text('Thursday 5')),
                      ListTile(title: Text('Friday 6')),
                      ListTile(title: Text('Saturday 7')),
                      ListTile(title: Text('Sunday 8')),
                      ListTile(title: Text('Monday 9')),
                      ListTile(title: Text('Tuesday 10')),
                      ListTile(title: Text('Wednesday 11')),
                      ListTile(title: Text('Thursday 12')),
                      ListTile(title: Text('Friday 13')),
                      ListTile(title: Text('Saturday 14')),
                    ],
                  ),
                  ListView(
                    children: <Widget>[
                      ListTile(title: Text('January')),
                      ListTile(title: Text('February')),
                      ListTile(title: Text('March')),
                      ListTile(title: Text('April')),
                      ListTile(title: Text('May')),
                      ListTile(title: Text('June')),
                      ListTile(title: Text('July')),
                      ListTile(title: Text('August')),
                      ListTile(title: Text('September')),
                      ListTile(title: Text('October')),
                      ListTile(title: Text('November')),
                      ListTile(title: Text('December')),
                    ],
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

Hem*_*Raj 39

您可以使用NestedScrollViewwith实现此行为Scaffold

由于我们需要在AppBar和之间TabBar动态构建和滚动直到TabBar到达的小部件AppBar,因此使用 的appBar属性Scaffold来构建您的AppBar和用于headerSliverBuilder构建未知高度的其他小部件。使用的body属性NestedScrollView来构建您的选项卡视图。

这样, 的元素headerSliverBuilder就会滚动到.body的底部AppBar

仅仅用文字来理解可能有点混乱,这里有一个例子给你。

代码:

// InstaProfilePage
class InstaProfilePage extends StatefulWidget {
  @override
  _InstaProfilePageState createState() => _InstaProfilePageState();
}

class _InstaProfilePageState extends State<InstaProfilePage> {
  double get randHeight => Random().nextInt(100).toDouble();

  List<Widget> _randomChildren;

  // Children with random heights - You can build your widgets of unknown heights here
  // I'm just passing the context in case if any widgets built here needs  access to context based data like Theme or MediaQuery
  List<Widget> _randomHeightWidgets(BuildContext context) {
    _randomChildren ??= List.generate(3, (index) {
      final height = randHeight.clamp(
        50.0,
        MediaQuery.of(context).size.width, // simply using MediaQuery to demonstrate usage of context
      );
      return Container(
        color: Colors.primaries[index],
        height: height,
        child: Text('Random Height Child ${index + 1}'),
      );
    });

    return _randomChildren;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // Persistent AppBar that never scrolls
      appBar: AppBar(
        title: Text('AppBar'),
        elevation: 0.0,
      ),
      body: DefaultTabController(
        length: 2,
        child: NestedScrollView(
          // allows you to build a list of elements that would be scrolled away till the body reached the top
          headerSliverBuilder: (context, _) {
            return [
              SliverList(
                delegate: SliverChildListDelegate(
                  _randomHeightWidgets(context),
                ),
              ),
            ];
          },
          // You tab view goes here
          body: Column(
            children: <Widget>[
              TabBar(
                tabs: [
                  Tab(text: 'A'),
                  Tab(text: 'B'),
                ],
              ),
              Expanded(
                child: TabBarView(
                  children: [
                    GridView.count(
                      padding: EdgeInsets.zero,
                      crossAxisCount: 3,
                      children: Colors.primaries.map((color) {
                        return Container(color: color, height: 150.0);
                      }).toList(),
                    ),
                    ListView(
                      padding: EdgeInsets.zero,
                      children: Colors.primaries.map((color) {
                        return Container(color: color, height: 150.0);
                      }).toList(),
                    )
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

输出:

输出图像

希望这可以帮助!