Android自定義實現(xiàn)羅盤視圖詳解
在開發(fā)Android應(yīng)用時,自定義視圖是一個非常重要的技能。本文將介紹如何創(chuàng)建一個自定義的羅盤視圖(CompassView),該視圖可以顯示設(shè)備的方向。我們將通過使用??SensorManager??來獲取方向數(shù)據(jù),并使用自定義繪圖方法來繪制羅盤。
1. 創(chuàng)建項目
首先,在Android Studio中創(chuàng)建一個新的項目,選擇“Empty Activity”模板,命名為??CustomCompass??。
2. 添加權(quán)限
為了能夠訪問傳感器數(shù)據(jù),需要在??AndroidManifest.xml??文件中添加相應(yīng)的權(quán)限:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
3. 創(chuàng)建自定義視圖
3.1 創(chuàng)建CompassView類
在??app/src/main/java/com/example/customcompass/??目錄下創(chuàng)建一個新的Java類??CompassView.java??:
package com.example.customcompass;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.AttributeSet;
import android.view.View;
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();
paint.setColor(Color.BLACK);
paint.setTextSize(50);
paint.setAntiAlias(true);
sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
magnetometer = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
int height = getHeight();
int centerX = width / 2;
int centerY = height / 2;
// 繪制圓形背景
paint.setColor(Color.LTGRAY);
canvas.drawCircle(centerX, centerY, Math.min(width, height) / 2, paint);
// 繪制指針
paint.setColor(Color.RED);
canvas.drawLine(centerX, centerY, (float) (centerX + Math.cos(Math.toRadians(direction)) * 150),
(float) (centerY - Math.sin(Math.toRadians(direction)) * 150), paint);
// 繪制方向文本
paint.setColor(Color.BLACK);
canvas.drawText("N", centerX, centerY - 100, paint);
canvas.drawText("S", centerX, centerY + 100, paint);
canvas.drawText("E", centerX + 100, centerY, paint);
canvas.drawText("W", centerX - 100, centerY, paint);
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
System.arraycopy(event.values, 0, mGravity, 0, 3);
} else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
System.arraycopy(event.values, 0, mGeomagnetic, 0, 3);
}
boolean success = SensorManager.getRotationMatrix(mRotationMatrix, null, mGravity, mGeomagnetic);
if (success) {
SensorManager.getOrientation(mRotationMatrix, mOrientationAngles);
direction = (float) Math.toDegrees(mOrientationAngles[0]);
invalidate(); // 重繪視圖
}
}
@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() {
sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
sensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_NORMAL);
}
public void unregisterSensor() {
sensorManager.unregisterListener(this);
}
}3.2 在布局文件中使用CompassView
在??activity_main.xml??中添加??CompassView??:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.example.customcompass.CompassView
android:id="@+id/compassView"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_centerInParent="true" />
</RelativeLayout>
4. 在MainActivity中注冊和注銷傳感器
在??MainActivity.java??中注冊和注銷傳感器:
package com.example.customcompass;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
private CompassView compassView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
compassView = findViewById(R.id.compassView);
compassView.registerSensor();
}
@Override
protected void onDestroy() {
super.onDestroy();
compassView.unregisterSensor();
}
}5. 運行應(yīng)用
現(xiàn)在,你可以運行你的應(yīng)用了。你應(yīng)該會看到一個羅盤視圖,它會隨著設(shè)備的方向變化而更新。
通過上述步驟,我們成功地創(chuàng)建了一個自定義的羅盤視圖。這個視圖利用了Android的傳感器管理器來獲取方向數(shù)據(jù),并使用自定義繪圖方法來顯示羅盤。
6.方法補充
在Android應(yīng)用開發(fā)中,自定義羅盤視圖是一個常見的需求,特別是在導航、戶外活動等應(yīng)用中。下面我將提供一個簡單的示例,展示如何創(chuàng)建一個自定義的羅盤視圖。這個例子將包括基本的布局文件、自定義視圖類以及使用傳感器數(shù)據(jù)來更新羅盤方向。
方法一
添加權(quán)限
首先,在??AndroidManifest.xml??文件中添加必要的權(quán)限,以允許應(yīng)用程序訪問設(shè)備的方向傳感器:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-feature android:name="android.hardware.sensor.compass" />
創(chuàng)建布局文件
創(chuàng)建一個新的布局文件??activity_main.xml??,用于顯示羅盤視圖:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<com.example.myapp.CompassView
android:id="@+id/compassView"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_centerInParent="true" />
</RelativeLayout>
創(chuàng)建自定義羅盤視圖
接下來,創(chuàng)建一個自定義的羅盤視圖??CompassView.java??。這個視圖將繪制一個圓形的羅盤,并根據(jù)傳入的角度旋轉(zhuǎn)指針:
package com.example.myapp;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
public class CompassView extends View {
private Paint paint;
private float direction = 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() {
paint = new Paint();
paint.setColor(Color.BLACK);
paint.setStrokeWidth(5f);
paint.setAntiAlias(true);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
int height = getHeight();
int radius = Math.min(width, height) / 2 - 10;
// 繪制圓
canvas.drawCircle(width / 2, height / 2, radius, paint);
// 繪制指針
paint.setColor(Color.RED);
canvas.save();
canvas.rotate(-direction, width / 2, height / 2); // 逆時針旋轉(zhuǎn)
canvas.drawLine(width / 2, height / 2 - radius, width / 2, height / 2 - 50, paint);
canvas.restore();
// 繪制N、S、E、W
paint.setTextSize(40);
paint.setColor(Color.BLACK);
canvas.drawText("N", width / 2 - 10, height / 2 - radius + 40, paint);
canvas.drawText("S", width / 2 - 10, height / 2 + radius - 10, paint);
canvas.drawText("E", width / 2 + radius - 40, height / 2 + 10, paint);
canvas.drawText("W", width / 2 - radius + 10, height / 2 + 10, paint);
}
public void setDirection(float direction) {
this.direction = direction;
invalidate(); // 重繪視圖
}
}使用傳感器數(shù)據(jù)更新羅盤方向
在主活動中,注冊一個傳感器監(jiān)聽器來獲取設(shè)備的方向變化,并更新羅盤視圖的方向:
package com.example.myapp;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity implements SensorEventListener {
private SensorManager sensorManager;
private Sensor rotationSensor;
private CompassView compassView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
compassView = findViewById(R.id.compassView);
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
rotationSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
}
@Override
protected void onResume() {
super.onResume();
sensorManager.registerListener(this, rotationSensor, SensorManager.SENSOR_DELAY_NORMAL);
}
@Override
protected void onPause() {
super.onPause();
sensorManager.unregisterListener(this);
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
float[] rotationMatrix = new float[9];
SensorManager.getRotationMatrixFromVector(rotationMatrix, event.values);
float[] orientation = new float[3];
SensorManager.getOrientation(rotationMatrix, orientation);
// 將弧度轉(zhuǎn)換為角度
float azimuth = (float) Math.toDegrees(orientation[0]);
compassView.setDirection(azimuth);
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// 不處理精度變化
}
}運行應(yīng)用
現(xiàn)在你可以運行這個應(yīng)用,它會顯示一個自定義的羅盤視圖,并且隨著設(shè)備的旋轉(zhuǎn)而更新方向。
方法二
這個示例展示了如何在Android中創(chuàng)建一個簡單的自定義羅盤視圖。你可以根據(jù)需要進一步擴展和美化這個視圖,例如添加更多的圖形元素或改進用戶界面。在Android中創(chuàng)建一個自定義的羅盤視圖涉及多個步驟,包括定義視圖、處理傳感器數(shù)據(jù)、繪制羅盤圖像等。下面是一個詳細的指南,幫助你實現(xiàn)一個基本的自定義羅盤視圖。
創(chuàng)建自定義視圖
首先,你需要創(chuàng)建一個自定義視圖類來繪制羅盤。這個類將繼承自 ??View?? 類,并重寫 ??onDraw?? 方法來繪制羅盤圖像。
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.view.View;
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 = BitmapFactory.decodeResource(getResources(), R.drawable.compass);
matrix = new Matrix();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
matrix.reset();
matrix.postRotate(-currentDegree, compassBitmap.getWidth() / 2, compassBitmap.getHeight() / 2);
canvas.drawBitmap(compassBitmap, matrix, null);
}
public void updateDegree(float degree) {
currentDegree = degree;
invalidate(); // 重新繪制視圖
}
}處理傳感器數(shù)據(jù)
為了獲取設(shè)備的方向數(shù)據(jù),你需要注冊一個 ??SensorEventListener?? 并監(jiān)聽 ??TYPE_ORIENTATION?? 傳感器(或更現(xiàn)代的 ??TYPE_ROTATION_VECTOR?? 傳感器)。
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity implements SensorEventListener {
private SensorManager sensorManager;
private Sensor sensor;
private CompassView compassView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
compassView = findViewById(R.id.compassView);
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
}
@Override
protected void onResume() {
super.onResume();
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL);
}
@Override
protected void onPause() {
super.onPause();
sensorManager.unregisterListener(this);
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
float degree = Math.round(event.values[0]);
compassView.updateDegree(degree);
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// 無需處理
}
}布局文件
在布局文件中添加自定義的 ??CompassView??。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.example.yourapp.CompassView
android:id="@+id/compassView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
</RelativeLayout>
添加資源文件
確保你有一個羅盤圖像資源文件(例如 ??res/drawable/compass.png??),并將其放置在項目的 ??res/drawable?? 目錄下。
權(quán)限
在 ??AndroidManifest.xml?? 中添加必要的權(quán)限:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
總結(jié)
以上步驟展示了如何在Android中創(chuàng)建一個自定義的羅盤視圖。通過自定義視圖類和傳感器事件監(jiān)聽器,你可以實現(xiàn)一個動態(tài)更新方向的羅盤。
以上就是Android自定義實現(xiàn)羅盤視圖詳解的詳細內(nèi)容,更多關(guān)于Android自定義視圖的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android使用ViewPager實現(xiàn)左右無限滑動
這篇文章主要為大家詳細介紹了Android使用ViewPager實現(xiàn)左右無限滑動,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-05-05
Android編程向服務(wù)器發(fā)送請求時出現(xiàn)中文亂碼問題的解決方法
這篇文章主要介紹了Android編程向服務(wù)器發(fā)送請求時出現(xiàn)中文亂碼問題的解決方法,實例分析了Android參數(shù)傳遞過程中中文亂碼的解決技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-11-11
Android中自定義view實現(xiàn)側(cè)滑效果
這篇文章主要介紹了Android中自定義view實現(xiàn)側(cè)滑效果的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-11-11
安卓Android6.0權(quán)限動態(tài)獲取操作示例
這篇文章主要介紹了安卓Android6.0權(quán)限動態(tài)獲取操作,結(jié)合實例形式分析了Android6.0針對權(quán)限的動態(tài)獲取、授權(quán)等相關(guān)操作技巧,需要的朋友可以參考下2018-02-02
android studio 打包自動生成版本號與日期,apk輸入路徑詳解
這篇文章主要介紹了android studio 打包自動生成版本號與日期,apk輸入路徑詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03

