본문 바로가기
  • GDG on campus Ewha Tech Blog
3-2기 스터디/플러터

[4주차] 튜토리얼 영상 #15-17

by vitaminmin 2022. 5. 23.

4주차 플러터 스터디에서는 튜토리얼 영상 #15-17을 참고하여 공부했다.


Flutter Tutorial for Beginners #15 - Ninja ID Project

지금까지 배웠던 플러터의 위젯 특성들을 활용하여, 플러터 데모 앱을 만들어보는 실습 강의였다.

  1. ‘Create New Flutter Project’ 클릭 → ‘test’ 폴더 삭제하기
  2. main.dart 파일에서 void main()⇒runApp(MyApp()); 이하 모두 삭제하기
  3. MyApp() 대신 다음 코드 작성:
MaterialApp(
  home: NinjaCard(),
)

*home property는 어플의 홈 스크린에 보여지는 것들을 결정하는 property이다. 
*Scaffold→ 빠르게 어플의 layout을 만들어준다.

  4. Stateless Widget 추가:

class NinjaCard extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey[900],
      appBar: AppBar(
        title: Text('Ninja ID Card'),
        centerTitle: true,
        backgroundColor: Colors.grey[850],
        elevation: 0.0,
      ),
      body: Padding(
        padding: const EdgeInsets.fromLTRB(30.0, 40.0, 30.0, 0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Center(
              child: CircleAvatar(
                radius: 40.0,
                backgroundImage: AssetImage('assets/thumb.jpg'),
              ),
            ),
            Divider(
              color: Colors.grey[800],
              height: 60.0,
            ),
            Text(
              'NAME',
              style: TextStyle(
                color: Colors.grey,
                letterSpacing: 2.0,
              ),
            ),
            SizedBox(height: 10.0),
            Text(
              'Chun-Li',
              style: TextStyle(
                color: Colors.amberAccent[200],
                fontWeight: FontWeight.bold,
                fontSize: 28.0,
                letterSpacing: 2.0,
              ),
            ),
            SizedBox(height: 30.0),
            Text(
              'HOMETOWN',
              style: TextStyle(
                color: Colors.grey,
                letterSpacing: 2.0,
              ),
            ),
            SizedBox(height: 10.0),
            Text(
              'Beijing, China',
              style: TextStyle(
                color: Colors.amberAccent[200],
                fontWeight: FontWeight.bold,
                fontSize: 28.0,
                letterSpacing: 2.0,
              ),
            ),
            SizedBox(height: 30.0),
            Text(
              'CURRENT NINJA LEVEL',
              style: TextStyle(
                color: Colors.grey,
                letterSpacing: 2.0,
              ),
            ),
            SizedBox(height: 10.0),
            Text(
              '8',
              style: TextStyle(
                color: Colors.amberAccent[200],
                fontWeight: FontWeight.bold,
                fontSize: 28.0,
                letterSpacing: 2.0,
              ),
            ),
            SizedBox(height: 30.0),
            Row(
              children: <Widget>[
                Icon(
                  Icons.email,
                  color: Colors.grey[400],
                ),
                SizedBox(width: 10.0),
                Text(
                  'chun.li@thenetninja.co.uk',
                  style: TextStyle(
                    color: Colors.grey[400],
                    fontSize: 18.0,
                    letterSpacing: 1.0,
                  ),
                )
              ],
            ),
          ],
        ),
      ),
    );
  }
}


  5. 새로운 directory 생성 → ‘assets’ 폴더 생성 → 이미지 추가 pubspec.yaml 파일 선언 후 새로고침

이미지를 사용하기 전, 반드시 pubspec.yaml 파일에 다음과 같이 선언해야한다:

assets:
	- assets/파일명.파일확장자

→ ‘Get dependencies’ 클릭 (pubspec.yaml 파일에 변화를 주었기 때문에 클릭해야한다.)

 

Flutter Tutorial for Beginners #16 - Stateful Widgets

지난 강의에서는 동적 데이터 또는 동적 상태(dynamic data or dynamic states) 사용하지 않았기 때문에 StatelessWidget을 사용해도 무방했다.

* Statelesswidget은 생성되고나서 거의 바뀌지 않으며, 시간에 따라 변화하는 states나 data를 포함하지 않는 Widget이다. (예: 버튼을 클릭하는 것)

