본문 바로가기
Flutter

[flutter 20] shopping_cart_app 만들기

by JINJINC 2025. 1. 13.
728x90
반응형

 쇼핑 카트 앱 만들기 

 

image -> stateFull위젯

container  - >  

 

테스트 코드 만들어 보기

 

테스트 코드 위젯트리 구성

 

 

1단계 > test코드

import 'package:flutter/material.dart';

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

//이벤트가 일어나면 다시 화면을 그려야 한다.(reRendering)
class MyApp extends StatefulWidget {
  MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  //현재시간 상태를 저장하는 변수
  String timeOfDay = '낮';

  @override
  Widget build(BuildContext context) {
    print('전체 build() 메서드 호출 ');
    return MaterialApp(
      home: SafeArea(
        child: Scaffold(
          body: Container(
            color: Colors.blue,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                Expanded(
                  flex: 1,
                  child: InkWell(
                    onTap: () {
                      print('이벤트 리스너 등록');
                      timeOfDay = (timeOfDay == '낮' ? '밤' : '낮');
                      print('현재 상태 값 : ${timeOfDay}');
                      // 화면을 새롭게 갱신하라고 명령해주어야 한다.
                      setState(() {
                        //이 메서드 실행시 build가 다시 호출됨
                        print('화면 다시 그려줘 --> build() 재 호출한다.');
                      });
                    },
                    child: Container(
                      alignment: Alignment.center,
                      color: (timeOfDay == '낮') ? Colors.green : Colors.black,
                      child: Text(
                        timeOfDay,
                        style: TextStyle(
                            fontSize: 25,
                            color: (timeOfDay == '밤'
                                ? Colors.white
                                : Colors.black)),
                      ),
                    ),
                  ),
                ),
                // 이미지
                Expanded(
                  flex: 1,
                  child: FlutterLogo(
                    size: 300,
                    style: FlutterLogoStyle.markOnly,
                    textColor: Colors.red,
                  ),
                )
              ],
            ),
          ),
        ),
      ),
    );
  }
}

2단계 > 화면이 다시 랜더링 되는 부분을 줄여보자 => 리팩토링

import 'package:flutter/material.dart';

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

