自定義View之游戲搖桿鍵盤實現(xiàn)(二)

前言

去年開發(fā)項目,需要實現(xiàn)一個遙感按鈕,控制公司機器人行走,于是通過自定義SurfaceView實現(xiàn)了該功能,想了解的話,傳送門在這自定義View之游戲搖桿鍵盤實現(xiàn),但由于傳輸指令過程中對時間準確度要求較高,調(diào)試后發(fā)現(xiàn),自定義繪制過程中時間不穩(wěn)定,性能較差。于是決定不自定義SurfaceView,改而采用自定義View實現(xiàn)。

最終效果

此版本相對于之前自定義SurfaceView版本,增加角度之間的計算,以及指針的跟隨。根據(jù)公司需求,方向分為八個,除了常規(guī)的上下左右外,還有上左,上右,下左,下右。如圖

方向.png

實際開發(fā)使用后,性能,穩(wěn)定性,都優(yōu)于上一版本,上最后效果圖

未觸摸狀態(tài)下
未觸摸.jpg
觸摸狀態(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" />

如果你有其他思路,可以留言交流

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容