Chuyển đến nội dung chính

Google Maps Android Custom Info Window Example

https://www.zoftino.com/google-maps-android-custom-info-window-example

You can display information about a location where you add a marker on the Google map by customizing info window. This post shows how to define custom info window layout and custom info window adapter and use it to display customized info window on the Google map.


You can read my previous tutorial about Google maps android API to know how to use Google play service API in android applications and view Google maps android API examples.
Before you continue with this example, you may want to learn android and latest features with examples. Please visit android tutorials for all android concepts, components and libraries with examples which use latest components and API.

Google Maps Android Custom Info Window Example Output

android google maps custom info window example

Google Maps Android Custom Info Window Example

To create custom info window, first you need to define layout for info window with elements such as image and text view which you want to display in your custom info window.
 <?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="@style/TextAppearance.AppCompat.Headline"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
    <ImageView
        android:id="@+id/pic"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/name"/>
    <TextView
        android:id="@+id/details"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:singleLine="false"
        android:layout_marginTop="8dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/pic" />
    <TextView
        android:id="@+id/hotels"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:textColor="#c2185b"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/details"/>
    <TextView
        android:id="@+id/food"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:textColor="#1976d2"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/hotels"/>
    <TextView
        android:id="@+id/transport"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:textColor="#64dd17"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/food"/>

</android.support.constraint.ConstraintLayout>
 
After custom info window layout is defined, you need to define custom InfoWindowAdapter class by implementing GoogleMap.InfoWindowAdapter interface. InfoWindowAdapter interface has two methods getInfoContents and getInfoWindow methods which you need to implement.
If you want to define your own window, you need to implement getInfoWindow method otherwise just return null to indicate that you use default window. To provide content for info window, you need to implement getInfoContents methods. You need to use your custom layout in this method and populate values into the elements of the layout.
To pass information from activity to custom InfoWindowAdapter, you can create data transfer object. In your activity, this object is added to marker using setTag method passing the object. Since Marker object is passed to getInfoContents method, you can get tag object and use data to populate elements in info window layout as show in the example.
 import android.app.Activity;
import android.content.Context;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

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

public class CustomInfoWindowGoogleMap implements GoogleMap.InfoWindowAdapter {

    private Context context;

    public CustomInfoWindowGoogleMap(Context ctx){
        context = ctx;
    }

    @Override
    public View getInfoWindow(Marker marker) {
        return null;
    }

    @Override
    public View getInfoContents(Marker marker) {
        View view = ((Activity)context).getLayoutInflater()
.inflate(R.layout.map_custom_infowindow, null);

        TextView name_tv = view.findViewById(R.id.name);
        TextView details_tv = view.findViewById(R.id.details);
        ImageView img = view.findViewById(R.id.pic);

        TextView hotel_tv = view.findViewById(R.id.hotels);
        TextView food_tv = view.findViewById(R.id.food);
        TextView transport_tv = view.findViewById(R.id.transport);

        name_tv.setText(marker.getTitle());
        details_tv.setText(marker.getSnippet());

        InfoWindowData infoWindowData = (InfoWindowData) marker.getTag();

        int imageId = context.getResources().getIdentifier(infoWindowData.getImage().toLowerCase(),
                "drawable", context.getPackageName());
        img.setImageResource(imageId);

        hotel_tv.setText(infoWindowData.getHotel());
        food_tv.setText(infoWindowData.getFood());
        transport_tv.setText(infoWindowData.getTransport());

        return view;
    }
}
 
In the activity, first define marker options and add to map, then instantiate data object, populate values and add it to Marker by calling setTag and finally instantiate custom info window class and add it to Marker by calling setInfoWindowAdapter method.
 import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

public class GoogleMapInfoWindowActivity extends AppCompatActivity implements OnMapReadyCallback {

    private GoogleMap mMap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.maps_infowindow);

        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.gmap);
        mapFragment.getMapAsync(this);
    }


    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;

        mMap.getUiSettings().setZoomControlsEnabled(true);
        mMap.setMinZoomPreference(11);

        LatLng snowqualmie = new LatLng(47.5287132, -121.8253906);

        MarkerOptions markerOptions = new MarkerOptions();
        markerOptions.position(snowqualmie)
                .title("Snowqualmie Falls")
                .snippet("Snoqualmie Falls is located 25 miles east of Seattle.")
                .icon(BitmapDescriptorFactory.defaultMarker( BitmapDescriptorFactory.HUE_BLUE));

        InfoWindowData info = new InfoWindowData();
        info.setImage("snowqualmie");
        info.setHotel("Hotel : excellent hotels available");
        info.setFood("Food : all types of restaurants available");
        info.setTransport("Reach the site by bus, car and train.");

        CustomInfoWindowGoogleMap customInfoWindow = new CustomInfoWindowGoogleMap(this);
        mMap.setInfoWindowAdapter(customInfoWindow);

        Marker m = mMap.addMarker(markerOptions);
        m.setTag(info);
        m.showInfoWindow();

        mMap.moveCamera(CameraUpdateFactory.newLatLng(snowqualmie));
    }
}
 
