스마트시대
USER PROFILE 12.1 CustomScrollView 12.2 SliverAppBar 12.3 SliverGrid 12.4 SliverPersistentHeader 12.5 VerticalDivider 12.6 TabBar 12.7 PersistentTabBar 본문
Programing/Flutter
USER PROFILE 12.1 CustomScrollView 12.2 SliverAppBar 12.3 SliverGrid 12.4 SliverPersistentHeader 12.5 VerticalDivider 12.6 TabBar 12.7 PersistentTabBar
스마트시대 2023. 5. 22. 23:21728x90
12.1 CustomScrollView
import 'package:flutter/material.dart';
class UserProfileScreen extends StatefulWidget {
const UserProfileScreen({super.key});
@override
State<UserProfileScreen> createState() => _UserProfileScreenState();
}
class _UserProfileScreenState extends State<UserProfileScreen> {
@override
Widget build(BuildContext context) {
return CustomScrollView(
//slivers: 사용자들이 스크롤할 수 있는 것들, scrollview의 일부, 위젯 안에 들어감
slivers: [
SliverAppBar(
floating: true,
stretch: true,
pinned: true,
backgroundColor: Colors.teal,
collapsedHeight: 80,
expandedHeight: 200,
flexibleSpace: FlexibleSpaceBar(
stretchModes: const [
StretchMode.blurBackground,
StretchMode.zoomBackground,
],
background: Image.asset(
"assets/images/image.jpeg",
fit: BoxFit.cover,
),
title: const Text("Hello!"),
),
)
],
);
}
}
12.2 SliverAppBar
class _UserProfileScreenState extends State<UserProfileScreen> {
@override
Widget build(BuildContext context) {
-------------------
return CustomScrollView(
//slivers: 사용자들이 스크롤할 수 있는 것들, scrollview의 일부, 위젯 안에 들어감
slivers: [
SliverAppBar(
pinned: true, //title항상 표시
snap: true, //스크롤할 때 appbar 확 내려오는 것
floating: true, //스크롤할 때 appbar가 조금씩 표시되는 것
stretch: true,
backgroundColor: Colors.teal,
collapsedHeight: 80,
expandedHeight: 200,
flexibleSpace: FlexibleSpaceBar(
stretchModes: const [
StretchMode.blurBackground,
StretchMode.zoomBackground,
StretchMode.fadeTitle,
],
background: Image.asset(
"assets/images/image.jpeg",
fit: BoxFit.cover,
),
title: const Text("Hello!"),
),
),
-------------------
-------------------
SliverFixedExtentList(
delegate: SliverChildBuilderDelegate(
childCount: 50,
(context, index) => Container(
color: Colors.amber[100 * (index % 9)],
child: Align(
alignment: Alignment.center,
child: Text("Item $index"),
),
),
),
itemExtent: 100,
-------------------
),
],
);
}
}
12.3 SliverGrid
itemExtent: 100,
------------------------
),
SliverGrid(
delegate: SliverChildBuilderDelegate(
childCount: 50,
(context, index) => Container(
color: Colors.blue[100 * (index % 9)],
child: Align(
alignment: Alignment.center,
child: Text("Item $index"),
),
),
),
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 100,
mainAxisSpacing: Sizes.size20,
crossAxisSpacing: Sizes.size20,
childAspectRatio: 1),
------------------------
),
],
);
}
}
12.4 SliverPersistentHeader
-------------------
SliverToBoxAdapter(
child: Column(
children: const [
CircleAvatar(
backgroundColor: Colors.red,
radius: 20,
),
],
),
),
-------------------
SliverFixedExtentList(
-------------------
SliverPersistentHeader(
delegate: CustomDelegate(),
pinned: true,
),
-------------------
SliverGrid(
-------------------
class CustomDelegate extends SliverPersistentHeaderDelegate {
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return Container(
color: Colors.indigo,
child: const FractionallySizedBox(
heightFactor: 1,
child: Center(
child: Text(
"Title!!!!!!!",
style: TextStyle(
color: Colors.white,
),
),
),
),
);
}
@override
//pinned: true,했을 때 위에서 표시되는 크기
double get maxExtent => 150;
@override
//pinned: true,했을 때 아래에서 표시되는 크기(스크롤 끝난뒤)
double get minExtent => 80;
@override
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
return false;
}
}
-------------------
slivers에서 제공하는 것 쓰려면 위의 코드와 공식 문서 참조
12.5 VerticalDivider
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:tiktok_clone/constants/gaps.dart';
import 'package:tiktok_clone/constants/sizes.dart';
class UserProfileScreen extends StatefulWidget {
const UserProfileScreen({super.key});
@override
State<UserProfileScreen> createState() => _UserProfileScreenState();
}
class _UserProfileScreenState extends State<UserProfileScreen> {
@override
Widget build(BuildContext context) {
return CustomScrollView(
------------------
slivers: [
SliverAppBar(
title: const Text("Joon"),
actions: [
IconButton(
onPressed: () {},
icon: const FaIcon(
FontAwesomeIcons.gear,
size: Sizes.size20,
),
),
],
),
SliverToBoxAdapter(
child: Column(
children: [
const CircleAvatar(
radius: 50,
foregroundColor: Colors.teal,
child: Text("joon"),
),
Gaps.v20,
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text(
"@joon",
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: Sizes.size20,
),
),
Gaps.h5,
FaIcon(
FontAwesomeIcons.solidCircleCheck,
size: Sizes.size16,
color: Colors.blue,
),
],
),
Gaps.v24,
// each column당 경계선 보이게 하려면 SizedBox로 묶어야 함
SizedBox(
height: Sizes.size48,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
children: [
const Text(
"97",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: Sizes.size18,
),
),
Gaps.v3,
Text(
"Following",
style: TextStyle(
color: Colors.grey.shade500,
),
),
],
),
// each column당 경계선 보이게 하려면 SizedBox로 묶어야 함
VerticalDivider(
width: Sizes.size32,
thickness: Sizes.size1,
color: Colors.grey.shade400,
indent: Sizes.size14,
endIndent: Sizes.size14,
),
Column(
children: [
const Text(
"10.5M",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: Sizes.size18,
),
),
Gaps.v3,
Text(
"Follower",
style: TextStyle(
color: Colors.grey.shade500,
),
),
],
),
// each column당 경계선 보이게 하려면 SizedBox로 묶어야 함
VerticalDivider(
width: Sizes.size32,
thickness: Sizes.size1,
color: Colors.grey.shade400,
indent: Sizes.size14,
endIndent: Sizes.size14,
),
Column(
children: [
const Text(
"149.3M",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: Sizes.size18,
),
),
Gaps.v3,
Text(
"Likes",
style: TextStyle(
color: Colors.grey.shade500,
------------------
),
),
],
),
],
),
),
],
),
),
],
);
}
}
12.6 TabBar
size: Sizes.size20,
),
),
],
),
--------------------
//SliverGrid는 SliverToBoxAdapter안에서 쓸 수 없음(sliver위젯중복사용안됨),GridView.builder사용
SliverToBoxAdapter(
--------------------
child: Column(
color: Colors.grey.shade500,
),
),
],
),
],
),
),
--------------------
Gaps.v10,
//father의 너비와 높이에 의존하여 크기를 갖음
FractionallySizedBox(
widthFactor: 0.33,
child: Container(
padding: const EdgeInsets.symmetric(
vertical: Sizes.size12,
),
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
borderRadius: const BorderRadius.all(
Radius.circular(Sizes.size4),
),
),
child: const Text(
"Follow",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
),
textAlign: TextAlign.center,
),
),
),
Gaps.v14,
const Padding(
padding: EdgeInsets.symmetric(
horizontal: Sizes.size32,
),
child: Text(
"All highlights and where to watch live matches on FIFA+.",
textAlign: TextAlign.center,
),
),
Gaps.v14,
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
FaIcon(
FontAwesomeIcons.link,
size: Sizes.size12,
),
Gaps.h4,
Text(
"© https://www.fifa.com/fifaplus/en/home",
style: TextStyle(
fontWeight: FontWeight.w600,
),
),
],
),
Gaps.v20,
Container(
decoration: BoxDecoration(
border: Border.symmetric(
horizontal: BorderSide(
color: Colors.grey.shade200,
width: 0.5,
),
),
),
child: const TabBar(
indicatorSize: TabBarIndicatorSize.label,
indicatorColor: Colors.black,
labelPadding: EdgeInsets.only(
bottom: Sizes.size10,
),
labelColor: Colors.black,
tabs: [
Padding(
padding: EdgeInsets.symmetric(
horizontal: Sizes.size20,
),
child: Icon(Icons.grid_4x4_rounded),
),
Padding(
padding: EdgeInsets.symmetric(
horizontal: Sizes.size16,
),
child: FaIcon(FontAwesomeIcons.heart),
),
],
),
),
SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.width,
child: TabBarView(
children: [
//SliverGrid는 SliverToBoxAdapter안에서 쓸 수 없음(sliver위젯중복사용안됨),GridView.builder사용
GridView.builder(
//GridView뿐만 아니라 여기서 만든 CustomScrollView도 동시에 스크롤 할 수 있게 하는 설정
physics: const NeverScrollableScrollPhysics(),
//스크롤하면 키보드 가리게 하는 설정
keyboardDismissBehavior:
ScrollViewKeyboardDismissBehavior.onDrag,
itemCount: 20,
padding: const EdgeInsets.all(
Sizes.size8,
),
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: Sizes.size10,
mainAxisSpacing: Sizes.size10,
childAspectRatio: 9 / 20,
),
itemBuilder: (context, index) => Column(
children: [
Container(
//AspectRatio가 BoxDecoration까지 overflow하고 있으므로 clipBehavior로 잘라주기
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(
Sizes.size4,
),
),
//특정한 비율을 따르는 위젯을 만드는 위젯
child: AspectRatio(
aspectRatio: 9 / 16,
// 네트워크에 있는 이미지 가지고 오는 동안 로컬에 저장되어 있는 이미지 가져오기
child: FadeInImage.assetNetwork(
fit: BoxFit.cover,
placeholder: "assets/images/image.jpeg",
image:
"https://plus.unsplash.com/premium_photo-1683880731792-39c07ceea617?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=687&q=80",
),
),
),
Gaps.v10,
const Text(
"This is a very long cation for my tiktok that im upload just for now",
//아무리 긴 문장이라도 2줄로 잘라준다
overflow: TextOverflow.ellipsis,
maxLines: 2,
style: TextStyle(
fontSize: Sizes.size16 + Sizes.size2,
fontWeight: FontWeight.bold,
),
),
Gaps.v7,
//text style을 자식 text들에 동시 적용할 수 있는 위젯
DefaultTextStyle(
style: TextStyle(
color: Colors.grey.shade600,
fontWeight: FontWeight.w600),
child: Row(
children: [
const CircleAvatar(
radius: 12,
backgroundImage: NetworkImage(
"https://media.licdn.com/dms/image/C4D03AQEfaXwimUdjmw/profile-displayphoto-shrink_100_100/0/1517469163893?e=1689811200&v=beta&t=0i37nt-0uT5JvkQGUUzQlZtA5fUFFYUVinTFDTyo0iQ",
),
),
Gaps.h4,
const Expanded(
child: Text(
"My avatar is going to be very long",
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
Gaps.h4,
FaIcon(
FontAwesomeIcons.heart,
size: Sizes.size16,
color: Colors.grey.shade600,
),
Gaps.h2,
const Text(
"2.5M",
),
],
),
),
],
),
),
const Center(
child: Text("Page 2"),
--------------------
),
],
),
),
],
),
),
],
),
);
}
}
12.7 PersistentTabBar
12.6 TabBar에서의 설정만으로는 GridView.builder의 내용을 다 볼 수는 없다.
NestedScrollView를 통해 스크롤 문제를 해결해야 함.
NestedScrollView는 여러 개의 스크롤 가능한 view들을 넣을 수 있게 해주고 그 안의 모든 scroll position들을 연결해준다.
여기서는 사진만 나오게 DiscoverScreen의 내용 아래와 같이 변경해주기
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:tiktok_clone/constants/gaps.dart';
import 'package:tiktok_clone/constants/sizes.dart';
class UserProfileScreen extends StatefulWidget {
const UserProfileScreen({super.key});
@override
State<UserProfileScreen> createState() => _UserProfileScreenState();
}
class _UserProfileScreenState extends State<UserProfileScreen> {
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
----------------------
//CustomScrollView를 NestedScrollView로 바꿔주기
child: NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled) {
return [
SliverAppBar(
title: const Text("Joon"),
actions: [
IconButton(
onPressed: () {},
icon: const FaIcon(
FontAwesomeIcons.gear,
size: Sizes.size20,
),
),
],
),
//SliverGrid는 SliverToBoxAdapter안에서 쓸 수 없음(sliver위젯중복사용안됨),GridView.builder사용
SliverToBoxAdapter(
child: Column(
children: [
const CircleAvatar(
radius: 50,
foregroundColor: Colors.teal,
child: Text("joon"),
),
Gaps.v20,
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text(
"@joon",
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: Sizes.size20,
),
),
Gaps.h5,
FaIcon(
FontAwesomeIcons.solidCircleCheck,
size: Sizes.size16,
color: Colors.blue,
),
],
),
Gaps.v24,
// each column당 경계선 보이게 하려면 SizedBox로 묶어야 함
SizedBox(
height: Sizes.size48,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
children: [
const Text(
"97",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: Sizes.size18,
),
),
Gaps.v3,
Text(
"Following",
style: TextStyle(
color: Colors.grey.shade500,
),
),
],
),
// each column당 경계선 보이게 하려면 SizedBox로 묶어야 함
VerticalDivider(
width: Sizes.size32,
thickness: Sizes.size1,
color: Colors.grey.shade400,
indent: Sizes.size14,
endIndent: Sizes.size14,
),
Column(
children: [
const Text(
"10.5M",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: Sizes.size18,
),
),
Gaps.v3,
Text(
"Follower",
style: TextStyle(
color: Colors.grey.shade500,
),
),
],
),
// each column당 경계선 보이게 하려면 SizedBox로 묶어야 함
VerticalDivider(
width: Sizes.size32,
thickness: Sizes.size1,
color: Colors.grey.shade400,
indent: Sizes.size14,
endIndent: Sizes.size14,
),
Column(
children: [
const Text(
"149.3M",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: Sizes.size18,
),
),
Gaps.v3,
Text(
"Likes",
style: TextStyle(
color: Colors.grey.shade500,
),
),
],
),
],
),
),
Gaps.v10,
//father의 너비와 높이에 의존하여 크기를 갖음
FractionallySizedBox(
widthFactor: 0.33,
child: Container(
padding: const EdgeInsets.symmetric(
vertical: Sizes.size12,
),
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
borderRadius: const BorderRadius.all(
Radius.circular(Sizes.size4),
),
),
child: const Text(
"Follow",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
),
textAlign: TextAlign.center,
),
),
),
Gaps.v14,
const Padding(
padding: EdgeInsets.symmetric(
horizontal: Sizes.size32,
),
child: Text(
"All highlights and where to watch live matches on FIFA+.",
textAlign: TextAlign.center,
),
),
Gaps.v14,
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
FaIcon(
FontAwesomeIcons.link,
size: Sizes.size12,
),
Gaps.h4,
Text(
"© https://www.fifa.com/fifaplus/en/home",
style: TextStyle(
fontWeight: FontWeight.w600,
),
),
],
),
Gaps.v20,
Container(
decoration: BoxDecoration(
border: Border.symmetric(
horizontal: BorderSide(
color: Colors.grey.shade200,
width: 0.5,
),
),
),
child: const TabBar(
indicatorSize: TabBarIndicatorSize.label,
indicatorColor: Colors.black,
labelPadding: EdgeInsets.only(
bottom: Sizes.size10,
),
labelColor: Colors.black,
tabs: [
Padding(
padding: EdgeInsets.symmetric(
horizontal: Sizes.size20,
),
child: Icon(Icons.grid_4x4_rounded),
),
Padding(
padding: EdgeInsets.symmetric(
horizontal: Sizes.size16,
),
child: FaIcon(FontAwesomeIcons.heart),
),
],
),
),
],
),
)
];
},
// NestedScrollView에서 TabBarView는 body로 옮겨줘야 함
body: TabBarView(
children: [
//SliverGrid는 SliverToBoxAdapter안에서 쓸 수 없음(sliver위젯중복사용안됨),GridView.builder사용
GridView.builder(
//GridView뿐만 아니라 여기서 만든 CustomScrollView도 동시에 스크롤 할 수 있게 하는 설정
physics: const NeverScrollableScrollPhysics(),
//스크롤하면 키보드 가리게 하는 설정
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
itemCount: 20,
padding: EdgeInsets.zero,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: Sizes.size2,
mainAxisSpacing: Sizes.size2,
childAspectRatio: 9 / 16,
),
itemBuilder: (context, index) => Column(
children: [
AspectRatio(
aspectRatio: 9 / 16,
// 네트워크에 있는 이미지 가지고 오는 동안 로컬에 저장되어 있는 이미지 가져오기
child: FadeInImage.assetNetwork(
fit: BoxFit.cover,
placeholder: "assets/images/image.jpeg",
image:
"https://plus.unsplash.com/premium_photo-1683880731792-39c07ceea617?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=687&q=80",
),
),
],
),
),
----------------------
const Center(
child: Text("Page 2"),
),
],
),
),
);
}
}
Tabbar 고정해주는 방법
그때 써주는 것이 PersistentTabBar위젯
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:tiktok_clone/constants/gaps.dart';
import 'package:tiktok_clone/constants/sizes.dart';
import 'package:tiktok_clone/features/users/widgets/persistent_tab_bar.dart';
class UserProfileScreen extends StatefulWidget {
const UserProfileScreen({super.key});
@override
State<UserProfileScreen> createState() => _UserProfileScreenState();
}
class _UserProfileScreenState extends State<UserProfileScreen> {
@override
Widget build(BuildContext context) {
------------------
//safe area에 잘 랜더링(상태 바의 시계,베터리 상태 등을 침범하지 않게)하는 위젯
return SafeArea(
------------------
child: DefaultTabController(
length: 2,
------------------
//CustomScrollView를 NestedScrollView로 바꿔주기
child: NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled) {
return [
SliverAppBar(
title: const Text("Joon"),
actions: [
IconButton(
onPressed: () {},
icon: const FaIcon(
FontAwesomeIcons.gear,
size: Sizes.size20,
),
),
],
),
------------------
------------------
//SliverGrid는 SliverToBoxAdapter안에서 쓸 수 없음(sliver위젯중복사용안됨),GridView.builder사용
SliverToBoxAdapter(
------------------
child: Column(
children: [
const CircleAvatar(
radius: 50,
foregroundColor: Colors.teal,
child: Text("joon"),
),
Gaps.v20,
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text(
"@joon",
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: Sizes.size20,
),
),
Gaps.h5,
FaIcon(
FontAwesomeIcons.solidCircleCheck,
size: Sizes.size16,
color: Colors.blue,
),
],
),
Gaps.v24,
// each column당 경계선 보이게 하려면 SizedBox로 묶어야 함
SizedBox(
height: Sizes.size48,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
children: [
const Text(
"97",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: Sizes.size18,
),
),
Gaps.v3,
Text(
"Following",
style: TextStyle(
color: Colors.grey.shade500,
),
),
],
),
// each column당 경계선 보이게 하려면 SizedBox로 묶어야 함
VerticalDivider(
width: Sizes.size32,
thickness: Sizes.size1,
color: Colors.grey.shade400,
indent: Sizes.size14,
endIndent: Sizes.size14,
),
Column(
children: [
const Text(
"10.5M",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: Sizes.size18,
),
),
Gaps.v3,
Text(
"Follower",
style: TextStyle(
color: Colors.grey.shade500,
),
),
],
),
// each column당 경계선 보이게 하려면 SizedBox로 묶어야 함
VerticalDivider(
width: Sizes.size32,
thickness: Sizes.size1,
color: Colors.grey.shade400,
indent: Sizes.size14,
endIndent: Sizes.size14,
),
Column(
children: [
const Text(
"149.3M",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: Sizes.size18,
),
),
Gaps.v3,
Text(
"Likes",
style: TextStyle(
color: Colors.grey.shade500,
),
),
],
),
],
),
),
Gaps.v10,
//father의 너비와 높이에 의존하여 크기를 갖음
FractionallySizedBox(
widthFactor: 0.33,
child: Container(
padding: const EdgeInsets.symmetric(
vertical: Sizes.size12,
),
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
borderRadius: const BorderRadius.all(
Radius.circular(Sizes.size4),
),
),
child: const Text(
"Follow",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
),
textAlign: TextAlign.center,
),
),
),
Gaps.v14,
const Padding(
padding: EdgeInsets.symmetric(
horizontal: Sizes.size32,
),
child: Text(
"All highlights and where to watch live matches on FIFA+.",
textAlign: TextAlign.center,
),
),
Gaps.v14,
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
FaIcon(
FontAwesomeIcons.link,
size: Sizes.size12,
),
Gaps.h4,
Text(
"© https://www.fifa.com/fifaplus/en/home",
style: TextStyle(
fontWeight: FontWeight.w600,
),
),
],
),
Gaps.v20,
],
),
),
------------------
//TabBar고정 시켜주는 위젯
SliverPersistentHeader(
delegate: PersistentTabBar(),
pinned: true,
),
];
},
------------------
------------------
// NestedScrollView에서 TabBarView는 body로 옮겨줘야 함
body: TabBarView(
------------------
children: [
//SliverGrid는 SliverToBoxAdapter안에서 쓸 수 없음(sliver위젯중복사용안됨),GridView.builder사용
GridView.builder(
//GridView뿐만 아니라 여기서 만든 CustomScrollView도 동시에 스크롤 할 수 있게 하는 설정
physics: const NeverScrollableScrollPhysics(),
//스크롤하면 키보드 가리게 하는 설정
keyboardDismissBehavior:
ScrollViewKeyboardDismissBehavior.onDrag,
itemCount: 20,
padding: EdgeInsets.zero,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: Sizes.size2,
mainAxisSpacing: Sizes.size2,
childAspectRatio: 9 / 14,
),
itemBuilder: (context, index) => Column(
children: [
AspectRatio(
aspectRatio: 9 / 14,
// 네트워크에 있는 이미지 가지고 오는 동안 로컬에 저장되어 있는 이미지 가져오기
child: FadeInImage.assetNetwork(
fit: BoxFit.cover,
placeholder: "assets/images/image.jpeg",
image:
"https://plus.unsplash.com/premium_photo-1683880731792-39c07ceea617?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=687&q=80",
),
),
],
),
),
const Center(
child: Text("Page 2"),
),
],
),
),
),
);
}
}
이 부분 위에 코드로 따로 분리하기
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:tiktok_clone/constants/sizes.dart';
class PersistentTabBar extends SliverPersistentHeaderDelegate {
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.symmetric(
horizontal: BorderSide(
color: Colors.grey.shade200,
width: 0.5,
),
),
),
child: const TabBar(
indicatorSize: TabBarIndicatorSize.label,
indicatorColor: Colors.black,
labelPadding: EdgeInsets.symmetric(
vertical: Sizes.size10,
),
labelColor: Colors.black,
tabs: [
Padding(
padding: EdgeInsets.symmetric(
horizontal: Sizes.size20,
),
child: Icon(Icons.grid_4x4_rounded),
),
Padding(
padding: EdgeInsets.symmetric(
horizontal: Sizes.size20,
),
child: FaIcon(FontAwesomeIcons.heart),
),
],
),
);
}
@override
double get maxExtent => 47;
@override
double get minExtent => 47;
@override
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
return true;
}
}
728x90
반응형
'Programing > Flutter' 카테고리의 다른 글
Comments