인프런 커뮤니티 질문&답변

김의성님의 프로필 이미지
김의성

작성한 질문수

[2024 최신] [코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!

모달창이 안뜹니다.

작성

·

580

0

import 'package:calendar_scheduler/component/custom_text_feild.dart';
import 'package:calendar_scheduler/const/colors.dart';
import 'package:calendar_scheduler/database/drift_database.dart';
import 'package:calendar_scheduler/model/category_color.dart';
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:calendar_scheduler/database/drift_database.dart';

class ScheduleBottomSheet extends StatefulWidget {    //form 3. StatefulWidget이어야한다.
  const ScheduleBottomSheet({Key? key}) : super(key: key);

  @override
  State<ScheduleBottomSheet> createState() => _ScheduleBottomSheetState();
}

class _ScheduleBottomSheetState extends State<ScheduleBottomSheet> {
  final GlobalKey<FormState> formKey = GlobalKey();      //form 4. formKey변수만들어준다.

  int? startTime;          //3개의 값을 반복적으로 사용하기 위해 저장을한다.
  int? endTime;
  String? content;
  int? selectedColorId;     //color를 id로 관리하기 위해 id값을 넣기 위해 변수를 만든다.

  @override
  Widget build(BuildContext context) {
    final bottomInset = MediaQuery.of(context).viewInsets.bottom;   //키보드같은 시스템의 높이를 알 수 있음. 상하좌우 가능
    return GestureDetector(
      onTap: (){
        FocusScope.of(context).requestFocus(FocusNode());
      },
      child: SafeArea(
        child: Container(
          color: Colors.white,
          height: MediaQuery.of(context).size.height /2 + bottomInset,  //핸드폰 전체높이에 /2 절반
          child: Padding(
            padding: EdgeInsets.only(bottom: bottomInset),
            child: Padding(
              padding: EdgeInsets.only(left: 8.0, right: 8.0, top: 16.0),
              child: Form(               //form 2. _Time,_Content 이거 있는거 상위에 form을 해준다. key가 컨트롤러가 된다.
                key: formKey,             //form 5. formKey변수 넣어준다. 컨트롤러가 된다.
                autovalidateMode: AutovalidateMode.always,   //에러메시지를 실시간 표현해줌.
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    _Time(
                      onStartSaved: (String? val){
                        startTime = int.parse(val!);     //String으로 값이 들어오니 int로 파싱 그걸 위에서 만든 변수에 넣는다.
                      },
                      onEndSaved: (String? val){
                        endTime = int.parse(val!);    //val이 값이 없으면 에러메시지뜨도록 했으니 값이 없을수 없다.
                      },
                    ),
                    SizedBox(height: 16.0,),
                    _Content(
                      onSaved: (String? val){
                        content = val;             //String이니 걍 넣는다.
                      },
                    ),
                    SizedBox(height: 16.0,),
                    FutureBuilder<List<CategoryColor>>(
                      future:  GetIt.I<LocalDatabase>().getCategoryColors(),
                        //디비가져오기 4 이페이지에서 디비값 가져올수 있게 세팅, LocalDatabase이거는 drift_database파일에서 import
                      builder: (context, snapshot) {
                        //print(snapshot.data);            //디비가져오기 5 디비에서 가져온 색깔 출력
                        if(snapshot.hasData && selectedColorId == null && snapshot.data!.isNotEmpty){
                          //if(데이터가 있고, selectedColorId를 클릭하지 않았음, 하나라도 값이 있거나)
                          selectedColorId = snapshot.data![0].id;    //0번째 빨강색으로 셀렉트 한다.
                        }
                        return _ColorPicker(
                          colors: snapshot.hasData ? snapshot.data! : [],
                          //디비가져오기 6 hasData 값이 있으면  .hasData 값이 없으면 : [] 걍 빈값을 보낸다.
                          selectedColorId: selectedColorId!,
                        );
                      }
                    ),
                    SizedBox(height: 8.0,),
                    _SaveButton(onPressed: onSavePressed,), //form 7 onSavePressed 함수 만든다.
                  ],
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
  void onSavePressed(){
    if(formKey.currentState == null){  //현재 null이 나올수는 없으나 혹시나 null인경우 그냥 리턴해 버린다.
      return;
    }

    if(formKey.currentState!.validate()){   //form 8 에러가 없으면 null값을 리턴하면서 true
      print('에러 없음');
      formKey.currentState!.save();
      print('--------------------');
      print('startTime : $startTime');
      print('endTime : $endTime');
      print('content : $content');
    }else{
      print('에러 있음');
    }
  }
}
class _SaveButton extends StatelessWidget {
  final VoidCallback onPressed;
  const _SaveButton({required this.onPressed, Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        Expanded(
          child: ElevatedButton(
            onPressed: onPressed,     //form 6 외부로 보낼수 있게 required 만든다.
            style: ElevatedButton.styleFrom(
              primary: PRIMARY_COLOR,
            ),
            child: Text('저장'),
          ),
        ),
      ],
    );
  }
}

class _ColorPicker extends StatelessWidget {
  final List<CategoryColor> colors;             //디비가져오기 1.디비에 있는 칼라를 이걸로 가져올 거임
  final int selectedColorId;                  // 아이디 값을 받아준다.
  const _ColorPicker({
    required this.colors,
    required this.selectedColorId,
    Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Wrap(
      spacing: 8.0,                   //좌우간격
      runSpacing: 10.0,               //상하 간격
      children: colors.map((e) => renderColor(e, selectedColorId == e.id)).toList(),  //디비가져오기 2. colors값 렌더링하기 ->main에서 GetIt한다.
            //여기 e=<CategoryColor>
    );
  }
  Widget renderColor(CategoryColor color, bool isSelected){
    return Container(
      decoration: BoxDecoration(
        shape: BoxShape.circle,
        color: Color(
              int.parse(
              'FF${color.hexCode}',          //hexCode 컬럼에 있는 값을 가져온다.
              radix: 16,                 //16진수로 표현한다.
          ),
        ),
        border: isSelected         //선택 되었을대 보더를 넣어준다.
          ? Border.all(
          color: Colors.black,
          width: 4.0,
          )
            : null,
      ),
      height: 32.0,
      width: 32.0,
    );
  }
}

class _Content extends StatelessWidget {
  final FormFieldSetter<String> onSaved;
  const _Content({required this.onSaved, Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Expanded( //1.텍스필드 꽉차게 다음은 custom_text_feild에
      child: CustomTextField(
        label: '내용',
        isTime: false,
        onSaved: onSaved,
      ),
    );
  }
}

class _Time extends StatelessWidget {
  final FormFieldSetter<String> onStartSaved;
  final FormFieldSetter<String> onEndSaved;
  const _Time({
    required this.onStartSaved,
    required this.onEndSaved,
    Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        Expanded(
          child: CustomTextField(
            label: '시작시간',
            isTime: true,
            onSaved: onStartSaved,
          ),
        ),
        SizedBox(width: 8.0,),
        Expanded(
          child: CustomTextField(
            label: '종료시간',
            isTime: true,
            onSaved: onEndSaved,
          ),
        ),
      ],
    );
  }
}

 

초급 섹션 19. [프로젝트] [★★★★☆] 캘린더 스케쥴러에 > 색상 상태관리 강의 따라 하고 있습니다.

그런데 3:25초 부분에서 selectedColorId: selectedColorId!, 만 넣으면 아래 그림처럼 모달창이 안뜹니다. 몇번을 다시 하고 해봤는데 원인을 모르겠습니다.
schedule_bottom_sheet.dart 파일 입니다.

캡처.JPG

답변 6

0

김의성님의 프로필 이미지
김의성
질문자

강사님~ 처음부터 차근차근 다시 했는데 같은곳에서 같은 에러가 생겼습니다. 도저히 뭐를 잘못했는지 모르겠습니다.

https://github.com/cloud5k/test111

 

레포지토리 이렇게 올리면 되는건가요?

코드팩토리님의 프로필 이미지
코드팩토리
지식공유자

안녕하세요!

제가 오늘 오후에 리뷰해보고 확인드리겠습니다

코드팩토리님의 프로필 이미지
코드팩토리
지식공유자

강의 혹시 어디까지 들으셨나요?

제가 확인하는거로는 schedule_bottom_sheet.dart 파일의 78번줄에 selectedColorId가 null인 상황을 예외처리하면 에러가 사라집니다.

제 완료코드에는 이 부분이 있는것으로 보아 이 코드 작성을 까먹으셨거나 이 코드를 작성하는 강의 직전에 멈추신 것 같습니다.

김의성님의 프로필 이미지
김의성
질문자

안녕하세요~ 강사님
다음 강의 Schedule 저장해버리기~!에 바로 나오네요. ㅜㅜ 감사합니다~ 해결했습니다~

코드팩토리님의 프로필 이미지
코드팩토리
지식공유자

다행입니다~! 질문 또 있으시면 언제든 문의주세요~

0

김의성님의 프로필 이미지
김의성
질문자

터미널 창에 flutter pub run build_runner build 실행하고 앱삭제 후에 다시 실행해봤습니다 그래도 같은 현상입니다. ㅜㅜ

import 'package:calendar_scheduler/model/category_color.dart';

import 'package:calendar_scheduler/database/drift_database.dart';

이거 2개가 비활성처럼 보이는데 혹시 이것 때문일까요?

코드팩토리님의 프로필 이미지
코드팩토리
지식공유자

레포지토리 올려주시면 제가 직접 한번 봐드리겠습니다

김의성님의 프로필 이미지
김의성
질문자

레포지토리 만든다고 해보다가 파일이 다 날라 갔네요~ ㅎㅎ 처음부터 다시 한번 해보겠습니다. 감사합니다~

코드팩토리님의 프로필 이미지
코드팩토리
지식공유자

또 안되시면 여기에 댓글 달아주시면 제가 바로 레포지토리 봐드릴게요~

0

김의성님의 프로필 이미지
김의성
질문자

삭제후 재설치하고image

이 버튼 눌렀는데 이거 말고 다른걸 해야 하는건가요?

코드팩토리님의 프로필 이미지
코드팩토리
지식공유자

Hive 관련 파일을 수정하시고 flutter pub run build_runner build를 안하시면 .g.dart 파일 갱신이 안됩니다.

강의에서 Hive파일 수정할때마다 실행해주고 있습니다.

하신대로 앱 삭제 후 코드제너레이션 "꼭" 실행해주시고 다시 앱 실행 해보세요.

코드팩토리님의 프로필 이미지
코드팩토리
지식공유자

flutter pub run build_runner build 커맨드가 기억이 아예 안나신다면 다시 처음부터 강의를 들어보시는걸 추천드립니다. 플러터에서 코드제너레이션은 상당히 중요한 부분이라 놓치고 가시면 안됩니다.

김의성님의 프로필 이미지
김의성
질문자

네 답변 감사합니다. 다시 한번 보겠습니다~

코드팩토리님의 프로필 이미지
코드팩토리
지식공유자

코드제너레이션 생성 후 앱 삭제 후 재실행했는데 또 안되시면 말씀 주세요. 레포지토리 봐드리겠습니다. (하지만 벌써 수백명의 수강생이 완강한만큼 높은 확률로 되실겁니다.) 제 생각엔 Hive 코드 수정 후 코드제너레이션 실행을 안하셔서 생기는 문제로 보입니다.

0

코드팩토리님의 프로필 이미지
코드팩토리
지식공유자

null 값이 들어가면 안되는데 null 값이 들어가서 그렇습니다.

앱 삭제 후 코드제너레이션 다시 하신거 맞나요? flutter pub run build_runner build

0

김의성님의 프로필 이미지
김의성
질문자

에뮬레이터 다시 설치 했는데도 똑같습니다~ ㅜㅜ 에러 메시지 입니다~

======== Exception caught by widgets library =======================================================

The following CastError was thrown building FutureBuilder<List<CategoryColor>>(dirty, state: FutureBuilderState<List<CategoryColor>>#f31e4):

Null check operator used on a null value

The relevant error-causing widget was:

FutureBuilder<List<CategoryColor>> FutureBuilder:file:///D:/app/calendar_scheduler/lib/component/schedule_bottom_sheet.dart:60:21

When the exception was thrown, this was the stack:

#0 ScheduleBottomSheetState.build.<anonymous closure> (package:calendarscheduler/component/schedule_bottom_sheet.dart:72:59)

#1 _FutureBuilderState.build (package:flutter/src/widgets/async.dart:615:55)

#2 StatefulElement.build (package:flutter/src/widgets/framework.dart:4919:27)

#3 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4806:15)

#4 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4977:11)

#5 Element.rebuild (package:flutter/src/widgets/framework.dart:4529:5)

#6 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4787:5)

#7 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4968:11)

#8 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4781:5)

#9 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3817:16)

#10 MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6350:36)

#11 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6362:32)

... Normal element mounting (362 frames)

#373 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3817:16)

#374 MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6350:36)

#375 Element.updateChild (package:flutter/src/widgets/framework.dart:3551:18)

#376 RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:5883:32)

#377 MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6375:17)

#378 Element.updateChild (package:flutter/src/widgets/framework.dart:3530:15)

#379 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4832:16)

#380 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4977:11)

#381 Element.rebuild (package:flutter/src/widgets/framework.dart:4529:5)

#382 StatefulElement.update (package:flutter/src/widgets/framework.dart:5009:5)

#383 Element.updateChild (package:flutter/src/widgets/framework.dart:3530:15)

#384 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4832:16)

#385 Element.rebuild (package:flutter/src/widgets/framework.dart:4529:5)

#386 ProxyElement.update (package:flutter/src/widgets/framework.dart:5154:5)

#387 Element.updateChild (package:flutter/src/widgets/framework.dart:3530:15)

#388 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4832:16)

#389 Element.rebuild (package:flutter/src/widgets/framework.dart:4529:5)

#390 ProxyElement.update (package:flutter/src/widgets/framework.dart:5154:5)

#391 InheritedNotifierElement.update (package:flutter/src/widgets/inheritednotifier.dart:108:11)

#392 Element.updateChild (package:flutter/src/widgets/framework.dart:3530:15)

#393 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6222:14)

#394 Element.updateChild (package:flutter/src/widgets/framework.dart:3530:15)

#395 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4832:16)

#396 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4977:11)

#397 Element.rebuild (package:flutter/src/widgets/framework.dart:4529:5)

#398 StatefulElement.update (package:flutter/src/widgets/framework.dart:5009:5)

#399 Element.updateChild (package:flutter/src/widgets/framework.dart:3530:15)

#400 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6222:14)

#401 Element.updateChild (package:flutter/src/widgets/framework.dart:3530:15)

#402 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6222:14)

#403 Element.updateChild (package:flutter/src/widgets/framework.dart:3530:15)

#404 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4832:16)

#405 Element.rebuild (package:flutter/src/widgets/framework.dart:4529:5)

#406 ProxyElement.update (package:flutter/src/widgets/framework.dart:5154:5)

#407 Element.updateChild (package:flutter/src/widgets/framework.dart:3530:15)

#408 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4832:16)

#409 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4977:11)

#410 Element.rebuild (package:flutter/src/widgets/framework.dart:4529:5)

#411 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2659:19)

#412 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:891:21)

#413 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:370:5)

#414 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1146:15)

#415 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1083:9)

#416 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:997:5)

#420 _invoke (dart:ui/hooks.dart:151:10)

#421 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:308:5)

#422 _drawFrame (dart:ui/hooks.dart:115:31)

(elided 3 frames from dart:async)

====================================================================================================

 

0

코드팩토리님의 프로필 이미지
코드팩토리
지식공유자

안녕하세요.

먼저 에뮬레이터에서 앱을 완전 삭제한 후 flutter pub build_runner build 커맨드를 다시 실행해보시고 앱을 실행해보세요.

그래도 안되면 에러메세지 첨부 부탁드립니다.

김의성님의 프로필 이미지
김의성

작성한 질문수

질문하기