본문 바로가기

Flutter/12 Clone 'Used Goods app'

[Flutter] Clone - 당근마켓26(InputScreen - layout/사진추가)

이번에는 InputScreen 에 필요한 layout 을 구현해보겠습니다.

개발환경 : 윈도우11, 안드로이드 스튜디오, flutter 3.0.1

 

 

 

오늘 구현한 화면은 아래와 같습니다. 단계별로 변경된 부분입니다.

오른쪽 마지막 캡쳐가 오늘의 최종버전입니다.

 

 

 

 

./src/screens/input/multi_image_select.dart - 상단의 사진 관련 부분 구현

 

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

import '../../constants/common_size.dart';

class MultiImageSelect extends StatefulWidget {
  const MultiImageSelect({Key? key}) : super(key: key);

  @override
  State<MultiImageSelect> createState() => _MultiImageSelectState();
}

class _MultiImageSelectState extends State<MultiImageSelect> {

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (BuildContext context, BoxConstraints constraints) {
        Size _size = MediaQuery.of(context).size;
        var imgSize = (_size.width / 3) - padding_16 * 2;

        return SizedBox(
          height: _size.width / 3,
          child: ListView(
            // 기본 스크롤 방향을 위/아래 에서 좌/우로 변경해줌,
            // 사이즈를 강제로 설정해야 함. 그래서 SizedBox 로 wrapping,
            scrollDirection: Axis.horizontal,
            children: <Widget>[
              Padding(
                // 패딩 - 여기서는 전체를 16으로 처리해서 아래는 위/아래/오른쪽만 16 처리할 것,
                padding: const EdgeInsets.all(padding_16),
                child: InkWell(
                  onTap: () async {
                  },
                  child: Container(
                    width: imgSize,
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(padding_16),
                      border: Border.all(color: Colors.grey, width: 1),
                    ),
// 첫번째 사진 아이콘 부분 구현 
                    child: Column(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: [
                              const Icon(Icons.camera_alt_rounded, color: Colors.grey),
                              Text('0/10', style: Theme.of(context).textTheme.subtitle2),
                            ],
                          ),
                  ),
                ),
              ),
// 중복되는 사진 부분 구현
// ... 으로 시작하면 기존 리스트에 새로운 결과(List.generate 결과)를 추가할 수 있다.
              ...List.generate(
                20,
                (index) => Padding(
                  // 패딩 - 위에서 전체를 16으로 처리해서 여기서는 위/아래/오른쪽만 16 처리할 것,
                  padding:
                      const EdgeInsets.only(right: padding_16, top: padding_16, bottom: padding_16),
                  child: ExtendedImage.network(
                    'https://picsum.photos/200',
                    width: imgSize,
                    height: imgSize,
                    fit: BoxFit.cover,
                    // shape 을 지정해야만 borderRadius 설정이 정상 동작함,
                    borderRadius: BorderRadius.circular(padding_16),
                    shape: BoxShape.rectangle,
                  ),
                ),
              ),
            ],
          ),
        );
      },
    );
  }
}

 

 

 

./src/screens/input/input_screen.dart - MultiImageSelect() 클래스 호출

 

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

import 'multi_image_select.dart';

import '../../constants/common_size.dart';

class InputScreen extends StatefulWidget {
  const InputScreen({Key? key}) : super(key: key);

  @override
  _InputScreenState createState() => _InputScreenState();
}

class _InputScreenState extends State<InputScreen> {
  final dividerCustom = Divider(
    height: 1,
    thickness: 1,
    color: Colors.grey[350],
    indent: padding_16,
    endIndent: padding_16,
  );

  bool isCreatingItem = false;

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (BuildContext context, BoxConstraints constraints) {
        Size _size = MediaQuery.of(context).size;

        return IgnorePointer(
          ignoring: isCreatingItem,
          child: Scaffold(
            appBar: AppBar(
              centerTitle: true,
              // leading 을 통해서 back 버튼을 "뒤로" 버튼으로 대체할 수 있음.
              leading: TextButton(
                onPressed: () {
                  debugPrint('뒤로가기 버튼 클릭');
                  Get.back();
                  // context.beamBack();
                },
                style: TextButton.styleFrom(
                  primary: Colors.black,
                  // backgroundColor 는 기본으로 흰색으로 설정되어 있음,
                  backgroundColor: Theme.of(context).appBarTheme.backgroundColor,
                ),
                child: Text(
                  '뒤로',
                  style: Theme.of(context).textTheme.bodyText1,
                ),
              ),
              bottom: PreferredSize(
                preferredSize: Size(_size.width, 2),
                child: isCreatingItem? const LinearProgressIndicator(minHeight: 2,) : Container(),
              ),
              actions: <Widget>[
                TextButton(
                  onPressed: (){}, //attemptCreateItem,
                  style: TextButton.styleFrom(
                    primary: Colors.black,
                    backgroundColor: Theme.of(context).appBarTheme.backgroundColor,
                  ),
                  child: Text(
                    '완료',
                    style: Theme.of(context).textTheme.bodyText1,
                  ),
                ),
              ],
              title: Text(
                '중고거래 등록',
                style: Theme.of(context).textTheme.headline6,
              ),
            ),
            // 컬럼으로 안하고 ListView 로 하는 이유는 스크롤 기능이 필요해서,
            body: ListView(
              children: <Widget>[
                // 멀티 이미지 영역
                const MultiImageSelect(),
                dividerCustom,
              ],
            ),
          ),
        );
      },
    );
  }
}