Flutter动画路径插件animated_flight_paths的使用

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

Flutter动画路径插件animated_flight_paths的使用

Features

  • 地图投影:包括墨卡托(Mercator)和罗宾逊(Robinson)世界地图投影。
    • 或者设置任何自定义地图或其他背景。
  • 自定义飞行路径:多种选项用于自定义飞行路径的颜色和动画曲线。
  • 确定地图上的点:使用 debugShowOffsetOnTap 然后点击或点击来确定地图上的点。

Quick Start

示例代码

import 'package:animated_flight_paths/animated_flight_paths.dart';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';

void main() => runApp(const MyApp());

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Animated Flight Paths Example',
      debugShowCheckedModeBanner: false,
      home: AnimatedFlightPathsExample(),
    );
  }
}

class AnimatedFlightPathsExample extends StatefulWidget {
  const AnimatedFlightPathsExample({super.key});

  @override
  State<AnimatedFlightPathsExample> createState() =>
      _AnimatedFlightPathsExampleState();
}

class _AnimatedFlightPathsExampleState extends State<AnimatedFlightPathsExample>
    with SingleTickerProviderStateMixin {
  late AnimationController controller;

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 12),
    )..repeat();
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        padding: const EdgeInsets.all(32),
        decoration: const BoxDecoration(
          gradient: LinearGradient(
            begin: Alignment.topLeft,
            end: Alignment.bottomRight,
            stops: [0.4, 1],
            colors: [Color(0xFF27163e), Color(0xFF432a72)],
          ),
        ),
        child: ListView(
          children: [
            Center(child: _title),
            const SizedBox(height: 24),
            Center(child: _animatedFlightPaths),
          ],
        ),
      ),
    );
  }

  Widget get _title => AutoSizeText(
        'AnimatedFlightPaths',
        maxLines: 1,
        style: GoogleFonts.righteous(
          fontSize: 56,
          foreground: Paint()
            ..style = PaintingStyle.stroke
            ..strokeWidth = 2
            ..color = SynthwaveColors.blue,
        ),
      );

  Widget get _animatedFlightPaths => AnimatedFlightPaths(
        controller: controller,
        debugShowOffsetOnTap: false,
        flightSchedule: FlightSchedule(
          start: DateTime.parse('2023-01-01 00:00:00'),
          end: DateTime.parse('2023-01-01 23:59:00'),
          flights: flights,
        ),
        options: const FlightPathOptions(
          showLabels: true,
          fromEndpointColor: SynthwaveColors.yellow,
          toEndpointColor: SynthwaveColors.yellow,
          flightPathColor: SynthwaveColors.yellow,
          fromEndpointCurve: Curves.easeInOut,
          flightPathCurve: Curves.easeInOutSine,
          toEndpointCurve: Curves.easeInOut,
          flightPathStrokeWidth: 2,
          endpointRadius: 5,
          endpointToLabelSpacing: 12,
          endpointDotAlwaysVisible: false,
          endpointLabelAlwaysVisible: false,
          keepFlightPathsVisible: false,
          curveDepth: 0.5,
          endpointWeight: 0.2,
        ),
        child: const MapSvg(
          map: FlightMap.worldMercatorProjection,
          outlineColor: SynthwaveColors.pink,
          fillColor: SynthwaveColors.black,
        ),
      );
}

final flights = <Flight>[
  Flight(
    from: Cities.paris,
    to: Cities.tokyo,
    departureTime: DateTime.parse('2023-01-01 00:00:00'),
    arrivalTime: DateTime.parse('2023-01-01 14:00:00'),
  ),
  Flight(
    from: Cities.sydney,
    to: Cities.capeTown,
    departureTime: DateTime.parse('2023-01-01 00:00:00'),
    arrivalTime: DateTime.parse('2023-01-01 18:00:00'),
  ),
  Flight(
    from: Cities.buenosAires,
    to: Cities.losAngeles,
    departureTime: DateTime.parse('2023-01-01 06:00:00'),
    arrivalTime: DateTime.parse('2023-01-01 21:00:00'),
  ),
  Flight(
    from: Cities.newYork,
    to: Cities.london,
    departureTime: DateTime.parse('2023-01-01 16:00:00'),
    arrivalTime: DateTime.parse('2023-01-01 23:00:00'),
  ),
  Flight(
    from: Cities.cairo,
    to: Cities.london,
    departureTime: DateTime.parse('2023-01-01 17:00:00'),
    arrivalTime: DateTime.parse('2023-01-01 23:00:00'),
  ),
  Flight(
    from: Cities.bangkok,
    to: Cities.london,
    departureTime: DateTime.parse('2023-01-01 10:00:00'),
    arrivalTime: DateTime.parse('2023-01-01 23:00:00'),
  ),
];

abstract class Cities {
  static final bangkok = FlightEndpoint(
    offset: const Offset(75, 65),
    label: const Label(text: 'Bangkok'),
  );

  static final buenosAires = FlightEndpoint(
    offset: const Offset(32, 87),
    label: const Label(text: 'Buenos Aires'),
  );

  static final cairo = FlightEndpoint(
    offset: const Offset(56, 58),
    label: const Label(text: 'Cairo'),
  );

