SoFunction
Updated on 2025-04-07

Android custom implementation compass view detailed explanation

Custom views are a very important skill when developing Android applications. This article will explain how to create a custom CompassView that displays the orientation of the device. We will get the orientation data by using SensorManager and use a custom drawing method to draw the compass.

1. Create a project

First, create a new project in Android Studio, select the "Empty Activity" template, named CustomCompass.

2. Add permissions

In order to be able to access sensor data, you need to add the corresponding permissions to the file:

<uses-permission android:name=".ACCESS_FINE_LOCATION"/>

3. Create a custom view

3.1 Create a CompassView class

Create a new Java class in the app/src/main/java/com/example/customcompass/ directory:

package ;
 
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
 
public class CompassView extends View implements SensorEventListener {
 
    private Paint paint;
    private float direction = 0f;
    private SensorManager sensorManager;
    private Sensor accelerometer;
    private Sensor magnetometer;
 
    public CompassView(Context context) {
        super(context);
        init(context);
    }
 
    public CompassView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }
 
    public CompassView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }
 
    private void init(Context context) {
        paint = new Paint();
        ();
        (50);
        (true);
 
        sensorManager = (SensorManager) (Context.SENSOR_SERVICE);
        accelerometer = (Sensor.TYPE_ACCELEROMETER);
        magnetometer = (Sensor.TYPE_MAGNETIC_FIELD);
    }
 
    @Override
    protected void onDraw(Canvas canvas) {
        (canvas);
        int width = getWidth();
        int height = getHeight();
        int centerX = width / 2;
        int centerY = height / 2;
 
        // Draw a circular background        ();
        (centerX, centerY, (width, height) / 2, paint);
 
        // Draw pointer        ();
        (centerX, centerY, (float) (centerX + ((direction)) * 150),
                (float) (centerY - ((direction)) * 150), paint);
 
        // Draw directional text        ();
        ("N", centerX, centerY - 100, paint);
        ("S", centerX, centerY + 100, paint);
        ("E", centerX + 100, centerY, paint);
        ("W", centerX - 100, centerY, paint);
    }
 
    @Override
    public void onSensorChanged(SensorEvent event) {
        if (() == Sensor.TYPE_ACCELEROMETER) {
            (, 0, mGravity, 0, 3);
        } else if (() == Sensor.TYPE_MAGNETIC_FIELD) {
            (, 0, mGeomagnetic, 0, 3);
        }
 
        boolean success = (mRotationMatrix, null, mGravity, mGeomagnetic);
        if (success) {
            (mRotationMatrix, mOrientationAngles);
            direction = (float) (mOrientationAngles[0]);
            invalidate(); //Repaint the view        }
    }
 
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {}
 
    private float[] mGravity = new float[3];
    private float[] mGeomagnetic = new float[3];
    private float[] mRotationMatrix = new float[9];
    private float[] mOrientationAngles = new float[3];
 
    public void registerSensor() {
        (this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
        (this, magnetometer, SensorManager.SENSOR_DELAY_NORMAL);
    }
 
    public void unregisterSensor() {
        (this);
    }
}

3.2 Using CompassView in Layout Files

Add CompassView in activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:andro
    xmlns:tools="/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
 
    <
        android:
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_centerInParent="true" />
 
</RelativeLayout>

4. Register and log out of sensors in MainActivity

Register and log out of sensors in ​​​​​:

package ;
 
import ;
import ;
 
public class MainActivity extends AppCompatActivity {
 
    private CompassView compassView;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        (savedInstanceState);
        setContentView(.activity_main);
 
        compassView = findViewById();
        ();
    }
 
    @Override
    protected void onDestroy() {
        ();
        ();
    }
}

5. Run the application

Now you can run your app. You should see a compass view that updates as the device changes direction.

Through the above steps, we successfully created a custom compass view. This view utilizes Android's sensor manager to get direction data and uses a custom drawing method to display the compass.

6. Method supplement

In Android application development, custom compass view is a common requirement, especially in applications such as navigation and outdoor activities. Below I will provide a simple example showing how to create a custom compass view. This example will include basic layout files, custom view classes, and using sensor data to update compass orientation.

Method 1

Add permissions

First, add the necessary permissions to the file to allow the application to access the device's orientation sensor:

<uses-permission android:name=".ACCESS_FINE_LOCATION"/>
<uses-feature android:name="" />

Create a layout file

Create a new layout file activity_main.xml to display the compass view:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:andro
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp">
 
    <
        android:
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_centerInParent="true" />
 
</RelativeLayout>

Create a custom compass view

Next, create a custom compass view. This view will draw a circular compass and rotate the pointer according to the angle passed in:

package ;
 
import ;
import ;
import ;
import ;
import ;
import ;
 
public class CompassView extends View {
 
    private Paint paint;
    private float direction = 0f; // Direction angle 
    public CompassView(Context context) {
        super(context);
        init();
    }
 
    public CompassView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
 
    public CompassView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
 
    private void init() {
        paint = new Paint();
        ();
        (5f);
        (true);
    }
 
