|
안드로이드개발 SensorManager, SensorEventListener 이용해서 나침판 구현하기 |
|
환경: Android Studio |
나침판을 구현하기 위해서 클래스를 두 부분으로 나누었습니다. 자석계 Sensor 로 부터 값을 가져오는 메인 activity 와 나침판을 그리는 View 클래스가 그것 입니다. View 위젯을 상속받은 CustomDrawableView 클래스는 나침판을 그리고 azimut 값을 이용해서 실시간 방위를 나타냅니다.
▼ CustomDrawableView 클래스의 onDraw() 함수에 그리는 소스들이 들어갑니다. 움직일때 마다 나침판 효과를 내기 위해 Canvas 의 rotate() 함수로 방위각을 구해 회전을 시킵니다. 그럼 센스에서 받아 온 실시간 데이터로 계속해서 움직이겠죠. 그리고 회전한 Canvas 위에 나침판의 남북 선을 긋습니다.
// 방위각 구하기
dir = azimuth * 360 / (2 * 3.14159f);
// Canvas 를 회전 시킨다
if (azimuth != null){
canvas.rotate(-dir, centerx, centery);
}
// 나침판 선 표시
paint.setColor(Color.BLUE);
paint.setTextSize(100);
canvas.drawLine(centerx, centery - radius, centerx, centery + radius, paint);
canvas.drawText("N", centerx - 30, centery - radius - 20, paint);
canvas.drawText("S", centerx - 30, centery + radius + 80, paint);
paint.setColor(Color.RED);
▼ 스마트폰 Sensor 로 부터 방위각을 구하기 위해 onCreate() 에서 가속계와 자석계 센스를 SensorManager 로부터 객체를 가져옵니다. 그리고 센서의 값이 변경될 때 마다 변경된 값을 받기 위해 onResume() 함수에 이벤트 리스너를 등록합니다.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCustomDrawableView = new CustomDrawableView(this);
setContentView(mCustomDrawableView); // Register the sensor listeners
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
accelerometer = mSensorManager
.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
magnetometer = mSensorManager
.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
}
protected void onResume() {
super.onResume();
mSensorManager.registerListener(this, accelerometer,
SensorManager.SENSOR_DELAY_UI);
mSensorManager.registerListener(this, magnetometer,
SensorManager.SENSOR_DELAY_UI);
}
▼ 등록한 이벤트 리스너에서 센스에 변경이 있을 때 작동하는 함수는 onSensorChanged 입니다. SensorEvent 객체를 분석해서 3가지 azimuth, pitch, roll 값을 얻을 수 있습니다. 그 3가지 값 중 첫 번째 배열에 있는 값이 azimuth (방위각) 입니다. 이것을 View 클래스에서 가져다 쓰는 것입니다.
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){
mGravity = event.values;
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD){
mGeomagnetic = event.values;
}
if (mGravity != null && mGeomagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I,
mGravity, mGeomagnetic);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
azimuth = orientation[0]; // orientation contains: azimut, pitch and roll
}
}
mCustomDrawableView.invalidate();
}
▼ 아래 샘플 소스는 View 와 Activity 가 합쳐 진 전체 소스입니다. 화면 레이아웃을 구성하는 xml 파일은 없습니다.
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.View;
public class CompassActivity2 extends Activity implements
SensorEventListener {
private CustomDrawableView mCustomDrawableView;
private SensorManager mSensorManager;
private Sensor accelerometer;
private Sensor magnetometer;
private float[] mGravity;
private float[] mGeomagnetic;
private Float azimut; // View to draw a compass
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCustomDrawableView = new CustomDrawableView(this);
setContentView(mCustomDrawableView); // Register the sensor listeners
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
accelerometer = mSensorManager
.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
magnetometer = mSensorManager
.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
}
protected void onResume() {
super.onResume();
mSensorManager.registerListener(this, accelerometer,
SensorManager.SENSOR_DELAY_UI);
mSensorManager.registerListener(this, magnetometer,
SensorManager.SENSOR_DELAY_UI);
}
protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(this);
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){
mGravity = event.values;
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD){
mGeomagnetic = event.values;
}
if (mGravity != null && mGeomagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I,
mGravity, mGeomagnetic);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
azimut = orientation[0]; // orientation contains: azimut, pitch and roll
}
}
mCustomDrawableView.invalidate();
}
public class CustomDrawableView extends View {
Paint paint = new Paint();
public CustomDrawableView(Context context) {
super(context);
paint.setColor(Color.RED);
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(4);
paint.setAntiAlias(true);
};
protected void onDraw(Canvas canvas) {
int width = getWidth();
int height = getHeight();
int centerx = width / 2;
int centery = height / 2;
float radius, dir;
if (centerx > centery) {
radius = (float) (centery * 0.9);
} else {
radius = (float) (centerx * 0.9);
}
// 방위각 구하기
dir = azimut * 360 / (2 * 3.14159f);
// 나침판 그리기
canvas.drawCircle(centerx, centery, radius, paint);
canvas.drawLine(centerx, centery - radius, centerx, centery + radius, paint);
canvas.drawLine(centerx - radius, centery, centerx + radius, centery, paint);
// 방위 중앙에 표시
paint.setColor(Color.DKGRAY);
paint.setTextSize(300);
canvas.drawText(String.valueOf((int)dir), centerx-150, centery, paint);
// Canvas 를 회전 시킨다
if (azimut != null){
canvas.rotate(-dir, centerx, centery);
}
// 나침판 선 표시
paint.setColor(Color.BLUE);
paint.setTextSize(100);
canvas.drawLine(centerx, centery - radius, centerx, centery + radius, paint);
canvas.drawText("N", centerx - 30, centery - radius - 20, paint);
canvas.drawText("S", centerx - 30, centery + radius + 80, paint);
paint.setColor(Color.RED);
}
}
}
'안드로이드 개발' 카테고리의 다른 글
| 안드로이드 개발 전화번호 조회 퍼미션 에러 해결하는 방법 (0) | 2018.03.12 |
|---|---|
| 안드로이드 개발 SMS 조회 퍼미션 에러 해결하는 방법 (0) | 2018.03.07 |
| 안드로이드(Android) Debug 모드 상태 체크하는 방법 (0) | 2018.03.01 |
| 안드로이드 개발 Vibration 이용해서 스마트폰 진동 설정하는 방법 (0) | 2018.02.22 |
| 안드로이드 개발 레이아웃 인플레이션(LayoutInflater)으로 추가한 화면 삭제하는 방법 (0) | 2018.01.28 |
| 안드로이드(Android) SensorManager 와 SensorEventListener 이용해서 x, y, z 축 감지하는 방법 (0) | 2018.01.26 |
| 안드로이드(Android) 다양한 애니메이션 이동(translate) 을 구현하는 여러가지 방법 (0) | 2018.01.19 |
| 안드로이드 개발 서비스 바인딩 (Service Bind) 예제 구현하는 방법 (0) | 2018.01.18 |