  static final capeTown = FlightEndpoint(
    offset: const Offset(53.5, 86),
    label: const Label(text: 'Cape Town'),
  );

  static final losAngeles = FlightEndpoint(
    offset: const Offset(16, 54),
    label: const Label(text: 'Los Angeles'),
  );

  static final london = FlightEndpoint(
    offset: const Offset(48, 45),
    label: const Label(text: 'London'),
  );

  static final newYork = FlightEndpoint(
    offset: const Offset(28, 51),
    label: const Label(text: 'New York'),
  );

  static final paris = FlightEndpoint(
    offset: const Offset(49, 48),
    label: const Label(text: 'Paris'),
  );

  static final sydney = FlightEndpoint(
    offset: const Offset(89, 87),
    label: const Label(text: 'Sydney'),
  );

  static final tokyo = FlightEndpoint(
    offset: const Offset(86, 54),
    label: const Label(text: 'Tokyo'),
  );
}

abstract class SynthwaveColors {
  static const pink = Color(0xFFeb2bb2);
  static const yellow = Color(0xFFfdfe43);
  static const blue = Color(0xFF74f7ff);
  static const black = Color(0xFF201130);
}

class Label extends StatelessWidget {
  const Label({super.key, required this.text});

  final String text;

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
      decoration: BoxDecoration(
        color: SynthwaveColors.black,
        border: Border.all(color: SynthwaveColors.blue, width: 2),
        borderRadius: BorderRadius.circular(32),
      ),
      child: Text(
        text,
        style: GoogleFonts.righteous(color: SynthwaveColors.blue, fontSize: 14),
      ),
    );
  }
}

确定飞行终点坐标

要确定地图上的点,可以使用 debugShowOffsetOnTap 属性。运行应用并点击或点击任何位置,会显示一个 📍 和一个带有该位置坐标的提示框。使用箭头键 [↑ ↓ → ←] 微调 📍 的位置。

AnimatedFlightPaths(
  controller: controller,
  debugShowOffsetOnTap: true, // 设置为 true
  flightSchedule: FlightSchedule(
      start: DateTime.parse('2023-01-01 00:00:00'),
      end: DateTime.parse('2023-01-01 23:59:00'),
      flights: <Flight>[],
  ),
);

在截图中,提示框显示的是 (21.99, 52.79),这是 Kansas City 的坐标。我们可以用这些坐标创建一个新的 FlightEndpoint

abstract class Cities {
  static final kansasCity = FlightEndpoint(
    offset: const Offset(21.99, 52.79),
    label: const Text('Kansas City'),
  );
}

现在可以在任何飞行路径中使用这个终点。

✈️ Bon Voyage!!


更多关于Flutter动画路径插件animated_flight_paths的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter动画路径插件animated_flight_paths的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter中使用animated_flight_paths插件来创建动画路径的一个示例。这个插件允许你定义和渲染复杂的路径动画,非常适合展示飞行路线或任何需要沿路径移动的动画。

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

dependencies:
  flutter:
    sdk: flutter
  animated_flight_paths: ^最新版本号 # 请替换为最新版本号

然后,运行flutter pub get来安装依赖。

接下来,在你的Dart文件中(例如main.dart),你可以按照以下步骤来创建和使用动画路径:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Animated Flight Paths Demo'),
        ),
        body: Center(
          child: AnimatedFlightPathsDemo(),
        ),
      ),
    );
  }
}

class AnimatedFlightPathsDemo extends StatefulWidget {
  @override
  _AnimatedFlightPathsDemoState createState() => _AnimatedFlightPathsDemoState();
}

class _AnimatedFlightPathsDemoState extends State<AnimatedFlightPathsDemo> with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 5),
      vsync: this,
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final path = Path()
      ..moveTo(50, 150)
      ..quadraticBezierTo(100, 100, 150, 150)
      ..lineTo(250, 150)
      ..cubicTo(300, 100, 350, 200, 400, 150);

    return AnimatedFlightPaths(
      points: [
        FlightPathPoint(
          path: path,
          offset: 0.0,
          child: Container(
            width: 20,
            height: 20,
            decoration: BoxDecoration(
              shape: BoxShape.circle,
              color: Colors.blue,
            ),
          ),
        ),
      ],
      controller: _controller,
    );
  }
}

在这个示例中,我们创建了一个简单的Flutter应用,其中包含一个AnimatedFlightPaths组件。这个组件接受一个FlightPathPoint列表,每个FlightPathPoint定义了一个路径和在该路径上的一个子组件(在这个例子中是一个蓝色的圆形)。

  1. 定义路径:我们使用Path类来定义一个二次贝塞尔曲线和一个三次贝塞尔曲线的组合路径。
  2. 创建动画控制器:我们使用AnimationController来控制动画的时长和同步。
  3. 使用AnimatedFlightPaths:我们将路径和动画控制器传递给AnimatedFlightPaths,并将一个带有蓝色圆形的FlightPathPoint添加到路径点列表中。

运行这个应用,你将看到一个蓝色圆形沿着定义的路径移动。你可以根据需要调整路径和动画属性,以创建更复杂和有趣的动画效果。

回到顶部