Flutter/일반

ν”ŒλŸ¬ν„°(Flutter) νšŒμ›κ°€μž… μ•½κ΄€ λ™μ˜ νŽ˜μ΄μ§€ λ§Œλ“€μ–΄ 보기

Hac. Dog 🌭 2024. 1. 22. 16:38

 

PlayStoreλ‚˜ AppStore μ–΄λŠ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ λ‹€μš΄μ„ 받아도 νšŒμ›κ°€μž… μ•½κ΄€ λ™μ˜ νŽ˜μ΄μ§€λŠ” 많이 봀을 κ²ƒμž…λ‹ˆλ‹€.

μŠ€ν† μ–΄μ— 앱을 μ˜¬λ¦΄λ•Œ νšŒμ›κ°€μž…/둜그인/κ°œμΈμ •λ³΄ λ“± μ‚¬μš©μžμ˜ 정보λ₯Ό λ°›μ•„μ•Ό ν•˜κ²Œ λœλ‹€λ©΄

ν•„μˆ˜μ μœΌλ‘œ κ°œμΈμ •λ³΄μ²˜λ¦¬λ°©μΉ¨μ„ λ„£μ–΄μ•Όλ§Œ μŠΉμΈμ„ ν•΄μ£ΌκΈ° λ•Œλ¬Έμ΄λ‹€. κ·Έλž˜μ„œ 이 νŽ˜μ΄μ§€λ₯Ό μ œμž‘ν•΄ 보렀고 ν•©λ‹ˆλ‹€.

 

λ™μ˜λ₯Ό μœ„ν•œ 총 4개의 μ²΄ν¬λ°•μŠ€λ₯Ό μ œμž‘

ν‰κ· μ μœΌλ‘œ μ²΄ν¬λ°•μŠ€λŠ” 3κ°€μ§€ νƒ€μž…μ˜ μœ ν˜•μ„ λ”°λ‘œ λ§Œλ“€μ–΄ μ£Όμ–΄μ•Ό ν•©λ‹ˆλ‹€.

1. λͺ¨λ‘ λ™μ˜ ( λͺ¨λ“  λ™μ˜λ₯Ό ν•˜λŠ” μ²΄ν¬λ°•μŠ€ )
2. ν•„μˆ˜ λ™μ˜ ( λ°˜λ“œμ‹œ ν•΄μ•Όλ§Œ λ‹€μŒνŽ˜μ΄μ§€ λ„˜μ–΄κ°ˆ 수 μžˆλ‹€. )
3. 선택적 λ™μ˜ ( μ•ˆν•΄λ„ λ‹€μŒ νŽ˜μ΄μ§€λ‘œ λ„˜μ–΄ 갈 수 μžˆλ‹€. )

그리고 λ§Œμ•½ ν•„μˆ˜ λ™μ˜κ°€ μ „λΆ€ 체크가 λ˜μ—ˆλ‹€λ©΄ κ°€μž…ν•˜κΈ° λ²„νŠΌμ΄ ν™œμ„±ν™” λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.

자 그럼 이제 κ΅¬ν˜„ν•΄μ•Όν•˜λŠ” μ›λ¦¬λŠ” λŒ€κ°• μ•Œμ•˜μœΌλ‹ˆ ν•˜λ‚˜μ”© 뜯고 μ”Ήμ–΄ 맛을 λ΄…μ‹œλ‹€.

 


 

1. λͺ¨λ‘ λ™μ˜ λ²„νŠΌ κ΅¬ν˜„ν•˜κΈ°

μ‘°κ±΄λ¬ΈμœΌλ‘œλŠ” 총 4κ°€μ§€ νƒ€μž…μœΌλ‘œ κ°„λ‹¨ν•©λ‹ˆλ‹€.