    @Override
    protected void onDraw(Canvas canvas) {
        (canvas);
 
        int width = getWidth();
        int height = getHeight();
        int radius = (width, height) / 2 - 10;
 
        // Draw circles        (width / 2, height / 2, radius, paint);
 
        // Draw pointer        ();
        ();
        (-direction, width / 2, height / 2); // Rotate counterclockwise        (width / 2, height / 2 - radius, width / 2, height / 2 - 50, paint);
        ();
 
        // Draw N, S, E, W        (40);
        ();
        ("N", width / 2 - 10, height / 2 - radius + 40, paint);
        ("S", width / 2 - 10, height / 2 + radius - 10, paint);
        ("E", width / 2 + radius - 40, height / 2 + 10, paint);
        ("W", width / 2 - radius + 10, height / 2 + 10, paint);
    }
 
    public void setDirection(float direction) {
         = direction;
        invalidate(); //Repaint the view    }
}

Update compass direction using sensor data

In the main activity, register a sensor listener to get the device's orientation change and update the direction of the compass view:

package ;
 
import ;
import ;
import ;
import ;
import ;
import ;
 
public class MainActivity extends AppCompatActivity implements SensorEventListener {
 
    private SensorManager sensorManager;
    private Sensor rotationSensor;
    private CompassView compassView;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        (savedInstanceState);
        setContentView(.activity_main);
 
        compassView = findViewById();
 
        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        rotationSensor = (Sensor.TYPE_ROTATION_VECTOR);
    }
 
    @Override
    protected void onResume() {
        ();
        (this, rotationSensor, SensorManager.SENSOR_DELAY_NORMAL);
    }
 
    @Override
    protected void onPause() {
        ();
        (this);
    }
 
    @Override
    public void onSensorChanged(SensorEvent event) {
        if (() == Sensor.TYPE_ROTATION_VECTOR) {
            float[] rotationMatrix = new float[9];
            (rotationMatrix, );
            float[] orientation = new float[3];
            (rotationMatrix, orientation);
 
            // Convert radians to angles            float azimuth = (float) (orientation[0]);
            (azimuth);
        }
    }
 
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // No processing of accuracy changes    }
}

Run the application

Now you can run the app, it will display a custom compass view and update the orientation as the device rotates.

Method 2

This example shows how to create a simple custom compass view in Android. You can further expand and beautify this view as needed, such as adding more graphical elements or improving the user interface. Creating a custom compass view in Android involves multiple steps, including defining the view, processing sensor data, drawing compass images, etc. Here is a detailed guide to help you implement a basic custom compass view.

Create a custom view

First, you need to create a custom view class to draw the compass. This class will inherit from the View class and override the onDraw method to draw the compass image.

import ;
import ;
import ;
import ;
import ;
import ;
import ;
 
public class CompassView extends View {
 
    private Bitmap compassBitmap;
    private Matrix matrix;
    private float currentDegree = 0f;
 
    public CompassView(Context context) {
        super(context);
        init();
    }
 
    public CompassView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
 
    public CompassView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
 
    private void init() {
        compassBitmap = (getResources(), );
        matrix = new Matrix();
    }
 
    @Override
    protected void onDraw(Canvas canvas) {
        (canvas);
        ();
        (-currentDegree, () / 2, () / 2);
        (compassBitmap, matrix, null);
    }
 
    public void updateDegree(float degree) {
        currentDegree = degree;
        invalidate(); // Re-draw the view    }
}

Process sensor data

To get the device's orientation data, you need to register a SensorEventListener and listen for the TYPE_ORIENTATION sensor (or the more modern TYPE_ROTATION_VECTOR sensor).

import ;
import ;
import ;
import ;
import ;
import ;
 
public class MainActivity extends AppCompatActivity implements SensorEventListener {
 
    private SensorManager sensorManager;
    private Sensor sensor;
    private CompassView compassView;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        (savedInstanceState);
        setContentView(.activity_main);
 
        compassView = findViewById();
 
        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        sensor = (Sensor.TYPE_ORIENTATION);
    }
 
    @Override
    protected void onResume() {
        ();
        (this, sensor, SensorManager.SENSOR_DELAY_NORMAL);
    }
 
    @Override
    protected void onPause() {
        ();
        (this);
    }
 
    @Override
    public void onSensorChanged(SensorEvent event) {
        if (() == Sensor.TYPE_ORIENTATION) {
            float degree = ([0]);
            (degree);
        }
    }
 
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // No processing required    }
}

Layout file

Add a custom CompassView in the layout file.

<RelativeLayout xmlns:andro
    xmlns:tools="/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
 
    <
        android:
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" />
 
</RelativeLayout>

Add resource file

Make sure you have a compass image resource file (for example, res/drawable/) and place it in the project's res/drawable directory.

Permissions

Add the necessary permissions in ​​​​:

<uses-permission android:name=".ACCESS_FINE_LOCATION" />
<uses-permission android:name=".ACCESS_COARSE_LOCATION" />

Summarize

The above steps show how to create a custom compass view in Android. With custom view classes and sensor event listeners, you can implement a compass that dynamically update directions.

The above is the detailed explanation of the Android custom implementation compass view. For more information about Android custom view, please follow my other related articles!