答案 0 :(得分:1)
工作演示是修改PieChartSample2
官方示例https://github.com/imaNNeoFighT/fl_chart/blob/master/example/lib/pie_chart/samples/pie_chart_sample2.dart
您可以在 PieChartSectionData
中使用 badgeWidget
并设置 badgePositionPercentageOffset
/// If [badgeWidget] is not null, it draws a widget at the middle of section,
/// by default it draws the widget at the middle of section, but you can change the
/// [badgePositionPercentageOffset] to have your desire design,
/// the value works the same way as [titlePositionPercentageOffset].
代码片段
List<PieChartSectionData> showingSections() {
return List.generate(4, (i) {
...
final double widgetSize = isTouched ? 55 : 40;
switch (i) {
case 0:
return PieChartSectionData(
color: const Color(0xff0293ee),
value: 40,
title: '40%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/ophthalmology-svgrepo-com.svg',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
case 1:
return PieChartSectionData(
color: const Color(0xfff8b250),
...
工作演示
修改后的PieChartSample2
的完整代码
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'indicator.dart';
class _Badge extends StatelessWidget {
final String svgAsset;
final double size;
final Color borderColor;
const _Badge(
this.svgAsset, {
Key key,
@required this.size,
@required this.borderColor,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: PieChart.defaultDuration,
width: size,
height: size,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
border: Border.all(
color: borderColor,
width: 2,
),
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.black.withOpacity(.5),
offset: const Offset(3, 3),
blurRadius: 3,
),
],
),
padding: EdgeInsets.all(size * .15),
child: Center(
child: kIsWeb
? Image.network(svgAsset, fit: BoxFit.contain)
: SvgPicture.asset(
svgAsset,
fit: BoxFit.contain,
),
),
);
}
}
class PieChartSample2 extends StatefulWidget {
@override
State<StatefulWidget> createState() => PieChart2State();
}
class PieChart2State extends State {
int touchedIndex;
@override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 1.3,
child: Card(
color: Colors.white,
child: Row(
children: <Widget>[
const SizedBox(
height: 18,
),
Expanded(
child: AspectRatio(
aspectRatio: 1,
child: PieChart(
PieChartData(
pieTouchData:
PieTouchData(touchCallback: (pieTouchResponse) {
setState(() {
if (pieTouchResponse.touchInput is FlLongPressEnd ||
pieTouchResponse.touchInput is FlPanEnd) {
touchedIndex = -1;
} else {
touchedIndex = pieTouchResponse.touchedSectionIndex;
}
});
}),
borderData: FlBorderData(
show: false,
),
sectionsSpace: 0,
centerSpaceRadius: 40,
sections: showingSections()),
),
),
),
Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: const <Widget>[
Indicator(
color: Color(0xff0293ee),
text: 'First',
isSquare: true,
),
SizedBox(
height: 4,
),
Indicator(
color: Color(0xfff8b250),
text: 'Second',
isSquare: true,
),
SizedBox(
height: 4,
),
Indicator(
color: Color(0xff845bef),
text: 'Third',
isSquare: true,
),
SizedBox(
height: 4,
),
Indicator(
color: Color(0xff13d38e),
text: 'Fourth',
isSquare: true,
),
SizedBox(
height: 18,
),
],
),
const SizedBox(
width: 28,
),
],
),
),
);
}
List<PieChartSectionData> showingSections() {
return List.generate(4, (i) {
final isTouched = i == touchedIndex;
final double fontSize = isTouched ? 25 : 16;
final double radius = isTouched ? 60 : 50;
final double widgetSize = isTouched ? 55 : 40;
switch (i) {
case 0:
return PieChartSectionData(
color: const Color(0xff0293ee),
value: 40,
title: '40%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/ophthalmology-svgrepo-com.svg',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
case 1:
return PieChartSectionData(
color: const Color(0xfff8b250),
value: 30,
title: '30%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/ophthalmology-svgrepo-com.svg',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
case 2:
return PieChartSectionData(
color: const Color(0xff845bef),
value: 15,
title: '15%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/ophthalmology-svgrepo-com.svg',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
case 3:
return PieChartSectionData(
color: const Color(0xff13d38e),
value: 15,
title: '15%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/ophthalmology-svgrepo-com.svg',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
default:
return null;
}
});
}
}
png 的完整代码
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'indicator.dart';
class _Badge extends StatelessWidget {
final String svgAsset;
final double size;
final Color borderColor;
const _Badge(
this.svgAsset, {
Key key,
@required this.size,
@required this.borderColor,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: PieChart.defaultDuration,
width: size,
height: size,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
border: Border.all(
color: borderColor,
width: 2,
),
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.black.withOpacity(.5),
offset: const Offset(3, 3),
blurRadius: 3,
),
],
),
padding: EdgeInsets.all(size * .15),
child: Center(
child: kIsWeb
? Image.network(svgAsset, fit: BoxFit.contain)
: Image.asset(svgAsset, fit: BoxFit.contain) /*SvgPicture.asset(
svgAsset,
fit: BoxFit.contain,
)*/,
),
);
}
}
class PieChartSample2 extends StatefulWidget {
@override
State<StatefulWidget> createState() => PieChart2State();
}
class PieChart2State extends State {
int touchedIndex;
@override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 1.3,
child: Card(
color: Colors.white,
child: Row(
children: <Widget>[
const SizedBox(
height: 18,
),
Expanded(
child: AspectRatio(
aspectRatio: 1,
child: PieChart(
PieChartData(
pieTouchData:
PieTouchData(touchCallback: (pieTouchResponse) {
setState(() {
if (pieTouchResponse.touchInput is FlLongPressEnd ||
pieTouchResponse.touchInput is FlPanEnd) {
touchedIndex = -1;
} else {
touchedIndex = pieTouchResponse.touchedSectionIndex;
}
});
}),
borderData: FlBorderData(
show: false,
),
sectionsSpace: 0,
centerSpaceRadius: 40,
sections: showingSections()),
),
),
),
Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: const <Widget>[
Indicator(
color: Color(0xff0293ee),
text: 'First',
isSquare: true,
),
SizedBox(
height: 4,
),
Indicator(
color: Color(0xfff8b250),
text: 'Second',
isSquare: true,
),
SizedBox(
height: 4,
),
Indicator(
color: Color(0xff845bef),
text: 'Third',
isSquare: true,
),
SizedBox(
height: 4,
),
Indicator(
color: Color(0xff13d38e),
text: 'Fourth',
isSquare: true,
),
SizedBox(
height: 18,
),
],
),
const SizedBox(
width: 28,
),
],
),
),
);
}
List<PieChartSectionData> showingSections() {
return List.generate(4, (i) {
final isTouched = i == touchedIndex;
final double fontSize = isTouched ? 25 : 16;
final double radius = isTouched ? 60 : 50;
final double widgetSize = isTouched ? 55 : 40;
switch (i) {
case 0:
return PieChartSectionData(
color: const Color(0xff0293ee),
value: 40,
title: '40%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/test.png',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
case 1:
return PieChartSectionData(
color: const Color(0xfff8b250),
value: 30,
title: '30%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/test.png',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
case 2:
return PieChartSectionData(
color: const Color(0xff845bef),
value: 15,
title: '15%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/test.png',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
case 3:
return PieChartSectionData(
color: const Color(0xff13d38e),
value: 15,
title: '15%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/test.png',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
default:
return null;
}
});
}
}