Command Palette

Search for a command to run...

Hướng dẫn cách dùng React Native Maps: Hiển thị bản đồ & Lấy tọa độ GPS

Hướng dẫn cách dùng React Native Maps

Hãy thử tưởng tượng một ngày bạn mở ứng dụng Grab lên để gọi xe, nhưng thay vì nhìn thấy bản đồ trực quan với những chiếc xe đang di chuyển, bạn chỉ nhận được một danh sách các con số tọa độ khô khan. Chắc chắn bạn sẽ xóa app ngay lập tức!

Trong kỷ nguyên của các dịch vụ theo yêu cầu (On-demand services), Maps không còn là một tính năng xa xỉ, mà là tiêu chuẩn bắt buộc.

Ở những bài trước, chúng ta đã biết cách lấy những con số tọa độ vô tri (Kinh độ, Vĩ độ) thông qua expo-location. Hôm nay, trong bài học này, chúng ta sẽ biến những con số đó thành một trải nghiệm thị giác tuyệt vời bằng cách vẽ chúng lên bản đồ kỹ thuật số với thư viện react-native-maps.

1. Cài đặt thư viện cần thiết

react-native-maps là thư viện tiêu chuẩn vàng được cộng đồng sử dụng để hiển thị bản đồ trong React Native. Nó được bảo trợ bởi chính cộng đồng Expo, nên việc tích hợp cực kỳ trơn tru.

react-native-maps

Mở Terminal và chạy lệnh sau để đưa thư viện vào dự án của bạn:

npx expo install react-native-maps

Sự thật thú vị về hệ điều hành: Theo mặc định, thư viện này sẽ hiển thị Apple Maps trên các thiết bị iPhone/iPad, và hiển thị Google Maps trên các thiết bị Android. Điều này giúp ứng dụng của bạn có cảm giác "chuẩn Native" nhất đối với thói quen của từng tệp người dùng.

2. Khởi tạo "Tấm bản đồ" đầu tiên

Việc gọi bản đồ ra màn hình dễ đến mức bạn sẽ phải ngạc nhiên. Khác với lập trình Web (nơi bạn phải chèn iframe hay dùng SDK phức tạp), trong React Native, bản đồ hoạt động y hệt như một Core Component (như thẻ View hay Image).

Hãy tạo một file app/map.tsx và nhập đoạn code sau:

import React from 'react'
import { StyleSheet, View } from 'react-native'
import MapView from 'react-native-maps'

export default function MapScreen() {
  return (
    <View style={styles.container}>
      <MapView
        style={styles.map}
        // Thiết lập vị trí khởi tạo ( dụ: Hồ Gươm,  Nội)
        initialRegion={{
          latitude: 21.0285, //  độ
          longitude: 105.8542, // Kinh độ
          latitudeDelta: 0.05, // Độ zoom của bản đồ theo trục dọc (Càng nhỏ càng zoom sát)
          longitudeDelta: 0.05, // Độ zoom của bản đồ theo trục ngang
        }}
      />
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1, // Bắt buộc phải có để thẻ View cha chiếm hết màn hình
  },
  map: {
    width: '100%',
    height: '100%', // Bản đồ sẽ trải dài toàn bộ màn hình
  },
})

Lưu ý: Bất kỳ thẻ <MapView> nào cũng bắt buộc phải được cấp thuộc tính kích thước (width, height hoặc flex: 1). Nếu thiếu, bản đồ sẽ tàng hình!

3. Ghim vị trí trực quan bằng Marker

Bản đồ trống rỗng thì không có ý nghĩa gì cả. Bạn cần cắm các "chiếc ghim" lên đó để chỉ định vị trí cửa hàng, vị trí tài xế, hoặc nơi giao hàng. Chúng ta sử dụng component Marker.

Thẻ <Marker> phải luôn được đặt bên trong (làm con) của thẻ <MapView>.

import React from 'react'
import { StyleSheet, View, Text } from 'react-native'
import MapView, { Marker } from 'react-native-maps'

export default function StoreMap() {
  const storeLocation = { latitude: 21.0285, longitude: 105.8542 }

  return (
    <View style={styles.container}>
      <MapView style={styles.map} initialRegion={{ ...storeLocation, latitudeDelta: 0.01, longitudeDelta: 0.01 }}>
        {/* Cắm cờ vị trí cửa hàng */}
        <Marker coordinate={storeLocation} title="Cửa hàng trung tâm" description="Mở cửa từ 8h - 22h" />
      </MapView>
    </View>
  )
}

const styles = StyleSheet.create({
  container: { flex: 1 },
  map: { flex: 1 },
})

Khi người dùng chạm vào chiếc ghim đỏ trên màn hình, một khung thông tin (Callout) sẽ bật lên hiển thị titledescription cực kỳ chuyên nghiệp.

4. Tùy biến giao diện (Dark Mode & Custom Marker)

Để thiết kế UI/UX theo hơi hướng hiện đại, bạn không nên sử dụng chiếc ghim màu đỏ mặc định nhàm chán. react-native-maps cho phép bạn tùy biến mọi thứ.

  • Đổi Icon của Marker: Bạn chỉ cần truyền một thẻ <Image> hoặc các thẻ vẽ đồ họa vào bên trong <Marker>.
  • Kích hoạt Dark Mode cho bản đồ: Nếu ứng dụng của bạn có nền tối, bản đồ sáng chói sẽ làm hỏng trải nghiệm thị giác. Bạn có thể truyền một mảng JSON định dạng màu sắc vào thuộc tính customMapStyle.
