디바이스에 저장된 이미지와 글 입력 받고 게시물로 보여주기

바다구름·2023년 3월 10일
0

Flutter

목록 보기
17/19
import 'package:flutter/material.dart';
//style.Theme
import './style.dart' as style;
//서버 소통
import 'package:http/http.dart' as http;
import 'dart:convert';
//라우터
import 'package:flutter/rendering.dart';
//이미지 넣기
import 'package:image_picker/image_picker.dart';
import 'dart:io';

void main() {
  runApp(
      MaterialApp(
          theme: style.theme,
          initialRoute: '/',
          home: MyApp()
      )
  );
}

class MyApp extends StatefulWidget {
  MyApp({Key? key}) : super(key: key);
  
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  var tab = 0;
  var data = [];
  var getCount = 1;
  var userImage;  // 디바이스에 저장된 사진 중에 선택한 사진의 경로 변수
  var userContent; // 입력 한 값 저장 변수

  setUserConter(input){ // 파라미터에 입력 한 값을 저장하는 함수
    setState(() {
      userContent = input;
    });
  }

  setData(){ // data 라는 배열에 추가하기
    var myData = {
      'id': data.length, // 고유 id 할당
      'image': userImage, // 이미지 경로 할당
      'likes': 5,
      'date': 'July 25',
      'content': userContent, // 입력 값 할당
      'liked': false,
      'user': 'John Kim'
    };
    setState(() { // data 배열의 0번 째 자리에 myData 삽입
      data.insert(0, myData);
    });
  }

  addData(a) {
    setState(() {
      data.add(a);
    });
  }

  getData() async {
    var result = await http.get(Uri.parse('https://codingapple1.github.io/app/data.json'));
    var result2 = jsonDecode(result.body);
    setState(() {
      data = result2;
    });
  }

  getCountAdd () {
    setState(() {
      getCount++;
    });
  }

  //로드 될 때 실행되는 코드
  
  void initState() {
    super.initState();
    getData();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Instagram') ,
        actions: [
          IconButton(
            onPressed: () async { // 버튼 클릭시 이미지 가져오는 코드
              var picker = ImagePicker();
              var image = await picker.pickImage(source: ImageSource.gallery);
              if(image != null) {
                setState(() {
                  userImage = File(image.path); // 사진 경로
                });
              }
              Navigator.push(context, // 새창 띄우기
                //새 창에 띄울 위젯에 사용할 변수들 삽입.
                MaterialPageRoute(builder: (c) => Upload(userImage : userImage, setUserConter : setUserConter, setData : setData)),
              );
            },
            icon: Icon(Icons.add_box_outlined),
            iconSize: 30,
          )
        ],
      ),


      body: [Home(data : data, addData : addData, getCount : getCount, getCountAdd : getCountAdd,), Text('샵페이지')][tab],
      bottomNavigationBar: BottomNavigationBar(
        showSelectedLabels: false,
        showUnselectedLabels: false,

        // items를 눌렀을 때 보여줄 아이콘의 값
        // 1번 items를 눌렀을 때  tab의 값인 1임
        currentIndex : tab,
        onTap: (i){
          setState(() {
            tab = i;
          });
        },
        items: [
          BottomNavigationBarItem(
            icon: Icon(Icons.home_outlined),
            activeIcon: Icon(Icons.home), //눌렀을 때 보여줄 아이콘
            label: 'Home',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.shopping_bag_outlined),
            activeIcon: Icon(Icons.shopping_bag), //눌렀을 때 보여줄 아이콘
            label: 'Shop',
          ),
        ],
      ),

    );
  }
}

class Upload extends StatefulWidget {
  Upload({Key? key, this.userImage, this.setUserConter, this.setData}) : super(key: key);
  final userImage;
  final setUserConter;
  final setData;

  var inputVal = TextEditingController(); // TextField의 입력 값

  
  State<Upload> createState() => _UploadState();
}

class _UploadState extends State<Upload> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('MaterialPageRoute'), actions: [
        IconButton(onPressed: (){
          widget.setData(); // 입력한 값과 선택한 사진 배열에 추가.
          Navigator.pop(context);
        },icon: Icon(Icons.send)),
      ],),
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Container(
            width: 150,
            child: Image.file(widget.userImage) // 선택한 사진 보여주기
          ),
          Text('이미지 업로드 화면'),
          TextField(// 입력한 값 text를 변수에 담기, 값이 수정될 때 마자 실행.
            onChanged: (text){
              widget.setUserConter(text);
            },

          ),
          IconButton(
            onPressed: (){
              Navigator.pop(context);
            },
            icon: Icon(Icons.close),),

        ],
      ),
    );
  }
}



