Google Maps Android API – phần 3

ngày 30-03-2016

 
Phần 1 và 2, bạn đã biết cách đưa Google Map ra ứng dụng Android. Trong bài này Tui sẽ hướng dẫn các bạn cách tương tác nâng cao với Google Map.
 
Ta tiếp tục với Project LearnGoogleMap ở phần 2.
 
Để truy xuất đối tượng Google Map trong XML layout ta làm như sau:
 
GoogleMap map = ((MapFragment)getFragmentManager().findFragmentById(R.id.map)).getMap();
 
Thông thường khi tải Google Map thường tốn thời gian chờ, vì vậy ta nên dùng Progress control để cho người sử dụng biết là chương trình đang chạy.
 
GoogleMap cung cấp sự kiện OnMapLoadedCallback để cho phép ta kiểm tra xem Map đã được tải về ứng dụng hoàn thành hay chưa, ta có thể dựa vào sự kiện này để kiểm tra.
 
Ta sửa code MainActivity như sau:
 

package tranduythanh.com.learngooglemap;

 

import com.google.android.gms.maps.GoogleMap;

import com.google.android.gms.maps.MapFragment;

import com.google.android.gms.maps.GoogleMap.OnMapLoadedCallback;

 

import android.app.Activity;

import android.app.ProgressDialog;

import android.os.Bundle;

 

public class MainActivity extends Activity {

 

//Khai báo đối tượng Google Map

GoogleMap map;

//Khai báo Progress Bar dialog để làm màn hình chờ

ProgressDialog myProgress;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

//Tạo Progress Bar

myProgress = new ProgressDialog(this);

myProgress.setTitle("Đang tải Map ...");

myProgress.setMessage("Vui lòng chờ...");

myProgress.setCancelable(true);

//Hiển thị Progress Bar

myProgress.show();

//Lấy đối tượng Google Map ra:

map = ((MapFragment)getFragmentManager().

findFragmentById(R.id.map)).getMap();

//thiết lập sự kiện đã tải Map thành công

map.setOnMapLoadedCallback(new OnMapLoadedCallback() {

 

@Override

public void onMapLoaded() {

//Đã tải thành công thì tắt Dialog Progress đi

myProgress.dismiss();

}

});

map.setMapType(GoogleMap.MAP_TYPE_NORMAL);

map.getUiSettings().setZoomControlsEnabled(true);

map.setMyLocationEnabled(true);

}

}

 
Khởi động ứng dụng ta được như sau:
 
– Ta cần biết thêm số chức năng của Google Map như sau:
 
  • Làm sao biết biết được vị trí hiện tại của ta để di chuyển Map đúng vị trí
  • Cách xoay , quay Map như thế nào
  • Đường đi giữa các địa điểm ra sao….
 
* Để biết được vị trí hiện tại của ta trên bản đồ ta cần bổ sung thêm Manifest các thông số sau:
 

<uses-feature android:name="android.hardware.location" android:required="true" />

<uses-feature android:name="android.hardware.location.gps" android:required="true" />

 
Trong MainActivity bạn bổ sung thêm hàm “TuiDangODau” :
 

private void TuiDangODau() {

 

LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

Criteria criteria = new Criteria();

 

Location lastLocation = locationManager.getLastKnownLocation(locationManager.getBestProvider(criteria, false));

if (lastLocation != null)

{

map.animateCamera(CameraUpdateFactory.newLatLngZoom(

new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude()), 13));

 

CameraPosition cameraPosition = new CameraPosition.Builder()

.target(new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude()))      // Sets the center of the map to location user

.zoom(15)                // Sets the zoom

.bearing(90)            // Sets the orientation of the camera to east

.tilt(40)                      // Sets the tilt of the camera to 30 degrees

.build();                     // Creates a CameraPosition from the builder

map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));

}

}

 
Sau đó trong hàm OnCreate, ta gọi bổ sung thêm hàm TuiDangODau:
 

