안드로이드개발 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 |