android2012.10.11 20:37

MapView 상의 지도에 텍스트, 이미지, 도형 등을 출력하려면 Overlay 클래스를 상속하여 draw()를 오버라이드할 때 Canvas에 이미지(Bitmap클래스의 인스턴스)를 그리도록 작성하면 된다. 여기서는 지도상의 특정 위치를 가리키는 적색 화살표를 지도위에 그려본다.

이미지는 JPEG, GIF, PNG등을 사용하면 되고 프로젝트의 drawable 폴더에 import해 두면 R.java 파일에 자동으로 등록되어 Activity클래스의 onCreate() 안에서 쉽게 로드할 수 있다.

사용된 화살표 이미지

(arrow.png)

MyOverlay.java

앞글의 내용과 동일하며 다른 부분은 적색으로 표시했다.

package com.ojtit.android.demo;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;

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

public class MyOverlay extends Overlay {
 
 private Bitmap arrow;
 
 public MyOverlay(Bitmap bitmap){
  this.arrow = bitmap;
 }

 
 @Override
 public void draw(Canvas canvas, MapView mapView, boolean shadow) {
 
  super.draw(canvas, mapView, shadow);
        
     Paint paint1 = new Paint();
     Paint paint2 = new Paint();

     paint1.setARGB(255, 255, 0, 0); // a, r, g, b
     paint2.setARGB(255, 255, 0,0);

     // 아래에서 사용된 아규먼트는 위도, 경도 정보(40.756054)에서 가운데 '.' 을 뺀 것
     GeoPoint geoPoint = new GeoPoint(37517180,127041268); 
      
     Point pixPoint = new Point(); 
      
     mapView.getProjection().toPixels(geoPoint, pixPoint); // 지리적 위치를 화면상의 픽셀위치로 변환

     // drawCircle(float cx, float cy, float radius, Paint paint) ;
     // drawLine(float startX, float startY, float stopX, float stopY, Paint paint) ;
     // drawText(String text, float x, float y, Paint paint) ;
     //canvas.drawCircle(pixPoint.x, pixPoint.y, 10, paint1);
     //drawBitmap(Bitmap bitmap, float left, float top, Paint paint);

        
     canvas.drawBitmap(arrow, pixPoint.x-11, pixPoint.y, paint2);
     canvas.drawText("강남구청역", pixPoint.x-30, pixPoint.y + 30, paint2);    
 }
 
}


GoogleMapsActivity.java
앞글의 내용과 거의 동일하지만, 리소스로부터 화살표 이미지를 읽어서 Bitmap 인스턴스로 리턴하고 다시 MyOverlay 클래스의 생성자로 전달하여 Canvas에 화살표 이미지가 그려질 수 있도록 설정해준다

package com.ojtit.android.demo;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;

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

public class GoogleMapsActivity extends MapActivity
{

 @Override
 public void onCreate(Bundle savedInstanceState) 
 {
  super.onCreate(savedInstanceState); 
  setContentView(R.layout.main);
  MapView mapView = (MapView) findViewById(R.id.mapview);
  mapView.setBuiltInZoomControls(true); //지도 확대/축소기능 활성화
  
  // 리소스에서 arrow.png 를 가져와서 Bitmap 인스턴스를 생성한다
  Bitmap arrow = BitmapFactory.decodeResource(this.getResources(), R.drawable.arrow);


  //아래 라인을 사용하면 지도처럼 표현하는 것이 아니라 위성에서 촬영한 항공사진이 출력됨
  //mapView.setSatellite(true);

  
  //아래의 위도, 경도 좌표는 '37.517180' 에서 숫자 사이의 '.' 을 제거한 표현임
  GeoPoint geoPoint = new GeoPoint(37517180,127041268); // 강남구청역
  MapController mc = mapView.getController();
  mc.animateTo(geoPoint);
  mc.setZoom(17);
  
  // MapView 상의 지도 위에 표현할 것들을 그린다
  mapView.getOverlays().add(new MyOverlay(arrow));
 }
 
 @Override
 protected boolean isRouteDisplayed() {
  return true;
 }
}


Run As > Android Application

신고
Posted by 레드오이
android2012.10.11 20:34

* 현재 위치를 지도에 표시하기
1. 레이아웃 - my_map_view.xml 그대로 사용
2. 액티비티 - MyLocMap extends MapActivity implements LocationListener
:onCreate()에서 지도 초기화
1) 멤버변수 선언
LocationManager locationMgr = null;
MapController mapControl;
2) onCreate
setContentView(R.layout.my_map_view);
final MapView map = (MapView) findViewById(R.id.map);
mapControl = map.getController();

3. MyLocMap 액티비티가 실행되면 현재 위치 정보 가져오기
: onCreate()에서 현재 위치정보를 가져기 위한 requestLocationUpdates()함수 호출
locationMgr = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.NO_REQUIREMENT);
criteria.setPowerRequirement(Criteria.NO_REQUIREMENT);
String best = locationMgr.getBestProvider(criteria, true);
locationMgr.requestLocationUpdates(best, 1000, 0, MyLocationView.this);

