오늘은 기울기 감지 센서를 사용해 볼 것이다. 허나 플러그인을 사용하지 않고 코틀린 코드와 연결해서 구현을 해볼 것이다.
바로 만들어 보자!
전체 코드(Kotlin)
package com.example.your_packge
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.os.Bundle
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
class MainActivity : FlutterActivity(), SensorEventListener {
private val methodChannel = "com.example.your_packge"
private lateinit var sensorManager: SensorManager
private var accelerometer: Sensor? = null
private var tiltData: List<Float> = listOf(0f, 0f, 0f)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
}
override fun onResume() {
super.onResume()
accelerometer?.let {
sensorManager.registerListener(this, it, SensorManager.SENSOR_DELAY_UI)
}
}
override fun onPause() {
super.onPause()
sensorManager.unregisterListener(this)
}
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(
flutterEngine.dartExecutor.binaryMessenger,
methodChannel
).setMethodCallHandler { call, result ->
if (call.method == "getTilt") {
result.success(tiltData.map { it.toDouble() })
} else {
result.notImplemented()
}
}
}
override fun onSensorChanged(event: SensorEvent?) {
if (event?.sensor?.type == Sensor.TYPE_ACCELEROMETER) {
tiltData = listOf(event.values[0], event.values[1], event.values[2])
}
}
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
}
하나하나 순차적으로 알아보자.
class MainActivity : FlutterActivity(), SensorEventListener {
일단 센서 이벤트를 감지하기 위해선 위와 같이 SensorEventListener를 넣어 줘야 한다.
그다음엔 사용할 친구들을 선언해 준다.
private val methodChannel = "com.example.your_packge" // Flutter와 통신할 MethodChannel의 이름 정의
private lateinit var sensorManager: SensorManager // 센서를 관리할 SensorManager 선언 (나중에 초기화)
private var accelerometer: Sensor? = null // 가속도 센서 객체
private var tiltData: List<Float> = listOf(0f, 0f, 0f) // 기울기 데이터 초기값 (x, y, z)
이제 함수들을 만들어주자.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager // 시스템에서 SensorManager 가져오기
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) // 가속도 센서 가져오기
}
override fun onResume() {
super.onResume()
accelerometer?.let {
sensorManager.registerListener(this, it, SensorManager.SENSOR_DELAY_UI)
// 센서 리스너 등록 (this = 현재 액티비티, it = accelerometer, 센서 업데이트 속도 설정)
}
}
override fun onPause() {
super.onPause()
sensorManager.unregisterListener(this) // 센서 리스너 해제 (메모리 누수 방지)
}
onCreate()에 작성한 코드는 안드로이드 디벨로퍼에서 가져왔다.

