앱 프로그래밍/플러터(Flutter)

서브페이지와 네트워크 통신 구현하기

0_TLS 2025. 1. 20. 01:16

서브페이지 구현하기


1. 서브페이지 구현 이해하기

1. 내비게이션 기능의 필요성

  • 한 페이지로 만들기 => 페이지 이동이 필요 없으므로 내비게이션이 필요 없음
  • 여러 페이지로 만들기 => 버튼 동작, 페이지 이동을 고려하여 내비게이션 설계 필요

2. 서브페이지 구현 절차

1. 첫번째 페이지 만들기

새로운 플러터 프로젝트 만들기 -> main.dart 파일에 다음과 같은 코드 작성

2. 두번째 페이지 만들기

_FirstPage 클래스에 만든 플로팅 버튼을 눌렀을 때 호출되는 onPressed 이벤트 처리 함수 작성.

Navigator 는 스택을 이용해 페이지를 관리할 때 사용하는 클래스이다.

Navigator 클래스의 of 함수는 현재 페이지를 나타내고, push함수는 스택에 페이지를 쌓는 역할을 한다.

따라서 화면에 보이는 코드는 현재 페이지 위에 SecondPage를 쌓는것으로 해석할 수 있다.

이 "뒤로가기버튼"은 안드로이드와 iOS에 모두 기본으로 제공되고

이 버튼을 누르면 이전 페이지로 이동한다.

 

** 기본 버튼과 별개로 <돌아가기> 버튼에 이전 페이지로 이동하는 기능을 넣으려고 하면 다음 코드를 작성한다.

  • pop()함수 : 스택 메모리에서 맨 위에 있는 페이지를 제거

=> 따라서 두 번째 페이지에 있는 <돌아가기> 버튼을 누르면 두 번째 화면이 사라지고 첫 번째 화면이 보이게 된다.

 

  • pushReplacement는 기존에 있는 페이지를 다음 페이지로 갈아 낀다는 의미(A라는 페이지에서 B라는 페이지로 갈 때, A라는 페이지가 없어지고 B라는 페이지로 교체, 인트로 화면 등에서 적용)
  •  push는 기존에 있는 페이지에 다음 페이지가 엎어지는 느낌으로 두 번째 페이지가 없어지면 다시 남은 페이지가 나오는 것.
  • pushAndRemoveUntil은 스텝이 아주 많은 페이지가 있을 때, a,b,c,d 페이지가 있을 때 d에서 이걸 호출하면 기존에 있는 모든 히스토리가 다 지워지는 효과가 발생(너무 스텝이 많을 경우 그 스텝을 다 없애 버릴 때 유용하게 쓸 수 있는 푸시)

 


네트워크 통신 구현하기


1. 네트워크 통신 구현 개요

1. 공개된 데이터의 용이성

데이터 통신을 구현하려면 서버와 데이터가 필요하다. 서버를 직접 구축하고 통신으로 주고받을 데이터도 직접 생성할 수도 있지만 공개된 데이터를 활용하면 시간을 더 아낄 수 있다. 또 앱의 목적에 따라 시시각각 바뀌는 공공데이터가 필요할 수도 있다.

 

2. 공개된 데이터 이용 출처

=> 카카오에서 제공하는 검색 API를 이용하도록 하겠음.

* 자사의 데이터를 개발자들이 사용할 수 있도록 여러 API를 제공

 

developers.kakao.com에서 새로운 앱을 등록하고 RESP API키를 가져온다.

플러터는 네이티브 앱은 아니고 하이브리드 앱이지만 http통신을 통해 데이터를 가져오기도 하기 때문에 REST API키를 복사한다.

(노출하지 않도록 조심할 것)

 

2. 네트워크 통신 구현 절차

1. http 연습하기

새로운 프로젝트 만들기 -> pubspec.yaml 파일을 열고 decependencies 설정에 앞에서 소개한 http 패키지를 추가