만약 어플에 시간에 따라 변화하는 동적 데이터를 표현하고자 한다면, 우리는 StatefulWidget을 사용해야한다.

* Statefulwidget은 시간에 따라 state가 변화할 수 있으며, 시간에 따라 바뀌는 동적 데이터를 포함할 수 있는 Widget이다. (예: 버튼 클릭에 따라서 숫자가 증가하는 것)

Widget build(BuildContext context){
	return 
}

class Test extends StatefulWidget {
	@override
	_TestState createState() => _TestState();
}

class _TestState extends State<Test> {

	int counter = 1;

	@override
	Widget build(BuildContext context) {
		return Scaffold(
      backgroundColor: Colors.grey[900],
      appBar: AppBar(
        title: Text('Ninja ID Card'),
        centerTitle: true,
        backgroundColor: Colors.grey[850],
        elevation: 0.0,
      ),
      body: Padding(
        padding: const EdgeInsets.fromLTRB(30.0, 40.0, 30.0, 0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Center(
              child: CircleAvatar(
                radius: 40.0,
                backgroundImage: AssetImage('assets/thumb.jpg'),
              ),
            ),
            Divider(
              color: Colors.grey[800],
              height: 60.0,
            ),
            Text(
              'NAME',
              style: TextStyle(
                color: Colors.grey,
                letterSpacing: 2.0,
              ),
            ),
            SizedBox(height: 10.0),
            Text(
              'Chun-Li',
              style: TextStyle(
                color: Colors.amberAccent[200],
                fontWeight: FontWeight.bold,
                fontSize: 28.0,
                letterSpacing: 2.0,
              ),
            ),
            SizedBox(height: 30.0),
            Text(
              'HOMETOWN',
              style: TextStyle(
                color: Colors.grey,
                letterSpacing: 2.0,
              ),
            ),
            SizedBox(height: 10.0),
            Text(
              'Beijing, China',
              style: TextStyle(
                color: Colors.amberAccent[200],
                fontWeight: FontWeight.bold,
                fontSize: 28.0,
                letterSpacing: 2.0,
              ),
            ),
            SizedBox(height: 30.0),
            Text(
              'CURRENT NINJA LEVEL',
              style: TextStyle(
                color: Colors.grey,
                letterSpacing: 2.0,
              ),
            ),
            SizedBox(height: 10.0),
            Text(
              '8',
              style: TextStyle(
                color: Colors.amberAccent[200],
                fontWeight: FontWeight.bold,
                fontSize: 28.0,
                letterSpacing: 2.0,
              ),
            ),
            SizedBox(height: 30.0),
            Row(
              children: <Widget>[
                Icon(
                  Icons.email,
                  color: Colors.grey[400],
                ),
                SizedBox(width: 10.0),
                Text(
                  'chun.li@thenetninja.co.uk',
                  style: TextStyle(
                    color: Colors.grey[400],
                    fontSize: 18.0,
                    letterSpacing: 1.0,
                  ),
                )
              ],
            ),
          ],
        ),
      ),
    );
  };
	}
}

 

StatelessWidget을 StatefulWidget으로 바꾸기

* Flutter에서 변수를 출력하는 방법: ' dollar sign($) + 변수명 ' (예: $ninjaLevel)

class NinjaCard extends StatefulWidget {
	@override
	_NinjaCardState createState() => _NinjaCardState();
}

class _NinjaCardState extends State<NinjaCard> {

	int ninjaLevel = 0; 

