[Flutter] 내맘대로 위젯 만들기 - Custom Widget, ListView

yunulog·2022년 11월 20일
1

Flutter

목록 보기
7/8
post-thumbnail

레이아웃용 위젯들이 너무 길어진다면 커스텀 위젯(Custom Widget)을 이용하면 된다.

커스텀 위젯

<커스텀 위젯 만드는 순서>

  1. stless + Enter(Tab)
  2. class 작명
  3. return 오른쪽에 축약할 레이아웃 넣기
  4. 원하는 위치에 위젯명() 추가하면 끝
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  
  Widget build(BuildContext context) {

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(),
        body: Widget_name(),
      )
    );
  }
}

// 커스텀 위젯
class Widget_name extends StatelessWidget {
  const Widget_name({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return SizedBox (
      child: Text('안녕하세오 커스텀위젯이에오'),
    );
  }
}

<커스텀 위젯 문법 정리>

line1
class: 위젯은 class로 만듦
extends: 오른쪽 클래스를 복사하는 코드(복사해서 쓰면 코드 쓰기 간편해지니까)

line3
@override: extends 코드로 기존 클래스를 복붙해서 위젯을 만들다보면 기존 클래스와 중복되는 부분이 생기는데 이 때 “내꺼 먼저 써주세요”라고 요청하는 코드

line4
build: build라는 함수를 만듦(build라는 함수가 있어야 위젯으로 인정해줌)

변수 이용해서 축약하는 것도 가능하다

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  
  Widget build(BuildContext context) {

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(),
        body: a,
      )
    );
  }
}

var a = SizedBox (
          child: Text('안녕하세오 커스텀위젯이에오'),
        );

위 방법처럼 커스텀 위젯을 정의하지 않고 그냥 변수 a에 담아서 코드를 작성하는 방법도 있다.

변하지 않는 UI(로고, 상단바, 하단바 등)들은 변수에 담아서 써도 상관이 없다.

그러나 변하는 UI(좋아요 개수와 같이 반응형 개체)들은 성능 이슈 위험이 있다.

ListView

앱에 보여줄 항목이 너무 많아지면 하나하나 개체를 만들어주기 힘들어진다.
또한 항목이 많아진다고 해서 스크롤바가 저절로 생기지 않는다.

이 때 사용하는 위젯이 ListView

  • 스크롤바가 생긴다.
  • 스크롤 위치 감시가 편해진다.
  • 메모리 절약이 가능하다 (화면에 나타나지 않는 부분들은 메모리에서 삭제할 수 있음)

ListView 만들기

ListView를 사용해서 아래와 같은 연락처 목록을 만들어보려고 한다.

ListTile 항목 만들기

우선 ListTile을 이용해서 항목 하나를 구성해준다.

ListTile _tile(String title, String subtitle) => ListTile(
  title: Text(title),
  subtitle: Text(subtitle),
  leading: Image.network("https://randomuser.me/api/portraits/women/10.jpg")
);

ListTile 오른쪽에는 클래스 이름을 설정해준다(_tile)

클래스 이름 오른쪽에는 사용할 데이터를 데이터 타입과 함께 정의해준다. 위에서는 titlesubtitle 두가지 데이터를 넣어 사용할 것이다.

화살표(=>)를 이용해 ListTile 클래스로 연결시켜주고 여기서도 데이터를 한 줄 한 줄 정의해준다.

마지막 줄에 leading항목 왼쪽에 해당 개체를 넣을 것임을 의미한다.
Image.network이미지 주소를 이용해서 이미지 개체를 추가할 때 쓰인다.
(이미지는 Random User Generator | Home 링크에서 복붙해왔다)

여기까지 하면 다음과 같은 항목 하나가 만들어진다.
(title은 ‘안녕하세요’, subtitle은 ‘반가워요’로 설정된 상태)

Widget 으로 앱에 항목 보여주기

위와 같이 항목을 만들었으면 이를 화면에 보여주어야 한다.

이때 Widget을 만들어서 화면에 보여주면 코드가 깔끔해진다.

Widget _buildList() => ListView(
  children: [
    _tile("안녕하세요", "반가워요"),
  ],
);

Widget 오른쪽에는 위젯 이름을 설정해준다.

화살표(=>)로 ListView로 연결시켜준다음 children 아래에 위에서 만든 ListTile 항목(_tile)을 연결시켜주면 끝

