DevBoi

[Flutter] 팝업 구현 본문

[Mobile]/[Flutter]

[Flutter] 팝업 구현

HiSmith 2023. 8. 26. 20:28
반응형

팝업창은 간혹 필요하여 모듈로 구현하면 편하다.

showDialog(
              context: context,
              barrierDismissible: true, // 바깥 영역 터치시 닫을지 여부
              builder: (BuildContext context) {
                return AlertDialog(
                  content: CreateGroupPopUp(userId: userId),
                  insetPadding: const  EdgeInsets.fromLTRB(0,80,0, 80),
                );
              }
          );

 

단순히 이렇게 하고, content 클래스를 구현해주면 된다.

import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:intl/intl.dart';

import '../../../http/group-httpapi.dart';
import 'group-item.dart';

class CreateGroupPopUp extends StatefulWidget {
  final String userId;

  const CreateGroupPopUp({required this.userId});

  @override
  _CreateGroupPopUpState createState() => _CreateGroupPopUpState(userId);
}

class _CreateGroupPopUpState extends State<CreateGroupPopUp> {
  String userId='';
  _CreateGroupPopUpState(String userId){
    this.userId =userId;
  }
  bool autoValidate = true;
  bool readOnly = false;
  bool showSegmentedControl = true;
  final _formKey = GlobalKey<FormBuilderState>();
  bool _ageHasError = false;
  bool _genderHasError = false;
  bool _titleHasError = false;
  bool _contentHasError = false;
  var genderOptions = ['남자', '여자', '상관없음'];
  void _onChanged(dynamic val) => debugPrint(val.toString());

