Flutter 앱 개발일지

Movie Reviews 만들기

우제혁 2022. 12. 31. 21:45

목표

완성된 앱화면을 보고 똑같이 디자인 해보기

 

 

사전 준비

주어진 코드

더보기
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: HomePage(), // 홈페이지 보여주기
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // 음식 사진 데이터
    List<Map<String, dynamic>> dataList = [
      {
        "category": "탑건: 매버릭",
        "imgUrl": "https://i.ibb.co/sR32PN3/topgun.jpg",
      },
      {
        "category": "마녀2",
        "imgUrl": "https://i.ibb.co/CKMrv91/The-Witch.jpg",
      },
      {
        "category": "범죄도시2",
        "imgUrl": "https://i.ibb.co/2czdVdm/The-Outlaws.jpg",
      },
      {
        "category": "헤어질 결심",
        "imgUrl": "https://i.ibb.co/gM394CV/Decision-to-Leave.jpg",
      },
      {
        "category": "브로커",
        "imgUrl": "https://i.ibb.co/MSy1XNB/broker.jpg",
      },
      {
        "category": "문폴",
        "imgUrl": "https://i.ibb.co/4JYHHtc/Moonfall.jpg",
      },
    ];

    // 화면에 보이는 영역
    return Scaffold();
  }
}

 

 

완성코드

더보기
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: HomePage(), // 홈페이지 보여주기
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // 음식 사진 데이터
    List<Map<String, dynamic>> dataList = [
      {
        "category": "탑건: 매버릭",
        "imgUrl": "https://i.ibb.co/sR32PN3/topgun.jpg",
      },
      {
        "category": "마녀2",
        "imgUrl": "https://i.ibb.co/CKMrv91/The-Witch.jpg",
      },
      {
        "category": "범죄도시2",
        "imgUrl": "https://i.ibb.co/2czdVdm/The-Outlaws.jpg",
      },
      {
        "category": "헤어질 결심",
        "imgUrl": "https://i.ibb.co/gM394CV/Decision-to-Leave.jpg",
      },
      {
        "category": "브로커",
        "imgUrl": "https://i.ibb.co/MSy1XNB/broker.jpg",
      },
      {
        "category": "문폴",
        "imgUrl": "https://i.ibb.co/4JYHHtc/Moonfall.jpg",
      },
    ];

    // 화면에 보이는 영역
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.transparent,
        elevation: 0.0,
        title: Text(
          "Movie Reviews",
          style: TextStyle(fontSize: 28, color: Colors.black),
        ),
        iconTheme: IconThemeData(color: Colors.black),
        actions: [
          IconButton(
            icon: Icon(Icons.person_outline),
            onPressed: () {
              print('info');
            },
          ),
        ],
      ),
      body: Column(
        children: [
          Container(
            child: Padding(
              padding: const EdgeInsets.all(20.0),
              child: TextField(
                decoration: InputDecoration(
                  suffixIcon: Icon(Icons.search),
                  labelText: '영화 제목을 검색해주세요.',
                  enabledBorder: OutlineInputBorder(
                    borderSide: BorderSide(width: 1, color: Colors.grey),
                  ),
                ),
              ),
            ),
          ),
          Divider(
            height: 10,
          ),
          Expanded(
            child: Container(
              child: ListView.builder(
                  itemCount: dataList.length,
                  itemBuilder: (BuildContext ctx, int idx) {
                    String name = dataList[idx]['category'];
                    String url = dataList[idx]['imgUrl'];
                    return Container(
                        child: Card(
                            child: Stack(
                      alignment: Alignment.center,
                      children: [
                        Container(
                            child: Image.network(url,
                                fit: BoxFit.cover,
                                width: double.infinity,
                                height: 200)),
                        Container(
                          color: Color.fromARGB(145, 35, 35, 34),
                          height: 200,
                        ),
                        Container(
                            child: Text(name,
                                style: TextStyle(
                                    fontSize: 30, color: Colors.white),
                                textAlign: TextAlign.center)),
                      ],
                    )));
                  }),
            ),
          )
        ],
      ),
    );
  }
}

 

알게된 개념

  • appbar의 위치요소
    왼쪽 leading, 가운데 title, 오른쪽 action
  • elevation
    elevation: 0 을 해주면 그림자가 사라진다.
  • TextField의 테두리 설정
1.


TextField(
              decoration: InputDecoration(
                border: OutlineInputBorder(
                  borderSide: BorderSide(color: Colors.black),
                ),
                ),
              ),
2.

TextField(
                decoration: InputDecoration(
                  enabledBorder: OutlineInputBorder(
                    borderSide: BorderSide(width: 1, color: Colors.grey),
                  ),
                ),
              ),
  • TextFeild안에 아이콘 넣을때 prefixIcon와 suffixIcon의 차이
child: TextField(
                decoration: InputDecoration(
                  suffixIcon: Icon(Icons.search),
                ),
              ),
prefixIcon: Icon(Icons.edit), // this is left side
suffixIcon: Icon(Icons.edit), // this is right side.
  • ListView 오류
    크기가 얼마나 될지 모르기 때문에 Expanded로 감싸줘야한다 Expanded의 역할의 텍스트 오버플로우를 막아주면서 다른 영역으로 넘치지 않게 해주는 역할을 한다.
  • Column의 역할
    Column은 세로로 위젯들을 배열할때 사용
  • TextFormField vs TextField T
    extFormField는 주로 값의 유효성을 판단하는 로그인 부분에 사용되며 TextField는 일반적인 입력창이다.
  • map과 list의 활용
    map을 list로 묶을 수 있으며 검색할때는 dataList[idx]['category'] 다음과 같이 검색한다.
  • width: double.infinity
    화면에 맞게 최대로 키우기
  • alignment: Alignment.center
    텍스트를 가운데 정렬하는 방법으로 처음에 textAlign: TextAlign.center를 사용했지만 alignment: Alignment.center 위코드와 같이 상위(Stack) 개념을 정렬해줘야함
  • fit: BoxFit.cover
    지정한 영역 꽉채우기 (width: double.infinity와 같이 써야함)
    참고:https://devmg.tistory.com/181
  • Expanded
    다른 영역으로 넘치지 않게 해주기
  • Divider()
    구분선 만들기
  • Image.network()
    url로 주소로 이미지 표시
  • stack 
    stack을 사용하면 같은 공간에 여러 위젯을 겹칠수 있다 먼저쓰는 코드가 아래에 깔린다.
  • 투명도 만들기
Container(
                          color: Color.fromARGB(145, 35, 35, 34),
                          height: 200, //-> 높이를 똑같이 지정해줘야 적용됨
                          color: Colors.black.withOpacity(0.5),// 투명도 지정

                        ),