Flutter地铁连接管理插件dart_connect_metro的使用

发布于 1周前 作者 sinazl 来自 Flutter

Flutter地铁连接管理插件dart_connect_metro的使用

Dart Connect Metro Logo

Dart Connect Metro 是一个帮助开发者将华盛顿DC地铁系统数据集成到应用程序中的宝贵资源。该SDK提供了便捷访问实时更新和时刻表信息的功能,增强了与DC地铁相关的应用程序的功能和用户体验。

安装

在项目的 pubspec.yaml 文件中添加以下依赖:

dependencies:
  dart_connect_metro: ^0.1.2

导入到你使用的每个文件中:

import 'package:dart_connect_metro/dart_connect_metro.dart';

入门指南

生成API密钥

你需要在华盛顿大都会区交通管理局(WMATA)网站上为你的程序生成自定义的API密钥。

  1. 首先,在这里创建一个账户。
  2. 接下来,前往产品页面,订阅(默认层是免费的)。
  3. 最后,前往你的个人资料页面,查看你的API密钥。

使用方法

示例1 - 车费查询

此示例展示了如何获取一次旅程的费用。需要注意的是,有普通票价和老年人/残疾人票价之分。普通票价又分为高峰时段和非高峰时段。

// 示例路线的车站代码。通常情况下,这些代码会通过编程方式获取。
static const String federalTriangleCode = 'D01';
static const String rosslynCode = 'C05';

/// 获取站到站的信息。
List<StationToStation> stationToStation =
    await fetchStationToStation(
        apiKey,
        startStationCode: federalTriangleCode,
        destinationStationCode: rosslynCode,
);

/// 获取旅程费用。
final double cost = stationToStation.first.railFare.currentFare;

/// 获取老年人的旅程费用。
final double seniorCost = stationToStation.first.railFare.seniorCitizen;

示例2 - 路线上的车站

此示例展示了如何获取一条路线上的所有车站名称。

/// 获取路径信息。
Path path = await fetchPath(
    apiKey,
    startStationCode: federalTriangleCode,
    destinationStationCode: rosslynCode,
);

List<String> stationNames = [];

for(PathItem pathItem in path.items) {
    stationNames.add(pathItem.stationName);
}

示例3 - 出发和到达时间

此示例展示了如何查找从一个车站到另一个车站的下一班列车的出发时间和到达时间。

/// 获取站到站的信息。
List<StationToStation> stationToStation =
    await fetchStationToStation(
        apiKey,
        startStationCode: federalTriangleCode,
        destinationStationCode: rosslynCode,
);

/// 获取路径信息。
Path path = await fetchPath(
    apiKey,
    startStationCode: federalTriangleCode,
    destinationStationCode: rosslynCode,
);

/// 获取下一班列车的信息。
List<NextTrain> nextTrain = await fetchNextTrains(
    apiKey,
    stationCodes: [federalTriangleCode],
);

// 获取线路代码以匹配下一班列车。
final String lineCode = path.items.first.lineCode;

// 获取该线路上的下一班列车。
late final NextTrain nextTrainObj;
for (NextTrain train in nextTrain) {
    if (train.line == lineCode) {
        nextTrainObj = train;
        break;
    }
}

// 获取下一班列车的时间。
final DateTime nextTrainTime =
    DateTime.now().add(Duration(minutes: nextTrainObj.minutesAway ?? 0));

/// 列车来接您开始旅程的时间。
final Time departureTime = Time.fromDateTime(nextTrainTime);

/// 您到达目的地车站的时间。
final Time arrivalTime = Time.fromDateTime(nextTrainTime);

// 添加旅程所需的时间以获得到达时间。
for (StationToStation station in stationToStation) {
    arrivalTime.add(Duration(minutes: station.travelTimeMinutes));
}

完整的示例Demo

下面是一个完整的Flutter应用示例,展示了如何使用 dart_connect_metro 插件来展示地铁信息:

import 'package:dart_connect_metro/dart_connect_metro.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';