protected void onCreate(Bundle savedInstanceState) {

//.....

 

//Thêm dòng lệnh này:

TuiDangODau();

}

 
Khi chạy ứng dụng lên, phần mềm sẽ tự động đưa ta về đúng vị trí trên bản đồ …:
 
 
Bạn muốn thêm ghi chú cho địa điểm của bạn thì bổ sung tiếp MarkerOptions, bạn sửa lại hàm TuiDangODau như sau:
 

private void TuiDangODau() {

 

LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

Criteria criteria = new Criteria();

 

Location lastLocation = locationManager.getLastKnownLocation(locationManager.getBestProvider(criteria, false));

if (lastLocation != null)

{

LatLng latLng=new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude());

map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 13));

 

CameraPosition cameraPosition = new CameraPosition.Builder()

.target(latLng)      // Sets the center of the map to location user

.zoom(15)                   // Sets the zoom

.bearing(90)                // Sets the orientation of the camera to east

.tilt(40)                   // Sets the tilt of the camera to 30 degrees

.build();                   // Creates a CameraPosition from the builder

map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));

//Thêm MarketOption cho Map:

MarkerOptions option=new MarkerOptions();

option.title("Chỗ Tui đang ngồi đó");

option.snippet("Gần làng SOS");

option.position(latLng);

Marker currentMarker= map.addMarker(option);

currentMarker.showInfoWindow();

}

}

 
Tiến hành chạy lại ứng dụng ta có kết quả như hình dưới đây:
 
 
-Tuy nhiên trong nhiều trường hợp ta cần hiệu chỉnh lại MarkerOption theo ý của Ta cho nó đẹp và phục vụ những mục đích khác… Do đó ta cần phải biết hiệu chỉnh InfoWindowAdapter:
 
Giả sử ta sửa lại Marker Option như sau:
 
 
Bạn quan sát khi Tui nhấn ngón tay vào núm màu xám xanh thì nó hiển thị lên MarkerOption theo định dạng của riêng Tui, cái này rất hay và tiện dung trong việc quảng bá thương hiệu của một địa điểm nào đó, với những thông tin thật chi tiết và hữu ích.
 
Bạn để ý Marker Tui hiển thị các thông tin sau:
 
  • Hình Tui tải từ link trên Facebook
  • Kinh độ (longtitude)
  • Vĩ độ (latitude)
  • Title
  • Snippet
 
Bạn thấy háo hức không? Tui thấy rất là háo hức khi các bạn làm được như trên. Nó quá hay và tiện dụng.
 
Vậy làm sao để có thể coding cho nó hiểu như trên?
 
Tiếp tục với bài LearnGoogleMap ở trên, bạn tạo thêm lớp ImageLoadTask để tải hình từ Facebook, MyInfoWindowAdapter và custom_info.xml để hiển thị thông tin Marker theo ý mình:
 
 
– Layout để hiển thị Marker Option theo ý mình như sau (custom_info.xml):
 

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical" >

 

<ImageView

android:id="@+id/img_drthanh"

android:layout_width="400dp"

android:layout_height="200dp"

android:src="@drawable/common_full_open_on_phone" />

 

<TextView

android:id="@+id/tv_lat"

android:layout_width="wrap_content"

android:layout_height="wrap_content" />

 

<TextView

android:id="@+id/tv_lng"

android:layout_width="wrap_content"

android:layout_height="wrap_content" />

 

<TextView

android:id="@+id/textView1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="title:" />

 

<TextView

android:id="@+id/tv_title"

android:layout_width="wrap_content"

android:layout_height="wrap_content" />

 

<TextView

android:id="@+id/textView3"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="snippet:" />

 

<TextView

android:id="@+id/tv_snippet"

android:layout_width="wrap_content"

android:layout_height="wrap_content" />

 

</LinearLayout>

 
Lớp ImageLoadTask để tải hình ảnh từ Facebook về sau đó hiển thị lên Custom Marker Option như sau:
 

package tranduythanh.com.learngooglemap;

 

import java.io.InputStream;

import java.net.HttpURLConnection;

import java.net.URL;

 

import com.google.android.gms.maps.GoogleMap;

import com.google.android.gms.maps.model.Marker;

 

import android.app.Activity;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.os.AsyncTask;

 