1. λͺ¨λ‘ λ™μ˜λ₯Ό 눌러 5개 μ²΄ν¬λ°•μŠ€λ₯Ό λͺ¨λ‘ ν™œμ„±ν™” μƒνƒœλ‘œ λ³€κ²½
2. 5개의 μ²΄ν¬λ°•μŠ€κ°€ λͺ¨λ‘ ν™œμ„±ν™” 된 μƒνƒœμΌλ•Œ λͺ¨λ‘ λ™μ˜λ₯Ό λ‹€μ‹œ 눌러 전체 ν•΄μ œ
3. 4개 쀑 1κ°œλΌλ„ 선택이 λ˜μ–΄ μžˆμ§€ μ•Šμ„ 경우 λͺ¨λ‘ λ™μ˜ μ²΄ν¬λ°•μŠ€ ν™œμ„±ν™” ν•΄μ œ
4. 4개 μ²΄ν¬λ°•μŠ€κ°€ μ „λΆ€ 선택이 λ˜μ–΄ μžˆμ„ κ²½μš°μ— λͺ¨λ‘ λ™μ˜ μ²΄ν¬λ°•μŠ€ ν™œμ„±ν™”

 

2. 각각의 μ²΄ν¬λ°•μŠ€ λ²„νŠΌ κ΅¬ν˜„ν•˜κΈ°

 

각각의 μ²΄ν¬λ°•μŠ€λŠ” 총 3κ°€μ§€ 쑰건문으둜 이루어지면 λ©λ‹ˆλ‹€.

1. λ²„νŠΌμ„ ν΄λ¦­ν–ˆμ„ μ‹œ toggle (ON / OFF)
2. ν•„μˆ˜ λ²„νŠΌμ΄ μ „λΆ€ 체크가 λ˜μ—ˆμ„ μ‹œ κ°€μž…ν•˜κΈ° λ²„νŠΌ ν™œμ„±ν™”
3. λͺ¨λ‘ λ™μ˜ λ²„νŠΌμ„ ν΄λ¦­ν•΄μ„œκ°€ μ•„λ‹Œ 각각의 λ²„νŠΌμ„ λˆŒλŸ¬μ„œ λͺ¨λ‘ 체크가 λ˜μ—ˆμ„ μ‹œ λͺ¨λ‘ λ™μ˜ λ²„νŠΌ ν™œμ„±ν™”

 

일단 이둜써 λ²„νŠΌμ˜ 트리거 뢀뢄은 λλ‚¬μŠ΅λ‹ˆλ‹€.

이제 UIλ₯Ό λ§Œλ“€λ©΄μ„œ 이 트리거 λΆ€λΆ„λ§Œ 잘 μƒκ°ν•˜λ©΄μ„œ λ§Œλ“€λ©΄ λμž…λ‹ˆλ‹€. 이제 μ†ŒμŠ€ μ½”λ“œλ₯Ό λ΄…μ‹œλ‹€.

 

https://dartpad.dev/?id=753b34cd5a6b6b861be6d1deee8af476

 

DartPad

 

dartpad.dev

 

μœ„ μ½”λ“œλŠ” λ‚΄κ°€ μž‘μ„±ν•œ μ½”λ“œμΈλ° μ­‰ 읽어보면 크게 μ–΄λ €μš΄ 뢀뢄은 μ—†μŠ΅λ‹ˆλ‹€.

ν•œκ°€μ§€ λΆ€λΆ„λ§Œ μ„€λͺ…ν•˜μžλ©΄ 각 λ²„νŠΌμ„ 클릭 ν• λ•Œλ§ˆλ‹€ μ‹€ν–‰λ˜λŠ” _updateCheckState(int index)κ°€ μžˆμŠ΅λ‹ˆλ‹€.

void _updateCheckState(int index) {
    setState(() {
      // λͺ¨λ‘ λ™μ˜ μ²΄ν¬λ°•μŠ€μΌ 경우
      if (index == 0) {
        bool isAllChecked = !_isChecked.every((element) => element);
        _isChecked = List.generate(5, (index) => isAllChecked);
      } else {
        _isChecked[index] = !_isChecked[index];
        _isChecked[0] = _isChecked.getRange(1, 5).every((element) => element);
      }
    });
  }

 

