
* 겪고 있는 문제 상황을 최대한 자세하게 작성해주세요.
* 문제 해결을 위해 어떤 시도를 해보았는지 구체적으로 함께 알려주세요.
질문 내용
안녕하세요. 핀 메모 수정 함수에서 정렬 부분 설명 부탁 드립니다. 저는 updateMemo(메모 수정 함수)에서
a.pinYn.compareTo(b.pinYn) 사용해서 개발을 했는데 updatePinMemo(핀 메모 수정 함수)에서
정렬 부분은 이해하기가 힘듭니다.
확인 부탁 드립니다.
감사합니다.
----------------------------------------------------------------------------------------------------------
// 핀 메모 수정 함수 호출
updatePinMemo({required int index}) {
Memo memo = memoList[index];
memo.isPinned = !memo.isPinned; // 핀 체크 여부
memoList = [...memoList.where((element) => element.isPinned), ...memoList.where((element) => !element.isPinned)]; // 정렬 부분 @@@@ ■■■■■■
notifyListeners(); // Consumer<MemoService>의 builder 부분을 호출해서 화면 새로 고침
saveMemoList(); // 메모 저장 함수 호출
}
----------------------------------------------------------------------------------------------------------
// 메모 수정 함수
updateMemo({required int index, required String pinYn, content}) {
debugPrint("■ [/MemoService.C] [updateMemo()] ==> [T_01] [메모 수정 함수]");
var now = new DateTime.now(); //반드시 다른 함수에서 해야함, Mypage같은 클래스에서는 사용 불가능
String editTime = DateFormat('yyyy-MM-dd HH:mm:ss').format(now); // 메모 수정 시간(현재 시간)
debugPrint("■ [/MemoService.C] [updateMemo()] ==> [T_03] [index]" + index.toString() + "[메모 내용]" + content + "[메모 수정 시간]" + editTime + "[sPinYn]" + pinYn);
Memo memo = memoList[index]; // 메모 List
memo.pinYn = pinYn; // 핀 여부
memo.content = content; // 메모 내용
memo.editTime = editTime; // 메모 수정 시간
debugPrint("■ [/MemoService.C] [updateMemo()] ==> [T_23] [index]" + index.toString() + "[메모 내용]" + content + "[메모 수정 시간]" + editTime + "[sPinYn]" + pinYn);
notifyListeners(); // Consumer<MemoService>의 builder 부분을 호출해서 화면 새로 고침
saveMemoList(); // 메모 저장 함수 호출
memoList.sort((b, a) => a.pinYn.compareTo(b.pinYn)); // 핀 아이콘별 리스트 정렬(sort) / / 정렬 부분 @@@@ ■■■■■■
debugPrint("■ [/MemoService.C] [updateMemo()] ==> [T_91] [index]" + index.toString() + "[메모 내용]" + content + "[메모 수정 시간]" + editTime + "[sPinYn]" + pinYn);
notifyListeners(); // Consumer<MemoService>의 builder 부분을 호출해서 화면 새로 고침
}
==============================================================================================================
- flutter/dart sort 간단한 설명 / List 정렬하기 TIL # 46
https://daldalhanstory.tistory.com/246
==============================================================================================================

