How to implement a SliverAppBar with Tabs & Widgets above Tabs?
How to create a SliverAppBar like Talabat App:
Please, check the below - video.
How to solve it?
What can I do?
I am doing...
https://youtube.com/shorts/HeuOTpdRZYY
I tried the below code:
=========================================================
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
var textTheme = Theme.of(context).textTheme;
// return Scaffold(
// body: NestedScrollView(
// headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
// return <Widget>[
// const SliverAppBar(
// backgroundColor: Colors.red,
// flexibleSpace: FlexibleSpaceBar(),
// )
// ];
// },
// body: Container(
// child: Builder(builder: (context) {
// return Column(
// mainAxisAlignment: MainAxisAlignment.start, children: const []);
// }),
// ),
// ),
// );
return Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar(
pinned: true,
expandedHeight: 500,
toolbarHeight: AppSize.s60,
collapsedHeight: 200,
leading: GestureDetector(
onTap: () {},
child: Center(
child: Container(
width: AppSize.s50,
height: AppSize.s44,
decoration: const BoxDecoration(
color: Palette.kPrimaryColor,
borderRadius: BorderRadius.all(
Radius.circular(AppSize.s10),
),
),
child: Center(
child: SvgPicture.asset(
AppAssets.menu,
height: AppSize.s14,
),
),
),
),
),
title: const Text(
"FASDFASD F",
style: TextStyle(
color: Colors.black,
),
),
actions: [
const SizedBox(width: AppSize.s10),
IconButton(
onPressed: () {},
splashRadius: AppSize.s28,
icon: SvgPicture.asset(
AppAssets.shoppingCart,
height: AppSize.s32,
),
),
],
flexibleSpace: Container(
color: Colors.deepOrange,
// height: 250,
child: Column(
children: [
Container(
height: 100,
color: Colors.green,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.black,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.black26,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.black45,
margin: const EdgeInsets.all(10),
),
Container(
height: 120,
color: Colors.blueGrey,
),
],
),
),
bottom: const CustomAppBarBottom(),
backgroundColor: Palette.kWhiteColor,
),
SliverToBoxAdapter(
child: Column(
children: [
Container(
height: 100,
color: Colors.green,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.purple,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.purple,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.green,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.purple,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.purple,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.green,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.purple,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.green,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.black87,
margin: const EdgeInsets.all(10),
),
],
),
),
],
),
);
}
}
class CustomAppBarBottom extends StatelessWidget
implements PreferredSizeWidget {
const CustomAppBarBottom({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
var outlineInputBorder = OutlineInputBorder(
borderRadius: AppRadius.bottomRadius,
borderSide: BorderSide.none,
);
return Container(
margin: EdgeInsets.symmetric(
horizontal: getUIPadding(context),
vertical: 10,
),
decoration: BoxDecoration(
color: Palette.kWhiteColor,
borderRadius: AppRadius.bottomRadius,
boxShadow: const [
BoxShadow(
color: Color.fromARGB(20, 0, 0, 0),
blurRadius: 7,
)
],
),
child: TextFormField(
style: const TextStyle(
height: 1.2,
),
decoration: InputDecoration(
hintText: "عن ماذا تبحث؟",
hintStyle: const TextStyle(
color: Palette.onboardingDescriptionColor,
),
prefixIcon: Align(
// alignment: Alignment.centerRight,
widthFactor: 1.0,
child: SvgPicture.asset(
AppAssets.search,
width: AppSize.s25,
),
),
isDense: true,
border: outlineInputBorder,
errorBorder: outlineInputBorder,
enabledBorder: outlineInputBorder,
focusedBorder: outlineInputBorder,
disabledBorder: outlineInputBorder,
focusedErrorBorder: outlineInputBorder,
),
),
);
}
@override
Size get preferredSize => const Size.fromHeight(AppSize.s60);
}
CodePudding user response:
This widget give you some sample idea, Also check SliverPersistentHeader
for custom header. You can check sliver_tools
package for pinned header. Also TabBar can be replace with scroll_to_index.
class TestWidget extends StatefulWidget {
const TestWidget({Key? key}) : super(key: key);
@override
State<TestWidget> createState() => _TestWidgetState();
}
class _TestWidgetState extends State<TestWidget>
with SingleTickerProviderStateMixin {
late final TabController tabController =
TabController(length: 10, vsync: this);
double itemHeight = 120;
double? appBarHeight;
late final ScrollController controller = ScrollController()
..addListener(() {
if (controller.hasClients) {
final moveTo =
((controller.offset - appBarHeight!) / itemHeight).toInt();
tabController.animateTo(moveTo < 0 ? 0 : moveTo);
setState(() {});
}
});
@override
Widget build(BuildContext context) {
return Scaffold(
body: LayoutBuilder(builder: (context, constraints) {
appBarHeight ??= constraints.maxHeight;
return CustomScrollView(
controller: controller,
slivers: [
SliverAppBar(
pinned: true,
expandedHeight: constraints.maxHeight * .7,
bottom: PreferredSize(
child: TabBar(
controller: tabController,
tabs: List.generate(
10,
(index) => Container(
width: 100,
height: 40,
alignment: Alignment.center,
color: index == tabController.index
? Colors.deepOrange
: Colors.cyanAccent,
child: Text("$index"),
)),
),
preferredSize: Size.fromHeight(kToolbarHeight),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
height: itemHeight,
color: index.isEven ? Colors.green : Colors.pink,
width: constraints.maxWidth,
);
},
),
)
],
);
}),
);
}
}
CodePudding user response:
I want to add some widgets above TabBar and show TabBar only on top (On scrolling).