월 28,600원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 해결됨Flutter 앱 개발 실전
Flutter 빌드 범위
안녕하세요 flutter 개발을 수행하려고합니다.flutter로 강의를 들어보면서 build를 수행해보니 궁금한 점이 하나 있습니다.macos 환경에서 사용할 애플리케이션을 만들려면 macPC에서만 빌드를 할 수 있나요? window 환경에서는 macos 애플리케이션이 빌드 바이너리 생성이 불가능한지 궁금합니다. 반대로 window환경에서 사용할 애플리케이션을 만들려면 windowPC에서만 빌드를 할 수 있나요?만약 된다면 둘을 한번에 shall script 배치 등을 통해 아웃풋으로 각각의 환경의 애플리케이션을 만들 수 있는게 가능한지 궁금합니다.아직 관련 프로젝트 경험이 많지않아 문의 드려봅니다
- 미해결Flutter 앱 개발 실전
파이어베이스 연결만 하면 에러가 발생해요
파이어베이스 연결하려고 하면 에러가 발생하네요그래들과 플러그인 버전의 문제인거 같기도 하고 ㅜㅜㅜ아무리 검색해도 해결방법을 잘 모르겠어요아래가 에러 내용이에요 FAILURE: Build failed with an exception.* What went wrong:A problem occurred configuring root project 'android'.> Could not resolve all artifacts for configuration ':classpath'. > Could not find com.android.tools.build:gradle:8.7. Searched in the following locations: - https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/8.7/gradle-8.7.pom - https://jcenter.bintray.com/com/android/tools/build/gradle/8.7/gradle-8.7.pom - https://repo.maven.apache.org/maven2/com/android/tools/build/gradle/8.7/gradle-8.7.pom Required by: project :* Try:> Run with --stacktrace option to get the stack trace.> Run with --info or --debug option to get more log output.> Run with --scan to get full insights.> Get more help at https://help.gradle.org.BUILD FAILED in 5sRunning Gradle task 'assembleDebug'... 5.7sError: Gradle task assembleDebug failed with exit code 1
- 해결됨Flutter 앱 개발 실전
riverpod 에서 상태가 여러개일 때
Riverpod을 이용해서 MVVM 구조로 변경중인데 하나의 뷰모델에서 여러개의 상태관리가 필요한 경우에는 어떻게 해야되나요?올려주신 riverpod을 이용한 mvvm 코드를 참고해봤는데 각 뷰 별로 상태가 한개라 어려움이 있습니다.여러개 상태를 하나의 객체로 만들어서 관리를 해야될까요?
- 해결됨Flutter 앱 개발 실전
flutter SDK not available
커맨드 팔레트에서 flutter Intl: Initialize클릭시 위와 같은 에러가 뜹니다.. 해결방법이 있을까요
- 해결됨Flutter 앱 개발 실전
CartService 강의에서 질문이요
안녕하세요. CartService 강의에서 CartService의 cartItemList를 굳이 const 로 선언하는 이유가 있는지 궁금합니다.
- 해결됨Flutter 앱 개발 실전
강의 자료 문의
회사 사내망에서는 노션 접속이 차단되어 강의 자료를 PDF로 다운받아 사용하고 있습니다.그런데 PDF 에서 코드스니펫 소스코드 일부가 짤려있어 진행하는데 문제가 있습니다.혹시 실습을 위한 소스코드를 따로 제공해주실 수 있는지요?
- 해결됨Flutter 앱 개발 실전
Lang Tile
Tile( icon: 'language', title: S.current.language, subTitle: IntlHelper.isKo ? S.current.ko : S.current.en, onPressed: () => langService.toggleLang(), )안녕하세요.강의 정말 큰 도움이 되고 있습니다!Lang Tile 구현에서 onPressed 콜백에서 context.watch<LangService>().toggleLang() 으로 쓰면 왜 에러가 나는건가요,,??(아래와 같은 에러가 발생합니다..)Tried to listen to a value exposed with provider, from outside of the widget tree.This is likely caused by an event handler (like a button's onPressed) that calledProvider.of without passing listen: false.To fix, write:Provider.of<LangService>(context, listen: false);It is unsupported because may pointlessly rebuild the widget associated to theevent handler, when the widget tree doesn't care about the value.The context used was: SettingBottomSheet(dependencies: [_InheritedProviderScope<LangService?>, _InheritedProviderScope<ThemeService?>])'package:provider/src/provider.dart':Failed assertion: line 274 pos 7: 'context.owner!.debugBuilding || listen == false || debugIsInInheritedProviderUpdate'
- 해결됨Flutter 앱 개발 실전
추가되었으면 하는 사항과 조언 요청
안녕하세요. riverpod 기반으로 BaseView, BaseViewModel, BaseViewState 를 구현해주셔서 이를 활용하여 로그인 예제 샘플코드에 적용하여 잘 동작되는 걸 확인했습니다.다시 한번 감사드립니다. 섹터2 상태관리 동영상이 도움 되지만 기회가 되신다면 Riverpod 구현 코드 변경 부분 관련으로 동영상 강의 추가해주시면 수강자 및 수강신청 예정자에게 큰 도움이 될 거 같습니다. 좀 더 추가되면 좋을 사항도 적어봅니다.로그인 예제, Retrofit 활용한 JSON 데이터 처리 과정, LogInterceptor 활용한 JWT 인증처리 또는 Session 처리 BaseView 구현하는 역량을 향상시키기 위해서 어떤 과정을 수강(학습)하면 도움이 될지 조언해주시면 큰 도움이 될 거 같습니다. 언어 상관없이 어떤 과정을 배우면 도움될런지요?
- 해결됨Flutter 앱 개발 실전
riverpod 코드 변환 질문
안녕하세요.기회가 되신다면 코드 전체를 riverpod 버전으로 변경해서 notion 에 올려주실 수 있으실까요?riverpod 버전으로 변경해보면서 Dart 문법에 대해 더 이해하게 되는 거 같습니다. 코드변환 질문1class LangService with ChangeNotifier { /// 현재 언어 Locale locale; LangService({ Locale? locale, }) : locale = locale ?? IntlHelper.en; /// 언어 변경 void toggleLang() { locale = IntlHelper.isKo ? IntlHelper.en : IntlHelper.ko; notifyListeners(); } }위 코드를 final langProvider = NotifierProvider<LangNotifier, Locale?> (LangNotifier.new); class LangNotifier extends Notifier<Locale?> { @override Locale? build() => IntlHelper.en; /// 언어 변경 void toggleLang() { state = IntlHelper.isKo ? IntlHelper.en : IntlHelper.ko; } }로 변경하면 맞나요? Notifier<Locale> 로 해야 하는지?Notifier<Locale?> 로 해야 하는지요? 코드변환 질문2class ThemeService with ChangeNotifier { ThemeService({ AppTheme? theme, }) : theme = theme ?? LightTheme(); /// 현재 테마 AppTheme theme; /// 테마 변경 void toggleTheme() { if (theme.brightness == Brightness.light) { theme = DarkTheme(); } else { theme = LightTheme(); } notifyListeners(); } /// Material ThemeData 커스텀 ThemeData get themeData { return ThemeData( /// Scaffold scaffoldBackgroundColor: theme.color.surface, /// AppBar appBarTheme: AppBarTheme( backgroundColor: theme.color.surface, elevation: 0, centerTitle: false, iconTheme: IconThemeData( color: theme.color.text, ), titleTextStyle: theme.typo.headline2.copyWith( color: theme.color.text, ), ), /// BottomSheet bottomSheetTheme: const BottomSheetThemeData( backgroundColor: Colors.transparent, constraints: BoxConstraints( maxWidth: Breakpoints.bottomSheet, ), ), ); } } extension ThemeServiceExt on BuildContext { ThemeService get themeService => watch<ThemeService>(); AppTheme get theme => themeService.theme; AppColor get color => theme.color; AppDeco get deco => theme.deco; AppTypo get typo => theme.typo; }위 코드를final themeProvider = NotifierProvider<ThemeNotifier, AppTheme>(ThemeNotifier.new); class ThemeNotifier extends Notifier<AppTheme> { @override AppTheme build() => LightTheme(); AppTheme get theme => state; AppColor get color => state.color; AppDeco get deco => state.deco; AppTypo get typo => state.typo; /// 테마 변경 void toggleTheme() { if (state.brightness == Brightness.light) { state = DarkTheme(); } else { state = LightTheme(); } } /// Material ThemeData 커스텀 ThemeData get themeData { return ThemeData( /// Scaffold scaffoldBackgroundColor: state.color.surface, /// AppBar appBarTheme: AppBarTheme( backgroundColor: state.color.surface, elevation: 0, centerTitle: false, iconTheme: IconThemeData( color: state.color.text, ), titleTextStyle: state.typo.headline2.copyWith( color: state.color.text, ), ), /// BottomSheet bottomSheetTheme: const BottomSheetThemeData( backgroundColor: Colors.transparent, constraints: BoxConstraints( maxWidth: Breakpoints.bottomSheet, ), ), ); } }로 변경하면 맞는지요?
- 해결됨Flutter 앱 개발 실전
riverpod 코드 변경 질문
안녕하세요. Provider 로 된 코드를 Riverpod 로 변경 해보려고 하면 벽에 부딪쳐네요. class CartService with ChangeNotifier { List<CartItem> _cartItemList = const []; List<CartItem> get cartItemList => _cartItemList; // 상품 목록 // 선택된 상품 목록 List<CartItem> get selectedCartItemList { return _cartItemList.where((cartItem) => cartItem.isSelected).toImmutable(); // cartItemList에서 isSelected 값이 true 항목만 불변 배열로 반환하는 Getter를 구현 } // 상품 추가 void add(CartItem newCartItem){ _cartItemList = [..._cartItemList, newCartItem].toImmutable(); notifyListeners(); } // 상품 수정 void update(int selectedIndex, CartItem newCartItem) { _cartItemList = _cartItemList.asMap().entries.map((entry) { return entry.key == selectedIndex ? newCartItem : entry.value; }).toImmutable(); notifyListeners(); /*** * 업데이트하고 싶은 항목의 인덱스인 selectedIndex에 해당하는 항목을 * 새로운 newCartItem으로 변경하여 새로운 불변 배열을 생성하도록 구현 */ } // 상품 삭제 void delete(List<CartItem> deleteList){ _cartItemList = _cartItemList.where((cartItem) { return !deleteList.contains(cartItem); }).toImmutable(); notifyListeners(); /*** * 삭제하고 싶은 목록을 deleteList로 전달받고, * 해당 배열에 들어있지 않은 CartItem만 남긴 불변 배열을 생성하도록 구현 */ } } 위 코드를 아래와 같이 변경하고자 일부 구현을 해보고 있습니다. 틀린 부분 수정 및 상품 수정 코드를 어떻게 추가해야 될까요?final cartProvider = NotifierProvider<CartNotifier, List<CartItem>>(CartNotifier.new); class CartNotifier extends Notifier<List<CartItem>> { @override List<CartItem> build() => const []; // 상품 목록 // 상품 추가 void add(CartItem newCartItem){ state = [...state, newCartItem]; // state 는 immutable 데이터이기 때문에 직접적으로 state 를 변경할 수 없다. } // 상품 삭제 void delete(List<CartItem> deleteList){ state = state.where((cartItem) => cartItem != deleteList).toList(); } // 상품 수정 void update(int selectedIndex, CartItem newCartItem) { // CartItem 에 유니크한 id 값이 없는 거 같고, 선택한 index 값으로 찾아서 update 해야 하는데 모르겠음. } /* state = [ for (final item in state) if (item.id == id) newCartItem else item, ]; */ // 선택된 상품 목록 List<CartItem> get selectedCartItemList { return state.where((cartItem) => cartItem.isSelected).toList(); } }
- 해결됨Flutter 앱 개발 실전
섹션3 - Tile 강의 질문
SettingBottomSheet에서 ThemeServices는 context.read해도 되고, LangService는 context.watch로 해야하는 이유가 무엇인가요? toggleLang, toggleTheme 함수 안에서 똑같이 notifyListeners를 호출하는데 무슨 차이가 있는지 궁금합니다.
- 해결됨Flutter 앱 개발 실전
노션 자료 어떻게 활용하나요?
노션은 처음이라 몇가지 구글링 해봤는데, 제가 개인적으로 가져와 오프라인으로 볼 수는 없나 봐요? 그냥, 링크로 웹으로 들어가서 봐야 하는게 다인가요?
- 해결됨Flutter 앱 개발 실전
NotifierProvider 로 변경하고 싶어요
안녕하세요.Riverpod 상태관리에서 StateNotiferProvider 대신에 NotifierProvider를 사용하는 것을 권장하신다고 하셨는데요.StateNotifierProvider 로 작성한 코드를 NotiferProvider 로 변경하고 싶은데 잘 안되어 문의 드립니다. contactStateProvier 코드로는 정상 동작됩니다.이 코드를 NotifierProvider 로 변경해보려고 하는데 잘 안되네요.final contactStateProvider = StateNotifierProvider<ContactStateNotifier, ContactResultBase>( (ref) { final repository = ref.watch(restClientProvider); final notifier = ContactStateNotifier(restClient: repository); return notifier; }, ); class ContactStateNotifier extends StateNotifier<ContactResultBase> { final RestClient restClient; ContactStateNotifier({required this.restClient}) : super(ContactResultLoading()) { postContactList(); } postContactList() async { final resp = await restClient.postContactList( Crypto.AES_encrypt(Crypto.URLkey()), ''); state = resp; } }@RestApi(baseUrl: RetrofitURL.baseUrl) abstract class RestClient { factory RestClient(Dio dio, {String baseUrl}) = _RestClient; @POST(RetrofitURL.mLogin) @FormUrlEncoded() Future<LoginResponse> userLogin( @Field() String keyword, @Field() String userID, @Field() String password, @Field() String uID, @Field() String mfoneNO, ); @POST(RetrofitURL.contactData) @FormUrlEncoded() Future<ContactResult> postContactList( @Field() String keyword, @Field() String search, ); }final secureStorageProvider = Provider<FlutterSecureStorage>((ref) => const FlutterSecureStorage()); final dioProvider = Provider<Dio>((ref) { final dio = Dio(); final storage = ref.watch(secureStorageProvider); dio.interceptors.add(LogInterceptor()); dio.interceptors.add( CustLogInterceptor(storage: storage,), ); return dio; }); final restClientProvider = Provider<RestClient>((ref) { final dio = ref.watch(dioProvider); final repository = RestClient(dio); return repository; }); contactStateProvider 를 변경시도 해보다가 에러가 발생한 코드final contactProvider = NotifierProvider<ContactNotifier, ContactResultBase>( () { final repository = ref.watch(restClientProvider); final notifier = ContactNotifier(restClient: repository); return notifier; }, ); class ContactNotifier extends Notifier<ContactResultBase> { @override ContactResultBase build() => ContactResultLoading(); final RestClient restClient; ContactStateNotifier({required this.restClient}) { postContactList(); } postContactList() async { final resp = await restClient.postContactList( Crypto.AES_encrypt(Crypto.URLkey()), ''); state = resp; } }
- 해결됨Flutter 앱 개발 실전
[문의] ListView.builder 처리
안녕하세요. 처음부터 List<ContactItem> 으로 데이터를 반환받아서 처리해야 하는 것인지, 아니면 아래 코드에서 분기처리할 방법이 있는지 궁금합니다.import 'package:json_annotation/json_annotation.dart'; import 'package:retrofit_ex2/model/contact_item.dart'; part 'contact_result.g.dart'; @JsonSerializable() class ContactResult { final String status; final String message; final List<ContactItem>? addrinfo; const ContactResult({ required this.status, required this.message, this.addrinfo, }); factory ContactResult.fromJson(Map<String, dynamic> json) => _$ContactResultFromJson(json); Map<String, dynamic> toJson() => _$ContactResultToJson(this); }import 'package:dio/dio.dart'; import 'package:retrofit/retrofit.dart'; import 'package:retrofit_ex2/common/repository/retrofit_url.dart'; import 'package:retrofit_ex2/model/contact_result.dart'; part 'rest_client.g.dart'; @RestApi(baseUrl: RetrofitURL.baseUrl) abstract class RestClient { factory RestClient(Dio dio, {String baseUrl}) = _RestClient; @GET(RetrofitURL.contactData) Future<ContactResult> getContactList(); }class ContactListPage extends StatefulWidget { const ContactListPage({Key? key}) : super(key: key); @override State<ContactListPage> createState() => _ContactListPageState(); } class _ContactListPageState extends State<ContactListPage> { late final RestClient restClient; @override void initState() { Dio dio = Dio(); restClient = RestClient(dio); super.initState(); } @override Widget build(BuildContext context) { return Scaffold( body: FutureBuilder<ContactResult>( future: restClient.getContactList(), builder: (BuildContext context, AsyncSnapshot<ContactResult> snapshot) { if (!snapshot.hasData) { return const Center( child: CircularProgressIndicator(), ); } final ids = snapshot.data as ContactResult; //print(ids.runtimeType); if (ids.status.contains("success")) { final addrinfo = ids.addrinfo as List<ContactItem>; print('addrinfo_count ::: ${addrinfo.length}'); // 15개 for(ContactItem item in addrinfo){ print('${item.idx} | ${item.userNM} | ${item.mobileNO} | ${item.photo}'); // 여기서 출력은 잘 됨. } return ListView.builder( itemCount: addrinfo.length, itemBuilder: (context, index) { // 총 15개의 List 데이터를 출력하기 위해서 어떻게 해야하는지요? return Text(''); }, ); } else { return const Center( child: Text('에러가 발생했습니다.'), ); } }, ), ); } Widget _contactListWidget(ContactItem item) { return Column( children: [ Text(item.idx.toString()), Text(item.userNM), Text(item.mobileNO), Text(item.telNO!), Text(item.photo!), ], ); } }15개의 데이터를 GET으로 가져오는 것까지는 잘 되는 걸 확인했습니다.JSON 데이터 전체는 ContactResult 이고, addrinfo 는 List<ContactItem> 입니다.ContactItem 15개를 ListView.builder 를 이용하여 출력하려고 하는데 어떻게 해야 되는지 몰라 도움 요청드립니다.
- 해결됨Flutter 앱 개발 실전
Unhandled Exception: type '_Map<String, dynamic>' is not a subtype of type 'Contact_Item'
안녕하세요. 강의를 듣고나서 테스트를 해보는데 안되어서 문의 좀 드립니다.addrinfo: json['addrinfo'] == null ? null : List<Contact_Item>.from(json['addrinfo']),위 부분을 어떻게 처리해야 해결될 수 있는지를 모르겠습니다.addrinfo 는 값이 서버에서 null을 반환할 수도 있고List<Contact_Item> 을 반환할 수도 있습니다. class Contact_Item { final String idx; final String userNM; final String mobileNO; final String telNO; final String photo; final bool checkBoxState; const Contact_Item({ required this.idx, required this.userNM, required this.mobileNO, required this.telNO, required this.photo, required this.checkBoxState, }); factory Contact_Item.fromJson(Map<String, dynamic> json) { return Contact_Item( idx: json['idx'] as String, userNM: json['userNM'] as String, mobileNO: json['mobileNO'] as String, telNO: json['telNO'] as String, photo: json['photo'] as String, checkBoxState: json['checkBoxState'] as bool, ); } }class ContactResult { final String status; final String message; final List<Contact_Item>? addrinfo; const ContactResult({ required this.status, required this.message, this.addrinfo, }); factory ContactResult.fromJson(Map<String, dynamic> json) { return ContactResult( status: json['status'] ?? '', message: json['message'] ?? '', addrinfo: json['addrinfo'] == null ? null : List<Contact_Item>.from(json['addrinfo']), ); } }abstract class ContactRepo { Future<ContactResult> getAddressData(ContactRequest req); } class ContactService extends ContactRepo { Future<ContactResult> getAddressData(ContactRequest req) async { BaseOptions options = BaseOptions( baseUrl: RetrofitURL.baseUrl, ); Dio dio = Dio(options); dio.interceptors.add(Logging()); FormData formData = FormData.fromMap({ "keyword": req.keyword, "search": req.search, }); final response = await dio.post(RetrofitURL.contactData, data: formData); print(response); // print(response.data.runtimeType); //print(response.headers); if (response.statusCode == 200) { ContactResult result = ContactResult.fromJson(response.data); return result; } else { return ContactResult(status: "fail", message: "fail", addrinfo: null); } } }에러 메시지 내용I/flutter (23550): RESPONSE[200] => PATH: /androidSample/ContactList.phpI/flutter (23550): {"status":"success","message":"","addrinfo":[{"idx":1,"userNM":"개발자","mobileNO":"01000010001","telNO":"0234560001","photo":"1.jpg","checkBoxState":false},{"idx":2,"userNM":"이정은","mobileNO":"01001230001","telNO":"","photo":"2.jpg","checkBoxState":false},{"idx":3,"userNM":"김홍길","mobileNO":"01001230002","telNO":"","photo":"null","checkBoxState":false},{"idx":4,"userNM":"최신형","mobileNO":"01001230003","telNO":"","photo":"4.jpg","checkBoxState":false},{"idx":5,"userNM":"홍길동","mobileNO":"01000009880","telNO":"","photo":"5.jpg","checkBoxState":false},{"idx":6,"userNM":"김아정","mobileNO":"01001230005","telNO":"","photo":null,"checkBoxState":false},{"idx":7,"userNM":"이순신","mobileNO":"01001230006","telNO":"","photo":"7.jpg","checkBoxState":false},{"idx":8,"userNM":"이정민","mobileNO":"01000010887","telNO":"","photo":null,"checkBoxState":false},{"idx":9,"userNM":"최재수","mobileNO":"01001110000","telNO":"","photo":"9.jpg","checkBoxState":false},{"idx":10,"userNM":"장정은"E/flutter (23550): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type '_Map<String, dynamic>' is not a subtype of type 'Contact_Item'E/flutter (23550): #0 new List.from (dart:core-patch/array_patch.dart:29:5)E/flutter (23550): #1 new ContactResult.fromJson (package:login_ex/contact/model/contact_result.dart:19:51)E/flutter (23550): #2 ContactService.getAddressData (package:login_ex/contact/repository/contact_service.dart:32:44)E/flutter (23550): <asynchronous suspension>E/flutter (23550): #3 MainScreenState.getContactData (package:loginex/contact/view/main_screen.dart:35:30)E/flutter (23550): <asynchronous suspension>
- 해결됨Flutter 앱 개발 실전
노션 주소는 어디서 확인하나요?
노션 주소는 어디서 확인하나요?
- 해결됨Flutter 앱 개발 실전
IntelliJ에서 Flutter Intl 확장 프로그램 설치 방법
다국어 구현에서 VS Code 에서는 Flutter Intl 확장 프로그램을 추가하는데 IntelliJ에서는 어떻게 하는지요?설치를 안해도 상관 없는지요?
- 해결됨Flutter 앱 개발 실전
context 관련 질문입니다!
섹션3 / AssetIcon / 04:41~04:51 / Line24color ?? context.color.text,04:47에서 context.co까지만 입력해도 자동완성이 뜨는데요.Q1. context가 어떤걸(어떤 파일의 어떤 클래스?) 지칭하는지 궁금합니다Q2. 어떤 매커니즘으로 theme_service import가 자동완성으로 뜨는지 궁금합니다(어떻게 인식했는지..?)질문이 난해할 수도 있는데, context에 관한 질문입니다!
- 해결됨Flutter 앱 개발 실전
커스텀 클래스 깊은복사 - copyWith
섹션1 / 객체 복사 / 14:15~14:32Line25에서 copyWith 메서드가 A클래스의 copyWith를 쓰는건지, B 클래스에서 정의한 copyWith 메서드를 호출하게 되는 건지 궁금합니다!후자라면, 클래스 A에서 copyWith를 정의하는 과정에서 어떻게 B의 메서드를 끌어쓰게 되는건지 궁금합니다!