Instagram Profile标题布局在Flutter中 [英] Instagram Profile Header Layout In Flutter

查看:108
本文介绍了Instagram Profile标题布局在Flutter中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've been investigating SliverAppBar, CustomScrollView, NestedScrollView, SliverPersistentHeader, and more. I cannot find a way to build something like the Instagram user profile screen's header where only the tab bar is pinned. The main body of the screen is a TabBarView and each pane has a scrollable list.

使用SliverAppBar,可以很容易地在底部参数中添加TabBar。但是我想在TabBar上方增加一个未知/可变高度的小部件。滚动页面时,多余的窗口小部件应该滚动开,然后将TabBar固定在屏幕顶部。

With SliverAppBar, it is easy to add the TabBar in the bottom parameter. But I want to have an extra widget of unknown/variable height above that TabBar. The extra widget should scroll out of the way when the page is scrolled and and then the TabBar is what is pinned at the top of the screen.

我能管理的只是标签栏和固定标签栏之前的固定内容。我无法使标题向上滚动并将 TabBar 粘贴在 AppBar 下方的顶部。

All I could manage was a fixed content before the tab bar and a fixed tab bar. I cannot get the header to scroll up and stick the TabBar at the top just just below the AppBar.

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')),
                    ],
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

推荐答案

您可以使用 NestedScrollView 和<$ c $来实现此行为。 c>脚手架。

因为我们需要 AppBar TabBar 要动态构建并滚动,直到 TabBar 达到 AppBar ,请使用 appBar Scaffold 的c $ c>属性来构建您的 AppBar 并使用 headerSliv​​erBuilder 来构建其他高度未知的小部件。使用 NestedScrollView body 属性来构建选项卡视图。

As we need the widgets between the AppBar and TabBar to be dynamically built and scrolled until TabBar reaches AppBar, use the appBar property of the Scaffold to build your AppBar and use headerSliverBuilder to build other widgets of unknown heights. Use the body property of NestedScrollView to build your tab views.

这样, headerSliv​​erBuilder 的元素将滚动直到 body 到达<$ c的底部$ c> AppBar

This way the elements of the headerSliverBuilder would scroll away till the body reaches the bottom of the AppBar.

仅凭文字可能会使您感到有些困惑,这是您的一个例子。

Might be a little confusing to understand with mere words, here is an example for you.

代码:

// 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(),
                    )
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

输出:

希望这会有所帮助!

这篇关于Instagram Profile标题布局在Flutter中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