شرح كيفية عمل انميشن على الموقع الخاص بالمستخدم باستخدام flutterMap

شرح كيفية عمل انميشن على الموقع الخاص بالمستخدم باستخدام flutterMap

شرح كيفية عمل انميشن على الموقع الخاص بالمستخدم باستخدام flutterMap

في الدروس السابقة تعلمنا التعامل مع خرائط جوجل وكيف نقوم بتحديد الموقع والبحث عن المواقع وايضا رسم خط وحساب المدة الزمنيه والمسافه بين موقعين وفي هذه المقالة سوف نشرح لكم مكتبة جديده لا تحتاج منك الى حساب google map وهيا flutter map وهذه المكتبة تقدم لك خريطة مخصصه ولكن عيب هذه المكتبة انها فقط تعمل على النسخه التجربيه وعند اطلاق التطبيق لن تظهر معك الخريطة ولكن يمكنك الاستفاده من الاكواد التي نقدمها لكم وهيا اننا سوف نقوم لكم كيف تقوم بعمل انميشن على موقع المستخدم في Flutter وايضا انميشن عند النقر على اي موقع كما سوف نلاحظ .


ما الذي يجعل Flutter فريدًا جدًا؟ تعد القدرة على تطوير تطبيقات عبر الأنظمة الأساسية من قاعدة بيانات واحدة هي الجانب الأول منها. وهذا يعني أنه لا يلزم إنشاء تطبيقات الويب والجوال وسطح المكتب المميزة. باستخدام Flutter ، ظهرت أداة واحدة تسهل إنشاء التطبيقات. 19 أغسطس 2022

العيب الرئيسي لـ Flutter هو لغة التنفيذ ، Dart. إذا كنت تدير بيئات استضافة Google عبر الإنترنت أو الخلفية ، فإن Dart هي إحدى اللغات التي يمكنك استخدامها. وهذا في الأساس كل شيء.


تعد خرائط جوجل من أكثر خدمات الخرائط استخدامًا في العالم، حيث تقدم مجموعة واسعة من الميزات والأدوات التي تجعل من السهل على المستخدمين التنقل والتعرف على المناطق المحيطة بهم. يمكن استخدام خرائط جوجل أيضًا لإنشاء تطبيقات ذكية تساعد المستخدمين على الوصول إلى المعلومات والمحتوى بشكل أكثر سهولة.


برمجة جوجل:

تقدم جوجل مجموعة واسعة من الأدوات والتقنيات التي تساعد المطورين على إنشاء تطبيقات ذكية، بما في ذلك خرائط جوجل. يمكن استخدام خرائط جوجل لإنشاء تطبيقات متنوعة، مثل تطبيقات التنقل والتوصيل وتطبيقات العلامات التجارية والإعلانات.


برمجة تطبيقات الأجهزة الذكية:

تتطلب برمجة تطبيقات الأجهزة الذكية معرفة بإحدى لغات البرمجة الشائعة، مثل جافا سكريبت أو دارت. كما تتطلب معرفة بتقنيات وأدوات تطوير التطبيقات، مثل فلاتر.


إنشاء تطبيقات الاندرويد:

يمكن استخدام فلاتر لإنشاء تطبيقات أندرويد وiOS. فلاتر هي تقنية تطوير تطبيقات ذكية مفتوحة المصدر من جوجل، تعتمد على لغة البرمجة دارت.


برمجة تطبيقات الاجهزة الذكية:

تتضمن برمجة تطبيقات الأجهزة الذكية مجموعة من الخطوات، مثل:


  • تصميم التطبيق: يتضمن هذه الخطوة تحديد وظائف التطبيق وتصميم واجهة المستخدم.
  • تطوير التطبيق: يتضمن هذه الخطوة كتابة الكود وتنفيذه.
  • اختبار التطبيق: يتضمن هذه الخطوة اختبار التطبيق للتأكد من سلامة عمله.
  • نشر التطبيق: يتضمن هذه الخطوة نشر التطبيق على متجر التطبيقات.


برمجة تطبيق اندرويد بسيط:

يمكن إنشاء تطبيق اندرويد بسيط باستخدام فلاتر من خلال الخطوات التالية:

  1. إنشاء مشروع جديد باستخدام فلاتر.
  2. إضافة مكتبة خرائط جوجل إلى المشروع.
  3. إنشاء الخريطة وإضافة المواقع إليها.
  4. تشغيل التطبيق على جهاز أندرويد.


يعد التعامل مع خرائط جوجل باستخدام فلاتر طريقة رائعة لإنشاء تطبيقات ذكية تفاعلية. فلاتر هي تقنية قوية وسهلة الاستخدام، يمكن استخدامها لإنشاء تطبيقات متنوعة للأجهزة الذكية.