작성한 코드 및 에러 메세지
- /main.dart 파일에서 @@@
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; // shared_preferences 패키지(기기에 파일로 저장)
void main() async {
debugPrint("■ [/main.dart] [main()] ==> [T_01] [Project Start] ■■■");
WidgetsFlutterBinding.ensureInitialized();
prefs = await SharedPreferences.getInstance(); // 인스턴스 생성(shared_preferences 패키지)
runApp(
MultiProvider(
providers: [
// providers 패키지(상태 관리)
ChangeNotifierProvider(create: (context) => MemoService()), // Memo 데이터 관리 class 호출
],
child: const MyApp(), // MyApp class 호출
),
);
}
/**
* @description HomePage class(00. MyA pp)
*/
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
debugPrint("■ [/MyApp.C] [build()] ==> [T_01] [MyApp Start] ■");
return MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(), // 홈 페이지 호출
);
}
}
/**
* @description HomePage class(01. 홈 페이지)
*/
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
/**
* @description _HomePageState class(01-2. 홈 페이지 Stateful Widget)
*/
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
debugPrint("■ [/_HomePageState.C] [build()] ==> [T_01] [HomePage Start] ■");
return Consumer<MemoService>(
builder: (context, memoService, child) {
debugPrint("■ [/_HomePageState.C] [build()] ==> [T_20]");
// memoService로 부터 memoList 가져오기
List<Memo> memoList = memoService.memoList;
debugPrint("■ [/_HomePageState.C] [build()] ==> [T_22] [memomemoList_총수]" + memoService.memoList.length.toString());
return Scaffold(
appBar: AppBar(
// 01. appBar 위젯■ =====================>
title: Text("mymemo"),
), // 01. appBar 위젯■ =====================>
body: memoList.isEmpty
? Center(child: Text("메모를 작성해 주세요"))
: ListView.builder(
// 01-1. 메모 리스트 ListView
itemCount: memoList.length, // memoList 개수 만큼 보여주기
itemBuilder: (context, index) {
Memo memo = memoList[index]; // index에 해당하는 memo 가져오기
return ListTile(
// ListTile
leading: IconButton(
// 메모 고정 아이콘
icon: Icon(memo.isPinned ? CupertinoIcons.pin_fill : CupertinoIcons.pin),
onPressed: () {
// 핀 Icon 클릭 이벤트
debugPrint("■ [/_HomePageState.C] [==> [T_61] [핀 Icon 클릭 이벤트]");
debugPrint("■ [/_HomePageState.C] [==> [T_62] [i_번째]" + index.toString() + "[메모 내용]" + memo.content);
memoService.updatePinMemo(index: index); // 핀 메모 수정 함수 호출
},
),
// 메모 내용 (최대 3줄까지만 보여주도록)
title: Text(
memo.content,
maxLines: 3,
overflow: TextOverflow.ellipsis,
),
trailing: Text(memo.updatedAt == null ? "" : memo.updatedAt.toString().substring(0, 19)), // 03. 메모 수정 시간 Text
onTap: () async {
// 51. onTap(메모 내용 Text 클릭 이벤트)
await Navigator.push(
context,
MaterialPageRoute(
builder: (_) => DetailPage(
// 메모 생성 및 수정 페이지로 이동
index: index,
),
),
);
// 해당 메모 내용이 비어 있으면(해당 메모가 삭제 처리)
debugPrint("■ [/_HomePageState.C] [==> [T_80_2] [메모 내용]" + memo.content);
if (memo.content.isEmpty) {
// 메모 내용이 널 이면
debugPrint("■ [/_HomePageState.C] [==> [T_82] [메모 삭제 함수 호출]");
memoService.deleteMemo(index: index); // 메모 삭제 함수 호출
}
},
);
},
),
floatingActionButton: FloatingActionButton(
// 51. floating ActionButton 위젯■ =====================>
child: Icon(Icons.add),
onPressed: () async {
// + 버튼 클릭시 메모 생성 및 수정 페이지로 이동
memoService.createMemo(content: ''); // 메모 생성 함수 호출
await Navigator.push(
context,
MaterialPageRoute(
builder: (_) => DetailPage(
index: memoService.memoList.length - 1,
),
),
);
// 해당 메모 내용이 비어 있으면(해당 메모가 삭제 처리)
debugPrint("■ [/_HomePageState.C] [==> [T_90] [해당 메모 내용이 비어 있으면]");
if (memoList[memoService.memoList.length - 1].content.isEmpty) {
// 메모 내용이 널 이면
debugPrint("■ [/_HomePageState.C] [==> [T_95] [빈 메모 삭제 함수 호출]");
memoService.deleteMemo(index: memoList.length - 1);
; // 메모 삭제 함수 호출
}
},
), // 51. floating ActionButton 위젯■ =====================>
);
},
);
}
}
/**
* @description 메모 생성 및 수정 페이지 class(02. 상세 페이지)
*/
class DetailPage extends StatelessWidget {
DetailPage({super.key, required this.index});
final int index;
TextEditingController contentController = TextEditingController();
@override
Widget build(BuildContext context) {
debugPrint("■ [/DetailPage.C] ==> [T_01] [메모 상세 페이지 Start] ■");
debugPrint("■ [/DetailPage.C] ==> [T_02] [index]" + index.toString());
MemoService memoService = context.read<MemoService>(); // context.read<(1회성으로 클래스 접근할 때 사용(화면 새로고침이 필요 없을 때))
Memo memo = memoService.memoList[index];
contentController.text = memo.content; // 메모 내용
return Scaffold(
appBar: AppBar(
// 01. appBar 위젯■ =====================>
actions: [
IconButton(
onPressed: () {
debugPrint("■ [/DetailPage.C] ==> [T_21] [삭제 버튼 클릭 이벤트]");
// 삭제 버튼 클릭시
showDeleteDialog(context, memoService);
},
icon: Icon(Icons.delete),
)
],
), // 01. appBar 위젯■ =====================>
body: Padding(
// 02. body 위젯■ ==================================>
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); // 메모 수정 함수 호출
},
),
), // 02. body 위젯■ ==================================>
);
}
/**
* @description 삭제 Dialog class
*/
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: () {
debugPrint("■ [/DetailPage.C] ==> [T_41] [확인 버튼 클릭 이벤트] [index]" + index.toString());
memoService.deleteMemo(index: index); // 메모 삭제 함수 호출
Navigator.pop(context); // 팝업 닫기
Navigator.pop(context); // HomePage 로 가기
},
child: Text(
"확인",
style: TextStyle(color: Colors.pink),
),
),
],
);
},
);
}
}
=============================================================================================================
- /memo_service.dart 파일에서 @@@
iimport 'dart:convert';
import 'package:flutter/material.dart';
import 'main.dart';
/**
* Memo 데이터 class
* 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() {
debugPrint("■ [/MemoService.C] [MemoService()] ==> [T_01] [Memo 데이터 관리 class(최초 실행시)]");
loadMemoList();
}
List<Memo> memoList = [
// 메모 List
Memo(content: '장보기 목록: 사과, 양파'), // 더미(dummy) 데이터
Memo(content: '새 메모'), // 더미(dummy) 데이터
];
// 메모 생성 함수
createMemo({required String content}) {
debugPrint("■ [/MemoService.C] [createMemo()] ==> [T_01] [메모 생성 함수]");
debugPrint("■ [/MemoService.C] [createMemo()] ==> [T_02] [메모 내용]" + content);
debugPrint("■ [/MemoService.C] [createMemo()] ==> [T_03] [메모 수정 시간]" + DateTime.now().toString());
Memo memo = Memo(content: content, updatedAt: DateTime.now());
memoList.add(memo); // 메모 생성
notifyListeners(); // Consumer<MemoService>의 builder 부분을 호출해서 화면 새로고침
saveMemoList(); // 메모 저장 함수 호출
}
// 메모 수정 함수
updateMemo({required int index, required String content}) {
debugPrint("■ [/MemoService.C] [updateMemo()] ==> [T_01] [메모 수정 함수]");
Memo memo = memoList[index]; // 메모 List
memo.content = content; // 메모 내용
memo.updatedAt = DateTime.now(); // 메모 수정 시간
notifyListeners(); // Consumer<MemoService>의 builder 부분을 호출해서 화면 새로 고침
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(); // Consumer<MemoService>의 builder 부분을 호출해서 화면 새로 고침
saveMemoList(); // 메모 저장 함수 호출
}
// 메모 삭제 함수
deleteMemo({required int index}) {
debugPrint("■ [/MemoService.C] [updateMemo()] ==> [T_01] [메모 삭제 함수]");
debugPrint("■ [/MemoService.C] [updateMemo()] ==> [T_02] [메모 index]" + index.toString());
memoList.removeAt(index); // index 메모 삭제
notifyListeners(); // Consumer<MemoService>의 builder 부분을 호출해서 화면 새로 고침
saveMemoList(); // 메모 저장 함수 호출
}
// 메모 저장 함수(기기에 파일로 저장)
saveMemoList() {
debugPrint("■ [/MemoService.C] [saveMemoList()] ==> [T_01] [메모 저장 함수]");
List memoJsonList = memoList.map((memo) => memo.toJson()).toList();
// [{"content": "1"}, {"content": "2"}]
String jsonString = jsonEncode(memoJsonList);
// '[{"content": "1"}, {"content": "2"}]'
prefs.setString('memoList', jsonString);
}
// 메모 load 함수(기기에 파일로 저장)
loadMemoList() {
debugPrint("■ [/MemoService.C] [loadMemoList()] ==> [T_01] [메모 load 함수]");
String? jsonString = prefs.getString('memoList');
// '[{"content": "1"}, {"content": "2"}]'
if (jsonString == null) return; // null 이면 로드하지 않음
debugPrint("■ [/MemoService.C] [loadMemoList()] ==> [T_41] [jsonStringList로 변환_전(String)]" + jsonString);
List memoJsonList = jsonDecode(jsonString);
// [{"content": "1"}, {"content": "2"}]
memoList = memoJsonList.map((json) => Memo.fromJson(json)).toList(); // String을 List로 변환
}
}
=============================================================================================================
오류 발생 시, 작성한 코드 전체와 에러 메시지를 첨부해 주세요.
Tip 1) </> 아이콘을 눌러 코드박스를 만들어 보세요.
Tip 2) Ctrl+A(맥의 경우 Command+A) 단축키로 코드를 한 번에 선택할 수 있어요!