-> pubspec.yaml 파일을 수정하면 플러터 명령줄이 나타나는데 <Pub get>을 클릭해 패키지를 가져옴.

 

http 패키지 불러오기
http.get을 통해 url에 입력한 주소에 데이터를 요청

 

해당 주소의 서버가 응답하면 가져온 데이터를 result에 넣고 그 중 본문을 텍스트 위젯에 출력하도록 한다.

 

**네트워크 통신은 속도나 데이터의 양과 같은 외부 요인으로 인해 정확한 데이터를 받아온 다음에 처리해야 한다.

=> 따라서 네트워크 프로그래밍 : 비동기 방식으로 구현

 

Future는 비동기 처리에서 데이터를 바로 처리할 수 없을 때 사용

 

2. 책 API 호출해서 데이터 가져오기

Authorization : 뒤에 카카오에서 발급받은 REST API키 입력

 


책을 검색하면 정보를 리스트로 보여주도록 작성하기

main.dart

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;


void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HttpApp(),
    );
  }
}

class HttpApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _HttpApp();
}

class _HttpApp extends State<HttpApp> {
  String result = '';
  TextEditingController? _editingController;
  ScrollController? _scrollController;
  List? data;
  int page = 1;

  @override
  void initState() {
    super.initState();
    data = new List.empty(growable: true);
    _editingController = new TextEditingController();
    _scrollController = new ScrollController();
    _scrollController!.addListener(() {
      if (_scrollController!.offset >=
              _scrollController!.position.maxScrollExtent &&
          !_scrollController!.position.outOfRange) {
        print('bottom');
        page++;
        getJSONData();
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: TextField(
          controller: _editingController,
          style: TextStyle(color: Colors.white),
          keyboardType: TextInputType.text,
          decoration: InputDecoration(hintText: '검색어를 입력하세요'),
        ),
      ),
      body: Container(
        child: Center(
          child: data!.length == 0
              ? Text(
                  '데이터가 존재하지 않습니다.\n검색해주세요',
                  style: TextStyle(fontSize: 20),
                  textAlign: TextAlign.center,
                )
              : ListView.builder(
                  itemBuilder: (context, index) {
                    print(data![index]['thumbnail']);
                    return Card(
                      child: Container(
                        child: Row(
                          children: <Widget>[
                            if(data?[index]['thumbnail'] != '')
                            Image.network(
                              data![index]['thumbnail'],
                              height: 100,
                              width: 100,
                              fit: BoxFit.contain,
                            ) else Container(  height: 100,
                              width: 100,),
                            Column(
                              children: <Widget>[
                                Container(
                                  width:
                                      MediaQuery.of(context).size.width - 150,
                                  child: Text(
                                    data![index]['title'].toString(),
                                    textAlign: TextAlign.center,
                                  ),
                                ),
                                Text(
                                    '저자 : ${data![index]['authors'].toString()}'),
                                Text(
                                    '가격 : ${data![index]['sale_price'].toString()}'),
                                Text(
                                    '판매중 : ${data![index]['status'].toString()}'),
                              ],
                            )
                          ],
                          mainAxisAlignment: MainAxisAlignment.start,
                        ),
                      ),
                    );
                  },
                  itemCount: data!.length,
                  controller: _scrollController,
                ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          page = 1;
          data!.clear();
          getJSONData();
        },
        child: Icon(Icons.search),
      ),
    );
  }

  Future<String> getJSONData() async {
    var url =
        'https://dapi.kakao.com/v3/search/book?target=title&page=$page&query=${_editingController!.value.text}';

    var response = await http.get(Uri.parse(url),
        headers: {"Authorization": "KakaoAK aa51bf3d875ea350a1d8bd05de36d8b8"});

    print(response.body); // 검색 결과 로그창으로 확인

    setState(() {
      var dataConvertedToJSON = json.decode(response.body);
      List result = dataConvertedToJSON['documents'];
      data!.addAll(result);
    });
    return response.body;
  }
}