4. 현재위치 정보 표시하기
: onLocationChanged()에서 GeoPoint 설정
double lat = location.getLatitude();
double lon = location.getLongitude();
GeoPoint newPoint = new GeoPoint((int)(lat * 1E6), (int)(lon*1E6));
mapControl.animateTo(newPoint);
mapControl.setZoom(15);
// 마커표시
MapView.LayoutParams mapMarkerParams = new MapView.LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT, newPoint,
MapView.LayoutParams.TOP_LEFT);
ImageView mapMarker = new ImageView(
getApplicationContext());
mapMarker.setImageResource(R.drawable.gmarker);
map.addView(mapMarker, mapMarkerParams);

///MyLocMap 액티비티 소스
package kcdi.map;

import android.content.Context;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;

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

public class MyLocMap extends MapActivity implements LocationListener {
MapController mapControl;
MapView map;
LocationManager locationMgr = null;
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.my_map_view);
map = (MapView) findViewById(R.id.map);
mapControl = map.getController();
locationMgr = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.NO_REQUIREMENT);
criteria.setPowerRequirement(Criteria.NO_REQUIREMENT);
String best = locationMgr.getBestProvider(criteria, true);
locationMgr.requestLocationUpdates(best, 1000, 0, MyLocMap.this);
}
@Override
public void onLocationChanged(Location location) {
double lat = location.getLatitude();
double lon = location.getLongitude();
GeoPoint newPoint = new GeoPoint((int)(lat * 1E6), (int)(lon*1E6));
mapControl.animateTo(newPoint);
mapControl.setZoom(15);
MapView.LayoutParams mapMarkerParams = new MapView.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, newPoint,
MapView.LayoutParams.TOP_LEFT);
ImageView mapMarker = new ImageView(getApplicationContext());
mapMarker.setImageResource(R.drawable.gmarker);
map.addView(mapMarker, mapMarkerParams);
}

@Override
protected boolean isRouteDisplayed() {
// TODO Auto-generated method stub
return false;
}
@Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub

}

@Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub

}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub

}

}

신고
Posted by 레드오이
android2012.10.11 20:32

[android] getTextBounds drawText

화면에 그릴 텍스트의 사이즈를 알아내기 위해
getTextBounds 함수를 사용하게 되는데,

이때 영어일경우엔 상관이 없었지만 한글이나 특수문자의 경우
영역이 내가 생각한대로 맞질않아서 계속 고생을 하였다.
몇번에 삽질끝에 알아낸 결과 getTextBounds 함수값에 그 해답이 있었다.

간단한 예제를 보자면


String text = "ABCD 1234";
Rect rt = new Rect();
ptText.getTextBounds(text, 0, text.length(), rt);
canvas.drawRect(rt, ptRound);
canvas.drawText(text, rt.left, rt.bottom, ptText);

 



위와같을경우 아무것도 출력되지않는다는걸 누구나 알수있다
getTextBounds로 구한 영역이 0,0을 기준으로 위에 있기때문이다



그러면 좌표를 조금 수정해서 다시 실행하여 보자.


int nX = 10;
int nY = 100;

String text = "ABCD 1234";
Rect rt = new Rect();
ptText.getTextBounds(text, 0, text.length(), rt);

rt.set(nX, nY-rt.height(), nX+rt.width(), nY);

canvas.drawRect(rt, ptRound);
canvas.drawText(text, nX, nY, ptText);




출력결과 Rect로 받아온값의 영역이 Text영역과 정확하게 일치한다
그런데 이때 영문과 숫자가 아닌 특수기호나 한글을 추가한다면
결과는 어떻게 될까?



String text = "ABC1234 한글출력 *_()";
Rect rt = new Rect();
ptText.getTextBounds(text, 0, text.length(), rt);

rt.set(nX, nY-rt.height(), nX+rt.width(), nY);

canvas.drawRect(rt, ptRound);
canvas.drawText(text, nX, nY, ptText);

 

텍스트에 들어가는 내용만 수정해주었다.
한글과 특수문자의 위치가 맞지않는것을 확인할수 있다.



이 이유는 getTextBounds 함수에 있다
getTextBounds 함수로 읽어온 값을 확인해보면
top 값은 음수이고 bottom 값은 0 또는 양수값이 들어오는걸 확인할 수 있다.
bottom 값이 0이상이 올경우가 바로 특수문자나 한글을 사용하였을때 발생하게 되는것이다.


따라서 getTextBounds 좌표체계는 다음과같다.

 





그렇다면 이제 Rect 값을 텍스트에 정확히 맞추어 보자


int nX = 10;
int nY = 100;

String text = "ABC1234 한글출력 *_()";
Rect rt = new Rect();
ptText.getTextBounds(text, 0, text.length(), rt);

rt.set(nX, nY + rt.top, nX + rt.width(), nY + rt.bottom);

canvas.drawRect(rt, ptRound);
canvas.drawText(text, nX, nY, ptText);

 


자 이제 화면에 출력되는 텍스트 영역을 완벽하게 구하였다.
물론 기초적이고 이미 다들 알고있을지도 모르지만
누군가 이문제로 인해 시간낭비할걸 막기위해 작성하였다.

신고
Posted by 레드오이

티스토리 툴바