Flutter 之 Stepper
  xx2YH4ad7R0N 2023年11月02日 24 0


Stepper 是 flutter 提供的步骤选择器

1. Stepper

1.1 Stepper 介绍

Stepper 定义

const Stepper({
Key? key,
required this.steps,
this.physics,
this.type = StepperType.vertical,
this.currentStep = 0,
this.onStepTapped,
this.onStepContinue,
this.onStepCancel,
this.controlsBuilder,
this.elevation,
this.margin,
})

Stepper 属性

Stepper 属性

介绍

steps

@required List<Step>

physics

滑动的物理效果

type

Stepper 类型,分为横向与纵向两种,默认为 StepperType.vertical

currentStep

当前 step,默认为 0

onStepTapped

step 点击回调函数

onStepContinue

Next 按钮点击回调函数

onStepCancel

Cancel 按钮点击回调函数

controlsBuilder

内容下方按钮构建函数

elevation

阴影 仅在Stepper的type为横向时有效

margin

外边距 仅在Stepper的type为垂直时有效

1.2 Step 介绍

Step 定义

const Step({
required this.title,
this.subtitle,
required this.content,
this.state = StepState.indexed,
this.isActive = false,
})

Step 属性

Step 属性

介绍

title

@required 标题控件

subtitle

副标题控件

content

@required 内容控件

state

当前 step 的状态,StepState 会改变每一个 step 的图标,默认为 StepState.indexed

isActive

是否激活状态,默认为 false,isActive == true 时会变成蓝色

2. Stepper 示例

2.1 垂直方向Stepper

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

@override
State<MSStepperDemo> createState() => _MSStepperDemoState();
}

class _MSStepperDemoState extends State<MSStepperDemo> {
List<MSStepModel> _datas = [];
int _currentStep = 0;
@override
void initState() {
_datas.add(MSStepModel(0, "第一步", "我们先进行第一步"));
_datas.add(MSStepModel(1, "第二步", "我们先进行第二步"));
_datas.add(MSStepModel(2, "第三步", "我们先进行第三步"));
_datas.add(MSStepModel(3, "第四步", "我们先进行第四步"));
_datas.add(MSStepModel(4, "第五步", "我们先进行第五步"));
super.initState();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("StepperDemo")),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Stepper(
currentStep: _currentStep, // 当前步骤
type: StepperType
.vertical, // Stepper 类型,分为横向与纵向两种 默认StepperType.vertical
steps: _getSteps(), // 步骤
//margin: EdgeInsets.all(10), // 自定义外边距 仅在垂直方向 有效
// 继续按钮点击回调函数
onStepContinue: () {
if (_currentStep < _datas.length - 1) {
_currentStep++;
setState(() {});
}
},
// step 点击回调函数
onStepTapped: (index) {
_currentStep = index;
setState(() {});
},
onStepCancel: () {
if (_currentStep > 0) {
_currentStep--;
setState(() {});
}
},
),
),
);
}

List<Step> _getSteps() {
List<Step> steps = [];
_datas.forEach((element) {
// 我们根据当前 step 进行区分,
// 当前 step 之前的认为 StepState.complete,
// 当前认为 StepState.editing,
// 之后认为 StepState.indexed
if (element.index < _currentStep) {
element.state = StepState.complete;
} else if (element.index == _currentStep) {
element.state = StepState.editing;
} else {
element.state = StepState.indexed;
}
steps.add(
Step(
// Step Title
title: Row(
children: [
Icon(Icons.title),
Text(element.title),
],
),
// Step Content
content: Text(element.content),
// 是否激活状态,true 时会变成蓝色
isActive: (_currentStep == _datas.indexOf(element)),
state: element.state,
),
);
});
return steps;
}
}

class MSStepModel {
MSStepModel(this.index, this.title, this.content);
int index;
String title;
String content;
StepState state = StepState.indexed;
}

Flutter 之 Stepper_回调函数

2.2 水平方向Stepper

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

@override
State<MSStepperDemo2> createState() => _MSStepperDemo2State();
}

class _MSStepperDemo2State extends State<MSStepperDemo2> {
List<MSStepModel> _datas = [];
int _currentStep = 0;
@override
void initState() {
_datas.add(MSStepModel(0, "第一步", "我们先进行第一步"));
_datas.add(MSStepModel(1, "第二步", "我们先进行第二步"));
_datas.add(MSStepModel(2, "第三步", "我们先进行第三步"));
_datas.add(MSStepModel(3, "第四步", "我们先进行第四步"));
_datas.add(MSStepModel(4, "第五步", "我们先进行第五步"));
super.initState();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("SteperDemo2")),
body: Padding(
padding: EdgeInsets.all(8),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Container(
width: 600,
child: Stepper(
currentStep: _currentStep, // 当前 Step
steps: _getSteps(), // Steps
type: StepperType.horizontal,
onStepTapped: (index) {
_currentStep = index;
setState(() {});
},
onStepContinue: () {
if (_currentStep < _datas.length - 1) {
_currentStep++;
setState(() {});
}
},
onStepCancel: () {
if (_currentStep > 0) {
_currentStep--;
setState(() {});
}
},
),
),
),
),
);
}

