文章目錄
最近在做一個手柄藍牙連接手機,通過手柄控制手機的焦點需求,這裏簡單總結記錄下。
先分析一下需求:
通過手柄搖桿或者十字按鍵控制手機的焦點,控制一個左側箭頭是減按鈕,中間是顯示數量的TextView
文本,右側箭頭是增加按鈕,當向左搖動搖桿或者按十字按鍵的左按鍵進行減少操作,當向右搖桿或者按十字按鍵的右按鍵進行增加操作。
最後,當選中某一列的時候,底部要給一個選中的反饋效果。
demo地址:https://github.com/jakezhang1990/BluetoothHandleDemo
看一效果圖:
也就是說期望的效果是:
按十字按鍵的左按鍵或者左搖桿,數字減少;
按十字按鍵的右按鍵或者右搖桿,增加;
按十字按鍵的向下十字按鍵或者向下搖桿到最後一個條目,吐司提示,是最後一個條目了,焦點停留在這裏。
首先,手柄設備藍牙連接到手機,這沒什麼說的,直接按照手柄的說明書進行連接即可。
其次,就是攔截,在onKeyDown
方法中進行攔截。
KeyEvent.KEYCODE_DPAD_LEFT 左搖桿或者十字按鍵左按鍵按下事件。
KeyEvent.KEYCODE_DPAD_RIGHT 右搖桿或者十字按鍵右按鍵按下事件。
KeyEvent.KEYCODE_DPAD_UP 向上搖桿或者十字按鍵向上按鍵按下事件。
KeyEvent.KEYCODE_DPAD_DOWN 向下搖桿或者十字按鍵向下按鍵按下事件
這麼多按鈕,必須得根據目前焦點在哪個按鈕上來判斷出現在會觸發哪個按鈕的事件。
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//item2
if (keyCode==KeyEvent.KEYCODE_DPAD_LEFT&&item2_leftBtn.hasFocus()){
//碼率左搖桿
bitRatLeftRock();
return true;
}else if (keyCode==KeyEvent.KEYCODE_DPAD_RIGHT&&item2_rightBtn.hasFocus()){
//碼率右搖桿
bitRatRightRock();
return true;
}
return super.onKeyDown(keyCode, event);
}
第三,反饋背景的設置問題。
可以通過焦點監聽來設置。setOnFocusChangeListener
。
但是這樣之後會有一個問題,左右箭頭的按鈕點擊事件被攔截掉了,無法觸發了,只能通過手柄的控制才能進行設置了,所以需要給箭頭按鈕加上點擊事件監聽setOnClickListener
。
最後,在android9.0上的bug解決。
在不同的狀態下顯示不同的圖片,使用的是在drawable
中通過state_focused
屬性和state_enable
來進行4種狀態的圖片展示。
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:state_focused="false" android:drawable="@drawable/triangle_left_disable"/>
<item android:state_enabled="true" android:state_focused="false" android:drawable="@drawable/triangle_left_enable"/>
<item android:state_enabled="true" android:state_focused="true" android:drawable="@drawable/triangle_left_focus_enable"/>
<item android:state_enabled="false" android:state_focused="true" android:drawable="@drawable/triangle_left_focus_disable"/>
</selector>
在8.0及以下的系統中是沒問題的,使用手柄正常展示。但是在9.0系統上會出現bug,焦點亂跑,也就是說,當向左一直按十字按鍵或者向左搖桿,當選擇成了最小值的時候,再向左側按鍵或者二搖桿,就會出現焦點亂跑到其他地方的bug,而且,左側如果是最小值的時候,左側按鍵,使用手柄上下移動焦點的時候,這個按鍵也無法獲取焦點,會直接跳過去,導致焦點錯亂。
解決:
仔細想想這裏應該使用state_focus
和state_selected
兩個屬性進行控制。state_enable
在android9.0
上會直接將焦點給過濾掉,將當前所在的焦點轉義到下一個可以獲得焦點的控件上。
step1:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="false" android:state_selected="false" android:drawable="@drawable/triangle_left_disable"/>
<item android:state_focused="false" android:state_selected="true" android:drawable="@drawable/triangle_left_enable"/>
<item android:state_focused="true" android:state_selected="true" android:drawable="@drawable/triangle_left_focus_enable"/>
<item android:state_focused="true" android:state_selected="false" android:drawable="@drawable/triangle_left_focus_disable"/>
<!--
<item android:state_enabled="false" android:state_focused="false" android:drawable="@drawable/triangle_left_disable"/>
<item android:state_enabled="true" android:state_focused="false" android:drawable="@drawable/triangle_left_enable"/>
<item android:state_enabled="true" android:state_focused="true" android:drawable="@drawable/triangle_left_focus_enable"/>
<item android:state_enabled="false" android:state_focused="true" android:drawable="@drawable/triangle_left_focus_disable"/>
-->
</selector>
step2:
將activity中,左右按鍵切換時,控制左右按鈕的state_enable的設置item2_leftBtn.setEnabled(xxx);
這類似的按鈕的可點不可點狀態的設置代碼全部註釋掉,或者全部替換成item2_leftBtn.setSelected(xxx);
進行設置。
這樣就解決了,在android9.0上焦點亂跑的問題。
參考鏈接:
https://www.jianshu.com/p/c0a76cc496fb
Google官方文檔:https://developer.android.google.cn/reference/android/view/MotionEvent.html#AXIS_LTRIGGER
亞馬遜也是做類似的產品,有一片參考文檔:https://developer.amazon.com/zh/docs/fire-tv/getting-started-developing-apps-and-games.html