Saturday, July 30, 2011

Draw on a custom View over MapView

By using FrameLayout, we can create a custom View overlap with a MapView, such that we can draw on the canvas of the customer View. Also we can call MapView.getProjection().fromPixels(x, y) to get the coresponding coordinates on the map.

Draw on a custom View over MapView

Further work on the last exercise "Get the the coordinates (Latitude and Longitude) currently displayed on MapView".

Create the custom view, MyView.java
package com.exercise.AndroidMap;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

public class MyView extends View {

Paint myPaint;

float x1, y1; //Top Left point
float x2, y2; //Bottom Right point

public MyView(Context context) {
super(context);
// TODO Auto-generated constructor stub
init();
}

public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}

public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
init();
}

private void init(){
myPaint = new Paint();
myPaint.setColor(Color.WHITE);
myPaint.setStyle(Paint.Style.STROKE);
myPaint.setStrokeWidth(3);
}

@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
int w = getWidth();
int h = getHeight();

x1 = (float)w/4;
x2 = (float)w * 3/4;
y1 = (float)h/4;
y2 = (float)h *3/4;

canvas.drawRect(x1, y1, x2, y2, myPaint);
}

public float getx1(){
return x1;
}

public float getx2(){
return x2;
}

public float gety1(){
return y1;
}

public float gety2(){
return y2;
}

}


main.xml, include own custom View overlap with MapView, using FrameLayout.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<Button
android:id="@+id/getinfo"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Get Info"
/>
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.google.android.maps.MapView
android:id="@+id/map"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true"
android:apiKey="0PE9qMoMP-Wy2MijPaIfdbg7dUHlub6gWJe-xQw" />
<com.exercise.AndroidMap.MyView
android:id="@+id/myview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</FrameLayout>
</LinearLayout>


main code, AndroidMapActivity.java
package com.exercise.AndroidMap;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class AndroidMapActivity extends MapActivity {

MapView myMap;
MyView myView;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myMap = (MapView) findViewById(R.id.map);
myMap.setBuiltInZoomControls(true);

Button buttonGetInfo = (Button)findViewById(R.id.getinfo);
buttonGetInfo.setOnClickListener(buttonGetInfoOnClickListener);

myView = (MyView)findViewById(R.id.myview);
}

@Override
protected boolean isRouteDisplayed() {
// TODO Auto-generated method stub
return false;
}

Button.OnClickListener buttonGetInfoOnClickListener
= new Button.OnClickListener(){

@Override
public void onClick(View v) {
// TODO Auto-generated method stub

GeoPoint mapCenter = myMap.getMapCenter();

float centerLatitude = (float)(mapCenter.getLatitudeE6())/1000000;
float centerLongitude = (float)(mapCenter.getLongitudeE6())/1000000;

float latitudeSpan = (float)(myMap.getLatitudeSpan())/1000000;
float longitudeSpan = (float)(myMap.getLongitudeSpan()/1000000);

GeoPoint mapTopLeft
= myMap.getProjection().fromPixels((int)myView.getx1(), (int)myView.gety1());
float topLatitude = (float)(mapTopLeft.getLatitudeE6())/1000000;
float leftLongitude = (float)(mapTopLeft.getLongitudeE6())/1000000;

GeoPoint mapBottomRight
= myMap.getProjection().fromPixels((int)myView.getx2(), (int)myView.gety2());
float bottomLatitude = (float)(mapBottomRight.getLatitudeE6())/1000000;
float rightLongitude = (float)(mapBottomRight.getLongitudeE6())/1000000;

int zoomLevel = myMap.getZoomLevel();

String info =
"Center: " + centerLatitude + "/" + centerLongitude + "\n"
+ "Top Left: " + topLatitude + "/" + leftLongitude + "\n"
+ "Bottom Right: " + bottomLatitude + "/" + rightLongitude + "\n"
+ "latitudeSpan: " + latitudeSpan + "\n"
+ "longitudeSpan: " + longitudeSpan + "\n"
+ "zoomLevel: " + zoomLevel;

Toast.makeText(AndroidMapActivity.this,
info,
Toast.LENGTH_LONG).show();
}};
}


AndroidManifest.xml, xml. Grand permission of "android.permission.INTERNET" and include uses-library of "com.google.android.maps".
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.exercise.AndroidMap"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="4" />

<application android:icon="@drawable/icon" android:label="@string/app_name">
<uses-library android:name="com.google.android.maps" />
<activity android:name=".AndroidMapActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

</application>
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>



Download the files.

1 comment:

Mice said...

Thks a lot! Your post save me!

Massimo