late final String apiKey;

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 为了使这个演示正常工作,你需要创建一个assets文件夹,并放入一个名为api_key.key的文件。
  // 该文件应包含你的API密钥,没有空格或换行符。
  apiKey = await rootBundle.loadString('assets/api_key.key');

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Dart Connect Metro Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  static const String federalTriangleCode = 'D01';
  static const String rosslynCode = 'C05';

  final Future<List<StationToStation>> stationToStationFuture =
      fetchStationToStation(
          apiKey,
          startStationCode: federalTriangleCode,
          destinationStationCode: rosslynCode);

  final Future<Path> pathFuture = fetchPath(
      apiKey,
      startStationCode: federalTriangleCode,
      destinationStationCode: rosslynCode);

  final Future<List<NextTrain>> nextTrainFuture = fetchNextTrains(
      apiKey, stationCodes: [federalTriangleCode]);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Dart Connect Metro Demo'),
      ),
      body: SingleChildScrollView(
        child: Padding(
          padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 25),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              _routeInfo(),
              const SizedBox(height: 40.0),
              _time(),
              const SizedBox(height: 15.0),
              _cost(),
            ],
          ),
        ),
      ),
    );
  }

  Widget _routeInfo() {
    return const Row(
      mainAxisAlignment: MainAxisAlignment.spaceAround,
      children: [
        Expanded(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              Icon(Icons.location_on_outlined),
              Text(
                'Current Station',
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
              Text('Federal Triangle'),
            ],
          ),
        ),
        Icon(Icons.keyboard_double_arrow_right_outlined),
        Expanded(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              Icon(Icons.not_listed_location_outlined),
              Text(
                'Destination Station',
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
              Text('Rosslyn'),
            ],
          ),
        ),
      ],
    );
  }

  Widget _time() {
    return _myContainer(
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: [
          Expanded(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                const Icon(Icons.departure_board_outlined, size: 30.0),
                const SizedBox(height: 9.0),
                FutureBuilder(
                  future: Future.wait([pathFuture, nextTrainFuture]),
                  builder: (context, snapshot) {
                    if (snapshot.hasData) {
                      if (snapshot.data != null && snapshot.data is List) {
                        final Path? path = snapshot.data?[0] as Path?;
                        final List<NextTrain>? nextTrains =
                            snapshot.data?[1] as List<NextTrain>?;
                        if (path != null && nextTrains != null) {
                          return _getTimeText(path, nextTrains);
                        }
                      }
                      return const Text('Error!');
                    } else if (snapshot.hasError) {
                      return const Text('Error!');
                    }
                    return const CircularProgressIndicator();
                  },
                ),
              ],
            ),
          ),
          const Text('to'),
          Expanded(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                const Icon(Icons.access_time_outlined, size: 30.0),
                const SizedBox(height: 9.0),
                FutureBuilder(
                  future: Future.wait([
                    stationToStationFuture,
                    pathFuture,
                    nextTrainFuture,
                  ]),
                  builder: (context, snapshot) {
                    if (snapshot.hasData) {
                      if (snapshot.data != null && snapshot.data is List) {
                        final List<StationToStation>? stationToStation =
                            snapshot.data?[0] as List<StationToStation>?;
                        final Path? path = snapshot.data?[1] as Path?;
                        final List<NextTrain>? nextTrains =
                            snapshot.data?[2] as List<NextTrain>?;
                        if (stationToStation != null &&
                            path != null &&
                            nextTrains != null) {
                          return _getTimeText(path, nextTrains, stationToStation);
                        }
                      }
                      return const Text('Error!');
                    } else if (snapshot.hasError) {
                      return const Text('Error!');
                    }
                    return const CircularProgressIndicator();
                  },
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }

  Widget _cost() {
    final NumberFormat dollarAmount = NumberFormat('#,##0.00', 'en_US');
    return _myContainer(
      child: FutureBuilder(
        future: Future.wait([
          stationToStationFuture,
          pathFuture,
          nextTrainFuture,
        ]),
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            if (snapshot.data != null && snapshot.data is List) {
              final List<StationToStation>? stationToStation =
                  snapshot.data?[0] as List<StationToStation>?;
              final Path? path = snapshot.data?[1] as Path?;
              final List<NextTrain>? nextTrains =
                  snapshot.data?[2] as List<NextTrain>?;
              if (path != null &&
                  nextTrains != null &&
                  stationToStation != null) {
                final Time time = _getTime(path, nextTrains);
                final double cost = stationToStation.first.railFare
                    .fareAtTime(time.toDateTime());
                final double seniorCost =
                    stationToStation.first.railFare.seniorCitizen;
                return Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Row(
                      crossAxisAlignment: CrossAxisAlignment.end,
                      children: [
                        Text(
                          '\$${dollarAmount.format(cost)}',
                          style: const TextStyle(fontSize: 20.0),
                        ),
                        const SizedBox(width: 3.0),
                        const Text('Fare'),
                      ],
                    ),
                    const SizedBox(height: 5.0),
                    Row(
                      crossAxisAlignment: CrossAxisAlignment.end,
                      children: [
                        Text('\$${dollarAmount.format(seniorCost)}'),
                        const SizedBox(width: 5.0),
                        const Text('Fare (Senior/Disabled)'),
                      ],
                    ),
                  ],
                );
              }
            }
            return const Text('Error!');
          } else if (snapshot.hasError) {
            return const Text('Error!');
          }
          return const CircularProgressIndicator();
        },
      ),
    );
  }

  Widget _myContainer({required Widget child}) {
    return Container(
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(10.0),
        color: const Color.fromRGBO(240, 240, 245, 1.0),
      ),
      padding: const EdgeInsets.all(10.5),
      child: child,
    );
  }

  Time _getTime(Path path, List<NextTrain> nextTrains,
      [List<StationToStation>? stationToStation]) {
    final String lineCode = path.items.first.lineCode;
    late final NextTrain nextTrain;
    for (NextTrain train in nextTrains) {
      if (train.line == lineCode) {
        nextTrain = train;
        break;
      }
    }
    final DateTime nextTrainTime =
        DateTime.now().add(Duration(minutes: nextTrain.minutesAway ?? 0));
    final Time time = Time.fromDateTime(nextTrainTime);
    if (stationToStation != null) {
      for (StationToStation station in stationToStation) {
        time.add(Duration(minutes: station.travelTimeMinutes));
      }
    }
    return time;
  }

  Widget _getTimeText(Path path, List<NextTrain> nextTrains,
      [List<StationToStation>? stationToStation]) {
    final Time time = _getTime(path, nextTrains, stationToStation);
    return Text(
      '${time.timeStr_12h}${time.hour < 12 ? '' : ' pm'}',
      style: const TextStyle(fontSize: 20.0),
    );
  }
}

