شرح كيفية البحث بداخل خرائط جوجل وعرض تفاصيل الموقع داخل Flutter

شرح كيفية البحث بداخل خرائط جوجل وعرض تفاصيل الموقع داخل Flutter

شرح كيفية البحث بداخل خرائط جوجل وعرض تفاصيل الموقع داخل Flutter

في هذا المقال سوف نشرح لكم كيف تتعامل مع api الخاص بخرائط جوجل حيث يمكنك من خلال ال api الخاص بهم ان تقوم بالبحث عن موقع معين وعرض جميع تفاصيل الموقع من خلال ال lat و long وهيا احداثيات الموقع الخاص بالموقع الذي تبحث عنه , والامر بسيط جدا ولكن قبل تنفيذ هذا الشرح عليك ان تقوم بتفعيل خاصية البحث وتتبع الموقع من خلال حسابك في maps google حيث لا يحدث معك مشاكل اثناء تنفيذ الشرح .


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


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


برمجة جوجل:

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


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

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


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

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


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

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


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


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

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

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


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


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

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


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

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


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

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


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


تهيئة ملف Webservices لقراءة البيانات من الانترنت

سوف نقوم بالبداية ببناء ملف Webservices والذي يكون مسؤول عن التعامل مع السيرفر الذي يعرض البيانات وهنا نستخدم baseUrl وايضا ال key الخاص بالمستخدم لكي يعرض البيانات بدون مشاكل كما هو موضح وايضا سوف نستخدم suggestionsBaseUrl لكي نعرض بيانات المواقع التي يتم البحث عنها .


تهيئة ملف Webservices لقراءة البيانات من الانترنت

Webservices.dart


const suggestionsBaseUrl = 'https://maps.googleapis.com/maps/api/place/autocomplete/json';
const String googleAPIKey = '###';


class PlacesWebservices {
  late Dio dio;

  PlacesWebservices() {
    BaseOptions options = BaseOptions(
      connectTimeout: 30 * 1000,
      receiveTimeout: 30 * 1000,
      receiveDataWhenStatusError: true,
    );
    dio = Dio(options);
  }

  Future<List<dynamic>> fetchSuggestions(String place,
      String sessionToken) async {
    try {
      Response response = await dio.get(
        suggestionsBaseUrl,
        queryParameters: {
          'input': place,
          'types': 'address',
          'components': 'country:eg',
          'key': googleAPIKey,
          'sessiontoken': sessionToken
        },
      );
      print(response.data['predictions']);
      print(response.statusCode);
      return response.data['predictions'];
    } catch (error) {
      print(error.toString());
      return [];
    }
  }
}


تهيئة json لاستقبال بيانات المواقع من الانترنت 

في هذا الجزء سوف نحاول تحويل الjson الذي نحصل عليه بعد عرض البيانات في flutter حتى يتمكن الجهاز من قراءة البيانات من الانترنت بدون اي مشاكل .


تهيئة json لاستقبال بيانات المواقع من الانترنت

PlaceSuggestion.dart


class PlaceSuggestion {
  late String placeId;
  late String description;

  PlaceSuggestion.fromJson(Map<String, dynamic> json) {
    placeId = json["place_id"];
    description = json["description"];
  }
}


الحصول على بيانات الخريطة بداخل ملف Repository

في هذه الخطوة سوف تكون اهم خطوة حيث اننا سوف نعرض بها البيانات ونقوم بإحضارها من السيرفر مع تمرير المتغيرات التي نرغب بها وايضا ارجاعها في الشكل الذي نرغب به وهنا سوف نرجعها في شكل list لانها مجموعه من القيم التي يتم عرضها كما هو موضح .


الحصول على بيانات الخريطة بداخل ملف Repository

MapsRepository.dart


class MapsRepository {
  final PlacesWebservices placesWebservices;
  MapsRepository(this.placesWebservices);


