중급

실생활 앱 (날씨 앱)

현재 위치를 기준으로 날씨를 조회하고, 온도와 상태, 접속 국가 모양을 한 화면에 표시하는 앱을 만듭니다.

동작

실생활 앱 (날씨 앱) 실행 화면

사용자가 날씨 조회를 누르면 기기의 현재 위치를 요청합니다. 요청 중에는 로딩 상태를 보여줍니다. 응답 JSON을 Weather 모델로 바꿔 온도, 상태, 접속 국가 모양을 표시합니다.

예제 코드

날씨 앱

현재 위치 날씨 중급
상태 대기
위치 대기 27°C 날씨 조회를 눌러 확인
접속 국가 대한민국

예제 코드 기능별 설명

코드를 나누어 읽기

import

material.dart는 버튼, 로딩 표시, 카드 UI를 제공합니다. 실제 위치와 날씨 API를 붙이면 geolocator로 현재 위치를 얻고, http 또는 dio로 날씨 서버에 요청합니다. 예제는 구조를 단순화하기 위해 네트워크 응답을 가짜 JSON으로 대신합니다.

import 'package:flutter/material.dart';

Weather 모델

Weather 모델은 API 응답을 앱 내부에서 쓰기 쉬운 형태로 바꾼 데이터 클래스입니다. place는 위치 이름, temp는 온도, description은 날씨 상태, country는 접속 국가 모양을 고르기 위한 값입니다. JSON을 그대로 UI에 넘기지 않으면 필드 이름 변경이나 누락에 더 안전하게 대응할 수 있습니다.

factory Weather.fromJson(Map<String, dynamic> json) {
  return Weather(place: json['place'], temp: json['temp'], description: json['description'], country: json['country']);
}

상태 변수

weather는 마지막으로 성공한 날씨 응답입니다. loading은 위치 확인과 API 요청이 진행 중인지 표시하고, error는 권한 거부나 네트워크 실패 메시지를 담습니다. 사용자가 버튼을 여러 번 눌러도 weather 값 하나만 교체하므로 결과 카드가 아래로 계속 쌓이지 않습니다.

Weather? weather;
bool loading = false;
String error = '';

현재 위치 조회

fetchWeather는 요청 시작 시 loading을 켜고 error를 비웁니다. 실제 앱에서는 이 위치에서 위치 권한을 요청하고 좌표를 얻은 다음, 좌표를 날씨 API에 전달합니다. 권한이 거부되면 기본 위치나 시간대 기반 국가를 사용해 화면이 비어 보이지 않게 처리합니다.

setState(() => loading = true);
final position = await locationService.currentPosition();
final json = await weatherApi.fetch(position.lat, position.lon);
setState(() => weather = Weather.fromJson(json));

단일 결과 카드

날씨 조회는 기록 목록을 만드는 기능이 아니라 현재 상태를 보여주는 기능입니다. 그래서 응답이 올 때마다 List에 추가하지 않고 weather 하나만 갱신합니다. 이 방식은 대시보드, 환율, 주식 현재가처럼 최신 값 하나가 중요한 화면에 잘 맞습니다.

setState(() {
  weather = Weather.fromJson(json);
  loading = false;
});

상태별 UI

API 앱은 성공 화면만 있으면 부족합니다. loading이 true이면 CircularProgressIndicator를 보여주고, error가 있으면 오류 문구를 보여주며, weather가 있으면 날씨 카드를 보여줍니다. 이렇게 나누면 네트워크 지연과 실패도 화면 흐름 안에서 처리할 수 있습니다.

if (loading) const CircularProgressIndicator()
if (error.isNotEmpty) Text(error)
if (weather != null) WeatherCard(weather: weather!)

접속 국가 모양

예제 화면에서는 지도 핀 대신 접속 국가 모양을 보여줍니다. 실제 Flutter 앱에서는 country 값에 따라 CustomPainter, SVG, 이미지 에셋 중 하나를 선택해 국가 실루엣을 그릴 수 있습니다. 이 사이트의 결과 블록은 CSS clip-path로 간단한 국가 모양을 표현합니다.

Widget countryShape(String country) {
  return switch (country) {
    '대한민국' => const KoreaShape(),
    '미국' => const UsaShape(),
    _ => const DefaultCountryShape(),
  };
}

실제 API 연결

실제 앱에서는 fetchWeather 안의 가짜 json을 OpenWeather, 기상청 API 같은 응답으로 교체합니다. 이때 API 키는 앱 코드에 직접 넣기보다 서버 프록시나 보안 저장소를 거쳐 관리하는 편이 좋습니다.

final response = await weatherApi.fetchByLocation(lat, lon);
final weather = Weather.fromJson(response);