  @override
  void initState() {
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    return  SingleChildScrollView(
      child: Column(
        children: <Widget>[
          FormBuilder(
            key: _formKey,
            // enabled: false,
            onChanged: () {
              _formKey.currentState!.save();
            },
            autovalidateMode: AutovalidateMode.disabled,
            initialValue: const {
              'gender': '상관없음'
            },
            skipDisabled: true,
            child: Column(
              children: <Widget>[
              FormBuilderTextField(
              autovalidateMode: AutovalidateMode.always,
                name: 'title',
                decoration: InputDecoration(
                  labelText: '제목',
                ),
                onChanged: (val) {
                  setState(() {
                    _titleHasError =
                    !(_formKey.currentState?.fields['title']?.validate() ??
                        false);
                  });
                },
                validator: FormBuilderValidators.compose([
                  FormBuilderValidators.required(errorText: '제목은 필수 값 입니다.'),
                  FormBuilderValidators.max(20,errorText: '제목은 20자 이하여야 합니다.'),
                ]),
                keyboardType: TextInputType.number,
                textInputAction: TextInputAction.next,),

                FormBuilderTextField(
                  maxLines:5,
                  autovalidateMode: AutovalidateMode.always,
                  name: 'content',
                  decoration: InputDecoration(
                    labelText: '본문',
                  ),
                  onChanged: (val) {
                    setState(() {
                      _contentHasError =
                      !(_formKey.currentState?.fields['content']?.validate() ??
                          false);
                    });
                  },
                  // valueTransformer: (text) => num.tryParse(text),
                  validator: FormBuilderValidators.compose([
                    FormBuilderValidators.required(errorText: '내용은 필수 값 입니다.'),
                    FormBuilderValidators.max(500,errorText: '내용은 500자 이하여야 합니다.'),
                  ]),
                  // initialValue: '12',
                  keyboardType: TextInputType.number,
                  textInputAction: TextInputAction.next,),

                FormBuilderDateTimePicker(
                  name: 'date',
                  initialEntryMode: DatePickerEntryMode.calendar,
                  initialValue: DateTime.now(),
                  inputType: InputType.both,
                  format: DateFormat("yyyy-MM-dd hh:mm"),
                  decoration: InputDecoration(
                    icon : const Icon(Icons.access_time,color: Colors.green,),
                    labelText: '시간',
                    suffixIcon: IconButton(
                      icon: const Icon(Icons.close),
                      onPressed: () {
                        _formKey.currentState!.fields['date']?.didChange(null);
                      },
                    ),
                  ),
                  initialTime: const TimeOfDay(hour: 8, minute: 0),
                  // locale: const Locale.fromSubtags(languageCode: 'fr'),
                ),

                const SizedBox(height: 15),

                FormBuilderSlider(
                  name: 'slider',
                  validator: FormBuilderValidators.compose([
                    FormBuilderValidators.min(1,errorText: "인원수는 1명 이상이여야 합니다."),
                  ]),
                  onChanged: _onChanged,
                  min: 0.0,
                  max: 20.0,
                  initialValue: 2.0,
                  divisions: 20,
                  activeColor: Colors.green,
                  inactiveColor: Colors.green[100],
                  decoration: const InputDecoration(
                    icon: const Icon(Icons.people_alt_rounded,color: Colors.green,),
                    labelText: '인원 수',
                  ),
                ),

                FormBuilderDropdown<String>(
                  name: 'gender',
                  decoration: InputDecoration(
                    icon: const Icon(Icons.back_hand_sharp,color: Colors.green,)
                  ),
                  items: genderOptions
                      .map((gender) => DropdownMenuItem(
                    alignment: AlignmentDirectional.center,
                    value: gender,
                    child: Text(gender),
                  ))
                      .toList(),
                  onChanged: (val) {
                    setState(() {
                      _genderHasError = !(_formKey
                          .currentState?.fields['gender']
                          ?.validate() ??
                          false);
                    });
                  },
                  valueTransformer: (val) => val?.toString(),
                ),


                FormBuilderCheckboxGroup<String>(
                  autovalidateMode: AutovalidateMode.onUserInteraction,
                  decoration: const InputDecoration(
                      labelText: '지역',
                    icon: const Icon(Icons.map),
                      iconColor: Colors.green
                  ),
                  name: 'region',
                  // initialValue: const ['Dart'],
                  options: const [
                    FormBuilderFieldOption(value: '서울'),
                    FormBuilderFieldOption(value: '경기'),
                    FormBuilderFieldOption(value: '충청'),
                    FormBuilderFieldOption(value: '전라'),
                    FormBuilderFieldOption(value: '경상'),
                  ],
                  onChanged: _onChanged,
                  separator: const VerticalDivider(
                    width: 10,
                    thickness: 5,
                    color: Colors.red,
                  ),
                  validator: FormBuilderValidators.compose([
                    FormBuilderValidators.minLength(1,errorText: "지역은 1개 이상 선택해야합니다."),
                    FormBuilderValidators.maxLength(3,errorText: "지역은 3개 이하로 선택해야합니다."),
                  ]),
                ),
                FormBuilderFilterChip<String>(
                  autovalidateMode: AutovalidateMode.onUserInteraction,
                  decoration: const InputDecoration(
                      labelText: '소개 태그'),
                  name: 'introduce_tag',
                  selectedColor: Colors.white,
                  options: const [
                    FormBuilderChipOption(
                      value: '요금은 더치',
                    ),
                    FormBuilderChipOption(
                      value: '요금은 주최자',
                    ),
                    FormBuilderChipOption(
                      value: '게임하고 식사도',
                    ),
                    FormBuilderChipOption(
                      value: '게임만',
                    ),
                    FormBuilderChipOption(
                      value: '초보만',
                    ),
                    FormBuilderChipOption(
                      value: '고수만',
                    ),
                  ],
                  onChanged: _onChanged,
                )
              ],
            ),
          ),
          Row(
            children: <Widget>[
              Expanded(
                child: ElevatedButton(
                  onPressed: () {
                    if (_formKey.currentState?.saveAndValidate() ?? false) {
                      debugPrint(_formKey.currentState?.value.toString());
                    } else {
                      debugPrint(_formKey.currentState?.value.toString());
                      debugPrint('validation failed');
                    }
                    String? groupItemString = _formKey.currentState?.value.toString();
                    debugPrint(groupItemString);
                    GroupItem grouItem = GroupItem.fromJson(groupItemString);
                    createGroupAPI(grouItem);
                  },
                  child: const Text(
                    '생성하기',
                    style: TextStyle(color: Colors.white),
                  ),
                ),
              ),
              const SizedBox(width: 20),
            ],
          ),
        ],
      ),
    );
  }
}

 

반응형