public class ImageLoadTask extends AsyncTask<Void, Void, Bitmap> {

 

//Link url hình ảnh bất kỳ

private String url;

private GoogleMap map;

private Activity context;

private boolean isCompleted=false;

private Marker currentMarker;

 

public boolean isCompleted() {

return isCompleted;

}

 

public void setCompleted(boolean isCompleted) {

this.isCompleted = isCompleted;

}

 

public ImageLoadTask(Activity context, String url,GoogleMap map,Marker currentMarker) {

this.context=context;

this.url = url;

this.map=map;

this.currentMarker=currentMarker;

}

 

@Override

protected Bitmap doInBackground(Void... params) {

try {

//Tiến hành tạo đối tượng URL

URL urlConnection = new URL(url);

//Mở kết nối

HttpURLConnection connection = (HttpURLConnection) urlConnection

.openConnection();

connection.setDoInput(true);

connection.connect();

//Đọc dữ liệu

InputStream input = connection.getInputStream();

//Tiến hành convert qua hình ảnh

Bitmap myBitmap = BitmapFactory.decodeStream(input);

if(myBitmap=null)

return null;

return myBitmap;

} catch (Exception e)

{

e.printStackTrace();

}

return null;

}

 

@Override

protected void onPostExecute(Bitmap result) {

super.onPostExecute(result);

//thiết lập Info cho Map khi tải hình hoàn tất

map.setInfoWindowAdapter(new MyInfoWindowAdapter(context,result));

//tiến hành hiển thị lên Custom marker option lên Map:

currentMarker.showInfoWindow();

}

}

 
– Chú ý dòng lệnh 67, 69 là để gán Custom cho Map và hiển thị nó lên.
 
Coding MyInfoWindowAdapter để custom layout cho Marker option:
 

package tranduythanh.com.learngooglemap;

 

import android.app.Activity;

import android.graphics.Bitmap;

import android.view.View;

import android.widget.ImageView;

import android.widget.TextView;

 

import com.google.android.gms.maps.GoogleMap.InfoWindowAdapter;

import com.google.android.gms.maps.model.LatLng;

import com.google.android.gms.maps.model.Marker;

 

public class MyInfoWindowAdapter implements InfoWindowAdapter {

 

private Activity context;

private Bitmap btmp;

public MyInfoWindowAdapter(Activity context,Bitmap result)

{

this.context=context;

this.btmp=result;

}

@Override

public View getInfoContents(Marker arg0) {

// Getting view from the layout file info_window_layout

View v = this.context.getLayoutInflater().inflate(R.layout.custom_info, null);

 

// Getting the position from the marker

LatLng latLng = arg0.getPosition();

 

// Getting reference to the TextView to set latitude

TextView tvLat = (TextView) v.findViewById(R.id.tv_lat);

 

// Getting reference to the TextView to set longitude

TextView tvLng = (TextView) v.findViewById(R.id.tv_lng);

 

TextView tvTitle = (TextView) v.findViewById(R.id.tv_title);

 

TextView tvSnippet = (TextView) v.findViewById(R.id.tv_snippet);

 

ImageView imgdrthanh=(ImageView) v.findViewById(R.id.img_drthanh);

 

// Setting the latitude

tvLat.setText("Latitude:" + latLng.latitude);

 

// Setting the longitude

tvLng.setText("Longitude:"+ latLng.longitude);

 

tvTitle.setText(arg0.getTitle());

tvSnippet.setText(arg0.getSnippet());

imgdrthanh.setImageBitmap(btmp);

return v;

}

 

@Override

public View getInfoWindow(Marker arg0) {

 

return null;

}

}

 
 
– Cuối cùng chỉnh sửa lại MainActivity như sau:
 

package tranduythanh.com.learngooglemap;

 

import com.google.android.gms.common.api.GoogleApiClient;

import com.google.android.gms.maps.CameraUpdateFactory;

import com.google.android.gms.maps.GoogleMap;

import com.google.android.gms.maps.MapFragment;

import com.google.android.gms.maps.GoogleMap.OnMapLoadedCallback;

import com.google.android.gms.maps.model.BitmapDescriptorFactory;