الميزات والأدوات المتوفرة في خرائط جوجل:

  • التنقل
  • البحث
  • عرض التضاريس
  • عرض الصور
  • عرض الاتجاهات
  • عرض المسافات
  • عرض الوقت المقدر للوصول
  • خطوات استخدام خرائط جوجل في فلاتر:


أمثلة لتطبيقات اندرويد التي تستخدم خرائط جوجل:

  • تطبيقات التنقل
  • تطبيقات التوصيل
  • تطبيقات العلامات التجارية والإعلانات
  • تطبيقات السياحة والسفر
  • تطبيقات التعليم
  • تطبيقات الألعاب


نصائح لبرمجة تطبيقات اندرويد باستخدام فلاتر:

  • استخدام مكتبة خرائط جوجل الرسمية.
  • اختيار لغة البرمجة المناسبة للمشروع.
  • تصميم واجهة مستخدم جذابة وسهلة الاستخدام.
  • اختبار التطبيق بعناية قبل نشره.


Add packages


  flutter_map: ^3.0.0

  latlong2: ^0.8.1


تصميم خريطة مع عمل انميشن للمواقع عند النقر عليها في flutterMap

في هذا الجزء قمنا بتصميم الخريطة وعمل الانميشن عليها لموقع المستخدم وايضا لبعض المواقع التي قمنا بتحديدها على الخريطة عن طريق النقاط الخاص بها , يمكنك الاستفاده من الاكواد التاليه في تحديد موقع المستخدم وايضا تنفيذ pageView بالاسفل وعند التحريك يتم تغيير الموقع الذي تبحث عنه كما هو موضح بالصورة الخاصه بالمقال , تعتبر هذه المقالة مخصصه لتنفيذ الانميشن على الخريطة .

تصميم خريطة مع عمل انميشن للمواقع عند النقر عليها في flutterMap

ui.dart


import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
import 'package:untitled/maps/pages/animat_map/model/model_map.dart';

// styles : https://docs.mapbox.com/api/maps/styles/
const String TOKEN_KEy =
    'pk.eyJ1IjoiYWhtZWRtOTl6IiwiYSI6ImNsOHlsMWhhbjBkOHEzeHAybzdkZzJhcWYifQ.z6p3syK-8MqitQZM2l4RAQ';
const String styleMapDark = 'mapbox/dark-v10';
const String styleMapNatural = 'mapbox/satellite-v9';
const String styleMapCartoon = 'mapbox/outdoors-v11';

const Color MARKER_COLOR = Color(0xff3dc5a7);
final LatLng _myLocation = LatLng(30.046772, 31.231778);
const double markerSizeExpanded = 50.0;
const double markerSizeSmall = 35.0;

class MapsAnimation extends StatefulWidget {
  const MapsAnimation({Key? key}) : super(key: key);

  @override
  State<MapsAnimation> createState() => _MapsAnimationState();
}

class _MapsAnimationState extends State<MapsAnimation>
    with SingleTickerProviderStateMixin {
  late final AnimationController _animatedContainer;
  final pageController = PageController();
  int selectIndex = 0;
  LatLng _center = _myLocation;

  List<Marker> buildMarker() {
    final markerList = <Marker>[];
    for (int i = 0; i < listMap.length; i++) {
      final mapItem = listMap[i];
      markerList.add(Marker(
          height: markerSizeExpanded,
          width: markerSizeExpanded,
          point: mapItem.location,
          builder: (_) {
            return GestureDetector(
              onTap: () {
                setState(() {
                  selectIndex = i;
                  pageController.animateToPage(i,
                      duration: const Duration(milliseconds: 500),
                      curve: Curves.easeInOut);
                  print('Marker ${mapItem.title} was tapped');
                });
              },
              child: LocationMarker(
                isSelected: selectIndex == i,
              ),
            );
          }));
    }
    return markerList;
  }

  @override
  void initState() {
    super.initState();
    _animatedContainer = AnimationController(
        vsync: this, duration: const Duration(milliseconds: 600));
    _animatedContainer.repeat(reverse: true);
  }

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

  @override
  Widget build(BuildContext context) {
    final markers = buildMarker();

    return Scaffold(
      appBar: AppBar(
        backgroundColor: Color(0xff2b2b2d),
        title: const Text(
          'Maps Animation',
          style: TextStyle(color: Colors.white),
        ),
      ),
      body: Stack(
        children: [
          FlutterMap(
            options: MapOptions(
              center: _center,
              zoom: 16,

            ),
            children: [
              TileLayer(
                urlTemplate:
                    'https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}',
                additionalOptions: {
                  'accessToken': TOKEN_KEy,
                  'id': styleMapDark,
                },
              ),
              MarkerLayer(
                markers: markers,
              ),
              MarkerLayer(
                markers: [
                  Marker(
                    width: 50.0,
                    height: 50.0,
                    point: _myLocation,
                    builder: (ctx) => MyLocationMarker(_animatedContainer),
                  ),
                ],
              ),
            ],
          ),
          Positioned(
            left: 0,
            right: 0,
            bottom: 30,
            height: MediaQuery.of(context).size.height * 0.3,
            child: PageView.builder(
              controller: pageController,
              onPageChanged: (index) {
                setState(() {
                  selectIndex = index;
                  _center = listMap[index].location;
                });
              },
              itemBuilder: (_, index) {
                print('index $index');
                final item = listMap[index];
                return MapItemDetails(
                  mapModel: item,
                );
              },
              itemCount: listMap.length,
            ),
          ),
        ],
      ),
    );
  }
}

