10 January 2013

Google Maps Android API v2 - การเลื่อนไปยังตำแหน่งที่ต้องการบน Google Maps

Updated on

สำหรับคราวนี้ก็มาต่อกันที่ Camera ใน Google Maps กันบ้าง
Camera ในที่นี้ไม่ได้หมายถึงกล้องถ่ายภาพนะ อย่าเข้าใจผิด
แต่สำหรับ Google Maps คือ มุมมองบนแผนที่นั่นเอง
ซึ่งก็คือมุมมองที่กำลังแสดงแผนที่ของ Google Maps อยู่



สำหรับการติดตั้งเบื้องต้นสำหรับใช้งาน API v2 ให้อ่านที่
[Android Code] การใช้งาน Google Map Android API v2

สำหรับการเลื่อนตำแหน่งไปยังตำแหน่งที่ต้องการจะใช้คำสั่ง
mMap.animateCamera(CameraUpdateFactory.newLatLng(coordinates));

โดยที่ coordinates เป็นพิกัดเป้าหมาย ซึ่งกำหนดด้วยคลาส LatLng
ซึ่งเป็นคลาสที่ถูกเพิ่มเข้ามาใน GMapsV2 เพื่อช่วยในการกำหนดพิกัด
LatLng coordinates = new LatLng(13.76488, 100.538334);

จากตัวอย่างข้างต้นนี่ก็คือ coordinates จะเป็นพิกัด 13.76488, 100.538334
ทีนี้ก็สามารถเอา coordinates ไปกำหนดในคำสั่งเลื่อนตำแหน่งได้เลยดังนี้
LatLng coordinates = new LatLng(13.76488, 100.538334); GoogleMap mMap = ((SupportMapFragment)getSupportFragmentManager() .findFragmentById(R.id.map)).getMap(); mMap.animateCamera(CameraUpdateFactory.newLatLng(coordinates));

เพียงเท่านี้มุมกล้องก็จะเลื่อนไปยังพิกัด 13.76488, 100.538334 ทันที

สมมติว่าถ้าต้องการให้เลื่อนไปยังตำแหน่งที่ต้องการพร้อมกับซูมล่ะ?
ก็สามารถเปลี่ยนคำสั่งจาก newLatLng เป็น newLatLngZoom ได้เลย
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(coordinates, 11));

เพียงเท่านี้มุมกล้องก็จะเลื่อนไปตำแหน่งที่กำหนดพร้อมกับซูมไปที่ระดับ 11
สำหรับระดับของแผนที่ใน Google Maps จะมีทั้งหมด 20 ระดับด้วยกัน
โดยที่ระดับ 1 คือซูมออกจนสุด และระดับ 20 ก็คือซูมใกล้สุดนั่นเอง

