상세페이지 만들기.

네비게이터를 사용하면 덮어씌워서 보여줄 수 있음.

웹사이트랑은 다름

새로운 페이지로 이동할 때, 사라지고 그 위에 올리는 것임.

밑에서 부터 덮어지는 것임.

네비게이터를 사용하면 됨.

또 새로운 페이지 덮이는 것이

그렇게 쌓이고 쌓이고 쌓이는 식으로 동작을 함.

그러면 뒤로가기 버튼이 먹게 됨. 그러면 위에서부터 하나씩 제거를 해줌. Stack 식으로 한다고 생각하면 됨.

사용하기

actions: [IconButton(
              icon: Icon(Icons.add_box_outlined),
            onPressed: (){
                Navigator.push(context, route)
            },
            iconSize: 30,
          )]),

context는 부모 MaterialApp을 가리키며 됨.

onPressed: (){
                Navigator.push(context,
                    MaterialPageRoute(builder: (c){return Text('새페이지'); })
                );
            },

이런식으로 만들면 세페이지 위에 Text 띄워줌. builder 안의 c 는 context를 의미함.

오 여기 Arrow function도 쓸 수 있음

// 이거
MaterialPageRoute(builder: (c){return Text('새페이지'); }));

// 이렇게 사용 가능
MaterialPageRoute(builder: (c) => Text('새페이지');));

upload 화면 다음과 같음


class Upload extends StatelessWidget {
  const Upload({Key? key}) : super(key: key);
  @override

  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(),
        body: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('이미지업로드화면'),
            IconButton( // 닫기 버튼 누름.
                onPressed: (){
                    Navigator.pop(context);
                },
                icon: Icon(Icons.close)
            ),
          ],
        )
    );

  }
}

Navigator.pop(context); 이거 쓰면 Navigator 스택에서 하나 빼줌.

페이지 많으면 route 를 사용하면 됨.

만드는 법 MaterialApp안에 아래와 같이 넣으면 됨..

MaterialApp(
    initialRoute: '/',
    routes: {
      '/': (context) => Text('첫페이지'),
      '/detail': (context) => Text('둘째페이지'),
    },
);

이렇게 사용하면 url을 기준으로 이동할 수 있음 그리고 복잡한 페이지들을 위와 같이 관리할 수 있다고 함.

입학상담앱은 메뉴로 메뉴에서 메뉴로 이동해야 하므로 routes를 사용해야할 것 같다.

폰에 있는 이미지 가져오기

환경설정(설치)
  1. image_picker 설치
    # pubspec.yaml
      image_picker: ^0.8.4+4
    
  2. ios/Runner/Info.plist 수정
     <key>NSPhotoLibraryUsageDescription</key>
     <string>사진첩좀 써도 됩니까</string>
     <key>NSCameraUsageDescription</key>
     <string>카메라좀 써도 됩니까</string>
     <key>NSMicrophoneUsageDescription</key>
     <string>마이크 권한좀 제발</string>
    
  3. dart 파일에 import 2개 추가
    import 'package:image_picker/image_picker.dart';
    import 'dart:io';
    
이미지 가져오기
var picker = ImagePicker();
var image = await picker.pickImage(source: ImageSource.gallery);
// 비디오 가져오기??
await picker.pickVideo 등등...

// 여러개의 이미지 가져오기
await picker.pickMultiImage  (배열로 반환)

userImage = File(image.path); 뭐이런식으로 만들어서 변수를 다 전달전달 사용 하면됨..

이미지 사이즈 조정등도 가능함.

  • 가로세로 사이즈 조정
  • 퀄리티 축소
  • 필터 적용 가능 photofilter 라는 애가 있음. (플러터 패키지)

내가 올린 글, 올린 사진 수정 발행버튼 누르면 글 발행 서버 지지고 볶고하는거 말고 state만 수정해서 보여지게 만들 것.

발행까지 할 수 있는 코드임.

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
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,
    home: MyApp()
    )
  );
}



class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {

  var tab = 0;
  var data = [];

  var userImage;
  var userContent;

  addMyData(){
    var myData = {
      'id': data.length,
      'image': userImage,
      'likes': 5,
      'date': 'July 25',
      'content': userContent,
      'liked': false,
      'user': 'John Kim'
    };

    setState(() {
      data.insert(0, myData);
    });
  }

