8. 검색화면 만들기 / 홈 화면,필터 화면 제작 중

2025. 2. 5. 00:15현 프로젝트 준비단계

728x90
소요시간

2025년 2월 5일 - 4시간

 

 

느낀 점

 

오늘은 머터리얼을 왜 추가해야 되는지 알게 되었습니다.

애니메이션이 작동을 안 했습니다. 구글과 관련된 아이콘, 애니메이션을 쓸려면 추가해야 되는지 처음 알게 되었다.

역시 이래서 기초가 매우 매우 중요한 거 같다.

 

또한 실시간 검색이 생각보다 API 호출량이 매우 번번하게 발생한다는 사실과 

이해 해당하는 방법이 있다는 사실을 처음 알았습니다.

원래는 검색버튼을 눌러서 결과를 찾는 건 만들어 봤어도

실시간으로 바로 뜨는 건 안 만들어봤었는데 새로운 경험이었다.

 

 

실시간 검색 만들기

 

먼저 함수를 설명해 주면

앞에 6번, 7번에서 가져왔던 네이버 지역 검색 API를 기점으로 만들었습니다.

bool _isLoading = false; // 로딩 상태를 나타내는 변수
String _responseBody = "검색 결과가 여기에 표시됩니다."; // API 응답을 저장할 변수
final TextEditingController _searchController = TextEditingController(); // 검색어 입력을 위한 컨트롤러
Timer? _debounce; // 입력 지연을 위한 타이머
static const int _minSearchLength = 2; // 최소 검색어 길이
static const Duration _debounceDuration = Duration(milliseconds: 500); // 입력 지연 시간

 

사실 AI로 그냥 실시간 검색을 뽑아서 만들긴 했는데

실시간 검색은 한모음자음 당 API호출을 한 번씩 했다.

매우 많이 API 호출이 발생하기 때문에 

500ms(0.5)라는 시간 텀을 두고 불러오게 만들었습니다 

또한 최소 검색어 길이가 2글자 ( 지역은 한 글자가 없기 때문에) 에만 api가 호출되게 만들었습니다.

 

 

앞서 검색 테스트를 할 때 썼던 코드만 가져와서 

도로명 주소만 뜨게 하였습니다.

Future<void> _fetchData(String query) async {
  if (query.length < _minSearchLength) return; // 최소 검색어 길이 미달 시 종료

  setState(() {
    _isLoading = true; // 로딩 시작
  });

  final String clientId = '1'; // 네이버 개발자 센터에서 발급받은 Client ID
  final String clientSecret = '1'; // 네이버 개발자 센터에서 발급받은 Client Secret
  final String url =
      '1'; // API 요청 URL

  try {
    // HTTP GET 요청
    final response = await http.get(
      Uri.parse(url),
      headers: {
        'X-Naver-Client-Id': clientId,
        'X-Naver-Client-Secret': clientSecret,
      },
    );

    if (response.statusCode == 200) {
      // 성공적으로 응답을 받았을 경우
      final Map<String, dynamic> data = json.decode(response.body); // JSON 응답 파싱
      final List<dynamic> items = data['items']; // 검색 결과 아이템 목록
      setState(() {
        // UI 업데이트
        _responseBody = items.map((item) {
          final title = item['title']; // 제목
          final document = html_parser.parse(title); // HTML 파싱
          final cleanTitle = document.body?.text ?? ''; // HTML 태그 제거
          final roadAddress = item['roadAddress'] ?? '도로명 주소 없음'; // 도로명 주소
          final address = item['address'] ?? '지번 주소 없음'; // 지번 주소

          final latitude = item['mapy']; // 위도
          final longitude = item['mapx']; // 경도
          final parsedLatitude = _parseCoordinate(latitude, isLatitude: true); // 위도 변환
          final parsedLongitude = _parseCoordinate(longitude, isLatitude: false); // 경도 변환

          // 결과 문자열 생성
          return '$cleanTitle';
          //return '$cleanTitle\n도로명: $roadAddress\n지번: $address\n위도: $parsedLatitude, 경도: $parsedLongitude\n';
        }).join('\n');
      });
    } else {
      // 응답 실패 시
      setState(() {
        _responseBody = 'Failed to load data: ${response.statusCode}';
      });
    }
  } catch (e) {
    // 예외 발생 시
    setState(() {
      _responseBody = 'Error: $e';
    });
  } finally {
    setState(() {
      _isLoading = false; // 로딩 종료
    });
  }
}

 

 

이런 식으로 json이 오기 때문에 

    {
     '이름' : '남도일', 
    
     '성별' : '남', 
     
     '나이' : 18
    },
    
    {
     '이름' : '유미란', 
    
     '성별' : '여', 
     
     '나이' : 17
    }

 

한 개씩 줄 바꿈 해서 

한 json에 들은 데이터를 불러올 때 버튼이 하나씩 생성되게 만들었습니다.

children: _responseBody.split('\n') // 한 개의 줄바꿈으로 그룹화
    .map((result)

 

 

그리고 디자인을 넣어 더 풍성하게 만들었습니다!

ElevatedButton(
  style: ElevatedButton.styleFrom(
    minimumSize: Size(360.w, 48.h),
    backgroundColor: Color(0xFF1A1A1A), // 버튼 배경색
    padding: EdgeInsets.only(left: 16, right: 16, top: 12, bottom: 12), // 버튼 안의 패딩
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.zero, // 모서리를 직각으로 설정
    ),
  ),
  onPressed: () {
    // 버튼 클릭 시 동작할 코드 작성
    print(result.trim()); // 예시: 결과를 콘솔에 출력
  },
  child: Row(
    mainAxisAlignment: MainAxisAlignment.spaceBetween, // 아이콘과 텍스트를 양쪽으로 배치
    children: [
      Row(
        children: [
          Icon(Icons.search, color: Colors.white), // 왼쪽 돋보기 아이콘
          SizedBox(width: 8), // 아이콘과 텍스트 사이의 간격
          Text(
            result.trim(), // 각 검색 결과 텍스트
            style: TextStyle(
              color: Color(0xFFF8F6FE),
              fontSize: 14,
              fontFamily: 'Pretendard',
              fontWeight: FontWeight.w500,
              height: 1.70,
              letterSpacing: -0.35,
            ),
          ),
        ],
      ),
      Icon(Icons.arrow_forward, color: Colors.white), // 오른쪽 화살표 아이콘
    ],
  ),
);

 

 

사실 검색 코드말고 다른 화면 ui 코드도 설명할려고 했으나

그냥 크기에 맞춰서 디자인 밖에한게 없어서 가져오지는 않았습니다.

결과

 

728x90