if(index == 0) /  "λͺ¨λ‘ λ™μ˜" 체크 λ°•μŠ€ 처리
1. _isChecked 리슀트의 λͺ¨λ“  ν•­λͺ©μ΄ μ²΄ν¬λ˜μ—ˆλŠ”μ§€ κ²€μ‚¬ν•©λ‹ˆλ‹€. λͺ¨λ‘ μ²΄ν¬λ˜μ–΄ μžˆμ§€ μ•Šλ‹€λ©΄ isAllCheckedλŠ” trueκ°€ λ©λ‹ˆλ‹€.
2. _isChecked 리슀트λ₯Ό isAllChecked κ°’μœΌλ‘œ μž¬μ„€μ •ν•©λ‹ˆλ‹€. 즉, 'λͺ¨λ‘ λ™μ˜' μ²΄ν¬λ°•μŠ€κ°€ μ„ νƒλ˜λ©΄ λͺ¨λ“  μ²΄ν¬λ°•μŠ€κ°€ μ„ νƒλ˜κ³ , ν•΄μ œλ˜λ©΄ λͺ¨λ“  μ²΄ν¬λ°•μŠ€κ°€ ν•΄μ œλ©λ‹ˆλ‹€.

else (index != 0)
1. μ„ νƒλœ μ²΄ν¬λ°•μŠ€μ˜ μƒνƒœλ₯Ό ν† κΈ€ν•©λ‹ˆλ‹€ (trueλ©΄ false둜, falseλ©΄ true둜).
2. getRange(1, 5)λ₯Ό μ‚¬μš©ν•˜μ—¬ 'λͺ¨λ‘ λ™μ˜' μ²΄ν¬λ°•μŠ€λ₯Ό μ œμ™Έν•œ λ‚˜λ¨Έμ§€ μ²΄ν¬λ°•μŠ€κ°€ λͺ¨λ‘ μ„ νƒλ˜μ–΄ μžˆλŠ”μ§€ ν™•μΈν•©λ‹ˆλ‹€. λͺ¨λ‘ μ„ νƒλ˜μ–΄ μžˆλ‹€λ©΄ 'λͺ¨λ‘ λ™μ˜' μ²΄ν¬λ°•μŠ€λ„ μ„ νƒλ©λ‹ˆλ‹€.

 

μ—¬κΈ°μ„œ List.generate() 뢀뢄이 뭐냐!? 라고 ν•˜μ‹€ 수 μžˆλŠ”λ° μ²΄ν¬λ°•μŠ€λ₯Ό List ν˜•νƒœλ‘œ 5개λ₯Ό λ§Œλ“€κΈ° μœ„ν•΄ μ‚¬μš©ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

즉 0 - 4 κΉŒμ§€ μˆœμ„œλŒ€λ‘œ

0. λͺ¨λ‘ λ™μ˜ / 1. 만 14μ„Έ 이상 / 2. κ°œμΈμ •λ³΄μ²˜λ¦¬λ°©μΉ¨ / 3. μ„œλΉ„μŠ€ 이용 μ•½κ΄€ / 4. 이벀트 및 할인 ν˜œνƒ..

μ΄λ ‡κ²Œ μƒκ°ν•˜κ³  μ΄ν•΄ν•˜λ©΄ λ©λ‹ˆλ‹€.

 


일단 λ‚΄κ°€ ν•  수 μžˆμ„ 만큼 κ°„λ‹¨ν•˜κ²Œ μ„€λͺ…은 ν•˜μ˜€λŠ”λ° ν˜Ήμ‹œ 이해가 μ•ˆλ˜λŠ” 뢀뢄은 λŒ“κΈ€λ‘œ 남겨μ£ΌκΈ° λ°”λžλ‹ˆλ‹€.

 

