自定義鍵盤(一)

稀飯_發表於2018-09-25

一初識自定義鍵盤

自定義鍵盤涉及到系統的兩個類Keyboard和KeyboardView。Keyboard設定鍵盤的佈局檔案(鍵盤長什麼樣子),KeyboardView處理繪製,檢測按鍵,觸控動作等。

首先,去寫一個鍵盤佈局檔案:在res下新建xml資料夾,在xml資料夾中新建.xml檔案,用來實現軟鍵盤的佈局,這裡先提供一個寫好鍵盤佈局,關於佈局標籤後邊再做介紹。

接下來,在我們Activity對應的佈局檔案中寫上KeyboardView控制元件

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.inputmethodservice.KeyboardView
        android:id="@+id/keyboardView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom" />

</FrameLayout>複製程式碼

最後,對應的Activity找到這個控制元件。給KeyboardView設定keyboard物件,然後給keyboardView設定key的點選事件。

程式碼如下:

//找到鍵盤控制元件
KeyboardView keyboardView = findViewById(R.id.keyboardView);
//建立keyboard,設定我們寫的佈局檔案
Keyboard keyboard = new Keyboard(this, R.xml.keyboard_number_abc);
//把建立的鍵盤佈局設定給控制元件
keyboardView.setKeyboard(keyboard);
//給鍵盤設定監聽
keyboardView.setOnKeyboardActionListener(this);...複製程式碼

執行程式碼顯示ui如下:

          自定義鍵盤(一)

一個很醜的自定義鍵盤出來了。

二自定義鍵盤佈局

通過上邊的介紹,我們對自定義鍵盤有一個整體的瞭解。當然如果想隨心所遇自定義,第一步就需要我們去學習自定義鍵盤佈局檔案的書寫,瞭解Keyboard類。

keyboard類繼承Object,作用是解析XML描述鍵盤和儲存的屬性鍵。一個鍵盤(Keyboard)由成排(Row)的鑰匙(Key)組成。而Row 和Key屬於Keyboard的內部類。

2.1Keyboard類

keyboard.Row :行,鍵在鍵盤的容器。

keyboard.Key: 按鈕,類用於描述一個鍵的位置和特徵的鍵盤.

keyboard的屬性有

  • android:horizontalGap 每個Key之間預設的水平間隙
  • android:keyHeight Key的預設高度.
  • android:keyWidth Key的預設寬度.
  • android:verticalGap 每行(Row)之間的預設行間隙

它們的取值單位可以是px,dp,sp,% ,%p。前三個單位都好理解,最後兩個單位官方文件說的很模糊。

 The % suffix always means a percentage of the base size; the optional %p suffix provides a size relative to some parent container.

字尾為%是相對於基準的高度或者寬度的百分比,而%p則是相對於某些父容器寬度或高度百分比,我並不知道鍵盤的基準高度和某些父容器指的是什麼。但我發現他們並沒有差別,但是保險起見,我們最好不要混著用,而是以一種參考系去設定大小。

2.2keyboard.Key類

keyboard.Key類繼承Object,類用於描述一個鍵的位置和特徵的鍵盤(按鈕)。

屬性有:

  • android:codes (點選key輸出的值)
  • android:horizontalGap key之間的水平間隙
  • android:iconPreview 彈出預覽中顯示的圖片
  • android:isModifier 是否這是一個功能key,如鍵盤中的Alt or Shift
  • android:isRepeatable 按住不放,是否一直輸出內容
  • android:isSticky 是否是一個切換鍵
  • android:keyEdgeFlags 邊界標記
  • android:keyHeight key的高度
  • android:keyIcon  key顯示的圖片
  • android:keyLabel key顯示的內容的內容.
  • android:keyOutputText 按這個鍵時,輸出字元的字串
  • android:keyWidth key寬度
  • android:popupCharacters 字元顯示在預覽鍵盤
  • android:popupKeyboard 自定義預覽佈局

2.3Keyboard.Row類

鍵(Key)在鍵盤的容器。他的屬性會覆蓋keyboard中的屬性

屬性有:

  • android:horizontalGap 每個Key之間的預設間距.
  • android:keyHeight Key的預設高度
  • android:keyWidth Key的預設寬度
  • android:keyboardMode keyboard的模式(Mode)
  • android:rowEdgeFlags 邊境標記
  • android:verticalGap 垂直Key之間的差距.

注意

1.觀察這三個類的屬性,Keyboard.Row類屬性和Keyboard類屬性有四個屬性是一樣的:

  • android:horizontalGap 每個Key之間預設的水平間隙
  • android:keyHeight Key的預設高度.
  • android:keyWidth Key的預設寬度.
  • android:verticalGap 每行(Row)之間的預設行間隙

當根佈局Keyboard和列布局Keyboard.Row都寫有這樣的屬性的時候,根佈局的屬性將會被取代。同理,Keyboard.Row 和keyboard.Key有的共同屬性,如果key重寫,也將按照key設定的為準,有點類似java中重寫方法的作用。

2.上邊的屬性都是設定key之前的間隙,卻沒有設定最外邊key和內邊距。那麼這個應該怎麼設定呢?

寫一個空的行或者空的key去解決;

<Row android:keyHeight="0%p" />複製程式碼
<Key
    android:codes="-9999"
    android:keyWidth="0%p" />複製程式碼

最後貼上一個帶有鍵盤佈局的註釋程式碼:

<?xml version="1.0" encoding="utf-8"?><!--根佈局設定鍵盤整體的每個key之間的間隙和鍵的寬度和高度-->
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:horizontalGap="3%p"
    android:keyHeight="7.5%p"
    android:keyWidth="21.25%p"
    android:verticalGap="1.5%p">

    <!--類似與內邊距屬性-->
    <Row android:keyHeight="0%p" />

    <Row>
        <Key
            android:codes="49"
            android:keyLabel="1" />
        <Key
            android:codes="50"
            android:keyLabel="2" />
        <Key
            android:codes="51"
            android:keyLabel="3" />
        <!--由於這個key的高度和其他key的高度不一樣,所以這裡需要重寫這個屬性-->
        <Key
            android:codes="-5"
            android:isRepeatable="true"
            android:keyHeight="16.5%p"
            android:keyIcon="@drawable/ic_outline_backspace_24dp" />
        <!--類似與內邊距屬性-->
        <Key
            android:codes="-9999"
            android:keyWidth="0%p" />
    </Row>
    <Row>
        <Key
            android:codes="52"
            android:keyLabel="4" />
        <Key
            android:codes="53"
            android:keyLabel="5" />
        <Key
            android:codes="54"
            android:keyLabel="6" />
    </Row>
    <Row>
        <Key
            android:codes="55"
            android:keyLabel="7" />
        <Key
            android:codes="56"
            android:keyLabel="8" />
        <Key
            android:codes="57"
            android:keyLabel="9" />
        <!--由於這個key的高度和其他key的高度不一樣,所以這裡需要重寫這個屬性-->
        <Key
            android:codes="-4"
            android:keyHeight="16.5%p"
            android:keyLabel="確定" />
    </Row>

    <Row>
        <!--這裡從新定於鍵的寬度-->
        <Key
            android:codes="789789"
            android:keyLabel="ABC"
            android:keyWidth="9.875%p" />
        <!--這裡從新定於鍵的寬度-->
        <Key
            android:codes="45"
            android:horizontalGap="1.5%p"
            android:keyLabel="-"
            android:keyWidth="9.875%p" />
        <Key
            android:codes="48"
            android:keyLabel="0" />
        <Key
            android:codes="46"
            android:keyLabel="." />
    </Row>
    <!--下邊的內邊距-->
    <Row android:keyHeight="0%p" />
</Keyboard>複製程式碼

到此我想讀者應該可以隨心所欲的寫出來一個滿足產品需求的鍵盤佈局。

三設定自定義鍵盤樣式

上邊我們寫出來一個黑不溜秋的鍵盤,滿足不了任何產品的需求,google設定鍵盤的樣式通過KeyboardView類屬性提供給開發者。

3.1KeyboardView類

它繼承View,實現了View.OnClickListener介面,官網對這個類的描述:一個呈現虛擬鍵盤的檢視。它處理key的渲染和檢測按鍵和觸控動作。

它有一個內部類KeyboardView.OnKeyboardActionListener:虛擬鍵盤事件的監聽器。

屬性有:

  • android:background :設定整個鍵盤的背景,View共有的屬性
  • android:keyBackground key的背景 ,建議用drawable型別選擇器,顯示選中與未選中效果,這個屬性設定的是所有key的背景,關於不同背景設定後邊介紹。
  • android:keyPreviewLayout 按鈕按下時提示佈局檢視,不要時候可以設定成@null
  • android:keyTextColor 按鈕文字的顏色
  • android:keyTextSize 按鈕文字的大小
  • android:labelTextSize 沒有圖片的按鈕中文字大小
  •  android:shadowColor 設定key中字型陰影的顏色要不字型顯示模糊。

當我們把我們需要設定的屬性設定進去,呈現出來的鍵盤如下圖:

        自定義鍵盤(一)

比上邊黑不溜秋的好看多了。通過上邊需求我們基本可以滿足產品需求。

3.2設定單個key的樣式

但是如果需求要求是“確定key”的背景顏色和其他的key顏色不一樣,比如就這一個key設定成藍色,對於這個需求google並未給我們提供設定單個key的背景顏色的屬性,但是我們要去實現這個效果,我們該怎麼辦呢?

這個時候我們就要自定義KeyboardView類,重寫onDraw方法,加上繪製特殊key的背景,覆蓋掉原來的key。

繪製程式碼如下:

public class CustomKeyboardView extends KeyboardView {

    private Paint mtextPaint;

    public CustomKeyboardView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CustomKeyboardView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mtextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mtextPaint.setTextAlign(Paint.Align.CENTER);
        mtextPaint.setTextSize(46);
        mtextPaint.setColor(Color.WHITE);
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        List<Keyboard.Key> keys = getKeyboard().getKeys();

        for (Keyboard.Key key : keys) {
            if (key.codes[0] == -4) {
                //獲取drawable資源
                Drawable drawable = getContext().getResources().getDrawable(R.drawable.srue_bg_key);
                //把真正的狀態設定給上層繪製的key鍵
                drawable.setState(key.getCurrentDrawableState());
                //rawable將在被繪製在canvas的哪個矩形區域內(這個矩形區域的座標是以canvas左上角為座標原點的)
                drawable.setBounds(key.x, key.y, key.x + key.width, key.y + key.height);
                //開始繪製
                drawable.draw(canvas);
                //繪製文字
                if (key.label != null) {
                    Paint.FontMetrics fontMetrics = mtextPaint.getFontMetrics();
                    //計算基線
                    Float baseLine = key.y + key.height / 2 + (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
                    //繪製文字
                    canvas.drawText(key.label.toString(), key.x + (key.width / 2), baseLine, mtextPaint);
                }

            }
        }


    }
}複製程式碼

效果圖如下:

       自定義鍵盤(一)

由於篇幅限制,另起一篇講解更多關於自定義鍵盤的更多技巧。



相關文章