List<Step> _getSteps() {
List<Step> steps = [];
_datas.forEach((element) {
if (element.index < _currentStep) {
element.state = StepState.complete;
} else if (element.index == _currentStep) {
element.state = StepState.editing;
} else {
element.state = StepState.indexed;
}
steps.add(
Step(
title: Row(
children: [
Icon(Icons.title),
Text(element.title),
],
),
content: Text(element.content),
isActive:
_currentStep == _datas.indexOf(element), // 是否激活状态,true 时会变成蓝色
state: element.state, // Step Status
),
);
});
return steps;
}
}

class MSStepModel {
MSStepModel(this.index, this.title, this.content);
int index;
String title;
String content;
StepState state = StepState.indexed;
}

Flutter 之 Stepper_ide_02

 

注意:横向的时候如果内容过多会溢出,这个是跟纵向有区别的,这时候要么减少内容,要么使用滑动组件嵌套,但还还需要嵌套一个已知宽度的父空间

2.3 controlsBuilder

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

@override
State<MSStepperDemo3> createState() => _MSStepperDemo3State();
}

class _MSStepperDemo3State extends State<MSStepperDemo3> {
List<MSStepModel> _datas = [];
int _currentStep = 0;
@override
void initState() {
_datas.add(MSStepModel(0, "第一步", "我们先进行第一步"));
_datas.add(MSStepModel(1, "第二步", "我们先进行第二步"));
_datas.add(MSStepModel(2, "第三步", "我们先进行第三步"));
_datas.add(MSStepModel(3, "第四步", "我们先进行第四步"));
_datas.add(MSStepModel(4, "第五步", "我们先进行第五步"));
super.initState();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("SteperDemo3")),
body: Padding(
padding: EdgeInsets.all(8),
child: Stepper(
currentStep: _currentStep, // 当前 Step
steps: _getSteps(), // Steps
type: StepperType.vertical,
controlsBuilder: (ctx, details) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: details.onStepContinue, child: Text("下一步")),
SizedBox(width: 20),
ElevatedButton(
onPressed: details.onStepCancel, child: Text("上一步")),
],
);
},
onStepTapped: (index) {
_currentStep = index;
setState(() {});
},
onStepContinue: () {
if (_currentStep < _datas.length - 1) {
_currentStep++;
setState(() {});
}
},
onStepCancel: () {
if (_currentStep > 0) {
_currentStep--;
setState(() {});
}
},
),
),
);
}

List<Step> _getSteps() {
List<Step> steps = [];
_datas.forEach((element) {
if (element.index < _currentStep) {
element.state = StepState.complete;
} else if (element.index == _currentStep) {
element.state = StepState.editing;
} else {
element.state = StepState.indexed;
}
steps.add(
Step(
title: Row(
children: [
Icon(Icons.title),
Text(element.title),
],
),
content: Text(element.content),
isActive:
_currentStep == _datas.indexOf(element), // 是否激活状态,true 时会变成蓝色
state: element.state, // Step Status
),
);
});
return steps;
}
}

class MSStepModel {
MSStepModel(this.index, this.title, this.content);
int index;
String title;
String content;
StepState state = StepState.indexed;
}

Flutter 之 Stepper_ico_03

 

3. 技术小结

  • 第一步,我们既然要做一个 Stepper,我们要准备一套数据模型,并且模型包含了状态,标题,内容,下标,等各个元素,然后将这些数据构造出来当做数据源。
  • 第二步,我们创建 Stepper,并对一些属性进行设置。
  • 第三步,我们创建 steps,这里很重要,要根据我们第一步中的数据源,将每一个 model 构造成对应的 Step 控件。
  • 第四步,我们在创建 steps 时,对 model 的状态进行管理,设置编辑中,已完成,未完成等不同状态。
  • 第五步,我们对 Stepper 的交互事件进行处理,点击时将 currentStep 设置到对应 index,cancel 时我们执行 currentStep -1 操作,Next 时我们执行 currentStep +1 操作,此处注意防止越界。

作者:maskerII
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  4koL3J55wyKx   2023年11月13日   38   0   0 icogitCentOS
  b1UHV4WKBb2S   2023年11月13日   37   0   0 裁剪ideflutter
  b1UHV4WKBb2S   2023年11月13日   29   0   0 flutterDart
  zSWNgACtCQuP   2023年11月13日   32   0   0 ide
xx2YH4ad7R0N