커뮤니티
포인트
쿠폰
내 강의실
국비 신청 내역
증명서
계정
로그아웃
학습 질문
개발 일지
나의 활동
답변 완료
3주차 마이메모 만드는 수업들으면서 생긴 질문들 드립니다.
앱개발 종합반 - 플러터 v8
3주차
북마크
이*헌
댓글
5
추천
0
조회수
16
조회수
16
답변 완료

* 겪고 있는 문제 상황을 최대한 자세하게 작성해주세요.

* 문제 해결을 위해 어떤 시도를 해보았는지 구체적으로 함께 알려주세요.


bool, string, Iso8601String, retrun 한다, Json, prefs 의 개념적인 부분을 잘 모르다보니까 수업을 따라가는데 좀 막히는 부분이 있었어요.

javascript, 파이썬 등에서 본 것 같지만, 왕초보다보니까 개념적인 부분에서 아무래도 헷갈리네요.

우선 그냥 따라가자 해서 따라가보고 있지만, 궁금증이 생겨서 여기저기 검색을 해봤지만 전문가 분들이 적어놓으신 설명 자체를 이해하는 게 더 어렵더라구요ㅠ

메모만들기 강의에 나온 위 용어들에 대해서, 강의내용을 따라가면서 나온 결과물들과 함께, 이런 용어가 이런 의미라서, 이런 결과가 나오는 것이다. 이해할 수 있도록 설명해주시면 너무 감사드리겠습니다.



import 'dart:convert';


import 'package:flutter/material.dart';


import 'main.dart';


// Memo 데이터의 형식을 정해줍니다. 추후 isPinned, updatedAt 등의 정보도 저장할 수 있습니다.

class Memo {

Memo({

required this.content,

this.isPinned = false,

this.updatedAt,

});


String content;

bool isPinned;

DateTime? updatedAt;


Map toJson() {

return {

'content': content,

'isPinned': isPinned,

'updatedAt': updatedAt?.toIso8601String(),

};

}


factory Memo.fromJson(json) {

return Memo(

content: json['content'],

isPinned: json['isPinned'] ?? false,

updatedAt:

json['updatedAt'] == null ? null : DateTime.parse(json['updatedAt']),

);

}

}


// Memo 데이터는 모두 여기서 관리

class MemoService extends ChangeNotifier {

MemoService() {

loadMemoList();

}


List<Memo> memoList = [

Memo(content: '장보기 목록: 사과, 양파'), // 더미(dummy) 데이터

Memo(content: '새 메모'), // 더미(dummy) 데이터

];


createMemo({required String content}) {

Memo memo = Memo(content: content, updatedAt: DateTime.now());

memoList.add(memo);

notifyListeners(); // Consumer<MemoService>의 builder 부분을 호출해서 화면 새로고침

saveMemoList();

}


updateMemo({required int index, required String content}) {

Memo memo = memoList[index];

memo.content = content;

memo.updatedAt = DateTime.now();

notifyListeners();

saveMemoList();

}


updatePinMemo({required int index}) {

Memo memo = memoList[index];

memo.isPinned = !memo.isPinned;

memoList = [

...memoList.where((element) => element.isPinned),

...memoList.where((element) => !element.isPinned)

];

notifyListeners();

saveMemoList();

}


deleteMemo({required int index}) {

memoList.removeAt(index);

notifyListeners();

saveMemoList();

}


saveMemoList() {

List memoJsonList = memoList.map((memo) => memo.toJson()).toList();

// [{"content": "1"}, {"content": "2"}]


String jsonString = jsonEncode(memoJsonList);

// '[{"content": "1"}, {"content": "2"}]'


prefs.setString('memoList', jsonString);

}


loadMemoList() {

String? jsonString = prefs.getString('memoList');

// '[{"content": "1"}, {"content": "2"}]'


if (jsonString == null) return; // null 이면 로드하지 않음


List memoJsonList = jsonDecode(jsonString);

// [{"content": "1"}, {"content": "2"}]


memoList = memoJsonList.map((json) => Memo.fromJson(json)).toList();

}

}

면 전체를 캡처해 주시면, 튜터님들이 빠르게 상황을 이해할 수 있어요.




작성한 코드 및 에러 메세지

import 'package:flutter/cupertino.dart';

import 'package:flutter/material.dart';

import 'package:provider/provider.dart';

import 'package:shared_preferences/shared_preferences.dart';


import 'memo_service.dart';


late SharedPreferences prefs;