이제 위 항목을 여러개 붙여넣으면 다음과 같이 연락처 목록 완성

Widget _buildList() => ListView(
  children: [
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
  ],
);

ClipRRect 이미지 둥글게 만들기

ClipRRect를 이용하면 이미지를 둥글게 만들 수 있다.

ClipRRect _userImage(String url) => ClipRRect(
  borderRadius: BorderRadius.circular(100),
  child:Image.network(url)
);

ListTile을 정의할 때 처럼 ClipRRect 오른쪽에는 클래스 이름과 데이터를 정의해준다.

borderRadius를 이용해서 이미지를 둥글게 만들어준다.

child 아래에는 Image.network(url) 코드로 이미지를 넣는다. url 부분에는 이미지 주소 데이터가 입력된다.

final 이미지 랜덤으로 바꾸기

그리고 처음 사진처럼 여러개의 이미지를 랜덤으로 뿌려주기 위해서는 final 코드를 이용한다.

final images = [
  "https://randomuser.me/api/portraits/women/10.jpg",
  "https://randomuser.me/api/portraits/women/11.jpg",
  "https://randomuser.me/api/portraits/women/14.jpg",
  "https://randomuser.me/api/portraits/women/13.jpg",
  "https://randomuser.me/api/portraits/women/24.jpg",
  "https://randomuser.me/api/portraits/men/14.jpg",
  "https://randomuser.me/api/portraits/men/13.jpg",
  "https://randomuser.me/api/portraits/men/24.jpg",
  "https://randomuser.me/api/portraits/men/25.jpg",
  "https://randomuser.me/api/portraits/men/12.jpg",
];

final 오른쪽에 배열 이름을 정의하고 배열에 여러 이미지 주소들을 넣어주면 된다.

그리고 위에서 써준 ListTile 부분을 다음과 같이 수정해준다.

ListTile _tile(String title, String subtitle) => ListTile(
  title: Text(title),
  subtitle: Text(subtitle),
  // leading: _userImage(images[Random().nextInt(images.length)]),
  leading: _userImage(images[Random().nextInt(images.length)]),
);

수정된 부분 : leading: _userImage(images[Random().nextInt(images.length)]),

이미지를 보여줄 때 images 요소에서 랜덤으로 항목을 가져와 이미지로 보여주겠다는 의미이다.
단, Random 함수를 쓰기 위해서는 코드 맨 위에 import 'dart:math'; 를 만드시 써줘야함!

즉, images.length에 해당하는 갯수의 요소에서 랜덤으로 요소를 가져와 _userImage 함수안에 넣어 사용하겠다는 의미

이렇게 하면 다음과 같이 연락처 목록이 완성된다.

전체 코드

import 'package:flutter/material.dart';
import 'dart:math';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  
  Widget build(BuildContext context) {

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("연락처"),),
        body: Center(child: _buildList()),
        bottomNavigationBar: BottomAppBar(),
      ),
    );
  }
}

Widget _buildList() => ListView(
  children: [
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
    _tile("안녕하세요", "반가워요"),
  ],
);

ListTile _tile(String title, String subtitle) => ListTile(
  title: Text(title),
  subtitle: Text(subtitle),
  // leading: _userImage(images[Random().nextInt(images.length)]),
  leading: _userImage(images[Random().nextInt(images.length)]),
);

ClipRRect _userImage(String url) => ClipRRect(
  borderRadius: BorderRadius.circular(100),
  child:Image.network(url)
);

final images = [
  "https://randomuser.me/api/portraits/women/10.jpg",
  "https://randomuser.me/api/portraits/women/11.jpg",
  "https://randomuser.me/api/portraits/women/14.jpg",
  "https://randomuser.me/api/portraits/women/13.jpg",
  "https://randomuser.me/api/portraits/women/24.jpg",
  "https://randomuser.me/api/portraits/men/14.jpg",
  "https://randomuser.me/api/portraits/men/13.jpg",
  "https://randomuser.me/api/portraits/men/24.jpg",
  "https://randomuser.me/api/portraits/men/25.jpg",
  "https://randomuser.me/api/portraits/men/12.jpg",
];

<참조>
개발하는 정대리 플러터 앱만들기 강좌 리스트뷰 - Flutter fundamental Tutorial (2021) - ListView
코딩애플 쉬운 플러터 6강 : 중요한 커스텀 위젯 문법

0개의 댓글