import com.google.android.gms.maps.model.CameraPosition;

import com.google.android.gms.maps.model.LatLng;

import com.google.android.gms.maps.model.Marker;

import com.google.android.gms.maps.model.MarkerOptions;

 

import android.app.Activity;

import android.app.ProgressDialog;

import android.location.Criteria;

import android.location.Location;

import android.location.LocationManager;

import android.os.Bundle;

 

public class MainActivity extends Activity {

 

//Khai báo đối tượng Google Map

GoogleMap map;

//Khai báo Progress Bar dialog để làm màn hình chờ

ProgressDialog myProgress;

GoogleApiClient googleApiClient;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

//Tạo Progress Bar

myProgress = new ProgressDialog(this);

myProgress.setTitle("Đang tải Map ...");

myProgress.setMessage("Vui lòng chờ...");

myProgress.setCancelable(true);

//Hiển thị Progress Bar

myProgress.show();

//Lấy đối tượng Google Map ra:

map = ((MapFragment)getFragmentManager().

findFragmentById(R.id.map)).getMap();

//thiết lập sự kiện đã tải Map thành công

map.setOnMapLoadedCallback(new OnMapLoadedCallback() {

 

@Override

public void onMapLoaded() {

//Đã tải thành công thì tắt Dialog Progress đi

myProgress.dismiss();

}

});

map.setMapType(GoogleMap.MAP_TYPE_NORMAL);

map.getUiSettings().setZoomControlsEnabled(true);

map.setMyLocationEnabled(true);

//lấy lấy được vị trí cuối cùng:

 

TuiDangODau();

}

private void TuiDangODau() {

 

LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

Criteria criteria = new Criteria();

 

Location lastLocation = locationManager.getLastKnownLocation(locationManager.getBestProvider(criteria, false));

if (lastLocation != null)

{

LatLng latLng=new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude());

map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 13));

 

CameraPosition cameraPosition = new CameraPosition.Builder()

.target(latLng)      // Sets the center of the map to location user

.zoom(15)                   // Sets the zoom

.bearing(90)                // Sets the orientation of the camera to east

.tilt(40)                   // Sets the tilt of the camera to 30 degrees

.build();                   // Creates a CameraPosition from the builder

map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));

//Thêm MarketOption cho Map:

MarkerOptions option=new MarkerOptions();

option.title("Chỗ Tui đang ngồi đó");

option.snippet("Gần làng SOS");

option.position(latLng);

option.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_VIOLET));

Marker currentMarker= map.addMarker(option);

 

ImageLoadTask imgTask=new ImageLoadTask(this,"https://scontent-a-lax.xx.fbcdn.net/hphotos-xpa1/v/t1.0-9/1488744_806006112761224_104751868_n.jpg?oh=18c334e98bdbc3454a0b72be9dc3f7dc&oe=55417543",map,currentMarker);

imgTask.execute();

}

}

}

 
Bạn để ý dòng lệnh 84, là dòng Tui gọi tải hình từ Facebook về, bạn có thể đổi link bất kỳ. Ở đây Tui truyền tham chiếu Map và MarkerOption qua Custom Adapter để hiển thị theo ý mình.
 
Bạn có thể tải source code phần Custom Marker Option ở đây:
 
Như vậy bạn đã biết được thao tác nâng cao với Google Map control, bài tiếp theo Tui sẽ hướng dẫn các bạn cách sử dụng các Autoshape trên Map (line, polyline, Rectangle, circle…)
 
Bạn cần phải làm lại bài này nhiều lần để hiểu được cơ chế làm việc của nó, đặc biệt là cách Custom Layout cho marker Option.
 
Chúc các bạn thành công
 
Nguồn: Thầy Trần Duy Thanh - Giảng viên tại Trung Tâm Tin Học ĐH Khoa Học Tự Nhiên
 
ai
Trung Tâm Tin Học
ai
Trung Tâm Tin Học
Chào mừng bạn đến với Trung Tâm Tin Học.
Bạn đang cần hỗ trợ thông tin gì ạ? Hãy Chat ngay với chúng tôi nhé.