12/08/2018, 14:56

Sử dụng PlaceAutocompleteFragment để xây dựng 1 ứng dụng tìm kiếm địa điểm đơn giản

Cách đơn giản nhất là các bạn khởi tạo 1 project với sử dụng template Google Maps Activity. Để lấy key cho ứng dụng các bạn cần làm những bước sau Vào https://console.developers.google.com/iam-admin/projects khởi tạo 1 project Vào https://console.developers.google.com/apis/library?project ...

Cách đơn giản nhất là các bạn khởi tạo 1 project với sử dụng template Google Maps Activity.

Để lấy key cho ứng dụng các bạn cần làm những bước sau

  • Vào https://console.developers.google.com/iam-admin/projects khởi tạo 1 project
  • Vào https://console.developers.google.com/apis/library?project=my-location-android click Google Maps Android API và Google Places API for Android chọn ENABLE để cho phép key của bạn được phép sử dụng 2 dịch vụ này của google.

(các bạn có thể tham khảo cách tạo key cho ứng dụng ở đây https://developers.google.com/maps/documentation/android-api/signup). Sau khi lấy dc key cho ứng dụng các bạn điền key cho Project vào thẻ <meta-data> trong file AndroidManifest

<meta-data
    android:name="com.google.android.geo.API_KEY"
    android:value="enter_your_key_here"/>

trong build.gradle các bạn thêm thư viện

  compile 'com.google.android.gms:play-services:10.0.1'

Các bạn thiết kế lại layout_main.xml 1 chút:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_awidth="match_parent"
    android:layout_height="match_parent"
    tools:context="com.lap.myapplication.MapsActivity"
    >
    <fragment
        android:id="@+id/map"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:layout_awidth="match_parent"
        android:layout_height="match_parent"
        />
    <fragment
        android:id="@+id/place_autocomplete_fragment"
        android:name="com.google.android.gms.location.places.ui.PlaceAutocompleteFragment"
        android:layout_awidth="match_parent"
        android:layout_height="wrap_content"
        />
</RelativeLayout>

Quay lại file MainAcvity

public class MainActivity extends FragmentActivity
        implements OnMapReadyCallback, PlaceSelectionListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        SupportMapFragment mapFragment =
                (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);

        PlaceAutocompleteFragment autocompleteFragment =
                (PlaceAutocompleteFragment) getFragmentManager().findFragmentById(
                        R.id.place_autocomplete_fragment);
        autocompleteFragment.setOnPlaceSelectedListener(this);
    }

    // Callback được gợi sau khi Map đã sẵn sàng
    @Override
    public void onMapReady(GoogleMap googleMap) {
        // do something
    }

    // Callback khi bạn click vào item
    @Override
    public void onPlaceSelected(Place place) {
        // do something
    }

    @Override
    public void onError(Status status) {

    }
}

tới đây các bạn có thể chạy để xem kết quả ban đầu rồi. Nhưng mà hiện tại khi các bạn chạy ứng dụng thì mới chỉ lên được map và có thanh tìm kiếm hiện lên màn hình.

Để cho thanh tìm kiếm đẹp đẽ hơn các bạn có thể thêm

android:background="@drawable/bg_search"

trong file bg_search

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#ffffff"/>
    <corners
        android:radius="4dp"/>
</shape>

Để lấy vị trí hiện tại bạn đang đứng mình khuyên các bạn sử dụng GoogleApiClient. Các bạn khởi tạo 2 biến GoogleApiClient, GoogleMap và implements thêm 2 Callback.

public class MainActivity extends FragmentActivity
        implements OnMapReadyCallback, PlaceSelectionListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {

    private GoogleApiClient googleApiClient;
    private GoogleMap googleMap;
    
    ...
    
    @Override
    public void onConnected(@Nullable Bundle bundle) {
        // do something
    }

    @Override
    public void onConnectionSuspended(int i) {
        // do something when Connection Error
    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult result) {
        // do something when Connection Failed
    }

Bây giở quay lại hàm onMapReady (các bạn chú ý là chú ta chỉ làm mọi thứ khi map đã sẵn sàng nhé).

    @Override
    public void onMapReady(GoogleMap googleMap) {
        //  Add permission in Manifests
        //  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
        //  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
        //  Request permission if SDK > 23
        
        buildGoogleApiClient();
        this.googleMap = googleMap;
        // Add icon my location
        this.googleMap.setMyLocationEnabled(true);
    } 
   ...
   private void buildGoogleApiClient() {
        googleApiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .addApi(Places.GEO_DATA_API)
                .addApi(Places.PLACE_DETECTION_API)
                .build();
        googleApiClient.connect();
    }

Trong Callback onConnected khi GoogleApiClient kết nối thành công

    @Override
    public void onConnected(@Nullable Bundle bundle) {
        // Check permission
        
        Location location = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
        LatLng myLatLng = new LatLng(location.getLatitude(), location.getLongitude());
        CameraPosition cameraPosition = new CameraPosition.Builder().target(
                myLatLng)                   // Sets the center of the map to Mountain View
                .zoom(17)                   // Sets the zoom
                .bearing(0)                // Sets the orientation of the camera to east
                .tilt(0)                   // Sets the tilt of the camera
                .build();
        googleMap.addMarker(new MarkerOptions().position(myLatLng).title("My Place"));
        googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
    }

Bây giờ run app thì sẽ được di chuyển về vị trí hiện tại của bạn.

Ở phần đầu mình có set callback cho sự kiện khi click vào item của Autocomplete. Trong Callback onPlaceSelected

    private Marker marker;
    ...
    @Override
    public void onPlaceSelected(Place place) {
        // remove old marker when add new marker
        if (marker != null) marker.remove();
        LatLng myLatLng = place.getLatLng();
        marker = googleMap.addMarker(
                new MarkerOptions().position(myLatLng).title(String.valueOf(place.getName())));
        googleMap.animateCamera(CameraUpdateFactory.newLatLng(myLatLng));
    }

PlaceAutocompleteFragment còn có nhiều lựa chọn cho gợi ý được tốt hơn:

  • setBoundsBias(LatLngBounds latLngBounds);
  • setFilter(AutocompleteFilter typeFilter);

setBoundsBias nhận vào 1 LatLngBounds(LatLng southwest, LatLng northeast) cho biết giới hạn của địa điểm gợi ý. setFilter nhận vào 1 AutocompleteFilter để set bộ lọc cho các gợi ý được hiển thị.

// ví dụ gợi ý chỉ hiển thị các địa điểm ở Việt Nam
AutocompleteFilter typeFilter = new AutocompleteFilter.Builder()
                .setCountry("VN") //  This should be a ISO 3166-1 Alpha-2 country code
                .build();
autocompleteFragment.setFilter(typeFilter);

các bạn có thể thao khảo chuẩn ISO 3166-1 Alpha-2 tại đây.

Vậy là đã xong, bây giờ bạn có thể run ứng dụng để xem kết quả, rất đơn giản có phải không nào. Các bạn có thể tham khảo Source code tại đây

0