Flutter

[Flutter] 탭으로 페이지 나누는 법 (사진 추가, ListView)

hminor 2023. 8. 9. 15:32

탭으로 페이지 나누는 법

  • 페이지 나누는 방법
    • Navigator
    • Router
    • Tab
  • 동적인 UI 만드는 방법
    • State 만들기
      • State에 현재 UI의 상태를 저장
    • 화면 구현
      • State에 따라 Tab이 어떻게 보일지 작성
    • UX 경험 반영
      • 유저가 쉽게 State 조작을 할 수 있도록 작성
  • 구현
    1. 우선 state를 만들고 추후 변형 될 것을 위해 statefull 한 클래스로 변경
    2. 변수 생성 후 현재 상태 값을 넣어주기
    3. 보여질 값을 작성
    4. state 변경 함수 작성
    5. 이후 현재 만들어 둔 BottomNavigationBar 에는 onPress가 없기에 onTap으로 state 변경 함수를 적용하기
      • 여기서 파라미터 값을 추가해주고, 해당 파라미터 값은 items에 있는 버튼들의 종류를 의미
import 'package:flutter/material.dart';
import './style.dart' as style;
void main() {
  runApp(
    MaterialApp(
      theme: style.theme,
      home: MyApp()
    )
  );
}

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

class _MyAppState extends State<MyApp> {

  // 0: home, 1: shop
  var tab = 1;

  changeTab(tabNumber){
    setState(() {
      tab = tabNumber;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Instagram'),
          actions: [
            IconButton(
              onPressed: (){},
              icon: Icon(Icons.add_box_outlined)
            )
          ],
        ),
      bottomNavigationBar: BottomNavigationBar(
        onTap: (i){
          changeTab(i);
        },
        items: [
          BottomNavigationBarItem(
            icon: Icon(Icons.home_outlined),
            label: 'Home',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.shopping_bag_outlined),
            label: 'Shopping',
          ),
        ],
        showSelectedLabels: false, 
        showUnselectedLabels: false, 
      ),
    );
  }
}

숙제

인스타그램 게시글을 커스텀 클래스를 만들어 총 3개 구현해오기

구현시 ListView를 사용해보면 편할듯?

  • 우선 지난 수업 과정에서 했었던
    • 사진 첨부하는 방법에 대해 잊어버려서 다시 공부
      • pubspec.yaml과 같은 경로에 assets 폴더 생성
        • 이후 원하는 이미지 파일 첨부
      • pubspec.yaml 안에 assets를 주석 해제 후 아래에 파일과 경로를 작성해주기
        • - assets/cat.jpg
      • 이후 상단에 Pub get을 눌러 완료 후
      • 사용하고자 하는 곳에 Image.assets(’경로’) 를 작성해주면 됨.
        • 여기서 assets 폴더 하나만 있는 경우엔 assets/cat.png가 아니라 cat/.png 만 작성해야 된다.
      • 그리고 이미지 경로를 첨부하고 싶다면
        • Image.network('경로')를 해주면 된다.
    • 하나의 위젯 또는 클래스를 반복해서 생성하고자 할 경우 사용할 ListView
      • ListView.builder() 위젯을 생성 후
        • itemCount로 반복 생성할 횟수
        • itemBuilder로 메서드를 작성 후 보여줄 것을 return 해주기
          • 2개의 인자 값이 필요하기에 context와 idx를 추가 
import 'package:flutter/material.dart';
import './style.dart' as style;
void main() {
  runApp(
    MaterialApp(
      theme: style.theme,
      home: MyApp()
    )
  );
}



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

class _MyAppState extends State<MyApp> {

  // 0: home, 1: shop
  var tab = 1;

  changeTab(tabNumber){
    setState(() {
      tab = tabNumber;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Instagram'),
          actions: [
            IconButton(
              onPressed: (){},
              icon: Icon(Icons.add_box_outlined)
            )
          ],
        ),
      body: [Home(),Text('shop')][tab],
      bottomNavigationBar: BottomNavigationBar(
        onTap: (i){
          changeTab(i);
        },
        items: [
          BottomNavigationBarItem(
            icon: Icon(Icons.home_outlined),
            label: 'Home',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.shopping_bag_outlined),
            label: 'Shopping',
          ),
        ],
        showSelectedLabels: false, // 선택된 아이템의 레이블 숨김
        showUnselectedLabels: false, // 선택되지 않은 아이템의 레이블 숨김
      ),
    );
  }
}

class Home extends StatelessWidget {
  const Home({super.key});

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
        itemCount: 3,
        itemBuilder: (context, idx){
          return Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Image.asset('cat.jpg'),
              Container(
                margin: EdgeInsets.fromLTRB(10, 20, 10, 20),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Row(
                      children: [
                        Text('좋아요'),
                        Text('100'),
                      ],
                    ),
                    Text('글쓴이'),
                    Text('글내용'),
                  ],
                ),
              )
            ],
          );
        },
    );
  }
}