// 이벤트가 일어 나면 다시 화면을 그려야 한다.
class MyApp extends StatelessWidget {
  MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    print('전체 build() 메서드 호출 : 111111111111111111111111111');
    return MaterialApp(
      home: SafeArea(
        child: Scaffold(
          body: Container(
            color: Colors.blue,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                Expanded(
                  flex: 1,
                  child: TodayWidget(),
                ),
                // 이미지
                Expanded(
                  flex: 1,
                  child: FlutterLogo(
                    size: 300,
                    style: FlutterLogoStyle.markOnly,
                    textColor: Colors.red,
                  ),
                )
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class TodayWidget extends StatefulWidget {
  const TodayWidget({super.key});

  @override
  State<TodayWidget> createState() => _TodayWidgetState();
}

class _TodayWidgetState extends State<TodayWidget> {
  //현재시간 상태를 저장하는 변수
  String timeOfDay = '낮';

  @override
  Widget build(BuildContext context) {
    print('_TodayWidgetState  build() 메서드 호출 ');

    return InkWell(
      onTap: () {
        print('이벤트 리스너 등록');
        timeOfDay = (timeOfDay == '낮' ? '밤' : '낮');
        print('현재 상태 값 : ${timeOfDay}');
        // 화면을 새롭게 갱신하라고 명령해주어야 한다.
        setState(() {
          //이 메서드 실행시 build가 다시 호출됨
          print('화면 다시 그려줘 --> build() 재 호출한다.');
        });
      },
      child: Container(
        alignment: Alignment.center,
        color: (timeOfDay == '낮') ? Colors.green : Colors.black,
        child: Text(
          timeOfDay,
          style: TextStyle(
              fontSize: 25,
              color: (timeOfDay == '밤' ? Colors.white : Colors.black)),
        ),
      ),
    );
  }
}

 

분리한 부분의 buil만 리랜더링 되는것을 볼 수 있다. 

/flutter ( 8276): 전체 build() 메서드 호출 : 111111111111111111111111111
I/flutter ( 8276): _TodayWidgetState  build() 메서드 호출 
D/ProfileInstaller( 8276): Installing profile for com.example.flutter_shopping_cart_app
I/flutter ( 8276): 이벤트 리스너 등록
I/flutter ( 8276): 현재 상태 값 : 밤
I/flutter ( 8276): 화면 다시 그려줘 --> build() 재 호출한다.
I/flutter ( 8276): _TodayWidgetState  build() 메서드 호출 
D/EGL_emulation( 8276): app_time_stats: avg=2834.68ms min=4.58ms max=5664.78ms count=2
I/flutter ( 8276): 이벤트 리스너 등록
I/flutter ( 8276): 현재 상태 값 : 낮
I/flutter ( 8276): 화면 다시 그려줘 --> build() 재 호출한다.
I/flutter ( 8276): _TodayWidgetState  build() 메서드 호출 
I/flutter ( 8276): 이벤트 리스너 등록
I/flutter ( 8276): 현재 상태 값 : 밤
I/flutter ( 8276): 화면 다시 그려줘 --> build() 재 호출한다.
I/flutter ( 8276): _TodayWidgetState  build() 메서드 호출

 

 

 

 쇼핑몰 앱  만들기

순서
1. lib/constants.dart 파일 만들기  
2. lib/theme.dart 파일 만들기
3. main.dart 기본 코드 설계하기
4. 쇼핑카트 헤더 만들기
5. main 앱바 추가
6. 쇼핑카트 바디 만들기

 

 constants.dart

import 'package:flutter/material.dart';

const kPrimaryColor = MaterialColor(
  0xFFeeeeee,
  <int, Color>{
    50: Color(0xFFeeeeee),
    100: Color(0xFFeeeeee),
    200: Color(0xFFeeeeee),
    300: Color(0xFFeeeeee),
    400: Color(0xFFeeeeee),
    500: Color(0xFFeeeeee),
    600: Color(0xFFeeeeee),
    700: Color(0xFFeeeeee),
    800: Color(0xFFeeeeee),
    900: Color(0xFFeeeeee),
  },
);

const kSecondaryColor = Color(0xFFc6c6c6); // 기본 버튼 색
const kAccentColor = Color(0xFFff7643); // 활성화 버튼 색

 thmem.dart   =>  테마 

import 'package:flutter/material.dart';
import 'package:shopping_cart_app/constants.dart';

ThemeData mTheme() {
  return ThemeData(
    primarySwatch: kPrimaryColor,
    scaffoldBackgroundColor: kPrimaryColor,
  );
}

main.dart 기본 코드 설계하기 

import 'package:flutter/material.dart';
import 'package:flutter_shopping_cart_app/components/shopping_cart_header.dart';
import 'package:flutter_shopping_cart_app/pages/shop_cart_page.dart';
import 'package:flutter_shopping_cart_app/theme.dart';

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

class MyApp extends StatelessWidget {
  MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: mTheme(),
      home: ShopCartPage(),
    );
  }
} //end of Page

 

 

쇼핑카트 헤더 만들기

 

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_shopping_cart_app/constants.dart';

class ShoppingCartHeader extends StatefulWidget {
  const ShoppingCartHeader({super.key});

  @override
  State<ShoppingCartHeader> createState() => _ShoppingCartHeaderState();
}

class _ShoppingCartHeaderState extends State<ShoppingCartHeader> {
  // 1. 상태
  int selectId = 0;

  List<String> selectPic = [
    'assets/images/p1.jpeg',
    'assets/images/p2.jpeg',
    'assets/images/p3.jpeg',
    'assets/images/p4.jpeg',
  ];

  //2.상태는 행위를 통해서 변경해야한다.
  void changeSelectId(int sId) {
    setState(() {
      selectId = sId;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        children: [
          AspectRatio(
            aspectRatio: 5 / 3,
            child: Image.asset(
              selectPic[selectId],
              fit: BoxFit.cover,
            ),
          ),
          const SizedBox(height: 25.0),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              _buildHeaderSelectContainer(Icons.pedal_bike, 0),
              _buildHeaderSelectContainer(Icons.motorcycle, 1),
              _buildHeaderSelectContainer(CupertinoIcons.car, 2),
              _buildHeaderSelectContainer(CupertinoIcons.airplane, 3),
            ],
          )
        ],
      ),
    );
  }

  Widget _buildHeaderSelectContainer(IconData micon, int sId) {
    return InkWell(
      child: Container(
        width: 70,
        height: 70,
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(20.0),
          color: (selectId == sId) ? kAccentColor : kSecondaryColor,
        ),
        child: IconButton(
          onPressed: () {
            //메소드로 호출해서 사용함
            changeSelectId(sId);
          },
          icon: Icon(
            micon,
            color: Colors.black,
          ),
        ),
      ),
    );
  }
}

 