class Home extends StatefulWidget { // 부모 클래스에서 변수와 함수 가져오기
  Home({Key? key, this.data, this.addData, this.getCount, this.getCountAdd}) : super(key: key);
  final data;
  final addData;
  final getCount; // 더보기 상태 변수
  final getCountAdd; // 더보기 상태 변수 증가

  
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  var scroll = ScrollController();

  getMore() async { // get으로 서버에 데이터 가져오기
    var result = await http.get(Uri.parse('https://codingapple1.github.io/app/more1.json'));
    var result2 = jsonDecode(result.body);
    widget.addData(result2); // 가져온 값을 기존 배열에 추가
  }

  getMore2() async {
    var result = await http.get(Uri.parse('https://codingapple1.github.io/app/more2.json'));
    var result2 = jsonDecode(result.body);
    widget.addData(result2);
  }

  
  void initState() {
    super.initState();
    scroll.addListener(() {
      //스크롤이 최대로 내려오면 서버에 get 요청하여 기존배열에 데이터 추가.
      // 만약 getCount가 2면 더 이상 서버에 데이터 요청하지 않음.
      if(scroll.position.pixels == scroll.position.maxScrollExtent) {
        if(widget.getCount == 1) {
          getMore();
          widget.getCountAdd();
        } else if (widget.getCount == 2) {
          getMore2();
          widget.getCountAdd();
        } else {
          print('끝');
        }
      }
    });
  }

  
  Widget build(BuildContext context) {

    if(widget.data.isNotEmpty) { // 데이터 안가져오면 로딩바 보여주기
      // controller: scroll로 스크롤 정보 가져 오기

      return ListView.builder(itemCount: widget.data.length, controller: scroll, itemBuilder: (c, i){
        return Column(
          children: [
            Container(
              constraints: BoxConstraints(maxWidth: 600),
              padding: EdgeInsets.all(20),
              width: double.infinity,
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  // 출력할 data의 image 값이 String이면 network함수 안에 넣어서 출력
                  // String이 아닌 _File 타입이면 file 함수에 넣어서 출력.
                  widget.data[i]['image'].runtimeType == String
                  ? Image.network(widget.data[i]['image'])
                  : Image.file(widget.data[i]['image']),

                  Text('좋아요 ${widget.data[i]['likes']}'),
                  Text(widget.data[i]['user']),
                  Text(widget.data[i]['content']),
                  Text(widget.data[i]['date']),

                ],
              ),
            )
          ],
        );
      });
    } else {
      return Container(
        width: double.infinity,
        height: double.infinity,
        child: CircularProgressIndicator(),
      );

    }
  }
}


1. 주목할 코드

			var picker = ImagePicker();
              var image = await picker.pickImage(source: ImageSource.gallery);
              if(image != null) {
                setState(() {
                  userImage = File(image.path); // 사진 경로
                });
              }
  • 디바이스에 저장된 이미지 가져오는 코드임
  • ImageSource.gallery가 아닌 ImageSource.camera 쓰면 카메라 열림.
  • File 타입으로 경로 값을 가져오니 주의.

2. 주목할 코드

				// 출력할 data의 image 값이 String이면 network함수 안에 넣어서 출력
                // String이 아닌 _File 타입이면 file 함수에 넣어서 출력.
                widget.data[i]['image'].runtimeType == String
                  ? Image.network(widget.data[i]['image'])
                  : Image.file(widget.data[i]['image']),

                  Text('좋아요 ${widget.data[i]['likes']}'),
                  Text(widget.data[i]['user']),
                  Text(widget.data[i]['content']),
                  Text(widget.data[i]['date']),
  • 현재 data 배열에 저장된 image 경로들은 network로 가져온 "http : //어쩌구" 임.
  • 디바이스 내부에 저장된 이미지는 file 로 가져온 "/src/경로/경로2" 이런 값임.
  • data의 배열들을 출력해보면
[
  {"image" : /src/경로/경로2},
  {"image" : http : //어쩌구},
]

이렇게 다르게 저장되어 있기 때문에 삼항 연산자로 각각 다르게 출력 하라는 조건을 줘야
오류가 발생하지 않음.

결과

  • 내가 저장한 문자와 이미지가 기존 게시글 위에 잘 출력되어 있다.
profile
안녕하세요.

0개의 댓글