	@override
	Widget build(BuildContext context) {
		return Scaffold(
      backgroundColor: Colors.grey[900],
      appBar: AppBar(
        title: Text('Ninja ID Card'),
        centerTitle: true,
        backgroundColor: Colors.grey[850],
        elevation: 0.0,
      ),
      body: Padding(
        padding: const EdgeInsets.fromLTRB(30.0, 40.0, 30.0, 0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Center(
              child: CircleAvatar(
                radius: 40.0,
                backgroundImage: AssetImage('assets/thumb.jpg'),
              ),
            ),
            Divider(
              color: Colors.grey[800],
              height: 60.0,
            ),
            Text(
              'NAME',
              style: TextStyle(
                color: Colors.grey,
                letterSpacing: 2.0,
              ),
            ),
            SizedBox(height: 10.0),
            Text(
              '$ninjaLevel', //Output the variable 'ninjaLevel'
              style: TextStyle(
                color: Colors.amberAccent[200],
                fontWeight: FontWeight.bold,
                fontSize: 28.0,
                letterSpacing: 2.0,
              ),
            ),
            SizedBox(height: 30.0),
            Text(
              'HOMETOWN',
              style: TextStyle(
                color: Colors.grey,
                letterSpacing: 2.0,
              ),
            ),
            SizedBox(height: 10.0),
            Text(
              'Beijing, China',
              style: TextStyle(
                color: Colors.amberAccent[200],
                fontWeight: FontWeight.bold,
                fontSize: 28.0,
                letterSpacing: 2.0,
              ),
            ),
            SizedBox(height: 30.0),
            Text(
              'CURRENT NINJA LEVEL',
              style: TextStyle(
                color: Colors.grey,
                letterSpacing: 2.0,
              ),
            ),
            SizedBox(height: 10.0),
            Text(
              '8',
              style: TextStyle(
                color: Colors.amberAccent[200],
                fontWeight: FontWeight.bold,
                fontSize: 28.0,
                letterSpacing: 2.0,
              ),
            ),
            SizedBox(height: 30.0),
            Row(
              children: <Widget>[
                Icon(
                  Icons.email,
                  color: Colors.grey[400],
                ),
                SizedBox(width: 10.0),
                Text(
                  'chun.li@thenetninja.co.uk',
                  style: TextStyle(
                    color: Colors.grey[400],
                    fontSize: 18.0,
                    letterSpacing: 1.0,
                  ),
                )
              ],
            ),
          ],
        ),
      ),
    );
  };
	}
}

위의 코드를 실행할 경우, 다음과 같은 에러가 발생: ‘NinjaCard’ is not a subtype of stateless widget
 에러 해결 방법: Run 패널에서 'Hot refresh' 또는 'Hot restart' 클릭

데이터를 수정/재설정하는 경우, Hot restart를 눌러야 변동된 데이터가 반영이 된다. 
이러한 번거로움은 setState 함수를 통해 해결할 수 있다.

우선, Scaffold 내부에, AppBar 속성 아래에 다음과 같은 코드를 삽입한다:

floatingActionButton : FloatingActionButton(
	onPressed: () {
	ninjaLevel += 1;
},
	child: Icon(Icons.add),
	backgroundColor: Colros.grey[800],
	
),

코드를 삽입하게 되면, NinjaLevel의 값은 변하지 않는다. 즉, 우리가 의도한 결과가 나오지 않는 것을 확인할 수 있다.
따라서, 위 코드 속 ninjaLevel += 1; 대신, 우리는 아래와 같이 setState라는 함수를 사용할 것이다:

floatingActionButton : FloatingActionButton(
	onPressed: () {
	setState(() {
	ninjaLevel += 1;
})
},
	child: Icon(Icons.add),
	backgroundColor: Colros.grey[800],
	
),

setState는 build를 재실행(rerun)하게끔한다. 따라서, 이렇게 ‘setState’를 사용하면 원하는 결과가 나오는 것을 알 수 있다. 

 

Flutter Tutorial for Beginners #17 - Lists of Data

위젯 내에서 동적으로 여러 데이터(lists of data)를 순환하며 이들을 출력하는 방법에 대해 알 수 있었던 영상이었다.

1. 'Create New Project' 클릭 → (불필요한) test folder 삭제

* 이때 Test 폴더 지우는 이유: 폴더 속에 있는 'widget_test.dart' 파일에서 'MyApp'을 참조하는데, 이것이 에러를 유발한다!

2. main.dart 코드 다음과 같이 작성:

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
  home: QuoteList()
));

/* We need a stateful widget because we need some changing data inside this widget

(we’re going to have a list of data we cycle through ultimately 
and it’s going to output to the screen so data could be changing)*/

class QuoteList extends StatefulWidget {
  @override
  _QuoteListState createState() => _QuoteListState();
}

class _QuoteListState extends State<QuoteList> {

  List<String> quotes = [
    'Be yourself; everyone else is already taken',
    'I have nothing to declare except my genius',
    'The truth is rarely pure and never simple'
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey[200],
      appBar: AppBar(
        title: Text('Awesome Quotes'),
        centerTitle: true,
        backgroundColor: Colors.redAccent,
      ),
      body: Column(
        children: quotes.map((quote) => Text(quote)).toList(),
      ),
    );
  }
}

댓글