스마트시대
RESPONSIVE FLUTTER WEB 웹상에서의 반응형 디자인 14.1 OrientationBuilder 14.2 kIsWeb 14.3 MediaQuery 14.4 LayoutBuilder 14.5 ConstrainedBox 본문
RESPONSIVE FLUTTER WEB 웹상에서의 반응형 디자인 14.1 OrientationBuilder 14.2 kIsWeb 14.3 MediaQuery 14.4 LayoutBuilder 14.5 ConstrainedBox
스마트시대 2023. 5. 23. 19:0414.1 OrientationBuilder
builder: (context) => const UsernameScreen(),
),
);
}
@override
Widget build(BuildContext context) {
-----------------
//smart폰의 방향을 알려주는 위젯
return OrientationBuilder(
builder: (context, orientation) {
-----------------
color: Colors.black45,
),
textAlign: TextAlign.center,
),
Gaps.v40,
-----------------------
//correction if .. for는 하나 밖에 못쓴다.
if (orientation == Orientation.portrait)
//list를 이런식으로 써서 복수 적용(표시 안되게 함)
...[
GestureDetector(
// email인증 하기 위해 클릭 가능하게
onTap: () => _onEmailTap(context),
child: const AuthButton(
icon: FaIcon(FontAwesomeIcons.user),
text: 'Use email and password',
),
),
Gaps.v16,
const AuthButton(
icon: FaIcon(FontAwesomeIcons.apple),
text: 'Continue with Apple',
),
],
if (orientation == Orientation.landscape)
Row(
children: [
//AuthButton에서 쓰고 있는 FractionallySizedBox관련 에러 고쳐 주기 위해 Expanded사용
Expanded(
child: GestureDetector(
// email인증 하기 위해 클릭 가능하게
onTap: () => _onEmailTap(context),
child: const AuthButton(
icon: FaIcon(FontAwesomeIcons.user),
text: 'Use email and password',
),
),
),
Gaps.v16,
//AuthButton에서 쓰고 있는 FractionallySizedBox관련 에러 고쳐 주기 위해 Expanded사용
const Expanded(
child: AuthButton(
icon: FaIcon(FontAwesomeIcons.apple),
text: 'Continue with Apple',
),
),
],
),
],
),
),
),
-----------------------
bottomNavigationBar: BottomAppBar(
color: Colors.grey.shade50,
@override
Widget build(BuildContext context) {
//smart폰의 방향을 알려주는 위젯
return OrientationBuilder(
builder: (context, orientation) {
-----------------
// phone 돌리지 않게 알리는 방법
if (orientation == Orientation.landscape) {
return const Scaffold(
body: Center(child: Text("Plz rotate your phone.")),
);
}
-----------------
return Scaffold(
body: SafeArea(
main.dart에서 안돌아가게 고정하는 방법도 있음
--------------
// phone 돌리지 않게 알리는 방법
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await SystemChrome.setPreferredOrientations(
[
DeviceOrientation.portraitUp,
],
);
--------------
// dart모드 관련 설정:
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle.dark,
);
runApp(const TikTokApp());
}
class TikTokApp extends StatelessWidget {
const TikTokApp({super.key});
14.2 kIsWeb
브라우저에서 음성이 포함된 영상을 자동 재생 못함(남용 등으로 다른 페이지 보고 있는데 음성이 재생되고 있는 등)
브라우저는 첫번째 load에서 영상(특히 음성)을 재생하는 것을 원치 않는다.(비디오 화면으로 들어와 즉시 영상과 음성을 재생하려하는 것)
영상 자동재생 자체는 괜찮고 사용자가 소리로 깜짝 놀라지 않게 하려는 목적
//한 영상 반복되게 해주는 파라메터
await _videoPlayerController.setLooping(true);
//autoplay
// _videoPlayerController.play();
------------------
//이 앱이 웹에서 작동하도록 complie되었는지를 나타내는 constant
if (kIsWeb) {
await _videoPlayerController.setVolume(0);
}
------------------
//VideoPlayerController를 어떻게 처리해줄 지 지정하는 listener
_videoPlayerController.addListener(_onVideoChange);
setState(() {});
}
14.3 MediaQuery
@override
Widget build(BuildContext context) {
-------------------
//웹용으로 화면 크기 알아내는 방법(padding으로 노치등 수정도 가능)
final width = MediaQuery.of(context).size.width;
-------------------
return DefaultTabController(
length: tabs.length,
child: Scaffold(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
-------------------
//웹용으로 5개 표시하도록 하기
crossAxisCount: width > Breakpoints.lg ? 5 : 2,
-------------------
crossAxisSpacing: Sizes.size10,
mainAxisSpacing: Sizes.size10,
14.4 LayoutBuilder
MediaQuery 와 LayoutBuilder 가장 큰 차이점
MediaQuery는 현재 너의 앱을 사용하고 있는 기기에 대한 정보를 준다.화면크기!!, 밝기, 다크모드 여부 방향, 높이, 패딩등을 신경 쓴다.
LayoutBuilder은 화면의 크기가 아니라 box의 최대 크기를 알기위해 사용한다. widget(row, column,container등)이 어느정도 크기인지가 중요함.
폰에서는 적당한 크기가 아이패트나 웹상의 어느 정도 크기에서는 폰 보다 column크기가 더 작을 수 있다.
14.3에서 컬럼 수를 5개로 늘렸기 땜에
MediaQuery 샘플 코드
LayoutBuilder
두개의 수치 비교
여기서는
width: constraints.maxWidth가 final size = MediaQuery.of(context).size가 같다(화면크기가 같고 scaffold body안에서는 LayoutBuilder가 나에게 이 컨테이너가 어느정도 크기인지 알려준다는 뜻). 이게 LayoutBuilder가 화면 크기를 알려준다고 착각하기 쉬운데 maxWidth가 화면크기라서 화면 크기일 뿐이다.
여기서 LayoutBuilder를 컨테이너 안에 집어 넣고 sizedbox(어떤 제한이 있는 상태)에 넣어 너비를 반으로 줄여서 표현하면
그러므로 LayoutBuilder는 유용하다. 화면 크기가 아닌 부모의 크기에 따라 혹은 children을 그 부모의 크기에 따라 변경하고 싶을 때 사용할 수 있다.
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
//웹용으로 5개 표시하도록 하기
crossAxisCount: width > Breakpoints.lg ? 5 : 2,
crossAxisSpacing: Sizes.size10,
mainAxisSpacing: Sizes.size10,
childAspectRatio: 9 / 20,
),
---------------------------
//웹용으로 5개 표시하도록 하여 일정한 크기에서는 아바타 표시 안하게 하기
itemBuilder: (context, index) => LayoutBuilder(
builder: (context, Constraints) => Column(
---------------------------
children: [
Container(
//AspectRatio가 BoxDecoration까지 overflow하고 있으므로 clipBehavior로 잘라주기
style: const TextStyle(
fontSize: Sizes.size16 + Sizes.size2,
fontWeight: FontWeight.bold,
),
),
Gaps.v7,
---------------------------
//웹용으로 5개 표시하도록 하여 일정한 크기에서는 아바타 표시 안하게 하기
if (Constraints.maxHeight < 200 ||
Constraints.maxHeight > 250)
---------------------------
//text style을 자식 text들에 동시 적용할 수 있는 위젯
DefaultTextStyle(
style: TextStyle(
color: Colors.grey.shade600,
fontWeight: FontWeight.w600),
child: Row(
14.5 ConstrainedBox
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,
container로 쓸수도 있음