반응형
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- typescript
- Babel standalone
- RouteObserver
- Raycasting
- Flutter
- Excel
- react
- Three js
- KakaoMap
- REST API
- userevent_tracker
- Completer
- Redux
- babel
- webrtc
- identifierForVender
- web track
- swagger-typescript-api
- Image Resize typescript
- node
- FirebaseAnalytics
- Game js
- code editor
- uint16array
- Three-fiber
- uint8array
- jszip
- methodChannel
- androidId
- Prism.js
Archives
- Today
- Total
Never give up
Flutter - Stepper with a problem 본문
반응형
material widget들 중 Stepper를 사용해보려고 예제를 만들어봤는데
생각보다 문제가 많은 위젯이란걸 느꼈습니다
소스코드와 함께 이 부분에 대해서 말해보고자 합니다
class StepperExample extends StatefulWidget {
final String title;
StepperExample(this.title);
@override
_StepperExampleState createState() => _StepperExampleState();
}
class _StepperExampleState extends State<StepperExample> {
List<Step> _list = List.generate(
5,
(index) => Step(
title: Text('Step - ${index + 1}'),
content: Text('Blah blah - $index'),
state: StepState.editing));
StreamController<int> _controller = StreamController<int>();
@override
void dispose() {
_controller.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body: StreamBuilder<int>(
stream: _controller.stream,
initialData: 0,
builder: (context, snapshot) {
int step = snapshot.data!;
return Stepper(
steps: _list,
currentStep: snapshot.data!,
onStepCancel: () {
_list[step] = Step(
title: Text('Step - ${step + 1}'),
content: Text('Blah blah - $step'),
state: StepState.error);
if (step <= 0) {
setState(() {});
return;
}
_controller.add(--step);
},
onStepContinue: () {
_list[step] = Step(
title: Text('Step - ${step + 1}'),
content: Text('Blah blah - $step'),
state: StepState.complete);
if (step >= _list.length - 1) {
setState(() {});
return;
}
_controller.add(++step);
},
onStepTapped: (index) => _controller.add(index));
}));
}
}
간단하게 Streambuilder를 이용해서 callback 이벤트에 따라 currentStep과 list를 갱신해주는 예제입니다
근데 여기서 왜 _list[step].state = State.complete 이런식으로 안했는지 궁금하신 분들이 있을텐데
Step class의 내부를 보면 답이 나옵니다
class Step {
const Step({
required this.title,
this.subtitle,
required this.content,
this.state = StepState.indexed,
this.isActive = false,
}) : assert(title != null),
assert(content != null),
assert(state != null);
final Widget title;
final Widget? subtitle;
final Widget content;
final StepState state;
final bool isActive;
}
네 초기화 할때 final로 되어있어서 이후에 변경이 불가능합니다
유저가 continue 혹은 cancel할 때 그 상태를 표시해주려면 새로 초기화를 해줘야된다는 얘기죠
즉 Step의 state를 변경하기 위해 전체를 초기화 해야된다는 말입니다..
다른 개발자분들은 어떻게 사용하는지 보려고 stackoverflow를 찾아봤는데
(링크 : stackoverflow.com/questions/52832710/how-to-modify-a-step-stepstate-on-continue)
가장 표를 많이받으신 분의 소스를 보니
class _State extends State<MyApp> {
int _current;
List<StepState> _listState;
@override
void initState() {
_current = 0;
_listState = [
StepState.indexed,
StepState.editing,
StepState.complete,
];
super.initState();
}
List<Step> _createSteps(BuildContext context) {
List<Step> _steps = <Step>[
new Step(
state: _current == 0
? _listState[1]
: _current > 0 ? _listState[2] : _listState[0],
title: new Text('Step 1'),
content: new Text('Do Something'),
isActive: true,
),
new Step(
state: _current == 1
? _listState[1]
: _current > 1 ? _listState[2] : _listState[0],
title: new Text('Step 2'),
content: new Text('Do Something'),
isActive: true,
),
new Step(
state: _current == 2
? _listState[1]
: _current > 2 ? _listState[2] : _listState[0],
title: new Text('Step 3'),
content: new Text('Do Something'),
isActive: true,
),
];
return _steps;
}
@override
Widget build(BuildContext context) {
List<Step> _stepList = _createSteps(context);
return new Scaffold(
appBar: new AppBar(
title: new Text('Stepper Example'),
),
body: new Container(
padding: new EdgeInsets.all(20.0),
child: new Center(
child: new Column(
children: <Widget>[
Expanded(
child: Stepper(
type: StepperType.vertical,
steps: _stepList,
currentStep: _current,
onStepContinue: () {
setState(() {
if (_current < _stepList.length - 1) {
_current++;
} else {
_current = _stepList.length - 1;
}
//_setStep(context);
});
},
onStepCancel: () {
setState(() {
if (_current > 0) {
_current--;
} else {
_current = 0;
}
//_setStep(context);
});
},
onStepTapped: (int i) {
setState(() {
_current = i;
});
},
),
),
],
),
),
),
);
}
}
이런식으로 사용을 하시는데 이것도 엄청난 낭비 같은데 왜 구조를 이렇게 만들어 놨는지 잘 모르겠습니다
제작자의 의도를 잘 모르겠고, 지금 당장은 좋은 패키지가 있다면 찾아서 쓰는게 훨씬 나을거 같습니다..
반응형
'해왔던 삽질..' 카테고리의 다른 글
Flutter - 첫번째 Package 등록 후기 kakaomap webview (18) | 2021.06.05 |
---|---|
Flutter - Multi image picker with SQFLite (0) | 2021.04.17 |
Flutter 2.0 - How to use previous version(1.22.6) (2) | 2021.03.16 |
Flutter 2.0 - Callback Function (0) | 2021.03.13 |
공지 (feat. Flutter 2.0) (0) | 2021.03.04 |
Comments