  Future<List<PlaceSuggestion>> fetchSuggestions(
      String place, String sessionToken) async {
    final suggestions =
    await placesWebservices.fetchSuggestions(place, sessionToken);

    return suggestions
        .map((suggestion) => PlaceSuggestion.fromJson(suggestion))
        .toList();
  }

}


عرض بيانات المواقع بعد البحث بداخل MapsCubit

الان ناتي الى مرحلة Cubit وهنا نقوم بجلب البيانات من Repository ووضعها بداخل emit حتى نتمكن من استقبالها في ui بسهوله .


عرض بيانات المواقع بعد البحث بداخل MapsCubit

MapsCubit.dart


class MapsCubit extends Cubit<MapsState> {
  final MapsRepository mapsRepository;

  MapsCubit(this.mapsRepository) : super(MapsInitial());

  void emitPlaceSuggestions(String place, String sessionToken) {
    mapsRepository.fetchSuggestions(place, sessionToken).then((suggestions) {
      emit(PlacesLoaded(suggestions));
    });
  }

}


تشغيل MapsRepository اثناء بدء تشغيل التطبيق في صفحة main

بالنسبة لصفحة main سوف نقوم بتعريف BlocProvider بداخل Repository حتى لا يحدث مشاكل اثناء تشغيل التطبيق .


تشغيل MapsRepository اثناء بدء تشغيل التطبيق في صفحة main

main.dart


void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (BuildContext context) =>
          MapsCubit(MapsRepository(PlacesWebservices())),
      
      child: BlocBuilder<MapsCubit, MapsState>(
        builder: (context, state) {
          return MaterialApp(
            debugShowCheckedModeBanner: false,
            title: 'Flutter Demo',
            theme: buildThemeData(),
            home: MainMaps(),
            ),
          );
        },
      ),
    );
  }
  


تصميم لصفحة البحث في الخريطه داخل Flutter

في الخطوة الاخيره وهيا التعامل مع المتغيرات السابقة في صفحة ui وهنا وضعنا تنوية حول كل خاصية قمنا بها حتى تتمكن من معرفة كل وظيفة بسهوله كما هو موضح .


تصميم لصفحة البحث في الخريطه داخل Flutter

ui.dart


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

  @override
  State<MainMaps> createState() => _MainMapsState();
}

class _MainMapsState extends State<MainMaps> {
  // التعرف على موقع المستخدم
  static Position? position;
  // الانتقال المباشر الى موقع المستخدم بمجرد فتح التطبيق
  final Completer<GoogleMapController> _controllerMaps = Completer();
  // المتحكم في عمليات البحث داخل التطبيق
  FloatingSearchBarController controller = FloatingSearchBarController();
  // العناصر التي تظهر بعد البحث عليها
  List<PlaceSuggestion> places = [];
  // موقع المستخدم الحالي على الخريطة
  static final CameraPosition _myCurrentLocationNow = CameraPosition(
    //عرض موقع المستخدم على الخريطة مع بعض الخصائص مثل نسبة التقريب
    // نسبة جعل الكاميرا مائله
    bearing: 0.0,
    // موقع المستخدم
    target: LatLng(position!.latitude, position!.longitude),
    tilt: 0.0,
    // نسبة التقريب
    zoom: 18,
  );

  // تحريك الكاميرا الى موقع المستخدم
  Future<void> getMyLocationNow() async {
    // الحصول على موقع المستخدم بمجرد فتح الخريطة وتحديث الصفحة بالموقع الحالي
    position = await LocationHelper.getCurrentLocation().whenComplete(() => 
        setState((){}));
  }

