본문 바로가기

06. 앱

00015. [APP-00002] 사진 기반 식물/동물 인식 앱 개발기 #6

반응형

#6. 결과 더 예쁘게 보여주기 (카드 UI + 유사 이미지 출력)

이번 편에서는 식물 이름만 출력하던 결과를 더 예쁘게 카드 형식으로 정리하고, Plant.id API에서 제공하는 유사 이미지(similar_images) 도 함께 표시해볼 거야.


✅ 1단계: 응답에서 필요한 데이터 추출하기

Plant.id의 suggestions 항목 안에는 다음 정보들이 포함돼 있어:

  • plant_name: 식물 이름
  • plant_details.common_names: 일반 이름 (있을 경우)
  • similar_images: 관련 이미지 리스트

plant_id_service.dart에서 결과 파싱을 좀 더 상세하게:

final suggestions = result['suggestions'] as List?;
if (suggestions != null && suggestions.isNotEmpty) {
  final first = suggestions[0];
  setState(() {
    _result = first['plant_name'];
    _commonNames = (first['plant_details']['common_names'] as List?)?.cast<String>() ?? [];
    _images = (first['similar_images'] as List?)?.map((img) => img['url'] as String).toList() ?? [];
  });
}

🖼️ 2단계: 결과 카드 UI 구성

home_screen.dart에서 _resultWidget() 함수로 분리해서 구성하면 깔끔해져.

Widget _resultWidget() {
  if (_loading) return const CircularProgressIndicator();
  if (_result == null) return const SizedBox();

  return Card(
    margin: const EdgeInsets.all(16),
    elevation: 4,
    child: Padding(
      padding: const EdgeInsets.all(16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text('이름: $_result', style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
          if (_commonNames.isNotEmpty)
            Text('일반 이름: ${_commonNames.join(', ')}'),
          const SizedBox(height: 16),
          const Text('유사 이미지:', style: TextStyle(fontWeight: FontWeight.w600)),
          const SizedBox(height: 8),
          SizedBox(
            height: 120,
            child: ListView.builder(
              scrollDirection: Axis.horizontal,
              itemCount: _images.length,
              itemBuilder: (context, index) {
                return Padding(
                  padding: const EdgeInsets.only(right: 8),
                  child: Image.network(_images[index]),
                );
              },
            ),
          )
        ],
      ),
    ),
  );
}

그리고 body에서 _resultWidget() 호출 추가:

Expanded(child: _resultWidget()),

✅ 3단계: 결과가 멋지게 나오는지 확인

  • 카드 안에 이름, 일반 이름, 이미지 슬라이드가 들어감
  • 예쁘게 보여주면서 UX 향상

다음 에피소드 예고

#7. 내 도감 저장 기능 만들기 (SharedPreferences 연동)

  • 인식된 결과를 저장하고 리스트로 보기
  • 로컬 저장소 사용 (간단한 도감 앱 기능 구현)
반응형