更多关于Flutter地铁连接管理插件dart_connect_metro的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter地铁连接管理插件dart_connect_metro的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用 dart_connect_metro 插件的示例代码,假设这个插件提供了连接和管理地铁服务的功能。请注意,dart_connect_metro 是一个假设的插件名称,实际中你需要根据具体的插件文档进行调整。

首先,确保你已经在 pubspec.yaml 文件中添加了 dart_connect_metro 依赖:

dependencies:
  flutter:
    sdk: flutter
  dart_connect_metro: ^1.0.0  # 假设版本号为1.0.0,请根据实际情况填写

然后,运行 flutter pub get 以获取依赖。

接下来,在你的 Flutter 应用中使用这个插件。以下是一个简单的示例,展示如何初始化插件、检查地铁连接状态以及获取地铁线路信息。

import 'package:flutter/material.dart';
import 'package:dart_connect_metro/dart_connect_metro.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late MetroConnect _metroConnect;
  bool _isConnected = false;
  List<MetroLine>? _metroLines;

  @override
  void initState() {
    super.initState();
    // 初始化插件
    _metroConnect = MetroConnect();

    // 检查连接状态
    _checkConnection();

    // 获取地铁线路信息
    _fetchMetroLines();
  }

  Future<void> _checkConnection() async {
    bool isConnected = await _metroConnect.checkConnection();
    setState(() {
      _isConnected = isConnected;
    });
  }

  Future<void> _fetchMetroLines() async {
    List<MetroLine>? metroLines = await _metroConnect.fetchMetroLines();
    setState(() {
      _metroLines = metroLines;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('地铁连接管理'),
        ),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                '地铁连接状态: ${_isConnected ? '已连接' : '未连接'}',
                style: TextStyle(fontSize: 18),
              ),
              SizedBox(height: 16),
              if (_metroLines != null)
                Expanded(
                  child: ListView.builder(
                    itemCount: _metroLines!.length,
                    itemBuilder: (context, index) {
                      MetroLine line = _metroLines![index];
                      return ListTile(
                        title: Text('线路 ${line.number}: ${line.name}'),
                        subtitle: Text('站点数: ${line.stations.length}'),
                      );
                    },
                  ),
                )
              else
                Center(
                  child: CircularProgressIndicator(),
                ),
            ],
          ),
        ),
      ),
    );
  }
}

// 假设的 MetroConnect 类和 MetroLine 数据模型
class MetroConnect {
  Future<bool> checkConnection() async {
    // 模拟网络请求检查连接状态
    await Future.delayed(Duration(seconds: 2));
    return true; // 假设总是连接成功
  }

  Future<List<MetroLine>> fetchMetroLines() async {
    // 模拟网络请求获取地铁线路信息
    await Future.delayed(Duration(seconds: 2));
    return [
      MetroLine(
        number: 1,
        name: '地铁1号线',
        stations: ['站点A', '站点B', '站点C'],
      ),
      MetroLine(
        number: 2,
        name: '地铁2号线',
        stations: ['站点D', '站点E', '站点F'],
      ),
    ];
  }
}

class MetroLine {
  final int number;
  final String name;
  final List<String> stations;

  MetroLine({required this.number, required this.name, required this.stations});
}

这个示例展示了如何使用一个假设的 dart_connect_metro 插件来检查地铁连接状态并获取地铁线路信息。请注意,实际插件的 API 可能会有所不同,你需要参考插件的官方文档来调整代码。

回到顶部