class MyLocationMarker extends AnimatedWidget {
  const MyLocationMarker(Animation<double> animation, {Key? key})
      : super(key: key, listenable: animation);
  final size = 50;

  @override
  Widget build(BuildContext context) {
    final value = (listenable as Animation<double>).value;
    final newValue = (lerpDouble(0.5, 1, value))!;

    return Center(
      child: Stack(
        children: [
          Center(
            child: Container(
              width: newValue * size,
              height: newValue * size,
              decoration: BoxDecoration(
                color: MARKER_COLOR.withOpacity(0.5),
                shape: BoxShape.circle,
              ),
            ),
          ),
          Center(
            child: Container(
              width: 15,
              height: 15,
              decoration: BoxDecoration(
                color: MARKER_COLOR,
                shape: BoxShape.circle,
              ),
            ),
          )
        ],
      ),
    );
  }
}

class MapItemDetails extends StatelessWidget {
  final MapModel mapModel;

  const MapItemDetails({Key? key, required this.mapModel}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: EdgeInsets.all(20),
      child: Card(
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(20),
        ),
        color: const Color(0xfffffefe),
        child: Column(
          children: [
            Expanded(
              child: Row(
                mainAxisAlignment: MainAxisAlignment.start,
                children: [
                  Expanded(
                    child: Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: ClipRRect(
                          borderRadius: BorderRadius.circular(20),
                          child: Image.network(
                            mapModel.image,
                            fit: BoxFit.cover,
                          )),
                    ),
                  ),
                  Expanded(
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Text(
                          mapModel.title,
                          style: const TextStyle(
                              fontSize: 22,
                              fontWeight: FontWeight.bold,
                              color: Colors.black),
                        ),
                        Text(
                          mapModel.address,
                          style: const TextStyle(
                              fontSize: 15, fontWeight: FontWeight.bold),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            ),
            Padding(
              padding:
                  const EdgeInsets.symmetric(horizontal: 15.0, vertical: 10),
              child: MaterialButton(
                onPressed: () {},
                color: MARKER_COLOR,
                minWidth: double.infinity,
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(8),
                ),
                child: Text(
                  'call',
                  style: TextStyle(color: Colors.white),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class LocationMarker extends StatelessWidget {
  const LocationMarker({Key? key, this.isSelected = false}) : super(key: key);
  final bool isSelected;

  @override
  Widget build(BuildContext context) {
    final size = isSelected ? markerSizeExpanded : markerSizeSmall;
    return Center(
      child: AnimatedContainer(
        height: size,
        width: size,
        duration: const Duration(milliseconds: 400),
        child: Image.asset('assets/img/icon/marker.png'),
      ),
    );
  }
}


إنشاء model يحتوي على اسم وصورة واحداثيات الموقع

في هذا الجزء وهو المسؤول عن وضع صورة واسم وخطوط الطول والعرض الخاصه بالمواقع التي تريد ارفاقها في الخريطة لتظهر للمستخدم .

إنشاء model يحتوي على اسم وصورة واحداثيات الموقع

model.dart


import 'package:latlong2/latlong.dart';

class MapModel {
  final String address;
  final String title;
  final String image;
  final LatLng location;

  const MapModel({required this.address,required this.title,required this.image,required this.location});

}

List<MapModel> listMap = [
  MapModel(
      image: 'https://images.unsplash.com/photo-1572252009286-268acec5ca0a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80',
      location: LatLng(30.0484477,31.2366900),
      title: 'Cairo',address: 'Zamalek city'
  ),
  MapModel(
      image: 'https://images.unsplash.com/photo-1577214407836-1f3a0604ecb2?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=736&q=80',
      location: LatLng(30.0502145,31.2334021),
      title: '10th ramadan',address: '10th of Ramadan city'
  ),
  MapModel(
      image: 'https://images.unsplash.com/photo-1627790497727-41fb43f961be?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80',
      location: LatLng(30.0485011,31.2338527),
      title: 'Zagazig',address: 'Zagazig city'
  ),
  MapModel(
      image: 'https://images.unsplash.com/photo-1618224237039-0f55d9f40c1c?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80',
      location: LatLng(31.056654, 31.400822),
      title: 'Mansuora',address: 'Mansuora city'
  ),

];

android sdk manager تحميل flutter developers applications create app android android studio mac


تعليقات