imagePicker를 사용하여 갤러리에 있는 image를 가지고 온다.
플러터에서 제공하는 datePicker를 활용하여 달력을 가지고 온다.
dropdownbutton위젯으로 카테고리 선택을 활용한다.
imagePicker 이미지 등록 정리
https://sub1-coding.tistory.com/305
이미지 등록하기
image_picker라이브러리를 사용한다. 다트 파일에 image picker와 dart:io를 임포트해 주자. import 'dart:io'; import 'package:image_picker/image_picker.dart'; 소스코드 import 'dart:io'; import 'package:flutter/foundation.dart'; import
sub1-coding.tistory.com
datePicker 달력정리
https://sub1-coding.tistory.com/304
datePicker 달력
DatePicker는 사용자가 날짜를 선택할 수 있게 해주는 Flutter의 Material 위젯이다. showDatePicker() 함수를 사용하여 달력을 보여준다. Flutter DateTime Picker는 쉽게 사용자가 지정할 수 있고 여러 언어로 날
sub1-coding.tistory.com
dropdown 버튼 정리
https://sub1-coding.tistory.com/297
DropDownButton
카드 결제페이지에서 할부여부 버튼을 누르면 아래와 같이 나오게 할것이다. pubdev에 있는 dropdown_button2 라이브러리 사용한다. 의존성 추가 버튼을 누르면 rebuild해서 보여주기 때문에 statefulwidget
sub1-coding.tistory.com
Provider 상태관리
lessonInsertReqDto
data값을 json으로 직렬화하여 전달해준다.
Map<String, dynamic> toJson() => {
"name": name,
"photo": photo,
"price": price,
"place": place,
"lessonTime": lessonTime,
"lessonCount": lessonCount,
"possibleDays": possibleDays,
"curriculum": curriculum,
"policy": policy,
"deadline": deadline,
"categoryId": categoryId,
// "categoryId": categoryId,
};
service
통신과 파싱을 한다.
Future<ResponseDto> fetchlessonInsert(LessonInsertReqDto lessonReqDto) async {
String requestBody = jsonEncode(lessonReqDto);
Response response = await httpConnector.post(path: "/api/lesson", body: requestBody);
ResponseDto responseDto = toResponseDto(response);
return responseDto;
}
실행화면
코드 실행
import 'dart:convert';
import 'dart:typed_data';
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:finalproject_front/constants.dart';
import 'package:finalproject_front/controller/lesson_controller.dart';
import 'package:finalproject_front/dto/request/lesson_req_dto.dart';
import 'package:finalproject_front/pages/lesson/components/category_period.dart';
import 'package:finalproject_front/size.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';
import 'package:intl/intl.dart';
import 'package:logger/logger.dart';
import 'lesson_deadline.dart';
class LessonInsertForm extends ConsumerStatefulWidget {
final _name = TextEditingController();
final _curriculum = TextEditingController();
final _count = TextEditingController();
final _place = TextEditingController();
final _policy = TextEditingController();
final _dateInput = TextEditingController();
final _time = TextEditingController();
final _price = TextEditingController();
final _possibleDay = TextEditingController();
final _photo = TextEditingController();
LessonInsertForm({Key? key}) : super(key: key);
@override
ConsumerState<LessonInsertForm> createState() => _LessonInsertFormState();
}
class _LessonInsertFormState extends ConsumerState<LessonInsertForm> {
XFile? pickedFile;
ImagePicker imgpicker = ImagePicker();
XFile? _imagefile;
late String profileImage;
// ValueChanged<T> select;
final _formKey = GlobalKey<FormState>();
late ScrollController scrollController;
@override
void initState() {
super.initState();
scrollController = new ScrollController();
}
void _buildShowDatePickerPop() {
Future<DateTime?> selectedDate = showDatePicker(
context: context,
initialDate: DateTime.now(), //초기값
firstDate: DateTime(2020), //시작일
lastDate: DateTime(2023), //마지막일
builder: (BuildContext context, Widget? child) {
return Theme(
data: ThemeData.dark(), //다크 테마
child: child!,
);
},
);
selectedDate.then((dateTime) {
Fluttertoast.showToast(
msg: dateTime.toString(),
toastLength: Toast.LENGTH_LONG,
//gravity: ToastGravity.CENTER, //위치(default 는 아래)
);
});
}
openImages() async {
try {
dynamic sendImage; // 디바이스 경로
var pickedfile = await imgpicker.pickImage(source: ImageSource.gallery);
//you can use ImageCourse.camera for Camera capture
if (pickedfile != null) {
_imagefile = pickedfile;
setState(() {}); // 상태 초기화
sendImage = _imagefile?.path;
final encodeImage = utf8.encode(sendImage);
List<int> data = encodeImage;
String profileImage = base64Encode(data);
Logger().d("레슨 이미지 : ${profileImage}");
return this.profileImage = profileImage;
} else {
print("No image is selected.");
}
} catch (e) {
print("error while picking file.");
}
}
void scrollAnimate() {
Future.delayed(Duration(milliseconds: 600), () {
//0.6초 이후 키보드 올라옴
// ViewInsets은 현재 페이지에서 내가 컨트롤 할 수 없는 영역을 뜻함,
// bottom은 키보드가 아래에서 올라오기 때문
scrollController.animateTo(MediaQuery.of(context).viewInsets.bottom,
duration: Duration(microseconds: 100), // 0.1초 이후 field가 올라간다.
curve: Curves.easeIn); //Curves - 올라갈때 애니메이션
});
}
@override
Widget build(BuildContext context) {
LessonInsertReqDto lessonInsertReqDto = LessonInsertReqDto.origin();
final lessonCT = ref.read(lessonController);
Size size = MediaQuery.of(context).size;
return Form(
key: _formKey,
child: ListView(
children: [
Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
_buildImageUploader(lessonInsertReqDto),
SizedBox(
height: gap_m,
),
_buildTextField(scrollAnimate, fieldTitle: "서비스제목", hint: "서비스 제목자리입니다", lines: 1, fieldController: widget._name, onChanged: (value) {
lessonInsertReqDto.name = value;
}),
SizedBox(height: gap_l),
_buildTextField(scrollAnimate, fieldTitle: "커리큘럼", hint: "상세설명", lines: 6, fieldController: widget._curriculum, onChanged: (value) {
lessonInsertReqDto.curriculum = value;
}),
SizedBox(height: gap_l),
_buildTextField(scrollAnimate, fieldTitle: "수강횟수", hint: "수강횟수를 입력하세요", lines: 1, fieldController: widget._count, onChanged: (value) {
lessonInsertReqDto.lessonCount = int.parse(value);
}),
SizedBox(height: gap_l),
_buildTextField(scrollAnimate, fieldTitle: "수강시간", hint: "수강시간을 입력하세요", lines: 1, fieldController: widget._time, onChanged: (value) {
lessonInsertReqDto.lessonTime = int.parse(value);
}),
SizedBox(height: gap_l),
_buildTextField(scrollAnimate, fieldTitle: "수강장소", hint: "수강장소를 입력하세요", lines: 1, fieldController: widget._place, onChanged: (value) {
lessonInsertReqDto.place = value;
}),
SizedBox(height: gap_l),
_buildTextField(scrollAnimate, fieldTitle: "가격", hint: "가격을 입력하세요", lines: 1, fieldController: widget._price, onChanged: (value) {
lessonInsertReqDto.price = int.parse(value);
}),
SizedBox(height: gap_l),
_buildTextField(scrollAnimate, fieldTitle: "취소 및 환불 정책", hint: "취소 및 환불 정책 작성", lines: 4, fieldController: widget._policy,
onChanged: (value) {
lessonInsertReqDto.policy = value;
}),
SizedBox(height: gap_l),
_buildTextField(scrollAnimate, fieldTitle: "가능일", hint: "가능일을 입력하세요", lines: 1, fieldController: widget._possibleDay,
onChanged: (value) {
lessonInsertReqDto.possibleDays = value;
}),
SizedBox(height: gap_l),
LessonDeadLine(
fieldController: widget._dateInput,
lessonInsertReqDto: lessonInsertReqDto,
),
SizedBox(height: gap_l),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"카테고리선택",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
SizedBox(height: gap_m),
Container(
decoration: BoxDecoration(
border: Border.all(color: gBorderColor, width: 3),
borderRadius: BorderRadius.circular(15),
),
child: DropdownButtonFormField<int?>(
decoration: InputDecoration(
hintText: '카테고리 선택',
enabledBorder: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(15),
),
//마우스 올리고 난 후 스타일
focusedBorder: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(15),
),
),
// underline: Container(height: 1.4, color: Color(0xffc0c0c0)),
onChanged: (int? newValue) {
lessonInsertReqDto.categoryId = newValue;
},
items: [1, 2, 3, 4, 5, 6, 7, 8].map<DropdownMenuItem<int?>>((int? i) {
return DropdownMenuItem<int?>(
value: i,
child: Text({1: '뷰티', 2: '운동', 3: '댄스', 4: '뮤직', 5: '미술', 6: '문학', 7: '공예', 8: '기타'}[i] ?? '미선택'),
);
}).toList(),
),
),
],
),
SizedBox(height: gap_l),
ElevatedButton(
onPressed: () {
Logger().d("레슨 이미지 확인 : ${profileImage}");
lessonInsertReqDto.photo = profileImage;
Logger().d("레슨 이미지 확인 : ${lessonInsertReqDto.photo}");
lessonCT.lessonInsert(lessonInsertReqDto: lessonInsertReqDto);
},
style: ElevatedButton.styleFrom(
primary: gButtonOffColor,
minimumSize: Size(getScreenWidth(context), 60),
),
child: Align(
alignment: Alignment.center,
child: Text(
"클래스 등록하기",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
)
// _buildLessonButton(context)
],
),
),
],
),
);
}
Widget _buildImageUploader(LessonInsertReqDto lessonInsertReqDto) {
return Row(
children: [
//open button ----------------
_imagefile != null
? Container(
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.file(
File(_imagefile!.path),
width: 200,
height: 100,
fit: BoxFit.cover,
),
),
)
: Container(
width: 200,
height: 100,
decoration: BoxDecoration(
border: Border.all(color: gBorderColor),
borderRadius: BorderRadius.circular(10),
),
),
SizedBox(width: gap_m),
Container(
height: 90,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"클래스 사진 등록",
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
SizedBox(
height: 30,
width: 140,
child: ElevatedButton(
onPressed: () {
openImages();
},
style: TextButton.styleFrom(
backgroundColor: gContentBoxColor,
primary: gPrimaryColor,
),
child: Text("이미지 선택",
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
)),
),
),
],
),
),
],
);
}
Widget _buildTextField(Function scrollAnimate,
{required String fieldTitle,
required String hint,
String? subTitle,
required int lines,
required TextEditingController fieldController,
required ValueChanged<String>? onChanged}) {
return Container(
child: Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: Text.rich(
TextSpan(
children: [
TextSpan(
text: "${fieldTitle}",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
if (subTitle != null)
TextSpan(
text: "${subTitle}",
style: TextStyle(color: gSubTextColor, fontSize: 10, fontWeight: FontWeight.bold),
)
],
),
),
),
SizedBox(height: gap_m),
TextFormField(
onTap: (() {
scrollAnimate;
}),
onChanged: onChanged,
controller: fieldController,
keyboardType: TextInputType.multiline,
maxLines: lines,
decoration: InputDecoration(
hintText: "${hint}",
hintStyle: TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
color: gSubTextColor,
),
//3. 기본 textFormfield 디자인 - enabledBorder
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: gClientColor, width: 3.0),
borderRadius: BorderRadius.circular(15),
),
//마우스 올리고 난 후 스타일
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: gClientColor, width: 3.0),
borderRadius: BorderRadius.circular(15),
),
),
),
],
),
);
}
//possibleDays: selectedValue,
Widget _selectCarrer(LessonInsertReqDto lessonInsertReqDto) {
return Container(
child: Column(
children: [
SizedBox(
height: 20,
),
Row(
children: [
Text(
"카테고리 선택",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
],
),
SizedBox(height: 10),
Container(
decoration: BoxDecoration(
border: Border.all(color: gBorderColor, width: 3),
borderRadius: BorderRadius.circular(15),
),
child: selectedCarrerButton(
lessonInsertReqDto: lessonInsertReqDto,
),
width: 400,
height: 60,
)
],
),
);
}
}
'Flutter' 카테고리의 다른 글
카드선택 페이지, 결제 정보 페이지 (0) | 2022.12.21 |
---|---|
클래스 리스트 (0) | 2022.12.21 |
고객센터 페이지, 결제/취소 내역 (0) | 2022.12.20 |
주문하기 페이지 (0) | 2022.12.20 |
검색페이지 (0) | 2022.12.20 |