전체 μ½”λ“œ
μ½”λ“œ 보기
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(
        theme: ThemeData(
          scaffoldBackgroundColor: Colors.white, // κΈ°λ³Έ 배경색은 ν•˜μ–€μƒ‰μœΌλ‘œ μ„€μ •
          appBarTheme: const AppBarTheme(
            backgroundColor: Colors.white,
            elevation: 0,
          ),
        ),
        debugShowCheckedModeBanner: false,
        home: const TermsOfServiceAgreement(),
      );
    }
  }


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

    @override
    State<TermsOfServiceAgreement> createState() => _TermsOfServiceAgreementState();
  }

  class _TermsOfServiceAgreementState extends State<TermsOfServiceAgreement> {
    List<bool> _isChecked = List.generate(5, (_) => false);

    bool get _buttonActive => _isChecked[1] && _isChecked[2] && _isChecked[3];

    void _updateCheckState(int index) {
      setState(() {
        // λͺ¨λ‘ λ™μ˜ μ²΄ν¬λ°•μŠ€μΌ 경우
        if (index == 0) {
          bool isAllChecked = !_isChecked.every((element) => element);
          _isChecked = List.generate(5, (index) => isAllChecked);
        } else {
          _isChecked[index] = !_isChecked[index];
          _isChecked[0] = _isChecked.getRange(1, 5).every((element) => element);
        }
      });
    }

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          leading: IconButton(
            onPressed: () {
              Navigator.of(context).pop();
            },
            icon: const Icon(
              Icons.arrow_back_ios_new_rounded,
              color: Colors.black,
            ),
          ),
        ),
        body: Padding(
          padding: const EdgeInsets.all(18.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Text('νšŒμ›κ°€μž… μ•½κ΄€ λ™μ˜', style: TextStyle(fontSize: 25.0, fontWeight: FontWeight.w700)),
              const SizedBox(height: 50),
              ..._renderCheckList(),
              const Spacer(),
              Row(
                children: [
                  Expanded(
                    child: ElevatedButton(
                      style: ElevatedButton.styleFrom(
                        backgroundColor: _buttonActive ? Colors.blue : Colors.grey,
                      ),
                      onPressed: () {},
                      child: const Text('κ°€μž…ν•˜κΈ°',style: TextStyle(color: Colors.white),),
                    ),
                  ),
                ],
              ),
            ],
          ),
        ),
      );
    }

    List<Widget> _renderCheckList() {
      List<String> labels = [
        'λͺ¨λ‘ λ™μ˜',
        '만 14μ„Έ μ΄μƒμž…λ‹ˆλ‹€.(ν•„μˆ˜)',
        'κ°œμΈμ •λ³΄μ²˜λ¦¬λ°©μΉ¨(ν•„μˆ˜)',
        'μ„œλΉ„μŠ€ 이용 μ•½κ΄€(ν•„μˆ˜)',
        '이벀트 및 할인 ν˜œνƒ μ•ˆλ‚΄ λ™μ˜(선택)',
      ];

      List<Widget> list = [
        renderContainer(_isChecked[0], labels[0], () => _updateCheckState(0)),
        const Divider(thickness: 1.0),
      ];

      list.addAll(List.generate(4, (index) => renderContainer(_isChecked[index + 1], labels[index + 1], () => _updateCheckState(index + 1))));

      return list;
    }

    Widget renderContainer(bool checked, String text, VoidCallback onTap) {
      return GestureDetector(
        onTap: onTap,
        child: Container(
          padding: const EdgeInsets.only(top: 20.0, bottom: 20.0),
          color: Colors.white,
          child: Row(
            children: [
              Container(
                decoration: BoxDecoration(
                  shape: BoxShape.circle,
                  border: Border.all(color: checked ? Colors.blue : Colors.grey, width: 2.0),
                  color: checked ? Colors.blue : Colors.white,
                ),
                child: Icon(Icons.check, color: checked ? Colors.white : Colors.grey, size: 18),
              ),
              const SizedBox(width: 15),
              Text(text, style: const TextStyle(color: Colors.grey, fontSize: 18)),
            ],
          ),
        ),
      );
    }
  }