import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:tiktok_clone/constants/breakpoints.dart';
import 'package:tiktok_clone/constants/gaps.dart';
import 'package:tiktok_clone/constants/sizes.dart';
final tabs = [
"Top",
"Users",
"Videos",
"Sounds",
"LIVE",
"Shopping",
"Brands",
];
class DiscoverScreen extends StatefulWidget {
const DiscoverScreen({super.key});
State<DiscoverScreen> createState() => _DiscoverScreenState();
}
class _DiscoverScreenState extends State<DiscoverScreen> {
final TextEditingController _textEditingController =
TextEditingController(text: "Initial Text");
void _onSearchChanged(String value) {
print("Searching form $value");
}
void _onSearchSubmitted(String value) {
print("Submitted $value");
}
void dispose() {
_textEditingController.dispose();
super.dispose();
}
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
return DefaultTabController(
length: tabs.length,
child: Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
elevation: 1,
title: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: Breakpoints.sm,
),
child: CupertinoSearchTextField(
controller: _textEditingController,
onChanged: _onSearchChanged,
onSubmitted: _onSearchSubmitted,
),
),
bottom: TabBar(
splashFactory: NoSplash.splashFactory,
padding: const EdgeInsets.symmetric(
horizontal: Sizes.size16,
),
isScrollable: true,
labelStyle: const TextStyle(
fontWeight: FontWeight.w600,
fontSize: Sizes.size16,
),
indicatorColor: Colors.black,
labelColor: Colors.black,
unselectedLabelColor: Colors.grey.shade500,
tabs: [
for (var tab in tabs)
Tab(
text: tab,
),
],
),
),
body: TabBarView(
children: [
GridView.builder(
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
itemCount: 20,
padding: const EdgeInsets.all(
Sizes.size10,
),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: width > Breakpoints.lg ? 5 : 2,
crossAxisSpacing: Sizes.size10,
mainAxisSpacing: Sizes.size10,
childAspectRatio: 9 / 20,
),
itemBuilder: (context, index) => LayoutBuilder(
builder: (context, constraints) => Column(
children: [
Container(
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(Sizes.size4),
),
child: AspectRatio(
aspectRatio: 9 / 16,
child: FadeInImage.assetNetwork(
fit: BoxFit.cover,
placeholder: "assets/images/placeholder.jpg",
image:
"https://images.unsplash.com/photo-1673844969019-c99b0c933e90?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1480&q=80",
),
),
),
Gaps.v10,
Text(
"${constraints.maxWidth} This is a very long caption for my tiktok that im upload just now currently.",
overflow: TextOverflow.ellipsis,
maxLines: 2,
style: const TextStyle(
fontSize: Sizes.size16 + Sizes.size2,
fontWeight: FontWeight.bold,
),
),
Gaps.v8,
if (constraints.maxWidth < 200 ||
constraints.maxWidth > 250)
DefaultTextStyle(
style: TextStyle(
color: Colors.grey.shade600,
fontWeight: FontWeight.w600,
),
child: Row(
children: [
const CircleAvatar(
radius: 12,
backgroundImage: NetworkImage(
"https://avatars.githubusercontent.com/u/3612017",
),
),
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",
)
],
),
)
],
),
),
),
for (var tab in tabs.skip(1))
Center(
child: Text(
tab,
style: const TextStyle(
fontSize: 28,
),
),
)
],
),
),
);
}
}
이 코드에서 ConstrainedBox
위젯은 CupertinoSearchTextField
의 최대 너비를 제한하는 데 사용됩니다. ConstrainedBox
는 자식 위젯에 대한 추가적인 제약 조건을 부여할 수 있는 위젯으로, 여기서는 검색 필드의 너비가 특정 최대 값(Breakpoints.sm
)을 초과하지 않도록 합니다. 이를 통해 검색 필드가 화면 너비에 관계없이 일관된 크기를 유지할 수 있게 됩니다.
ConstrainedBox
는 자식 위젯에 최소 및 최대 너비와 높이 제약 조건을 적용할 수 있게 해주는 위젯입니다.constraints
속성을 통해 BoxConstraints
객체를 전달함으로써, 이러한 제약 조건을 정의할 수 있습니다.BoxConstraints
는 minWidth
, maxWidth
, minHeight
, maxHeight
등의 속성을 제공하여, 자식 위젯이 이러한 값들의 범위 내에서 레이아웃이 결정되도록 합니다.AppBar
의 title
로 사용된 CupertinoSearchTextField
는 사용자가 검색어를 입력할 수 있는 필드입니다. 이 검색 필드는 앱 바 내에 배치되어 있으며, 사용자에게 일관된 사용자 경험을 제공하기 위해 너비가 제한되어야 합니다.ConstrainedBox
의 constraints
속성에 BoxConstraints(maxWidth: Breakpoints.sm)
를 지정함으로써, 검색 필드의 최대 너비를 Breakpoints.sm
값으로 제한합니다. 이는 검색 필드가 너무 넓어져서 UI 디자인을 해치는 것을 방지합니다.CupertinoSearchTextField
에는 사용자의 검색어 변경 및 제출을 처리하는 콜백(onChanged
, onSubmitted
)이 등록되어 있습니다.ConstrainedBox
를 사용함으로써, 개발자는 CupertinoSearchTextField
같은 자식 위젯의 크기를 유연하게 조절할 수 있으며, 디바이스 화면 크기나 방향에 관계없이 일관된 레이아웃을 유지할 수 있습니다. 이러한 접근 방식은 특히 반응형 디자인을 구현할 때 유용하며, 사용자에게 보다 안정적이고 예측 가능한 인터페이스를 제공할 수 있게 합니다.