  setUserContent(a){
    setState(() {
      userContent = a;
    });
  }

  getData() async {
    var result = await http.get(Uri.parse('https://codingapple1.github.io/app/data.json'));
    if(result.statusCode == 200){
      // 성공 코드
    }else {
      // 실패 코드
    }
    var result2 = jsonDecode(result.body);
    setState(() {
      data = result2;
    });
  }

  getMore(seq) async{
    var result;
    if(seq == 0)  result = await http.get(Uri.parse('https://codingapple1.github.io/app/more1.json'));
    else if(seq == 1) result = await http.get(Uri.parse('https://codingapple1.github.io/app/more2.json'));
    else return;
    var result2 = jsonDecode(result.body);
    setState(() {
      data.add(result2);
      print(data);
    });
  }



  var scroll = ScrollController();
  var isVisible = 1;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    getData();
    var getFlag = 0;
    scroll.addListener((){
      if(scroll.position.userScrollDirection == ScrollDirection.reverse){
        setState(() {
          isVisible = 0;
        });
      }
      else {
        setState(() {
          isVisible = 1;
        });
      }
        if(scroll.position.maxScrollExtent == scroll.position.pixels){
          getMore(getFlag);
          getFlag++;
        };
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold (
      appBar: AppBar(
          title: Text('Instagram'),
          actions: [IconButton(
              icon: Icon(Icons.add_box_outlined),
            onPressed: () async {
                var picker = ImagePicker();
                var image = await picker.pickImage(source: ImageSource.gallery);
                if(image != null) {
                  setState((){
                    userImage = File(image.path);
                  });
                }
                Image.file(userImage);
                Navigator.push(context,
                    MaterialPageRoute(builder: (c)
                    => Upload(userImage: userImage, setUserContent: setUserContent, addMyData: addMyData))
                );
            },
            iconSize: 30,
          )]),
      body: [
        Home(jsondata : data, scroll: scroll),
        Text('샵페이지')
      ][tab],
      bottomNavigationBar: AnimatedContainer(
        duration: Duration(milliseconds: 500),
        height: isVisible == 1 ? 60.0 : 0.0,
        child: isVisible == 1 ?
        BottomNavigationBar(
          showSelectedLabels: false,
          showUnselectedLabels: false,
          onTap: (i){
            setState(() {
              tab = i;
            });
          },
          items:[
            BottomNavigationBarItem(icon: Icon(Icons.home_outlined), label: '홈'),
            BottomNavigationBarItem(icon: Icon(Icons.shopping_bag_outlined), label: '샵'),
          ]
        ) : Container(
          color: Colors.white,
          width: MediaQuery.of(context).size.width,
        ),
      ),
    );
  }
}


class Upload extends StatelessWidget {
  const Upload({Key? key, this.userImage, this.setUserContent, this.addMyData}) : super(key: key);
  final userImage;
  final setUserContent;
  final addMyData;

  @override

  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          actions: [
            IconButton(onPressed: (){
              addMyData();
            }, icon: Icon(Icons.send))
          ],
        ),
        body: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Image.file(userImage),
            Text('이미지업로드화면'),
            TextField(onChanged: (text){
              setUserContent(text);
            },),
            IconButton(
                onPressed: (){
                  Navigator.pop(context);
                },
                icon: Icon(Icons.close)
            ),
          ],
        )
    );

  }
}


class Home extends StatefulWidget {
  const Home({Key? key, this.jsondata, this.scroll}) : super(key: key);

  final jsondata;
  final scroll;

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

class _HomeState extends State<Home> {

  @override
  Widget build(BuildContext context) {
    if(widget.jsondata.isNotEmpty) {
      return ListView.builder(
          itemCount: widget.jsondata.length, // 몇번 반복?
          controller: widget.scroll,
          itemBuilder: (context, index){
            return
              Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  widget.jsondata[index]['image'].runtimeType == String
                      ? Image.network(widget.jsondata[index]['image'].toString())
                      : Image.file(widget.jsondata[index]['image'])
                  ,
                  Text('좋아요 : ${widget.jsondata[index]["likes"]}'),
                  Text(widget.jsondata[index]["date"]),
                  Text(widget.jsondata[index]["content"]),
                ],
              );
          });
    }
    else {
      return CircularProgressIndicator();
    }

  }
}