https://developer.android.com/develop/sensors-and-location/sensors/sensors_motion#kotlin
움직임 감지 센서 | Sensors and location | Android Developers
이 페이지는 Cloud Translation API를 통해 번역되었습니다. 움직임 감지 센서 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Android 플랫폼은 기기의 동작을 모니
developer.android.com
이제 가장 중요한 플러터랑 연결하는 코드를 작성해 주자.
override fun configureFlutterEngine(flutterEngine: FlutterEngine) { // Flutter 엔진을 설정하는 함수
super.configureFlutterEngine(flutterEngine)
MethodChannel(
flutterEngine.dartExecutor.binaryMessenger, // Dart에서 보낸 메시지를 받는 메신저
methodChannel // MethodChannel의 이름 설정 (Flutter와 동일해야 함)
).setMethodCallHandler { call, result -> // Flutter에서 보낸 메시지 처리
if (call.method == "getTilt") { // "getTilt" 메서드가 호출되었을 경우
result.success(tiltData.map { it.toDouble() })
// Float 리스트를 Double 리스트로 변환하여 Flutter로 반환
} else {
result.notImplemented() // 지원하지 않는 메서드일 경우 처리
}
}
}
그리고 없어서는 안 될 코드들까지
override fun onSensorChanged(event: SensorEvent?) { // 센서 값이 변경될 때 호출됨
if (event?.sensor?.type == Sensor.TYPE_ACCELEROMETER) { // 가속도 센서 이벤트인지 확인
tiltData = listOf(event.values[0], event.values[1], event.values[2])
// 센서 데이터를 리스트에 저장 (x, y, z 방향 값)
}
}
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
// 센서의 정확도가 변경될 때 호출되지만 여기서는 사용하지 않음 (비워둠)
}
요약하자면
- 센서 설정
- sensorManager를 사용하여 가속도 센서(TYPE_ACCELEROMETER)를 가져옴.
- onResume()에서 센서 리스너 등록 → 센서 값 변경 감지.
- onPause()에서 센서 리스너 해제 → 메모리 누수 방지.
- Flutter와의 통신 (MethodChannel)
- configureFlutterEngine()에서 Flutter와 MethodChannel 설정.
- Flutter에서 "getTilt"을 호출하면 tiltData 값을 반환.
- 센서 데이터 처리
- onSensorChanged()에서 기울기 값(x, y, z)을 실시간 업데이트.
- 값이 변경되면 tiltData에 저장하고, Flutter에서 요청 시 전달.
이제 getTilt를 호출하면 Flutter에서 정상적으로 센서 데이터를 받을 수 있다
자 이러면 이제 코틀린 코드는 끝났다. dart 코드를 작성해 주자. (gpt로 요약한 건 안 비밀)
전체코드(Dart)
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:async';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: TiltScreen(),
);
}
}
class TiltScreen extends StatefulWidget {
const TiltScreen({super.key});
@override
State<TiltScreen> createState() => _TiltScreenState();
}
class _TiltScreenState extends State<TiltScreen> {
Future<List<double>> getTiltSensor() async {
final List<dynamic> result = await MethodChannel('com.example.your_packge').invokeMethod('getTilt');
return result.map((e) => e as double).toList();
}
List<double> _tilt = [0, 0, 0];
late Timer _timer;
@override
void initState() {
super.initState();
_timer = Timer.periodic(const Duration(milliseconds: 100), (timer) async {
List<double> tilt = await getTiltSensor();
setState(() {
_tilt = tilt;
});
});
}
@override
void dispose() {
_timer.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Tilt Sensor")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("X: ${_tilt[0].toStringAsFixed(2)}"),
Text("Y: ${_tilt[1].toStringAsFixed(2)}"),
Text("Z: ${_tilt[2].toStringAsFixed(2)}"),
SizedBox(
width: MediaQuery.sizeOf(context).width,
height: 400,
child: CustomPaint(painter: SlopePainter(_tilt[0] * 10),))
],
),
),
);
}
}
class SlopePainter extends CustomPainter {
final double slope;
SlopePainter(this.slope);
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.blue
..style = PaintingStyle.fill;
double leftHeight = (size.height / 2) + slope;
double rightHeight = (size.height / 2) - slope;
Path path = Path()
..moveTo(0, leftHeight)
..lineTo(size.width, rightHeight)
..lineTo(size.width, size.height)
..lineTo(0, size.height)
..close();
canvas.drawPath(path, paint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
다트 코드에서는 간단하게 로직만 알아보자. (커스텀 페인트는 다른 영역이기 때문에)
Future<List<double>> getTiltSensor() async {
final List<dynamic> result = await MethodChannel('com.example.your_packge').invokeMethod('getTilt');
return result.map((e) => e as double).toList();
}
당연하게도 필요한 메서드 채널 코드이다. 여기서는 안드로이드에서 'getTilt' 메서드를 호출하고 받은 데이터를 List<double> 타입으로 변환시켜 준다.
List<double> _tilt = [0, 0, 0];
late Timer _timer;
센서 데이터를 저장할 리스트 (초기값 [0, 0, 0])와 주기적으로 데이터 업데이트를 위한 타이머 선언.
@override
void initState() {
super.initState();
_timer = Timer.periodic(const Duration(milliseconds: 100), (timer) async {
// 100ms마다 반복 실행 (0.1초 간격)
List<double> tilt = await getTiltSensor(); // 센서 데이터 가져오기
setState(() {
_tilt = tilt; // 가져온 데이터를 _tilt 변수에 업데이트
});
});
}
@override
void dispose() {
_timer.cancel(); // 화면이 사라질 때 타이머 중지 (메모리 누수 방지)
super.dispose();
}
이렇게 iniState() 와 dispose () 까지 작성했다면 로직은 끝났다. 그렇게 받아온 값은 이제 알아서 잘 사용하면 되는데
나는 화면의 기울기에 따라 경사가 변하도록 만들었다.

이렇게 안드로이드 코드와 연결해서 외부 패키지 사용 없이 기울기감지를 구현해 봤다. 도움이 되었길 바라며 포스팅 마치겠다.
'flutter' 카테고리의 다른 글
[플러터] Flutter / Expended 제대로 사용하기!! (Expanded 사용법) (0) | 2025.03.16 |
---|---|
[플러터] Flutter / Text.rich 사용해서 텍스트 개별 사이즈 조절 하기 (Text Size 조절, TextSpan) (0) | 2025.01.10 |
[플러터] Flutter / 페이징 기능 제작 (Pagination, Paging) (페이지 넘기는 기능) (0) | 2025.01.07 |
[플러터] Flutter / shared_preferences 은 어떻게 데이터를 저장하는 것일까? (0) | 2024.11.19 |
[플러터] Flutter / 코드 자동 완성이 안될 때 해결 방법 (Restart Dart Analysis server)(안드로이드 스튜디오) (5) | 2024.10.17 |