void main() async {

WidgetsFlutterBinding.ensureInitialized();

prefs = await SharedPreferences.getInstance();

runApp(

MultiProvider(

providers: [

ChangeNotifierProvider(create: (context) => MemoService()),

],

child: const MyApp(),

),

);

}


class MyApp extends StatelessWidget {

const MyApp({super.key});


@override

Widget build(BuildContext context) {

return MaterialApp(

debugShowCheckedModeBanner: false,

home: HomePage(),

);

}

}


// 홈 페이지

class HomePage extends StatefulWidget {

const HomePage({super.key});


@override

State<HomePage> createState() => _HomePageState();

}


class _HomePageState extends State<HomePage> {

@override

Widget build(BuildContext context) {

return Consumer<MemoService>(

builder: (context, memoService, child) {

// memoService로 부터 memoList 가져오기

List<Memo> memoList = memoService.memoList;


return Scaffold(

appBar: AppBar(

title: Text("상헌이의 메모장"),

),

body: memoList.isEmpty

? Center(child: Text("메모를 작성해 주세요"))

: ListView.builder(

itemCount: memoList.length, // memoList 개수 만큼 보여주기

itemBuilder: (context, index) {

Memo memo = memoList[index]; // index에 해당하는 memo 가져오기

return ListTile(

// 메모 고정 아이콘

leading: IconButton(

icon: Icon(memo.isPinned

? CupertinoIcons.pin_fill

: CupertinoIcons.pin),

onPressed: () {

memoService.updatePinMemo(index: index);

},

),

// 메모 내용 (최대 3줄까지만 보여주도록)

title: Text(

memo.content,

maxLines: 3,

overflow: TextOverflow.ellipsis,

),

trailing: Text(memo.updatedAt == null

? ""

: memo.updatedAt.toString().substring(0, 16)),

onTap: () async {

// 아이템 클릭시

await Navigator.push(

context,

MaterialPageRoute(

builder: (_) => DetailPage(

index: index,

),

),

);

if (memo.content.isEmpty) {

memoService.deleteMemo(index: index);

}

},

);

},

),

floatingActionButton: FloatingActionButton(

child: Icon(Icons.add),

onPressed: () async {

// + 버튼 클릭시 메모 생성 및 수정 페이지로 이동

memoService.createMemo(content: '');

await Navigator.push(

context,

MaterialPageRoute(

builder: (_) => DetailPage(

index: memoService.memoList.length - 1,

),

),

);

if (memoList[memoService.memoList.length - 1].content.isEmpty) {

memoService.deleteMemo(index: memoList.length - 1);

}

},

),

);

},

);

}

}


// 메모 생성 및 수정 페이지

class DetailPage extends StatelessWidget {

DetailPage({super.key, required this.index});


final int index;


TextEditingController contentController = TextEditingController();


@override

Widget build(BuildContext context) {

MemoService memoService = context.read<MemoService>();

Memo memo = memoService.memoList[index];


contentController.text = memo.content;


return Scaffold(

appBar: AppBar(

actions: [

IconButton(

onPressed: () {

// 삭제 버튼 클릭시

showDeleteDialog(context, memoService);

},

icon: Icon(Icons.delete),

)

],

),

body: Padding(

padding: const EdgeInsets.all(16),

child: TextField(

controller: contentController,

decoration: InputDecoration(

hintText: "메모를 입력하세요",

border: InputBorder.none,

),

autofocus: true,

maxLines: null,

expands: true,

keyboardType: TextInputType.multiline,

onChanged: (value) {

// 텍스트필드 안의 값이 변할 때

memoService.updateMemo(index: index, content: value);

},

),

),

);

}


void showDeleteDialog(BuildContext context, MemoService memoService) {

showDialog(

context: context,

builder: (context) {

return AlertDialog(

title: Text("정말로 삭제하시겠습니까?"),

actions: [

// 취소 버튼

TextButton(

onPressed: () {

Navigator.pop(context);

},

child: Text("취소"),

),

// 확인 버튼

TextButton(

onPressed: () {

memoService.deleteMemo(index: index);

Navigator.pop(context); // 팝업 닫기

Navigator.pop(context); // HomePage 로 가기

},

child: Text(

"확인",

style: TextStyle(color: Colors.pink),

),

),

],

);

},

);

}

}

오류 발생 시, 작성한 코드 전체와 에러 메시지를 첨부해 주세요.

Tip 1) </> 아이콘을 눌러 코드박스를 만들어 보세요.

Tip 2) Ctrl+A(맥의 경우 Command+A) 단축키로 코드를 한 번에 선택할 수 있어요!




취소
 공유
취소
댓글 0
댓글 알림
나의얼굴