Below is the data transfer object used to transfer data from activity to info window adapter class.
 public class InfoWindowData {
    private String image;
    private String hotel;
    private String food;
    private String transport;

    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image;
    }

    public String getHotel() {
        return hotel;
    }

    public void setHotel(String hotel) {
        this.hotel = hotel;
    }

    public String getFood() {
        return food;
    }

    public void setFood(String food) {
        this.food = food;
    }

    public String getTransport() {
        return transport;
    }

    public void setTransport(String transport) {
        this.transport = transport;
    }
}

Nhận xét

Bài đăng phổ biến từ blog này

Camera2 - Android

Ở bài viết này mình xin giới thiệu về cách sử dụng Camera2 trong android SDK 21. Với các lập trình viên android việc sử dụng Camera có rất nhiều trong ứng dụng: Camera Capture Images, Barcode - QR Code Reader, AR, Video Record,.... Nhiều ứng dụng chỉ ở tầng ứng dụng sử dụng thông qua  Intent  như vậy hệ thống tự động được gọi ở mức tối ưu nhất, nhưng cũng không ít ứng dụng cần can thiệp vào tầng  native  để xử lý Với  Camera   developer.android.com  đã  deprecate  nó đã không còn được sử dụng cơ bản trong các ứng dụng nữa vì rất nhiều nguyên nhân trong đó phải kể tới: tốn tài nguyên, thời gian capture khá chậm và đặc biệt phục vụ nhu cầu ngày càng cao của người dùng như 'Chụp ảnh liên tục, chụp nhiều ảnh và tự động lấy nét' thì  Camera không đáp ứng được Với  Camera2  đã đáp ứng được những thiếu xót trên ngoài ra việc customize cho ảnh là rất dễ dàng mang lại chất lượng cao ngoài ra việc sử dụng cũng không có nhiều thay ...

Sự khác nhau giữa let, apply, with, run và also trong Kotlin

Với những ai đã sử dụng Kotlin để phát triển ứng dụng, chắc hẳn đã không ít lần sử dụng các standard functions run, with, let, also và apply. Để hiểu và sử dụng thành thục chúng không phải là dễ. Và dưới đây là những điều đúc kết lại được. https://viblo.asia/p/su-khac-nhau-giua-let-apply-with-run-va-also-trong-kotlin-RQqKLNdml7z Scoping functions Có thể hiểu đơn giản, scoping function là phạm vi ảnh hưởng nhất định của một hàm. Nó là điều cốt lõi để phân biệt giữa các scoping functions: run, with, T.run, T.let, T.also và T.apply. Dưới đây là minh hoạ phạm vi của hàm run: fun test ( ) { var mood = "I am sad" run { val mood = "I am happy" println ( mood ) // I am happy } println ( mood ) // I am sad } Ở trên, ta có thể thấy rõ ràng trong phạm vi của hàm run, biến mood đã được định nghĩa lại trước khi in ra mà không làm ảnh hưởng tới phần khác của chương trình 3 attributes of scoping functions 1.Normal vs. extension fun...

TỰ ĐỘNG HUỶ ACTIVITY SAU KHI STARTACTIVITY

Trước giờ để huỷ một Activity khi bạn thường dùng hàm  finish()  đúng không nào? Không đi đâu xa là khi bạn Intent từ một Activity này sang Activity khác mà muốn huỷ luôn Activity đầu tiên luôn thì bạn sẽ dùng đoạn code y chang bên dưới chứ? Cơ chế của Activity là khi bạn chuyển từ một Activity này sáng Activity khác thì nó sẽ Activity đó vào stack, và khi back về thì Activity sẽ được hiện lên lại và chạy vào onResume(), nếu bạn chưa hiểu về  vòng đời của Activity  thì xem lại bài viết kèm video tại blog mình nhé, mình ví dụ khá chi tiết. Intent intent = new Intent(MainActivity.this, LoginActivity.class); startActivity(intent); finish(); Đoạn code trên nghĩa là chuyển từ MainActivity sang LoginActivity và sau đó huỷ luôn MainActivity đúng không nào? Tuy nhiên đó không phải là cách duy nhất mà chúng ta làm đâu bởi Android hỗ trợ chúng ta một số thuộc tính mà bạn không phải dùng code Java để làm. Không lưu Activity vào stack Cũng logic như bài toán phí...