และมี Callback สำหรับ Camera ให้ด้วยสำหรับคำสั่ง newLatLng
mMap.animateCamera(CameraUpdateFactory.newLatLng(coordinates) , 2000, new CancelableCallback() { public void onCancel() { // Cancelled } public void onFinish() { // Finished } });

โดยที่ Callback จะมีฟังก์ชันอยู่สองฟังก์ชันคือ onCancel และ onFinish
สำหรับ onCancel เป็นฟังก์ชันที่ทำงานเมื่อมุมกล้องเลื่อนอยู่
แล้วถูกสั่งให้มุมกล้องหยุดเลื่อนตำแหน่ง ฟังก์ชันนี้ก็จะทำงาน
ส่วน onFinish เป็นฟังก์ชันที่ทำงานเมื่อมุมกล้องเลื่อนไปถึงตำแหน่งแล้ว
และ 2000 ก็คือระยะเวลาที่มุมกล้องเคลื่อนที่ไปตำแหน่งที่ต้องการ
โดยมีหน่วยเป็น มิลลิวินาที ดังนั้น 2,000 มิลลิวินาทีก็คือ 2 วินาที

สมมติว่าผู้ที่หลงเข้ามาอ่านกำหนดให้เลื่อนตำแหน่งไปที่แห่งหนึ่ง
แล้วระหว่างที่มุมกล้องกำลังเลื่อนไปอยู่ แล้วผู้ใช้กดปุ่มหยุดทันที
ฟังก์ชัน onCancel ก็จะทำงาน เพราะมุมกล้องหยุดเคลื่อนที่กลางคัน
แต่ถ้ามุมกล้องเลื่อนไปจนถึงตำแหน่งที่กำหนด onFinish ก็จะทำงาน

ในกรณีที่มุมกล้องอยู่ตำแหน่งเดิม แล้วผู้ใช้กดปุ่มเลื่อนไปที่เดิมอีกครั้ง
ฟังก์ชัน onCancel ก็จะทำงานแทนนะ ไม่ใช่ฟังก์ชัน onFinish นะ
ส่วนคำสั่งหยุดการเลื่อนตำแหน่งมุมกล้องก็จะใช้คำสั่งตามนี้
mMap.stopAnimation();

ทีนี้ลองมาดูตัวอย่างของบทความนี้กันเลยดีกว่า

สำหรับใครที่ยังไม่ได้ติดตั้ง Library ของ Google Maps ให้ไปดู



Main.java

1. ประกาศ mMap และ coordinates ไว้นอกฟังก์ชัน onCreate
เพื่อให้เรียกใช้ใน Listener ของ Button ได้ (กำหนดเป็น final ก็ได้)

2. กำหนดให้ coordinated เป็นพิกัด 13.76488, 100.538334

3. กำหนดให้ mMap เป็น R.id.map ที่ได้สร้างไว้ใน Layout 

4. ประกาศ buttonGoto และสร้าง Listener เป็น OnClickListener

5. เมื่อกดปุ่มก็จะเลื่อนมุมกล้องไปตำแหน่งที่กำหนดใน coordinates

6. ประกาศ buttonGotoListener และสร้าง Listener เป็น OnClickListener

7. เมื่อกดปุ่มก็จะเลื่อนมุมกล้องไปตำแหน่งที่กำหนดใน coordinates
โดยมีระยะเวลา 2 วินาที (2,000 มิลลิวินาที) และเรียกใช้ Callback

8. ถ้ามุมกล้องหยุดเคลื่อนที่กลางคันจะแสดง "Cancelled" ผ่าน Toast

9. ถ้ามุมกล้องเคลื่อนที่ไปจนถึงตำแหน่งที่กำหนดใน coordinates แล้ว
ก็จะแสดงข้อความ "Finished" ผ่าน Toast และซูมไปที่ระดับ 15

10. กำหนดให้มุมกล้องทำการซูมแผนที่ไปที่ระดับ 15 

11. ประกาศ buttonStop และสร้าง Listener เป็น OnClickListener

12. เมื่อกดปุ่มก็จะสั่งให้มุมกล้องหยุดเคลื่อนที่ทันที


Main.java
package app.akexorcist.googlemapsv2animate;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.GoogleMap.CancelableCallback;
import com.google.android.gms.maps.model.LatLng;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class Main extends FragmentActivity {
    GoogleMap mMap;
    LatLng coordinates;
    public void onCreate(Bundle savedInstanceState) {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        coordinates = new LatLng(13.76488, 100.538334);
        
        mMap = ((SupportMapFragment)getSupportFragmentManager()
                        .findFragmentById(R.id.map)).getMap();
        
        Button buttonGoto = (Button)findViewById(R.id.buttonGoto);
        buttonGoto.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                mMap.animateCamera(
                        CameraUpdateFactory.newLatLng(coordinates));
            }
        });
        
        Button buttonGotoListener = 
                (Button)findViewById(R.id.buttonGotoListener);
        buttonGotoListener.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                mMap.animateCamera(
                        CameraUpdateFactory.newLatLng(coordinates)
                        , 2000, new CancelableCallback() {
                    public void onCancel() {
                        Toast.makeText(Main.this
                                , "Cancelled", Toast.LENGTH_SHORT).show();
                    }

                    public void onFinish() {
                        Toast.makeText(Main.this
                                , "Finished", Toast.LENGTH_SHORT).show();
                        mMap.animateCamera(CameraUpdateFactory.zoomTo(15));
                    }
                });
            }
        });
        
        Button buttonStop = (Button)findViewById(R.id.buttonStop);
        buttonStop.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                mMap.stopAnimation();
            }
        });
    }
}

main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"  >

    <fragment
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        class="com.google.android.gms.maps.SupportMapFragment"/>

    <Button
        android:id="@+id/buttonGoto"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:background="#55000000"
        android:text="Go to Vistory Monument"
        android:textColor="#FFFFFF"
        android:textSize="15sp" />

    <Button
        android:id="@+id/buttonGotoListener"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_below="@id/buttonGoto"
        android:layout_centerHorizontal="true"
        android:background="#55000000"
        android:text="Go to Vistory Monument (Listener)"
        android:textColor="#FFFFFF"
        android:textSize="15sp" />

    <Button
        android:id="@+id/buttonStop"
        android:layout_width="120dp"
        android:layout_height="40dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="#55000000"
        android:text="Stop Animate"
        android:textColor="#FFFFFF"
        android:textSize="15sp" />

</RelativeLayout>

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="app.akexorcist.googlemapsv2animate"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="8" />
    
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name=
            "com.google.android.providers.gsf.permission.READ_GSERVICES"/>
    <uses-permission 
            android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission 
            android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name=
            "app.akexorcist.googlemapsv2animate.permission.MAPS_RECEIVE"/>
      
    <permission android:name=
            "app.akexorcist.googlemapsv2animate.permission.MAPS_RECEIVE"
            android:protectionLevel="signature"/>
    
    <uses-feature android:glEsVersion="0x00020000" android:required="true"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="app.akexorcist.googlemapsv2animate.Main"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <meta-data
           android:name="com.google.android.maps.v2.API_KEY"
           android:value="your_api_key"/>
    </application>
</manifest>

พอลองทดสอบแอปพลิเคชันดูก็ให้ทดลองกดปุ่มทั้งสามปุ่ม
เพื่อทดสอบการทำงานของโปรแกรมตัวอย่างในบทความนี้ดู