Instagram Profile标题布局在Flutter中 [英] Instagram Profile Header Layout In 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
并使用 headerSliverBuilder
来构建其他高度未知的小部件。使用 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.
这样, headerSliverBuilder
的元素将滚动直到 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屋!