<Marker coordinate={storeLocation}>
  {/* Thay ghim đỏ bằng một Icon tùy biến, ưu tiên phong cách đồ họa phẳng */}
  <View style={{ backgroundColor: '#2d3436', padding: 8, borderRadius: 20 }}>
    <Text style={{ color: '#fff', fontWeight: 'bold' }}>📍 CHÍNH</Text>
  </View>
</Marker>

5. Kết hợp GPS: Hiển thị vị trí Real-time

Bây giờ là lúc chúng ta ghép nối kiến thức ở bài expo-location vào tấm bản đồ này.

Mục tiêu: Mở app lên, tự động xin quyền, lấy tọa độ GPS hiện tại và dịch chuyển bản đồ về đúng chỗ bạn đang đứng.

import React, { useState, useEffect } from 'react'
import { View, StyleSheet, ActivityIndicator, Text } from 'react-native'
import MapView, { Marker } from 'react-native-maps'
import * as Location from 'expo-location'

export default function LiveMapScreen() {
  const [myLocation, setMyLocation] = useState(null)
  const [errorMsg, setErrorMsg] = useState(null)

  useEffect(() => {
    ;(async () => {
      // 1. Xin quyền GPS
      let { status } = await Location.requestForegroundPermissionsAsync()
      if (status !== 'granted') {
        setErrorMsg('Không thể hiển thị bản đồ vì thiếu quyền GPS.')
        return
      }

      // 2. Lấy tọa độ hiện tại
      let location = await Location.getCurrentPositionAsync({})
      setMyLocation({
        latitude: location.coords.latitude,
        longitude: location.coords.longitude,
        latitudeDelta: 0.01,
        longitudeDelta: 0.01,
      })
    })()
  }, [])

  // Nếu đang chờ GPS, hiển thị loading
  if (!myLocation && !errorMsg) {
    return (
      <View style={styles.center}>
        <ActivityIndicator size="large" color="#0984e3" />
        <Text>Đang dò vệ tinh GPS...</Text>
      </View>
    )
  }

  // Nếu bị lỗi từ chối quyền
  if (errorMsg) {
    return (
      <View style={styles.center}>
        <Text style={{ color: 'red' }}>{errorMsg}</Text>
      </View>
    )
  }

  // Hoàn tất: Vẽ bản đồ
  return (
    <View style={styles.container}>
      <MapView
        style={styles.map}
        region={myLocation} // Dùng region thay  initialRegion để bản đồ tự động di chuyển khi myLocation thay đổi
        showsUserLocation={true} // Bật chấm xanh lam hiển thị hướng điện thoại (Native feature)
        showsMyLocationButton={true} // Bật nút bấm để tự động quay về tâm
      >
        {/* Bạn có thể cắm thêm các Marker khác ở đây */}
      </MapView>
    </View>
  )
}

const styles = StyleSheet.create({
  container: { flex: 1 },
  map: { flex: 1 },
  center: { flex: 1, justifyContent: 'center', alignItems: 'center' },
})

6. Lưu ý quan trọng khi triển khai (Deployment)

Việc chạy bản đồ trên ứng dụng Expo Go (khi đang code) rất mượt mà vì Expo đã cấu hình sẵn mọi thứ. Tuy nhiên, khi bạn đóng gói ứng dụng (Build App) để đẩy lên Google Play Store hoặc Apple App Store, bản đồ có thể bị lỗi "Trắng màn hình".

Để khắc phục, bạn BẮT BUỘC phải tạo Google Maps API Key (miễn phí) từ Google Cloud Console và chèn vào file app.json của dự án.

Cấu hình trong app.json sẽ trông như sau:

{
  "expo": {
    "ios": {
      "bundleIdentifier": "com.yourcompany.app",
      "config": {
        "googleMapsApiKey": "MÃ_API_KEY_IOS_CỦA_BẠN"
      }
    },
    "android": {
      "package": "com.yourcompany.app",
      "config": {
        "googleMaps": {
          "apiKey": "MÃ_API_KEY_ANDROID_CỦA_BẠN"
        }
      }
    }
  }
}

Kết luận: Nắm trọn "công nghệ tỷ đô"

Giao diện trực quan làm nên đẳng cấp của ứng dụng. Bằng cách kết hợp react-native-mapsexpo-location, bạn đã nắm trong tay công nghệ lõi của những nền tảng tỷ đô.

  1. Khởi tạo <MapView> với flex: 1 để hiển thị bản đồ.
  2. Dùng <Marker> để đánh dấu các điểm cần lưu ý.
  3. Luôn lấy quyền GPS trước khi sử dụng thuộc tính showsUserLocation.

Hẹn gặp lại bạn ở những bài học thú vị tiếp theo!

Bài viết liên quan

Cách dùng FlatList trong React Native: Hiển thị danh sách không giật lag

Giải quyết bài toán hiển thị danh sách dữ liệu lớn với FlatList và SectionList. Hướng dẫn tối ưu hóa bộ nhớ và tốc độ cuộn (scroll) mượt mà.

Animation trong React Native: Hướng dẫn toàn tập Reanimated 3

Hướng dẫn cách khắc phục lỗi giật lag UI bằng React Native Reanimated 3. Khám phá bí quyết tạo animation mượt mà 60fps với useSharedValue và withSpring.

Hướng dẫn cài đặt môi trường React Native & Expo trong 15 phút

Bạn sợ cài đặt môi trường lập trình mobile phức tạp? Hướng dẫn chi tiết cách dùng Expo Go, Node.js để chạy app React Native ngay lập tức.

Hướng dẫn tích hợp Push Notifications với React Native và Expo

Hướng dẫn chi tiết cách cài đặt và cấu hình Push Notifications trong React Native sử dụng hệ thống Expo. Nắm vững cách xin quyền, lấy Token và gửi thông báo kiểm thử.