2 changed files with 102 additions and 0 deletions
@ -0,0 +1,96 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
|
||||
|
/// A widget that displays a navigation card with different modes of transportation. |
||||
|
Widget navigationCard( |
||||
|
BuildContext context, { |
||||
|
required List<Map<String, dynamic>> modes, |
||||
|
double height = 260, |
||||
|
}) { |
||||
|
int currentIndex = 0; |
||||
|
|
||||
|
return Container( |
||||
|
height: height, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.circular(16), |
||||
|
color: Colors.white, |
||||
|
boxShadow: const [ |
||||
|
BoxShadow( |
||||
|
blurRadius: 8, |
||||
|
color: Colors.black12, |
||||
|
offset: Offset(0, 4), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
child: StatefulBuilder( |
||||
|
builder: (context, setInnerState) { |
||||
|
return Column( |
||||
|
children: [ |
||||
|
// 路线图片 |
||||
|
ClipRRect( |
||||
|
borderRadius: |
||||
|
const BorderRadius.vertical(top: Radius.circular(16)), |
||||
|
child: AnimatedSwitcher( |
||||
|
duration: const Duration(milliseconds: 300), |
||||
|
child: Image.network( |
||||
|
modes[currentIndex]["image"] as String, |
||||
|
key: ValueKey<String>(modes[currentIndex]["ntype"] as String), |
||||
|
height: 160, |
||||
|
width: double.infinity, |
||||
|
fit: BoxFit.cover, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
|
||||
|
// 导航方式切换按钮 |
||||
|
Padding( |
||||
|
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4), |
||||
|
child: Row( |
||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly, |
||||
|
children: List.generate(modes.length, (index) { |
||||
|
final isSelected = index == currentIndex; |
||||
|
return GestureDetector( |
||||
|
onTap: () { |
||||
|
setInnerState(() => currentIndex = index); |
||||
|
}, |
||||
|
child: SizedBox( |
||||
|
width: 50, |
||||
|
child: Text( |
||||
|
modes[index]["ntype"] as String, |
||||
|
style: TextStyle( |
||||
|
color: isSelected ? Colors.blue : Colors.black87, |
||||
|
fontSize: 12, |
||||
|
fontWeight: FontWeight.w500, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
}), |
||||
|
), |
||||
|
), |
||||
|
|
||||
|
// 距离和耗时 |
||||
|
Padding( |
||||
|
padding: const EdgeInsets.all(8), |
||||
|
child: Row( |
||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
||||
|
children: [ |
||||
|
Text('距离:${modes[currentIndex]["distance"]}', |
||||
|
style: const TextStyle(fontSize: 12, color: Colors.blue)), |
||||
|
Container( |
||||
|
decoration: BoxDecoration( |
||||
|
shape: BoxShape.circle, // 👈 圆形背景 |
||||
|
color: Colors.blue, |
||||
|
), |
||||
|
child: Icon(Icons.turn_left, |
||||
|
color: Colors.white, // 👈 圆形图标 |
||||
|
size: 20), |
||||
|
) |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
); |
||||
|
}, |
||||
|
), |
||||
|
); |
||||
|
} |
||||
Loading…
Reference in new issue