前言
去年開發(fā)項目,需要實現(xiàn)一個遙感按鈕,控制公司機器人行走,于是通過自定義SurfaceView實現(xiàn)了該功能,想了解的話,傳送門在這自定義View之游戲搖桿鍵盤實現(xiàn),但由于傳輸指令過程中對時間準確度要求較高,調(diào)試后發(fā)現(xiàn),自定義繪制過程中時間不穩(wěn)定,性能較差。于是決定不自定義SurfaceView,改而采用自定義View實現(xiàn)。
最終效果
此版本相對于之前自定義SurfaceView版本,增加角度之間的計算,以及指針的跟隨。根據(jù)公司需求,方向分為八個,除了常規(guī)的上下左右外,還有上左,上右,下左,下右。如圖

實際開發(fā)使用后,性能,穩(wěn)定性,都優(yōu)于上一版本,上最后效果圖
未觸摸狀態(tài)下

觸摸狀態(tài)下
觸摸狀態(tài)下.png

實現(xiàn)
效果圖中,實現(xiàn)遙感按鈕所需圖片分為:中心懸浮球,外層圖,內(nèi)部方向背景圖,因此,先獲圖片,注意避免重復實例化
//外層圖
bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.control_rocker_arrow);
//中心懸浮球
bitmapInner = BitmapFactory.decodeResource(getResources(), R.mipmap.control_rocker_paws);
//外層圓形帶指針圖
bitmap1 = BitmapFactory.decodeResource(getResources(), R.mipmap.control_rocker_bg);
bitmap2 = BitmapFactory.decodeResource(getResources(), R.mipmap.control_rocker_not_active);
獲取之后,指定相關圖片的繪制區(qū)域(例如圖片的左上角區(qū)域)
src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
srcNoActive = new Rect(0, 0, bitmap2.getWidth(), bitmap2.getHeight());
srcInner = new Rect(0, 0, bitmapInner.getWidth(), bitmapInner.getHeight());
在onMeasure測量時,通過bitmap寬高,獲取外層圖片的顯示區(qū)域(指定圖片在屏幕上顯示的區(qū)域),
//觸摸
dst = new Rect((int) mWidth / 2 - bitmap.getWidth() / 2, (int) mHeight / 2 - bitmap.getHeight() / 2,
(int) mWidth / 2 + bitmap.getWidth() / 2, (int) mHeight / 2 + bitmap.getHeight() / 2);
//未觸摸
dstNoActive = new Rect((int) mWidth / 2 - bitmap2.getWidth() / 2, (int) mHeight / 2 - bitmap2.getHeight() / 2,
(int) mWidth / 2 + bitmap2.getWidth() / 2, (int) mHeight / 2 + bitmap2.getHeight() / 2);
測量完后,在onDraw進行繪制,在這過程中,對中心懸浮球,實時測量繪制區(qū)域,避免中心球顯示不全
dstInner = new Rect((int) posX - minRadius, (int) posY - minRadius, (int) posX + minRadius, (int) posY + minRadius);
通過Matrix矩陣移動及旋轉(zhuǎn),計算控制外層指針的旋轉(zhuǎn)角度,實現(xiàn)跟隨手指方向
matrix.reset();
matrix.setTranslate(mWidth / 2 - bitmap1.getWidth() / 2, mHeight / 2 - bitmap1.getHeight() / 2);
if (tempRad != 0) {
matrix.preRotate(tempRad + 90, (float) bitmap1.getWidth() / 2, (float) bitmap1.getHeight() / 2); //要旋轉(zhuǎn)的角度
} else {
matrix.preRotate(tempRad);
}
if (isStart) {
canvas.drawBitmap(bitmap1, matrix, null);
} else {
canvas.drawBitmap(bitmap2, srcNoActive, dstNoActive, null);
}
matrix.reset();
注意判斷觸摸狀態(tài),以及Matrix的reset,否則下次繪制時,圖片便會偏移。到此,遙感按鈕已經(jīng)實現(xiàn)
方向判斷
上面提到的,公司項目實際使用的遙感分為八個方向,因此需將遙感分為8個區(qū)域,這里給出相應的角度,弧度計算,根據(jù)個人需求更改。
弧度計算
/***
* 兩點弧度
*/
public float getRad(float px1, float py1, float px2, float py2) {
float x = px2 - px1;
float y = py1 - py2;
//斜邊的長
float z = (float) Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
float cosAngle = x / z;
float rad = (float) Math.acos(cosAngle);
if (py2 < py1) {
rad = -rad;
}
return rad;
}
角度計算
private float getAngle(float xTouch, float yTouch) {
RockerCircleX = mWidth / 2;
RockerCircleY = mHeight / 2;
return (float) (getRad(RockerCircleX, RockerCircleY, xTouch, yTouch) * 180f / Math.PI);
}
這里我采用用接口傳遞,將計算出的角度傳遞給Activity或者Fragment
public interface RemoteListener {
void onRemoteListener(int cmd);
}
最后
在xml文件中使用即可
<com.by.happydog.view.RemoteControlView
android:id="@+id/remote_view"
android:layout_width="270dp"
android:layout_height="270dp"
android:layout_marginLeft="15dp"
android:layout_marginTop="60dp" />
如果你有其他思路,可以留言交流