D-day

shin·2022년 10월 6일
0

Flutter

목록 보기
6/12
  • Font 적용하기
  • DatePicker
  • 날짜 다루기
  • 테마 적용하기

Font 적용하기

  • pubspec.yaml 파일에 작성한다.
  • family는 Font 이름이라고 보면 된다.

기본 디자인

  • 날짜를 계속 관리해야하기 때문에 StatefulWidget을 사용한다.

  • 대략적인 디자인을 만들어 놓았다.
  • 코드가 길어서 정리를 해보자.
import 'package:flutter/material.dart';

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.green[200],
      body: SafeArea(
        child: Container(
          width: MediaQuery.of(context).size.width,
          child: Column(
            children: [
              Text(
                'U & I',
                style: TextStyle(
                  color: Colors.white,
                  fontFamily: 'parisienne',
                  fontSize: 80.0,
                ),
              ),
              Text(
                '우리 처음 만난날',
                style: TextStyle(
                  color: Colors.white,
                  fontFamily: 'sunflower',
                  fontSize: 30.0,
                ),
              ),
              Text(
                '2022.01.01',
                style: TextStyle(
                  color: Colors.white,
                  fontFamily: 'sunflower',
                  fontSize: 20.0,
                ),
              ),
              IconButton(
                  iconSize: 60.0,
                  onPressed: () {},
                  icon: Icon(
                    Icons.favorite,
                    color: Colors.red,
                  )),
              Text(
                'D + 1',
                style: TextStyle(
                    color: Colors.white,
                    fontFamily: 'sunflower',
                    fontSize: 50.0,
                    fontWeight: FontWeight.w700),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
  • Column 위젯을 잘라내서 _TopPart 위젯을 새로 만든다. _TopPart의 밑줄 의미는 이 파일에서 만 사용가능하다는 의미이다.

  • _TopPart 밑에 이미지 파일을 넣고 마찬가지로 _BottomPart를 만든다.

  • Expanded를 사용해서 크기를 조절했다.

import 'package:flutter/material.dart';

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.green[200],
      body: SafeArea(
        child: Container(
          width: MediaQuery.of(context).size.width,
          child: Column(
            children: [
              _TopPart(),
              Expanded(
                child: Image.asset(
                  'asset/img/heart.png',
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class _TopPart extends StatelessWidget {
  const _TopPart({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Expanded(
      child: Column(
        children: [
          Text(
            'U & I',
            style: TextStyle(
              color: Colors.white,
              fontFamily: 'parisienne',
              fontSize: 80.0,
            ),
          ),
          Text(
            '우리 처음 만난날',
            style: TextStyle(
              color: Colors.white,
              fontFamily: 'sunflower',
              fontSize: 30.0,
            ),
          ),
          Text(
            '2022.01.01',
            style: TextStyle(
              color: Colors.white,
              fontFamily: 'sunflower',
              fontSize: 20.0,
            ),
          ),
          IconButton(
              iconSize: 60.0,
              onPressed: () {},
              icon: Icon(
                Icons.favorite,
                color: Colors.red,
              )),
          Text(
            'D + 1',
            style: TextStyle(
                color: Colors.white,
                fontFamily: 'sunflower',
                fontSize: 50.0,
                fontWeight: FontWeight.w700),
          ),
        ],
      ),
    );
  }
}
  • 스타일을 정리하고 코드를 정리했다.
  • 코드를 정리하는 습관을 들이는게 좋다.
import 'package:flutter/material.dart';

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.green[200],
      body: SafeArea(
        child: Container(
          width: MediaQuery.of(context).size.width,
          child: Column(
            children: [
              _TopPart(),
              _BottomPart(),
            ],
          ),
        ),
      ),
    );
  }
}

class _TopPart extends StatelessWidget {
  const _TopPart({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Expanded(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          Text(
            'U & I',
            style: TextStyle(
              color: Colors.white,
              fontFamily: 'parisienne',
              fontSize: 80.0,
            ),
          ),
          Column(
            children: [
              Text(
                '우리 처음 만난날',
                style: TextStyle(
                  color: Colors.white,
                  fontFamily: 'sunflower',
                  fontSize: 30.0,
                ),
              ),
              Text(
                '2022.01.01',
                style: TextStyle(
                  color: Colors.white,
                  fontFamily: 'sunflower',
                  fontSize: 20.0,
                ),
              ),
            ],
          ),
          IconButton(
              iconSize: 60.0,
              onPressed: () {},
              icon: Icon(
                Icons.favorite,
                color: Colors.red,
              )),
          Text(
            'D + 1',
            style: TextStyle(
                color: Colors.white,
                fontFamily: 'sunflower',
                fontSize: 50.0,
                fontWeight: FontWeight.w700),
          ),
        ],
      ),
    );
  }
}

class _BottomPart extends StatelessWidget {
  const _BottomPart({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Expanded(
      child: Image.asset(
        'asset/img/heart.png',
      ),
    );
  }
}

DatePicker 사용

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.green[200],
      body: SafeArea(
        child: Container(
          width: MediaQuery.of(context).size.width,
          child: Column(
            children: [
              _TopPart(),
              _BottomPart(),
            ],
          ),
        ),
      ),
    );
  }
}

class _TopPart extends StatelessWidget {
  const _TopPart({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Expanded(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          Text(
            'U & I',
            style: TextStyle(
              color: Colors.white,
              fontFamily: 'parisienne',
              fontSize: 80.0,
            ),
          ),
          Column(
            children: [
              Text(
                '우리 처음 만난날',
                style: TextStyle(
                  color: Colors.white,
                  fontFamily: 'sunflower',
                  fontSize: 30.0,
                ),
              ),
              Text(
                '2022.01.01',
                style: TextStyle(
                  color: Colors.white,
                  fontFamily: 'sunflower',
                  fontSize: 20.0,
                ),
              ),
            ],
          ),
          IconButton(
              iconSize: 60.0,
              onPressed: () {
                // dialog
                showCupertinoDialog(
                  context: context,
                  barrierDismissible: true,
                  // container 밖에 누르면 닫힌다.
                  builder: (BuildContext context) {
                    return Align(
                      // 정렬을 지정하지 않으면 container가 전체 영역을 차지한다.
                      alignment: Alignment.bottomCenter,
                      child: Container(
                        color: Colors.white,
                        height: 300.0,
                        child: CupertinoDatePicker(
                          // 날짜를 선택하는 위젯
                          mode: CupertinoDatePickerMode.date,
                          onDateTimeChanged: (DateTime date) {
                            print(date);
                          },
                        ),
                      ),
                    );
                  },
                );
              },
              icon: Icon(
                Icons.favorite,
                color: Colors.red,
              )),
          Text(
            'D + 1',
            style: TextStyle(
                color: Colors.white,
                fontFamily: 'sunflower',
                fontSize: 50.0,
                fontWeight: FontWeight.w700),
          ),
        ],
      ),
    );
  }
}

class _BottomPart extends StatelessWidget {
  const _BottomPart({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Expanded(
      child: Image.asset(
        'asset/img/heart.png',
      ),
    );
  }
}

DateTime 상태관리

  • _TopPart2022.01.01D + 1이 변경된 날짜에 기반에 데이터가 변경되어야 한다.
  • _TopPart 위젯을 Stateful 위젯으로 바꿔준다.
class _TopPart extends StatefulWidget {
  const _TopPart({Key? key}) : super(key: key);

  
  State<_TopPart> createState() => _TopPartState();
}

class _TopPartState extends State<_TopPart> {
  DateTime selectedDate = DateTime(
    DateTime.now().year,
    DateTime.now().month,
    DateTime.now().day,
  );

  // 관리할 변수를 넣어준다
  // 기본값을 현재 날짜로 설정한다.

  // 변경된 날짜를 selectedDate에 업데이트 해준다.
  
  // 선택된 날짜도 시분초가 필요없기 때문에 코드를 수정해준다.

  
  Widget build(BuildContext context) {
    final now = DateTime.now();
    // 반복되는 코드를 간소화 한다.

    return Expanded(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          Text(
            'U & I',
            style: TextStyle(
              color: Colors.white,
              fontFamily: 'parisienne',
              fontSize: 80.0,
            ),
          ),
          Column(
            children: [
              Text(
                '우리 처음 만난날',
                style: TextStyle(
                  color: Colors.white,
                  fontFamily: 'sunflower',
                  fontSize: 30.0,
                ),
              ),
              Text(
                '${selectedDate.year}.${selectedDate.month}.${selectedDate.day}',
                // 변경된 날짜를 반영시킨다.
                
                style: TextStyle(
                  color: Colors.white,
                  fontFamily: 'sunflower',
                  fontSize: 20.0,
                ),
              ),
            ],
          ),
          IconButton(
              iconSize: 60.0,
              onPressed: () {
                // dialog
                showCupertinoDialog(
                  context: context,
                  barrierDismissible: true,
                  // container 밖에 누르면 닫힌다.
                  builder: (BuildContext context) {
                    return Align(
                      // 정렬을 지정하지 않으면 container가 전체 영역을 차지한다.
                      alignment: Alignment.bottomCenter,
                      child: Container(
                        color: Colors.white,
                        height: 300.0,
                        child: CupertinoDatePicker(
                          // 날짜를 선택하는
                          mode: CupertinoDatePickerMode.date,
                          onDateTimeChanged: (DateTime date) {
                            setState(() {
                              selectedDate = date;
                              //  onDateTimeChanged에서 바뀐 날짜를 selectedDate에 넣어준다.
                            });
                            // stateful 위젯에서 변수를 변경시킬 때,  bulid가 변경될때  setState함수를 사용한다.
                            ;
                          },
                        ),
                      ),
                    );
                  },
                );
              },
              icon: Icon(
                Icons.favorite,
                color: Colors.red,
              )),
          Text(
            'D + ${DateTime(
                  now.year,
                  now.month,
                  now.day,
                ).difference(selectedDate).inDays + 1}',
                // 디데이에서 보통 `년, 월, 일`을 사용하기 때문에 코드를 수정해준다. 
                // 특정날짜까지의 기간을 구할 때는 difference를 사용한다.
                // 만난 당일부터 1일 이기 때문에 + 1을 해준다.
                // 반복되는 코드를 간소화 시킨다. DateTime.now()
                
            style: TextStyle(
                color: Colors.white,
                fontFamily: 'sunflower',
                fontSize: 50.0,
                fontWeight: FontWeight.w700),
          ),
        ],
      ),
    );
  }
}

버그수정

IconButton(
              iconSize: 60.0,
              onPressed: () {
                showCupertinoDialog(
                  context: context,
                  barrierDismissible: true,
                  builder: (BuildContext context) {
                    return Align(
                      alignment: Alignment.bottomCenter,
                      child: Container(
                        color: Colors.white,
                        height: 300.0,
                        child: CupertinoDatePicker(
                          initialDateTime: selectedDate,
                          maximumDate: DateTime(
                            now.year,
                            now.month,
                            now.day,
                          ),
                          // 미래의 날짜를 설정하게 되면 - 가 출력된다.
                          // 최대 날짜를 설정해 줘야한다.
                          // 하지마 미래 날짜를 설정하게 되면 에러가 출력된다.
                          // 이럴 때 initialDateTime을 사용하면 된다.
                          // CupertinoDatePicker가 처음 실행될 때의 날짜를 세팅한다.
                          mode: CupertinoDatePickerMode.date,
                          onDateTimeChanged: (DateTime date) {
                            setState(() {
                              selectedDate = date;
                            });
                          },
                        ),
                      ),
                    );
                  },
                );
              },

코드정리

  • 코드관리를 편하게 하기위해서 정리를 해준다.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  DateTime selectedDate = DateTime(
    DateTime.now().year,
    DateTime.now().month,
    DateTime.now().day,
  );

  
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.green[200],
      body: SafeArea(
        child: Container(
          width: MediaQuery.of(context).size.width,
          child: Column(
            children: [
              _TopPart(
                selectedDate: selectedDate,
                // 밑에 _TopPart에서 selectedDate가 필수이기 때문에 넣어준다.
                onPressed: onHeartPressed,
                // 여기에 onPressed 함수를 넣을 수 있지만 코드가 길어지기 때문에 _HomeScreenState 하단에  함수를 선언하고
                // onPressed를 넣어준다.
                
              ),
              _BottomPart(),
            ],
          ),
        ),
      ),
    );
  }

  void onHeartPressed() {
    final DateTime now = DateTime.now();

    showCupertinoDialog(
      context: context,
      barrierDismissible: true,
      builder: (BuildContext context) {
        return Align(
          alignment: Alignment.bottomCenter,
          child: Container(
            color: Colors.white,
            height: 300.0,
            child: CupertinoDatePicker(
              initialDateTime: selectedDate,
              maximumDate: DateTime(
                now.year,
                now.month,
                now.day,
                // now 에러가 발생하게 되는데 함수 상단부에 선언해주면 된다.
              ),
              mode: CupertinoDatePickerMode.date,
              onDateTimeChanged: (DateTime date) {
                setState(() {
                  selectedDate = date;
                });
                // setState는 stateless 위젯에서 사용할 수 없다.
                // 상위 위젯으로 옮겨서 받아오는 방법이 있다.
                // onPressed의 정의를 보면  VoidCallback 타입이다.
                // VoidCallback은 아무것도 들어있지 않은 함수이다.
              },
            ),
          ),
        );
      },
    );
  }
}

