Navigáció javítása, fejlesztése
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
|
||||
/// Egyenletes, ANIMÁLT térkép-követés — a `mapController.move()`/
|
||||
/// `.rotate()` közvetlen hívása helyett, amik AZONNAL ugranak az új
|
||||
/// pozícióra/irányba.
|
||||
///
|
||||
/// Ez a widget semmit nem jelenít meg (0 méretű) — kizárólag arra való,
|
||||
/// hogy a [target] (és opcionálisan [heading]) VÁLTOZÁSAKOR sima
|
||||
/// animációval, ne ugrással vigye át a térképet a régi pontból az újba.
|
||||
///
|
||||
/// Belül a Flutter beépített `TweenAnimationBuilder`-ét használja — ez
|
||||
/// IMPLICIT módon animál (a cél-érték változásakor magától, a jelenlegi
|
||||
/// állásból indulva animál az újig). A ticker a Flutter-widget
|
||||
/// belsejében él, nekünk nem kell saját State/AnimationController-t
|
||||
/// írnunk hozzá — ez az EGYETLEN pont, ahol animáció miatt egyáltalán
|
||||
/// szóba kerül egy ticker, de azt is a keretrendszer adja.
|
||||
class AnimatedMapFollow extends StatelessWidget {
|
||||
final MapController mapController;
|
||||
final LatLng? target;
|
||||
final double? heading; // fok — ha null, nincs forgatás
|
||||
final Duration duration;
|
||||
|
||||
const AnimatedMapFollow({
|
||||
super.key,
|
||||
required this.mapController,
|
||||
required this.target,
|
||||
this.heading,
|
||||
this.duration = const Duration(milliseconds: 400),
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = target;
|
||||
if (t == null) return const SizedBox.shrink();
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
TweenAnimationBuilder<LatLng>(
|
||||
tween: _LatLngTween(begin: t, end: t),
|
||||
duration: duration,
|
||||
curve: Curves.easeOut,
|
||||
builder: (context, animatedPos, _) {
|
||||
try {
|
||||
mapController.move(animatedPos, mapController.camera.zoom);
|
||||
} catch (_) {}
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
if (heading != null)
|
||||
TweenAnimationBuilder<double>(
|
||||
// A térkép a haladási irány ELLENTETTJÉVEL forog (track-up).
|
||||
tween: _DegreesTween(begin: -heading!, end: -heading!),
|
||||
duration: duration,
|
||||
curve: Curves.easeOut,
|
||||
builder: (context, animatedRotation, _) {
|
||||
try {
|
||||
mapController.rotate(animatedRotation);
|
||||
} catch (_) {}
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _LatLngTween extends Tween<LatLng> {
|
||||
_LatLngTween({required LatLng begin, required LatLng end})
|
||||
: super(begin: begin, end: end);
|
||||
|
||||
@override
|
||||
LatLng lerp(double t) {
|
||||
final b = begin!, e = end!;
|
||||
return LatLng(
|
||||
b.latitude + (e.latitude - b.latitude) * t,
|
||||
b.longitude + (e.longitude - b.longitude) * t,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Fok-interpoláció a "legrövidebb úton" — enélkül egy 350°→10° váltás
|
||||
/// hosszan, "visszafelé" animálna 340°-ot ahelyett hogy egyenesen 20°-ot
|
||||
/// lépne előre.
|
||||
class _DegreesTween extends Tween<double> {
|
||||
_DegreesTween({required double begin, required double end})
|
||||
: super(begin: begin, end: end);
|
||||
|
||||
@override
|
||||
double lerp(double t) {
|
||||
final b = begin!, e = end!;
|
||||
var diff = (e - b) % 360;
|
||||
if (diff > 180) diff -= 360;
|
||||
if (diff < -180) diff += 360;
|
||||
return b + diff * t;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user