main  app바  추가하기 

 

import 'package:flutter/material.dart';
import 'package:flutter_shopping_cart_app/components/shopping_cart_header.dart';

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

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        appBar: _buildAppBar(),
        body: Column(
          children: [
            ShoppingCartHeader(),
          ],
        ),
      ),
    );
  }

  AppBar _buildAppBar() {
    return AppBar(
      leading: IconButton(onPressed: () {}, icon: Icon(Icons.arrow_back)),
      actions: [IconButton(onPressed: () {}, icon: Icon(Icons.shopping_cart))],
    );
  }
} //end of page

 

 

 

 

main  body 부분 

  

import 'package:flutter/material.dart';

class ShoppingCartBody extends StatelessWidget {
  ShoppingCartBody({super.key});

  final List<Color> colorList = [
    Colors.black,
    Colors.green,
    Colors.orange,
    Colors.grey,
    Colors.white
  ];

  @override
  Widget build(BuildContext context) {
    return Expanded(
      flex: 1,
      child: Container(
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.only(
              topLeft: Radius.circular(30.0), topRight: Radius.circular(30.0)),
        ),
        child: Padding(
          padding: const EdgeInsets.all(20.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              _buildBodyNameAndPrice('Urban Soft AL 10.0', '699'),
              _buildBodyRatingAndReviews(4, 20),
              _buildBodyOption(),
              _buildBodyButtonToCart(),
            ],
          ),
        ),
      ),
    );
  } //end of build

  //1.상품의 이름과 가격을 표시
  Widget _buildBodyNameAndPrice(String name, String price) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: [
        Text(
          name,
          style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
        ),
        Text('\$ ${price}'),
      ],
    );
  }

  // 2. 별점 리뷰 카운트
  Widget _buildBodyRatingAndReviews(int rate, int count) {
    return Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
      Row(children: [
        ...List.generate(
          5,
          (index) {
            if (index < rate) {
              return Icon(
                Icons.star,
                color: Colors.amber,
              );
            } else {
              return Icon(Icons.star_border, color: Colors.amber);
            }
          },
        ),
        Spacer(),
        Text('review ( ${count} )'),
      ])
    ]);
  }

  //3. 색상 옵션 선택
  Widget _buildBodyOption() {
    return Column(
      mainAxisAlignment: MainAxisAlignment.start,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text('Color Options'),
        const SizedBox(height: 20.0),
        Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: List.generate(colorList.length,
                (index) => _buildBodyOptionContainer(colorList[index])))
      ],
    );
  }

  //4.색상 옵션 위젯을 만드는 함수
  Widget _buildBodyOptionContainer(Color mcolor) {
    return Padding(
      padding: const EdgeInsets.only(right: 10.0),
      child: Stack(
        children: [
          Positioned(
            child: Container(
              width: 50,
              height: 50,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.all(Radius.circular(50)),
                border: Border.all(color: Colors.black),
              ),
            ),
          ),
          Positioned(
            top: 3,
            left: 3,
            child: Container(
              width: 44,
              height: 44,
              decoration: BoxDecoration(
                color: mcolor,
                borderRadius: BorderRadius.all(Radius.circular(50)),
              ),
            ),
          ),
        ],
      ),
    );
  }

  //5.add to cart 버튼
  Widget _buildBodyButtonToCart() {
    return TextButton(
      style: TextButton.styleFrom(
          backgroundColor: Colors.orange,
          foregroundColor: Colors.white,
          shape:
              RoundedRectangleBorder(borderRadius: BorderRadius.circular(30.0)),
          minimumSize: Size(400, 60)),
      onPressed: () {},
      child: Text('Add to Cart'),
    );
  }
} //end of body

 

 

 

728x90
반응형

'Flutter' 카테고리의 다른 글

[flutter20] CallBack 함수  (0) 2025.01.14
[flutter19] LoginApp 만들기  (0) 2025.01.13
[Flutter00] Flutter 기초다지기3 _ List  (0) 2025.01.08

댓글