// _TopPart 위젯을 StatelessWidget으로 변경해야한다.
// selectedDate를 상단으로 옮긴다.
// 그러면 selectedDate와 setState 에러가 발생하게 된다.
// 이럴 때 constructor를 사용하면 된다.

class _TopPart extends StatelessWidget {
  final DateTime selectedDate;
  final VoidCallback onPressed;

  _TopPart({
    required this.selectedDate,
    required this.onPressed,
    Key? key,
  }) : super(key: key);

  
  Widget build(BuildContext context) {
    final now = DateTime.now();

    return Expanded(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          Text(
            'U & I',
            style: TextStyle(
              color: Colors.white,
              fontFamily: 'parisienne',
              fontSize: 80.0,
            ),
          ),
          Column(
            children: [
              Text(
                '우리 처음 만난날',
                style: TextStyle(
                  color: Colors.white,
                  fontFamily: 'sunflower',
                  fontSize: 30.0,
                ),
              ),
              Text(
                '${selectedDate.year}.${selectedDate.month}.${selectedDate.day}',
                style: TextStyle(
                  color: Colors.white,
                  fontFamily: 'sunflower',
                  fontSize: 20.0,
                ),
              ),
            ],
          ),
          IconButton(
              iconSize: 60.0,
              onPressed: onPressed,
              icon: Icon(
                Icons.favorite,
                color: Colors.red,
              )),
          Text(
            'D + ${DateTime(
                  now.year,
                  now.month,
                  now.day,
                ).difference(selectedDate).inDays + 1}',
            style: TextStyle(
                color: Colors.white,
                fontFamily: 'sunflower',
                fontSize: 50.0,
                fontWeight: FontWeight.w700),
          ),
        ],
      ),
    );
  }
}

class _BottomPart extends StatelessWidget {
  const _BottomPart({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Expanded(
      child: Image.asset(
        'asset/img/heart.png',
      ),
    );
  }
}

0개의 댓글