728x90
Flutter Provider로 작성된 상태관리 ViewModel이다.
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
class CatViewModel extends ChangeNotifier {
final List<String> _catImages = []; // 고양이 사진을 담을 변수
List<String> _favoriteImages = []; // 좋아요 사진을 담을 변수
List<String> get catImages => _catImages;
List<String> get favoriteImages => _favoriteImages;
Dio _dio = Dio();
// 생성자
CatViewModel() {
_dio.interceptors.add(LogInterceptor());
_dio.interceptors.add(CustLogInterceptor());
getRandomCatImages();
}
void getRandomCatImages() async {
Response resp = await _dio.get(
'https://api.thecatapi.com/v1/images/search?limit=10&mime_types=jpg');
print(resp.data);
for (int i = 0; i < resp.data.length; i++) {
final map = resp.data[i];
_catImages.add(map['url']); // url만 추출하여 catImages 에 이미지 추가.
}
notifyListeners();
}
// 좋아요 토글
void toggleFavoriteImage(String catImage) {
if (_favoriteImages.contains(catImage)) {
_favoriteImages.remove(catImage); // 이미 좋아요한 경우 제거
} else {
_favoriteImages.add(catImage); // 새로운 사진 추가
}
notifyListeners(); // 새로고침
}
}
|
ViewModel 로 클래스명을 정의하기도 하고 Service로 정의하기도 한다.
View 에서 코드를 분리하여 ViewModel에 코드를 대부분 구현하고, View에서는 UI중심으로 코드가 최소화되도록 구현하는 것이 중요하다.
ViewModel 에서는 UI에서 직접적으로 수정할 수 없도록 변수를 선언하는 것이 매우 중요하다.
그래서 위 예제에서는 Class 내부에 있는 변수에 언더바(_)를 붙여서 Private로 정의했고, 외부에서 접근하는 것은 Getter를 추가했다.
기능을 추가할 때 ViewModel 안에 선언한 변수를 외부에서 직접적으로 접근할 수 없도록 신경써야 한다.
CustLogInterceptor는 Interceptor를 상속받았고 특별하게 코드를 추가한 것은 없다.
아래 코드를 잘 활용하면 유용하게 사용할 수 있다.
import 'package:dio/dio.dart';
class CustLogInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
print('REQUEST[${options.method}] => PATH: ${options.path}');
return super.onRequest(options, handler);
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) async {
print('Response_URI >>> ${response.realUri.toString()}');
return super.onResponse(response, handler);
}
@override
void onError(DioError err, ErrorInterceptorHandler handler) {
print(
'ERROR[${err.response?.statusCode}] => PATH: ${err.requestOptions.path}',
);
return super.onError(err, handler);
}
}
|
HomePage UI 클래스
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext context) { return Consumer<CatViewModel>( builder: (context, viewModel, child) { return Scaffold( body: GridView.count( mainAxisSpacing: 8, crossAxisSpacing: 8, crossAxisCount: 2, padding: EdgeInsets.all(8), children: List.generate( viewModel.catImages.length, (index) { String catImage = viewModel.catImages[index]; return GestureDetector( onTap: () { viewModel.toggleFavoriteImage(catImage); // 사진 클릭시 }, child: Stack( children: [ // 사진 Positioned.fill( child: Image.network( catImage, fit: BoxFit.cover, ), ), // 좋아요 Positioned( bottom: 8, right: 8, child: Icon( Icons.favorite, color: viewModel.favoriteImages.contains(catImage) ? Colors.amber : Colors.transparent, ), ), ], ), ); }, ), ), ); }, ); } } |
728x90
'Flutter 앱 > 상태관리' 카테고리의 다른 글
Flutter riverpod 자동 생성 (0) | 2024.01.15 |
---|---|
Flutter Riverpod 예제 : Bucket List (0) | 2023.12.27 |
Flutter StatefulWidget (0) | 2023.12.13 |
Flutter Riverpod - NotifierProvider.family (0) | 2023.12.11 |
Flutter Riverpod - NotifierProvider (0) | 2023.12.11 |