*해당 블로그는 코딩애플의 쉬운 플러터 강의를 보고 제작되었습니다.
커스텀 위젯 제작하기
커스텀 위젯을 작성하여 사용하는 방법은 여러가지 방법이 있다.
오늘은 여러 방법들 중 두 가지 방법을 알아보고자 한다.
일단 커스텀 위젯을 작성하는 이유가 무엇일까??
커스텀 위젯을 사용하지 않을 경우 한 class에 모든 구현내용을 작성하게 되어 코드가 상당히 복잡해진다. 코드를 좀 더 가독성 있고 간결하게 표현하기 위해 혹은 같은 코드를 여러번 작성하지 않도록 하기 위해 작성하게 된다.
컴포넌트의 개념이라고 생각하면 되는 것 같다.
1. class 생성하여 커스텀 위젯 제작하기
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: SizedBox(
child: Text("안녕"),
)
)
);
}
}
기본 위젯을 작성하게 되면 이런식으로 작성할 것이다. 하지만 우리는 SizedBox의 내용을 커스텀으로 작성해보고자 한다.
일단 먼저 class를 하나 더 생성하여 커스텀 위젯을 작성할 것이다.
class ShopItem extends StatelessWidget {
const ShopItem({super.key});
@override
build(BuildContext context) {
return SizedBox(
child: Text("안녕"),
);
}
}
ShopItem이라는 커스텀 위젯을 제작하였다.
사용방법은 일반 컴포넌트를 사용하는 방법과 동일하게 커스텀위젯의 이름을 코드로 작성해준다.
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: ShopItem(),
)
);
}
}
이런식으로 커스텀 위젯 명을 불러오게 되면 화면에 '안녕'이라는 값이 뜨게 된다.
그럼 여기에서 코드 하나하나에 대한 문법을 배워보자
class ShopItem extends StatelessWidget {}
해당 코드의 경우 class를 먼저 지정해주는 코드로 extends의 의미를 설명하자면 오른쪽 (StatelessWidget) class를 왼쪽 (ShopItem)위젯으로 복사해서 사용할거에요! 라고 말하는것과 동일하다고 생각하면 된다.
Widget build(BuildContext context) {
return SizedBox(
child: Text("안녕"),
);
}
build() {}의 경우 js에서의 함수 라고 생각하면 된다. function build() {} 와 동일하다고 생각하면 되고 Widget은 제외해주어도 오류가 발생하지 않는다.
return 뒤에 축약할 레이아웃을 작성한다.
이러한 함수를 생성할때 다트에서는 함수명 () {}로 작성하면 함수가 생성된다.
위 코드는 간단하게 class 내 build라는 함수를 생성했다고 생각하면 간편하다.
class ShopItem extends StatelessWidget {
const ShopItem({super.key});
@override
Widget build(BuildContext context) {
return SizedBox(
child: Text("안녕"),
);
}
}
전체 코드를 같이 보면 이제 @override 라는 부분이 궁금하게 될 텐데 해당 부분은 StatelessWidget을 ShopItem으로 복사하는 과정에서 생기는 중복 코드를 해결해주는 코드이다.
간단하게 "StatelessWidget과 ShopItem의 중복사항이 있을때 내꺼 먼저 적용해주세요!" 라는 명령이라고 생각하면 될 것 같다
*나의 경우 다른 언어를 학습하면서 충분이 이해가 가는 부분이지만 코딩을 처음 접해보는 사람들에게는 좋은 예시 설명인 것 같다.
2. 변수를 생성하여 커스텀 위젯 생성하기
변수를 생성해서 커스텀 위젯을 생성하는 경우 class를 생성할 필요 없이 변수에 축약할 코드를 적어주면 되는 간단한 방법이다.
var a = SizedBox(
child: Text('안녕'),
);
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: a
)
);
}
}
정말 간단한 방법이지만 이 방법의 경우 성능상 이슈가 발생할 수도 있다.
변하지 않는 UI들은 변수 함수로 축약해도 상관 없지만 변수 안의 내용이 실시간 동적으로 변경되어야하는 위젯이라면 사용하지 않는 것이 좋다.
3. 커스텀 위젯을 만들기 최적의 조건
아무거나 나다커스텀 위젯화하는것은 좋지 않다. 대표적으로 나중에 다시 언급하겠지만 state의 관리가 어려워진다.
그러면 커스텀 위젯을 사용하기 좋은 조건은 무엇일까?
- 재사용이 많은 UI들의 경우 커스텀으로 만들어두는 것이 적절하다
- 큰 페이지들을 커스텀 위젯으로 만들어두어도 사용하기 용이할 것이다.
4. ListView
앱을 제작할때 요소의 갯수가 많아지는 경우가 있을 것 이다.
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: Column(
children: [
Text('안녕'),
Text('안녕'),
Text('안녕'),
Text('안녕'),
Text('안녕'),
],
)
)
);
}
}
하지만 이런 요소의 갯수가 많아진다고 해서 스크롤바가 자동으로 생성되는 것이 아니다.
때문에 스크롤바가 있는 긴 목록이 필요하다.
Column 대신에 ListView를 사용해보자
ListView 안에 요소들을 모두 넣을 경우
- 스크롤바가 생성된다.
- controller 파라미터 지정으로 통해 스크롤의 위치 감시가 가능해진다.
- 메모리 절약 기능이 있다.
여기에서 메모리 절약 기능이란 무엇인가 하면
1 ~ 100까지의 리스트가 있고 지금 유저가 보고있는 곳이 70~80 구간을 보고있다면, 현재 보고있는 부분이 아닌 부분들은 삭제해주는 기능을 가지고 있다.
때문에 성능 개선에 도움을 준다.
과제!
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue,
),
bottomNavigationBar: BottomAppBar(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [Icon(Icons.call), Icon(Icons.message), Icon(Icons.account_box)],
),
),
body: ListView(
children: [
PeopleItem(),
PeopleItem(),
PeopleItem(),
PeopleItem(),
PeopleItem(),
PeopleItem(),
PeopleItem(),
PeopleItem(),
PeopleItem(),
PeopleItem(),
PeopleItem(),
PeopleItem(),
PeopleItem(),
PeopleItem(),
PeopleItem()
],
)
)
);
}
}
class PeopleItem extends StatelessWidget {
const PeopleItem({super.key});
@override
Widget build(BuildContext context) {
return Row(
children: [
Icon(Icons.account_circle, size: 70, ),
Text("홍길동",
style: TextStyle(fontSize: 20,),)],
);
}
}
<결과물>