  // اضافة علامه على الخريطة لموقع المستخدم
  void buildCurrentLocationMarker() {
    currentLocationMarker = Marker(
      position: LatLng(position!.latitude, position!.longitude),
      markerId: MarkerId('2'),
      onTap: () {},
      infoWindow: InfoWindow(title: "Your current Location"),
      icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueRed),
    );
    addMarkerToMarkersAndUpdateUI(currentLocationMarker);
  }

  @override
  void initState() {
    super.initState();
    // عرض بيانات الموقع الحالي للمستخدم عند تشغيل التطبيق
    getMyLocationNow();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        fit: StackFit.expand,
        children: [
          position == null ? const Center(child: CircularProgressIndicator()) :
              // هرض الخريطة
          buildMaps(),
          // اضافة شريط للبحث في الاعلى
          buildFloatingSearchBar(),
        ],
      ),
      // بناء شريط جانبي
      drawer: MyDrawer(),
      floatingActionButton: FloatingActionButton(
        onPressed: _goToMyLocationNow,
        child: const Icon(Icons.location_searching),
      ),
    );
  }

  // الخريطة
  Widget buildMaps(){
    return GoogleMap(
      // نوع الخريطة
      mapType: MapType.normal,
      // وجود علامة زرقاء لاظهار موقعك الحالي على الخريطة
      myLocationEnabled: true,
      // اضافة زر في اعلى الخريطة للانتقال المباشر الى موقعك الحالي
      myLocationButtonEnabled: false,
      // وجود علامة التكبير والتصغير للخريطة في اسفل الخريطة
      zoomControlsEnabled: false,
      // الحصول على موقع المستخدم بمجرد فتح الخريطة وتحديث الصفحة بالموقع الحالي
      initialCameraPosition: _myCurrentLocationNow,

      onMapCreated: (GoogleMapController controller){
        _controllerMaps.complete(controller);
      },

    );
  }

  // البحث
  Widget buildFloatingSearchBar() {
    final isPortrait =
        MediaQuery.of(context).orientation == Orientation.portrait;

    return FloatingSearchBar(
      controller: controller,
      elevation: 6,
      hintStyle: TextStyle(fontSize: 18),
      queryStyle: TextStyle(fontSize: 18),
      hint: 'Find a place..',
      border: BorderSide(style: BorderStyle.none),
      margins: EdgeInsets.fromLTRB(20, 70, 20, 0),
      padding: EdgeInsets.fromLTRB(2, 0, 2, 0),
      height: 52,
      iconColor: Colors.blue[200],
      scrollPadding: const EdgeInsets.only(top: 16, bottom: 56),
      transitionDuration: const Duration(milliseconds: 600),
      transitionCurve: Curves.easeInOut,
      physics: const BouncingScrollPhysics(),
      axisAlignment: isPortrait ? 0.0 : -1.0,
      openAxisAlignment: 0.0,
      width: isPortrait ? 600 : 500,
      debounceDelay: const Duration(milliseconds: 500),
      progress: progressIndicator,
      onQueryChanged: (query) {
        getPlacesSuggestions(query);
      },
      onFocusChanged: (_) {},
      transition: CircularFloatingSearchBarTransition(),
      actions: [
        FloatingSearchBarAction(
          showIfOpened: false,
          child: CircularButton(
              icon: Icon(Icons.place, color: Colors.black.withOpacity(0.6)),
              onPressed: () {}),
        ),
      ],
      builder: (context, transition) {
        return ClipRRect(
          borderRadius: BorderRadius.circular(8),
          child: SizeBox()
        );
      },
    );
  }



  // عرض قائمه بجميع العناصر التي تم البحث عنها
  Widget buildPlacesList() {
    return ListView.builder(
        itemBuilder: (ctx, index) {
          return InkWell(
            onTap: () async {
              placeSuggestion = places[index];
              controller.close();
              getSelectedPlaceLocation();
              polylinePoints.clear();
              removeAllMarkersAndUpdateUI();
            },
            child: PlaceItem(
              suggestion: places[index],
            ),
          );
        },
        itemCount: places.length,
        shrinkWrap: true,
        physics: const ClampingScrollPhysics());
  }

}

تعليقات