스마트시대
INBOX 10.0 ListTile 10.1 RichText 10.2 Dismissible 10.3 onDismissed 10.4 RotationTransition 10.5 SlideTransition 10.6 AnimatedModalBarrier 10.7 Recap 본문
Programing/Flutter
INBOX 10.0 ListTile 10.1 RichText 10.2 Dismissible 10.3 onDismissed 10.4 RotationTransition 10.5 SlideTransition 10.6 AnimatedModalBarrier 10.7 Recap
스마트시대 2023. 5. 19. 19:04728x90
10.0 ListTile
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:tiktok_clone/constants/sizes.dart';
class InboxScreen extends StatelessWidget {
const InboxScreen({super.key});
//method
void _onPressed() {}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 1,
title: const Text("Inbox"),
actions: [
IconButton(
onPressed: _onPressed,
icon: const FaIcon(
FontAwesomeIcons.paperPlane,
),
),
],
),
body: ListView(
children: [
// inbox 안쪽의 타이틀 역할
const ListTile(
title: Text(
"Activity",
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: Sizes.size16,
),
),
// 뒤에 오는 아이콘
trailing: FaIcon(
FontAwesomeIcons.chevronRight,
size: Sizes.size14,
color: Colors.black,
),
),
//Activity와 New followers 나누는 경계
Container(
height: Sizes.size1,
color: Colors.grey.shade200,
),
ListTile(
// 앞에 오는 아이콘
leading: Container(
width: Sizes.size48,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.blue,
),
child: const Center(
child: FaIcon(
FontAwesomeIcons.users,
color: Colors.white,
),
),
),
title: const Text(
"New followers",
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: Sizes.size16,
),
),
subtitle: const Text(
"Messages from followers will appear here",
style: TextStyle(
fontSize: Sizes.size14,
),
),
trailing: const FaIcon(
FontAwesomeIcons.chevronRight,
size: Sizes.size14,
color: Colors.black,
),
),
],
),
);
}
}
10.1 RichText
inbox_screen.dart
//method
void _onPressed() {}
------------------
//_onActivityTap 넘어가기 메소드
void _onActivityTap(BuildContext context) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const ActivityScreen(),
),
);
}
------------------
body: ListView(
children: [
// inbox 안쪽의 타이틀 역할
ListTile(
------------------
//_onActivityTap 넘어가기 메소드
onTap: () => _onActivityTap(context),
------------------
title: const Text(
"Activity",
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 ActivityScreen extends StatelessWidget {
const ActivityScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("All activity"),
),
body: ListView(
padding: const EdgeInsets.symmetric(
horizontal: Sizes.size20,
),
children: [
Gaps.v14,
Text(
"New",
style: TextStyle(
fontSize: Sizes.size14,
color: Colors.grey.shade500,
),
),
Gaps.v14,
ListTile(
// 위에 패딩 있는 상태에서 이런 식으로 종 아이콘의 패딩 없을 수 있음
contentPadding: EdgeInsets.zero,
leading: Container(
width: Sizes.size52,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
border: Border.all(
color: Colors.grey.shade400,
width: Sizes.size1,
)),
child: const Center(
child: FaIcon(
FontAwesomeIcons.bell,
color: Colors.black,
),
),
),
//RichText위젯을 사용하여 한 ListTile에 있는 문장을 마음대로 커스터마이즈
title: RichText(
text: TextSpan(
text: "Account updates:",
style: const TextStyle(
fontWeight: FontWeight.w600,
color: Colors.black,
fontSize: Sizes.size16,
),
children: [
const TextSpan(
text: "Upload longer videos",
style: TextStyle(
fontWeight: FontWeight.normal,
),
),
TextSpan(
text: "1h",
style: TextStyle(
fontWeight: FontWeight.normal,
color: Colors.grey.shade500,
),
),
],
),
),
trailing: const FaIcon(
FontAwesomeIcons.chevronRight,
size: Sizes.size16,
),
),
],
),
);
}
}
10.2 Dismissible
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("All activity"),
),
body: ListView(
children: [
Gaps.v14,
Padding(
-----------------
padding: const EdgeInsets.symmetric(
horizontal: Sizes.size12,
-----------------
),
child: Text(
"New",
style: TextStyle(
fontSize: Sizes.size14,
color: Colors.grey.shade500,
),
),
),
Gaps.v14,
-----------------
//ListTile위젯을 옆으로 밀어내는 dismiss동작 구현 위젯
Dismissible(
key: const Key("x"),
background: Container(
// container 안에 있는 아이템들을 정렬해줌
alignment: Alignment.centerLeft,
color: Colors.green,
child: const Padding(
padding: EdgeInsets.only(
left: Sizes.size10,
),
child: FaIcon(
FontAwesomeIcons.checkDouble,
color: Colors.white,
size: Sizes.size32,
),
),
),
secondaryBackground: Container(
// container 안에 있는 아이템들을 정렬해줌
alignment: Alignment.centerRight,
color: Colors.red,
child: const Padding(
padding: EdgeInsets.only(
right: Sizes.size10,
),
child: FaIcon(
FontAwesomeIcons.trashCan,
color: Colors.white,
size: Sizes.size32,
-----------------
),
),
),
child: ListTile(
-----------------
// 위에 패딩 있는 상태에서 이런 식으로 종 아이콘의 패딩 없을 수 있음
// contentPadding: EdgeInsets.zero,
-----------------
leading: Container(
width: Sizes.size52,
10.3 onDismissed
10.2에서 생성한 위젯을 dismiss했다고 build메소드 안에서 지워지지는 않으니까 이 list 기반으로 rebuild하도록 state를 설정 후 dismiss된 위젯은 위젯트리에서 완전히 지워버리는 걸 구현해야 에러가 생기지 않는다
-------------------
class ActivityScreen extends StatefulWidget {
const ActivityScreen({super.key});
-------------------
@override
State<ActivityScreen> createState() => _ActivityScreenState();
}
-------------------
//위젯을 dismiss했다고 build메소드 안에서 지워지지는 않으니까
//이 list 기반으로 rebuild하도록 state를 설정 후 dismiss된 위젯은 위젯트리에서 완전히 지워버리는 클래스
class _ActivityScreenState extends State<ActivityScreen> {
final List<String> _notifications = List.generate(20, (index) => "${index}h");
//위젯트리에서 완전히 지워버리는 메소드
void _onDismissed(String notification) {
_notifications.remove(notification);
setState(() {});
}
-------------------
@override
Widget build(BuildContext context) {
-------------------
print(_notifications);
-------------------
return Scaffold(
appBar: AppBar(
title: const Text("All activity"),
),
color: Colors.grey.shade500,
),
),
),
Gaps.v14,
-----------
//위젯을 dismiss했다고 build메소드 안에서 지워지지는 않으니까
//이 list 기반으로 rebuild하도록 state를 설정 후 dismiss된 위젯은 위젯트리에서 완전히 지워버리는 for구문
for (var notification in _notifications)
-----------
//ListTile위젯을 옆으로 밀어내는 dismiss동작 구현 위젯
Dismissible(
key: Key(notification),
-----------
//1h,2h..별로 방향이 어쨋든 위젯트리에서 완전히 지워버리는 메소드
onDismissed: (direction) => _onDismissed(notification),
-----------
background: Container(
// container 안에 있는 아이템들을 정렬해줌
alignment: Alignment.centerLeft,
color: Colors.green,
child: const Padding(
child: ListTile(
-----------------
// 위젯 간의 간격 띄우기
minVerticalPadding: Sizes.size16,
-----------------
// 위에 패딩 있는 상태에서 이런 식으로 종 아이콘의 패딩 없을 수 있음
// contentPadding: EdgeInsets.zero,
leading: Container(
10.4 RotationTransition
class _ActivityScreenState extends State<ActivityScreen>
-------------------
with SingleTickerProviderStateMixin {
-------------------
//위젯을 dismiss했다고 build메소드 안에서 지워지지는 않으니까
//이 list 기반으로 rebuild하도록 state를 설정 후 dismiss된 위젯은 위젯트리에서 완전히 지워버리는 클래스
final List<String> _notifications = List.generate(20, (index) => "${index}h");
-------------------
//initState(animation builder,event listener,setstate등) 없이도 이런식으로 구현 할 수 있다. 이떄는 무조건 late써야함
late final AnimationController _animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 200),
);
//initState(animation builder,event listener,setstat 등) 없이도 이런식으로 구현 할 수 있다. 이떄는 무조건 late써야함
late final Animation<double> _animation =
//화살표 180도로 돌려주는 거
Tween(begin: 0.0, end: 0.5).animate(_animationController);
-------------------
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
-------------------
title: GestureDetector(
onTap: _onTitleTap,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("All activity"),
Gaps.h2,
RotationTransition(
turns: _animation,
child: const FaIcon(
FontAwesomeIcons.chevronDown,
size: Sizes.size14,
-------------------
),
)
],
),
),
),
body: ListView(
10.5 SlideTransition
final List<String> _notifications = List.generate(20, (index) => "${index}h");
-----------------
//All activity아이콘 리스트화
final List<Map<String, dynamic>> _tabs = [
{
"title": "All activity",
"icon": FontAwesomeIcons.solidMessage,
},
{
"title": "Likes",
"icon": FontAwesomeIcons.solidHeart,
},
{
"title": "Comments",
"icon": FontAwesomeIcons.solidComments,
},
{
"title": "Mentions",
"icon": FontAwesomeIcons.at,
},
{
"title": "Followers",
"icon": FontAwesomeIcons.solidUser,
},
{
"title": "From TikTok",
"icon": FontAwesomeIcons.tiktok,
}
];
-----------------
Tween(begin: 0.0, end: 0.5).animate(_animationController);
-----------------
//아이콘 리스트 감추기 함수
late final Animation<Offset> _panelAnimation = Tween(
// 수직축으로 50% 위로 올리도록 함(비율,픽셀X)
begin: const Offset(0, -1),
end: Offset.zero,
).animate(_animationController);
-----------------
//위젯트리에서 완전히 지워버리는 메소드
trailing: const FaIcon(
FontAwesomeIcons.chevronRight,
size: Sizes.size16,
),
),
),
],
),
-----------------
SlideTransition(
position: _panelAnimation,
child: Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(
Sizes.size5,
),
bottomRight: Radius.circular(
Sizes.size5,
),
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
for (var tab in _tabs)
ListTile(
title: Row(
children: [
FaIcon(
tab["icon"],
color: Colors.black,
size: Sizes.size16,
),
Gaps.h20,
Text(
tab["title"],
style: const TextStyle(
fontWeight: FontWeight.bold,
-----------------
),
),
],
),
),
],
),
),
),
],
),
);
}
}
10.6 AnimatedModalBarrier
---------------
//위젯 트리에서 barrier를 보여주고 숨기는 역할을 하는 flag
bool _showBarrier = false;
---------------
//initState(animation builder,event listener,setstate등) 없이도 이런식으로 구현 할 수 있다. 이떄는 무조건 late써야함
late final AnimationController _animationController = AnimationController(
).animate(_animationController);
---------------
//overlay(패널 뒤에 숨어서 어두워지기,모든이벤트 비활성화)
late final Animation<Color?> _barrierAnimation = ColorTween(
begin: Colors.transparent,
end: Colors.black38,
).animate(_animationController);
---------------
//위젯트리에서 완전히 지워버리는 메소드
void _onDismissed(String notification) {
---------------
//barrier 동작을 원할하게 하기 위해 future구문 써야 함
void _toggleAnimations() async {
if (_animationController.isCompleted) {
await _animationController.reverse();
} else {
_animationController.forward();
}
//위젯 트리에서 barrier를 보여주고 숨기는 역할을 하는 flag
setState(() {
_showBarrier = !_showBarrier;
});
}
---------------
trailing: const FaIcon(
FontAwesomeIcons.chevronRight,
size: Sizes.size16,
),
),
),
],
),
---------------
//위젯 트리에서 barrier를 보여주고 숨기는 역할을 하는 flag
if (_showBarrier)
//overlay(패널 뒤에 숨어서 어두워지기,모든이벤트 비활성화), 위치는 SlideTransition앞에 와야 함
AnimatedModalBarrier(
color: _barrierAnimation,
//이 설정으로 베리어 쪽 눌러도 아이콘 리스트(modal)가 최소화 됨
dismissible: true,
onDismiss: _toggleAnimations,
---------------
),
SlideTransition(
position: _panelAnimation,
@override
Widget build(BuildContext context) {
728x90
반응형
'Programing > Flutter' 카테고리의 다른 글
Comments