Ios 颤振-带有搜索栏的自定义条子应用程序栏
我想有一个自定义的银appBar与搜索栏在它。我制作了一个普通的应用程序条,看起来是这样的:但我希望当我们向下滚动时,应用程序条看起来是这样的: 实际上,普通应用程序栏的代码只是一个绿色的Ios 颤振-带有搜索栏的自定义条子应用程序栏,ios,flutter,dart,appbar,flutter-sliver,Ios,Flutter,Dart,Appbar,Flutter Sliver,我想有一个自定义的银appBar与搜索栏在它。我制作了一个普通的应用程序条,看起来是这样的:但我希望当我们向下滚动时,应用程序条看起来是这样的: 实际上,普通应用程序栏的代码只是一个绿色的AppBar,位于elevation:0的下方,我添加了我的标题()。以下是我的标题代码: 类头扩展StatefulWidget{ 字符串标题; Iconda图标; 标题({@required this.title,@required this.icon}); @凌驾 _HeaderState createS
AppBar
,位于elevation:0
的下方,我添加了我的标题()。以下是我的标题代码:
类头扩展StatefulWidget{
字符串标题;
Iconda图标;
标题({@required this.title,@required this.icon});
@凌驾
_HeaderState createState()=>U HeaderState();
}
类_HeaderState扩展状态{
TextEditingController\u editingController;
@凌驾
void initState(){
super.initState();
_editingController=TextEditingController();
}
@凌驾
小部件构建(构建上下文){
Size Size=MediaQuery.of(context).Size;
返回首选大小(
首选大小:大小,
子:容器(
边距:仅限边集(底部:kDefaultPadding*2.5),
高度:尺寸。高度*0.2,
子:堆栈(
儿童:[
容器(
高度:尺寸。高度*0.2-27,
宽度:size.width,
装饰:盒子装饰(
颜色:主题。背景。原色,
borderRadius:仅限borderRadius(
左下角:半径。圆形(36),
右下角:半径。圆形(36),
)
),
子对象:对齐(
对齐:alignment.topCenter,
孩子:排(
mainAxisAlignment:mainAxisAlignment.center,
儿童:[
文本(widget.title,style:Theme.of(context).textTheme.headline4.copyWith(color:Colors.white,fontwweight:fontwweight.bold)),
尺寸箱(宽度:20,),
图标(widget.Icon,大小:40,颜色:Colors.white,)
],
)),
),
定位(
底部:0,
左:0,,
右:0,,
子:容器(
对齐:对齐.center,
边距:边集。对称(水平:kDefaultPadding),
填充:边集。对称(水平:kDefaultPadding),
身高:54,
装饰:盒子装饰(
颜色:颜色,白色,
边界半径:边界半径。圆形(20),
boxShadow:[boxShadow(
偏移量:偏移量(0,10),
半径:50,
颜色:主题。背景。原色。不透明度(0.23),
)]
),
孩子:排(
儿童:[
扩大(
孩子:TextField(
控制器:\ u编辑控制器,
textAlignVertical:textAlignVertical.center,
一旦更改:()=>setState((){}),
装饰:输入装饰(
hintText:'搜索',
hintStyle:TextStyle(颜色:Theme.of(context).primaryColor.withOpacity(0.5)),
enabledBorder:InputBorder.none,
FocusedOrder:InputBorder.none,
),
),
),
_editingController.text.trim().isEmpty?图标按钮(
图标:图标(Icons.search,颜色:Theme.of(context).primaryColor.withOpacity(0.5)),
onPressed:null):
图标按钮(
highlightColor:Colors.transparent,
splashColor:Colors.transparent,
图标:图标(Icons.clear,color:Theme.of(context.primaryColor.withOpacity(0.5)),
按下时:()=>设置状态(){
_editingController.clear();
})),
],
),
),
)
],
),
),
);
}
@凌驾
无效处置(){
_editingController.dispose();
super.dispose();
}
}
欢迎提供任何帮助。我已经制作了一个简单的示例来展示主要逻辑
创建自己的SliverPersistentHeaderDelegate
并计算收缩系数
import'dart:math';
进口“包装:颤振/材料.省道”;
void main()=>runApp(MyApp());
类MyApp扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回材料PP(
标题:“颤振演示”,
主题:主题数据(
主样本:颜色。蓝色,
),
主页:MyHomePage(),
);
}
}
类MyHomePage扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回脚手架(
背景颜色:Colors.white70,
正文:自定义滚动视图(
条子:[
滑冰机(
对,,
浮动:假,
代表:SearchHeader(
图标:Icons.terrain,
标题:"树木",,
搜索:_search(),
),
),
剩余碎片(
哈斯克罗博迪:没错,
子:ListView(
物理学:NeverscrollableScroll物理学(),
儿童:[
文本(“某些文本”),
占位符(
颜色:颜色,红色,
后备高度:200,
),
容器(
颜色:颜色。蓝灰色,
身高:500,
)
],
),
)
],
),
);
}
}
类搜索扩展了StatefulWidget{
_搜索({Key}):超级(Key:Key);
@凌驾
__SearchState createState()=>\u搜索
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white70,
body: CustomScrollView(
slivers: [
SliverPersistentHeader(
pinned: true,
floating: false,
delegate: SearchHeader(
icon: Icons.terrain,
title: 'Trees',
search: _Search(),
),
),
SliverFillRemaining(
hasScrollBody: true,
child: ListView(
physics: NeverScrollableScrollPhysics(),
children: [
Text('some text'),
Placeholder(
color: Colors.red,
fallbackHeight: 200,
),
Container(
color: Colors.blueGrey,
height: 500,
)
],
),
)
],
),
);
}
}
class _Search extends StatefulWidget {
_Search({Key key}) : super(key: key);
@override
__SearchState createState() => __SearchState();
}
class __SearchState extends State<_Search> {
TextEditingController _editingController;
@override
void initState() {
super.initState();
_editingController = TextEditingController();
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(left: 20, right: 5),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: TextField(
controller: _editingController,
// textAlignVertical: TextAlignVertical.center,
onChanged: (_) => setState(() {}),
decoration: InputDecoration(
hintText: 'Search',
hintStyle: TextStyle(
color: Theme.of(context).primaryColor.withOpacity(0.5)),
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
),
),
),
_editingController.text.trim().isEmpty
? IconButton(
icon: Icon(Icons.search,
color: Theme.of(context).primaryColor.withOpacity(0.5)),
onPressed: null)
: IconButton(
highlightColor: Colors.transparent,
splashColor: Colors.transparent,
icon: Icon(Icons.clear,
color: Theme.of(context).primaryColor.withOpacity(0.5)),
onPressed: () => setState(
() {
_editingController.clear();
},
),
),
],
),
);
}
}
class SearchHeader extends SliverPersistentHeaderDelegate {
final double minTopBarHeight = 100;
final double maxTopBarHeight = 200;
final String title;
final IconData icon;
final Widget search;
SearchHeader({
@required this.title,
this.icon,
this.search,
});
@override
Widget build(
BuildContext context,
double shrinkOffset,
bool overlapsContent,
) {
var shrinkFactor = min(1, shrinkOffset / (maxExtent - minExtent));
var topBar = Positioned(
top: 0,
left: 0,
right: 0,
child: Container(
alignment: Alignment.center,
height:
max(maxTopBarHeight * (1 - shrinkFactor * 1.45), minTopBarHeight),
width: 100,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(title,
style: Theme.of(context).textTheme.headline4.copyWith(
color: Colors.white, fontWeight: FontWeight.bold)),
SizedBox(
width: 20,
),
Icon(
icon,
size: 40,
color: Colors.white,
)
],
),
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(36),
bottomRight: Radius.circular(36),
)),
),
);
return Container(
height: max(maxExtent - shrinkOffset, minExtent),
child: Stack(
fit: StackFit.loose,
children: [
if (shrinkFactor <= 0.5) topBar,
Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: EdgeInsets.only(
bottom: 10,
),
child: Container(
alignment: Alignment.center,
child: search,
width: 200,
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.white,
boxShadow: [
BoxShadow(
offset: Offset(0, 10),
blurRadius: 10,
color: Colors.green.withOpacity(0.23),
)
]),
),
),
),
if (shrinkFactor > 0.5) topBar,
],
),
);
}
@override
double get maxExtent => 230;
@override
double get minExtent => 100;
@override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true;
}