前言
去年開發(fā)項目,需要實現(xiàn)一個遙感按鈕眠蚂,控制公司機(jī)器人行走,于是通過自定義SurfaceView實現(xiàn)了該功能昔脯,想了解的話笛臣,傳送門在這自定義View之游戲搖桿鍵盤實現(xiàn),但由于傳輸指令過程中對時間準(zhǔ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)部方向背景圖摔敛,因此全封,先獲圖片,注意避免重復(fù)實例化
//外層圖
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);
獲取之后刹悴,指定相關(guān)圖片的繪制區(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進(jìn)行繪制妒御,在這過程中,對中心懸浮球送讲,實時測量繪制區(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ū)域膳殷,這里給出相應(yīng)的角度,弧度計算赚窃,根據(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" />
如果你有其他思路,可以留言交流