Flutter 颤振:如何创建xy栅格以将图标精确定位在需要的位置
我想创建一个移动的水平滑块,跟踪任务的“进度”,并在滑块上方放置图标,指示进度点的某些里程碑。到目前为止,我已尝试使用TimeLineFile小部件移动滑块:Flutter 颤振:如何创建xy栅格以将图标精确定位在需要的位置,flutter,flutter-layout,Flutter,Flutter Layout,我想创建一个移动的水平滑块,跟踪任务的“进度”,并在滑块上方放置图标,指示进度点的某些里程碑。到目前为止,我已尝试使用TimeLineFile小部件移动滑块: Container( margin: const EdgeInsets.all(8), constraints: const BoxConstraints( maxHeight: 50, ), width: screenWidth, child: TimelineTile(
Container(
margin: const EdgeInsets.all(8),
constraints: const BoxConstraints(
maxHeight: 50,
),
width: screenWidth,
child: TimelineTile(
axis: TimelineAxis.horizontal,
alignment: TimelineAlign.end,
indicatorStyle: IndicatorStyle(
indicatorXY: currProgress / 1.0, //currProgress is a double from 0.0 to 1.0 updated by a setState elsewhere in the code
),
),
),
我知道我可以将其包装在一列中,并在其上方放置一行,其中包含一系列大小的框和图标,但如果能够从数据库中定位动态数量的图标及其位置,这是不准确和非常不混乱的,例如
child: Row(
children: [
SizedBox(
width: screenWidth * .2,
),
Icon(Icon(Icons.email,
color: Colors.purple),
),
SizedBox(width: screenWidth * .35),
Icon(Icon(Icons.email,
color: Colors.purple),
),
SizedBox(width: screenWidth * .2),
],
),
我已经查看了gridview,但它似乎需要填充每个网格,所以这不起作用。
我研究过谷歌图表和syncfusion笛卡尔图表,它们可以让我在两行双基网格上定位点,比如(0.2,0.0)和(0.35,1.0),但它们非常笨重,过于复杂,除了简单的圆圈之类的图标,似乎不允许使用,但有人可能比我更了解
最后,我尝试使用FixedTrackSize选项创建一个分辨率非常小的网格,如果用户感觉不到图标的位置是0.3或0.4(让我们将分辨率设为十分之一),而数据实际显示为0.34或0.41,我可以接受它
我希望这是有道理的。要说我只想要两行信息,需要写很多文章:
A.一个沿屏幕水平移动的点,该点由变量的设置状态递增(在上面的TimeLineFile示例中为currogress,但是如果某种网格可以工作,我可能不需要使用timelineTime)。以及,
B另一行显示从数据库动态读取的图标列表,在该行中,只有数据读取该列表时,您才知道该列表是什么。因此,数据的示例列表可以是:
//图标、位置
Icons.email,x=0.35
图标。飞机,x=0.54
等
其中x=0.0到1.0,但可以使用一些合理的分辨率水平,而不是精确到两倍精度,只要它在应用程序屏幕上看起来非常接近
谢谢你们,你们都很好 如果我理解正确,你想要这样的东西
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage();
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<IconData> stageIcons = [
Icons.send,
Icons.email,
Icons.done
];
double curProgress = -1.0;
final iconSize = 20.0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Demo"),
),
body: Padding(
padding: const EdgeInsets.all(32.0),
child: Stack(
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: iconSize, vertical: iconSize),
child: LinearProgressIndicator(
minHeight: 5,
value: curProgress,
backgroundColor: Colors.blue[100],
valueColor: AlwaysStoppedAnimation<Color>(Colors.blue),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children:
List.generate(stageIcons.length, (index) { // hack, like list.map((element, index) {...})
double stageProgress;
if (index == 0) {
stageProgress = 0.0;
} else if (index == stageIcons.length) {
stageProgress = 1.0;
} else {
stageProgress = (1 / (stageIcons.length - 1)) * index;
}
print("$curProgress $stageProgress ${(stageProgress >= curProgress)}");
final iconColor = (stageProgress <= curProgress) ? Colors.blue : Colors.blue[100];
return CircleAvatar(
radius: iconSize,
backgroundColor: iconColor,
child: Icon(stageIcons[index], color: Colors.white, size: iconSize),
);
}),
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed:
(curProgress > 0.0 && curProgress < 1.0) ? null // disable button if in progress
: () async {
for (var i = 1; i < 11; i++) {
await Future.delayed(Duration(milliseconds: 500));
setState(() {
curProgress = i / 10;
});
}
},
child: Icon(Icons.play_arrow),
),
);
}
}
导入“包装:颤振/材料.省道”;
void main(){
runApp(MyApp());
}
类MyApp扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回材料PP(
标题:“演示”,
主题:主题数据(
主样本:颜色。蓝色,
视觉密度:视觉密度。自适应平台密度,
),
主页:MyHomePage(),
);
}
}
类MyHomePage扩展StatefulWidget{
我的主页();
@凌驾
_MyHomePageState createState()=>\u MyHomePageState();
}
类_MyHomePageState扩展状态{
列表阶段图标=[
Icons.send,
Icons.email,
完成
];
双curProgress=-1.0;
最终iconSize=20.0;
@凌驾
小部件构建(构建上下文){
返回脚手架(
appBar:appBar(
标题:文本(“演示”),
),
主体:填充物(
填充:常数边集全部(32.0),
子:堆栈(
儿童:[
容器(
填充:边集。对称(水平:图标大小,垂直:图标大小),
子对象:线性表达式指示器(
身高:5,,
价值:进步,
背景颜色:颜色。蓝色[100],
valueColor:AlwaysStoppedAnimation(颜色.蓝色),
),
),
划船(
mainAxisAlignment:mainAxisAlignment.spaceBetween,
儿童:
generate(stageIcons.length,(index){//hack,像List.map((element,index){…})
双级推进;
如果(索引==0){
阶段进度=0.0;
}else if(索引==stageIcons.length){
阶段进度=1.0;
}否则{
阶段进度=(1/(stageIcons.length-1))*指数;
}
打印($curProgress$stageProgress${(stageProgress>=curProgress)});
最终iconColor=(stageProgress 0.0&&curProgress<1.0)?null//如果正在进行,则禁用按钮
:()异步{
对于(变量i=1;i<11;i++){
等待未来。延迟(持续时间(毫秒:500));
设置状态(){
curProgress=i/10;
});
}
},
子:图标(图标。播放箭头),
),
);
}
}
更新。自定义进度/位置
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class Stage {
final double progress;
final IconData icon;
Stage(this.progress, this.icon);
}
class MyHomePage extends StatefulWidget {
MyHomePage();
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<Stage> stages = [
Stage(0.0, Icons.send),
Stage(0.71, Icons.email),
Stage(1.0, Icons.done)
];
double curProgress = -1.0;
final iconSize = 20.0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Demo"),
),
body: Padding(
padding: const EdgeInsets.all(32.0),
child: Stack(
alignment: Alignment.center,
children: [
[Container(
padding: EdgeInsets.symmetric(horizontal: iconSize, vertical: iconSize),
child: LinearProgressIndicator(
minHeight: 5,
value: curProgress,
backgroundColor: Colors.blue[100],
valueColor: AlwaysStoppedAnimation<Color>(Colors.blue),
),
)],
List.generate(stages.length, (index) { // hack, like list.map((element, index) {...})
final stage = stages[index];
final iconColor = (stage.progress <= curProgress) ? Colors.blue : Colors.blue[100];
final position = stage.progress * 2 - 1; // progress from 0.0 to 1.0 and Align.position from -1.0 to 1.0 from center
return Align(
alignment: Alignment(position, 0.0),
child: CircleAvatar(
radius: iconSize,
backgroundColor: iconColor,
child: Icon(stage.icon, color: Colors.white, size: iconSize),
)
);
})
].expand((el) => el).toList(),
),
),
floatingActionButton: FloatingActionButton(
onPressed:
(curProgress > 0.0 && curProgress < 1.0) ? null // disable button if in progress
: () async {
for (var i = 1; i < 11; i++) {
await Future.delayed(Duration(milliseconds: 500));
setState(() {
curProgress = i / 10;
});
}
},
child: Icon(Icons.play_arrow),
),
);
}
}
导入“包装:颤振/材料.省道”;
void main(){
runApp(MyApp());
}
类MyApp扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回材料PP(
标题:“演示”,
主题:主题数据(
主样本:颜色。蓝色,
视觉密度:视觉密度。自适应平台密度,
),
主页:MyHomePage(),
);
}
}
班级阶段{
最终双倍进展;
最终的Iconda图标;
阶段(this.progress,this.icon);
}
类MyHomePage扩展StatefulWidget{
我的主页();
@凌驾
_MyHomePageState createState()=>\u MyHomePageState();
}
类_MyHomePageState扩展状态{
列出阶段=[
阶段(0.0,图标。发送),
阶段(0.71,图标。电子邮件),
阶段(1.0,图标。完成)
];
双curProgress=-1.0;
最终iconSize=20.0;
@凌驾
小部件构建(构建上下文){
返回脚手架(
appBar:appBar(
标题:文本(“演示”),
),
主体:填充物(
填充:常数边集全部(32.0),
子:堆栈(
对齐:对齐.center,
儿童:[
[集装箱(
填充:边集。对称(水平:图标大小,垂直:图标大小),
子对象:线性表达式指示器(
身高:5,,
价值:进步,
背景颜色:颜色。蓝色[100],
valueColor:始终停止动画(