Jak stworzyć niestandardową klawiaturę w systemie Android?


105

Chcę zrobić niestandardową klawiaturę. Nie wiem, jak to zrobić za pomocą XML i Java. Poniższe zdjęcie przedstawia model klawiatury, którą chcę wykonać. Potrzebuje tylko liczb.

wprowadź opis obrazu tutaj


6
[Utwórz własną klawiaturę niestandardową za pomocą układów XML dla urządzeń z systemem Android] ( tutorials-android.blogspot.com/2011/06/... )
Jorgesys

1
W Tuts jest dobry poradnik: link
Hamed Ghadirian

Google ma przykładowy projekt „SoftKeyboard” lub istnieje tutaj wiele zasobów połączonych: customkeyboarddetails.blogspot.com/2019/02/…
oliversisson

Odpowiedzi:


83

Przede wszystkim będziesz potrzebował keyboard.xmlpliku, który zostanie umieszczony w res/xmlfolderze (jeśli folder nie istnieje, utworzył go).

<?xml version="1.0" encoding="utf-8"?> 
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyWidth="15%p"
    android:keyHeight="15%p" >

    <Row>
        <Key android:codes="1"    android:keyLabel="1" android:horizontalGap="4%p"/>
        <Key android:codes="2"    android:keyLabel="2" android:horizontalGap="4%p"/>
        <Key android:codes="3"    android:keyLabel="3" android:horizontalGap="4%p" />
        <Key android:codes="4"    android:keyLabel="4" android:horizontalGap="4%p" />
        <Key android:codes="5"    android:keyLabel="5" android:horizontalGap="4%p" />
    </Row>
    <Row>
        <Key android:codes="6"    android:keyLabel="6" android:horizontalGap="4%p"/>
        <Key android:codes="7"    android:keyLabel="7" android:horizontalGap="4%p"/>
        <Key android:codes="8"    android:keyLabel="8" android:horizontalGap="4%p" />
        <Key android:codes="9"    android:keyLabel="9" android:horizontalGap="4%p" />
        <Key android:codes="0"    android:keyLabel="0" android:horizontalGap="4%p" />
    </Row>

    <Row>
        <Key android:codes="-1"    android:keyIcon="@drawable/backspace" android:keyWidth="34%p" android:horizontalGap="4%p"/>
        <Key android:codes="100"    android:keyLabel="Enter" android:keyWidth="53%p" android:horizontalGap="4%p"/>
    </Row>
 </Keyboard>

** Pamiętaj, że będziesz musiał utworzyć backspaceplik do rysowania i umieścić go w folderze res / drawable-ldpi o bardzo małym rozmiarze (np. 18x18 pikseli)

Następnie w pliku xml, którego chcesz użyć (gdzie znajduje się Twój TextView), powinieneś dodać następujący kod:

<RelativeLayout
 ...
>

        .....


        <android.inputmethodservice.KeyboardView
             android:id="@+id/keyboardview"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:layout_alignParentBottom="true"
             android:layout_centerHorizontal="true"
             android:focusable="true"
             android:focusableInTouchMode="true"
             android:visibility="gone" 
         />
         
        ......


</RelativeLayout>

** Zauważ, że plik xml, który umieścisz android.inputmethodservice.KeyboardView, musi być RelativeLayout, aby móc ustawić alignParentBottom="true"(Zwykle klawiatury są prezentowane na dole ekranu)

Następnie musisz dodać następujący kod w onCreatefunkcji Activityobsługującej element TextView, do którego chcesz dołączyć klawiaturę

    // Create the Keyboard
    mKeyboard= new Keyboard(this,R.xml.keyboard);

    // Lookup the KeyboardView
    mKeyboardView= (KeyboardView)findViewById(R.id.keyboardview);
    // Attach the keyboard to the view
    mKeyboardView.setKeyboard( mKeyboard );
    
    // Do not show the preview balloons
    //mKeyboardView.setPreviewEnabled(false);
    
    // Install the key handler
    mKeyboardView.setOnKeyboardActionListener(mOnKeyboardActionListener);

** Zauważ, że mKeyboardi mKeyboardViewsą to prywatne zmienne klasowe, które musisz utworzyć.

Następnie potrzebujesz następującej funkcji do otwierania klawiatury (musisz powiązać ją z TextView poprzez onClickwłaściwość xml)

    public void openKeyboard(View v)
    {
       mKeyboardView.setVisibility(View.VISIBLE);
       mKeyboardView.setEnabled(true);
       if( v!=null)((InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(v.getWindowToken(), 0);
    }

I wreszcie potrzebujesz narzędzia OnKeyboardActionListener, które obsłuży Twoje wydarzenia

private OnKeyboardActionListener mOnKeyboardActionListener = new OnKeyboardActionListener() {
    @Override public void onKey(int primaryCode, int[] keyCodes) 
    {
         //Here check the primaryCode to see which key is pressed 
         //based on the android:codes property
         if(primaryCode==1)
         {
            Log.i("Key","You just pressed 1 button");
         }
    }

    @Override public void onPress(int arg0) {
    }

    @Override public void onRelease(int primaryCode) {
    }

    @Override public void onText(CharSequence text) {
    }

    @Override public void swipeDown() {
    }

    @Override public void swipeLeft() {
    }

    @Override public void swipeRight() {
    }

    @Override public void swipeUp() {
    }
};

Mam nadzieję, że to pomoże !!!

Większość kodu znalezionego tutaj

____________________________________________________________-

EDYTOWAĆ:

Ponieważ KeyboardView jest przestarzały od poziomu 29 interfejsu API, możesz znaleźć jego kod w tej witrynie i utworzyć klasę w kodzie przed zaimplementowaniem klawiatury, jak opisano powyżej.


1
A jeśli nie chcę, aby klawiatura znajdowała się u dołu ekranu? (np. chcę, aby użytkownik mógł go przeciągać). Czy jest to coś, co mogę kontrolować za pomocą aplikacji na klawiaturę, czy jest to obsługiwane przez system Android?
user3294126

szerokość klawiatury nie wypełnia ekranu, co powinienem zrobić, aby wypełniła wszystkie ekrany
George Thomas,

jaki jest układ nadrzędny, w którym znajduje się KeyboardView? Czy sprawdziłeś także layout_width w KeyboardView?
Pontios

1
Należy pamiętać, że klasy KeyboardView i Keyboard zostały wycofane przez Google od 29 poziomu interfejsu API. Dlatego to rozwiązanie nie będzie już działać w przyszłości, jeśli trzeba będzie kierować się na nowszy poziom interfejsu API.
maex

keyboardView został wycofany przez Google. co to jest nowe rozwiązanie?
tohidmahmoudvand

78

Klawiatura systemowa

W tej odpowiedzi opisano, jak utworzyć niestandardową klawiaturę systemową, której można używać w dowolnej aplikacji zainstalowanej przez użytkownika na telefonie. Jeśli chcesz stworzyć klawiaturę, która będzie używana tylko w Twojej aplikacji, zobacz moją drugą odpowiedź .

Poniższy przykład będzie wyglądał następująco. Możesz go zmodyfikować dla dowolnego układu klawiatury.

wprowadź opis obrazu tutaj

Poniższe kroki pokazują, jak utworzyć działającą niestandardową klawiaturę systemową. W miarę możliwości starałem się usunąć niepotrzebny kod. Jeśli potrzebujesz innych funkcji, na końcu zamieściłem linki do dalszej pomocy.

1. Uruchom nowy projekt Android

Nazwałem swój projekt „Klawiatura niestandardowa”. Nazwij to, jak chcesz. Nie ma tu nic specjalnego. Po prostu zostawię MainActivityi „Hello World!” układ, jaki jest.

2. Dodaj pliki układu

Dodaj następujące dwa pliki do res/layoutfolderu aplikacji :

  • keyboard_view.xml
  • key_preview.xml

keyboard_view.xml

Ten widok jest jak kontener, w którym znajdzie się nasza klawiatura. W tym przykładzie jest tylko jedna klawiatura, ale możesz dodać inne klawiatury i wymieniać je z niej KeyboardView.

<?xml version="1.0" encoding="utf-8"?>
<android.inputmethodservice.KeyboardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/keyboard_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:keyPreviewLayout="@layout/key_preview"
    android:layout_alignParentBottom="true">

</android.inputmethodservice.KeyboardView>

key_preview.xml

Podgląd klawisza to układ, który pojawia się po naciśnięciu klawisza na klawiaturze. Pokazuje tylko, jaki klawisz naciskasz (na wypadek, gdybyś zakrywał go dużymi, grubymi palcami). To nie jest wyskakujące okienko wielokrotnego wyboru. W tym celu sprawdź widok Kandydaci .

<?xml version="1.0" encoding="utf-8"?>
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:background="@android:color/white"
    android:textColor="@android:color/black"
    android:textSize="30sp">
</TextView>

3. Dodaj pomocnicze pliki xml

Utwórz xmlfolder w swoim resfolderze. (Kliknij prawym przyciskiem myszy resi wybierz Nowy> Katalog ).

Następnie dodaj do niego następujące dwa pliki xml. (Kliknij xmlfolder prawym przyciskiem myszy i wybierz Nowy> Plik zasobów XML) .

  • number_pad.xml
  • method.xml

number_pad.xml

Tutaj zaczyna się robić ciekawiej. To Keyboarddefiniuje układ z klawiszami .

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyWidth="20%p"
    android:horizontalGap="5dp"
    android:verticalGap="5dp"
    android:keyHeight="60dp">

    <Row>
        <Key android:codes="49" android:keyLabel="1" android:keyEdgeFlags="left"/>
        <Key android:codes="50" android:keyLabel="2"/>
        <Key android:codes="51" android:keyLabel="3"/>
        <Key android:codes="52" android:keyLabel="4"/>
        <Key android:codes="53" android:keyLabel="5" android:keyEdgeFlags="right"/>
    </Row>

    <Row>
        <Key android:codes="54" android:keyLabel="6" android:keyEdgeFlags="left"/>
        <Key android:codes="55" android:keyLabel="7"/>
        <Key android:codes="56" android:keyLabel="8"/>
        <Key android:codes="57" android:keyLabel="9"/>
        <Key android:codes="48" android:keyLabel="0" android:keyEdgeFlags="right"/>
    </Row>

    <Row>
        <Key android:codes="-5"
             android:keyLabel="DELETE"
             android:keyWidth="40%p"
             android:keyEdgeFlags="left"
             android:isRepeatable="true"/>
        <Key android:codes="10"
             android:keyLabel="ENTER"
             android:keyWidth="60%p"
             android:keyEdgeFlags="right"/>
    </Row>

</Keyboard>

Oto kilka rzeczy, na które należy zwrócić uwagę:

  • keyWidth: To jest domyślna szerokość każdego klawisza. Te 20%pśrodki, które każdy klawisz powinien trwać 20% szerokości p Arent. Można go jednak zastąpić pojedynczymi klawiszami, jak widać z klawiszami Delete i Enter w trzecim rzędzie.
  • keyHeight: Jest tutaj zakodowany na sztywno, ale możesz użyć czegoś takiego, jak @dimen/key_heightustawić go dynamicznie dla różnych rozmiarów ekranu.
  • Gap: Pozioma i pionowa przerwa określa, ile wolnego miejsca między klawiszami. Nawet jeśli ustawisz to na, 0pxnadal jest mała luka.
  • codes: Może to być kod Unicode lub niestandardowa wartość kodu, która określa, co się dzieje lub co jest wprowadzane po naciśnięciu klawisza. Sprawdź, keyOutputTextczy chcesz wprowadzić dłuższy ciąg Unicode.
  • keyLabel: To jest tekst wyświetlany na klawiszu.
  • keyEdgeFlags: Wskazuje, do której krawędzi ma być wyrównany wpust.
  • isRepeatable: Jeśli przytrzymasz wciśnięty klawisz, wejście będzie powtarzane.

method.xml

Ten plik informuje system o dostępnych podtypach metod wejściowych. Załączam tutaj tylko minimalną wersję.

<?xml version="1.0" encoding="utf-8"?>
<input-method
    xmlns:android="http://schemas.android.com/apk/res/android">

    <subtype
        android:imeSubtypeMode="keyboard"/>

</input-method>

4. Dodaj kod Java do obsługi wprowadzania klucza

Utwórz nowy plik Java. Nazwijmy to MyInputMethodService. Ten plik łączy wszystko razem. Obsługuje dane wejściowe otrzymane z klawiatury i wysyła je do dowolnego widoku, który je otrzymuje ( EditTextna przykład).

public class MyInputMethodService extends InputMethodService implements KeyboardView.OnKeyboardActionListener {

    @Override
    public View onCreateInputView() {
        // get the KeyboardView and add our Keyboard layout to it
        KeyboardView keyboardView = (KeyboardView) getLayoutInflater().inflate(R.layout.keyboard_view, null);
        Keyboard keyboard = new Keyboard(this, R.xml.number_pad);
        keyboardView.setKeyboard(keyboard);
        keyboardView.setOnKeyboardActionListener(this);
        return keyboardView;
    }

    @Override
    public void onKey(int primaryCode, int[] keyCodes) {

        InputConnection ic = getCurrentInputConnection();
        if (ic == null) return;
        switch (primaryCode) {
            case Keyboard.KEYCODE_DELETE:
                CharSequence selectedText = ic.getSelectedText(0);
                if (TextUtils.isEmpty(selectedText)) {
                    // no selection, so delete previous character
                    ic.deleteSurroundingText(1, 0);
                } else {
                    // delete the selection
                    ic.commitText("", 1);
                }
                break;
            default:
                char code = (char) primaryCode;
                ic.commitText(String.valueOf(code), 1);
        }
    }

    @Override
    public void onPress(int primaryCode) { }

    @Override
    public void onRelease(int primaryCode) { }

    @Override
    public void onText(CharSequence text) { }

    @Override
    public void swipeLeft() { }

    @Override
    public void swipeRight() { }

    @Override
    public void swipeDown() { }

    @Override
    public void swipeUp() { }
}

Uwagi:

  • W OnKeyboardActionListenernasłuchuje dane z klawiatury. Wymaga również wszystkich tych pustych metod w tym przykładzie.
  • To InputConnectionjest to, co jest używane do wysyłania danych wejściowych do innego widoku, takiego jak plik EditText.

5. Zaktualizuj manifest

Umieszczam to na końcu zamiast na początku, ponieważ odnosi się do plików, które już dodaliśmy powyżej. Aby zarejestrować klawiaturę niestandardową jako klawiaturę systemową, musisz dodać servicesekcję do pliku AndroidManifest.xml . Umieść to w applicationsekcji po activity.

<manifest ...>
    <application ... >
        <activity ... >
            ...
        </activity>

        <service
            android:name=".MyInputMethodService"
            android:label="Keyboard Display Name"
            android:permission="android.permission.BIND_INPUT_METHOD">
            <intent-filter>
                <action android:name="android.view.InputMethod"/>
            </intent-filter>
            <meta-data
                android:name="android.view.im"
                android:resource="@xml/method"/>
        </service>

    </application>
</manifest>

Otóż ​​to! Teraz powinieneś móc uruchomić swoją aplikację. Jednak niewiele zobaczysz, dopóki nie włączysz klawiatury w ustawieniach.

6. Włącz klawiaturę w Ustawieniach

Każdy użytkownik, który chce korzystać z Twojej klawiatury, będzie musiał ją włączyć w ustawieniach Androida. Aby uzyskać szczegółowe instrukcje, jak to zrobić, zobacz poniższy link:

Oto podsumowanie:

  • Wybierz kolejno Ustawienia Androida> Języki i wprowadzanie> Bieżąca klawiatura> Wybierz klawiatury.
  • Na liście powinna pojawić się klawiatura niestandardowa. Odblokuj to.
  • Wróć i ponownie wybierz opcję Bieżąca klawiatura. Na liście powinna pojawić się klawiatura niestandardowa. Wybierz to.

Teraz powinieneś być w stanie używać klawiatury w dowolnym miejscu, w którym możesz wpisać Androida.

Dalsze badanie

Powyższa klawiatura jest użyteczna, ale aby stworzyć klawiaturę, której inne osoby będą chciały używać, prawdopodobnie będziesz musiał dodać więcej funkcji. Przeczytaj poniższe linki, aby dowiedzieć się, jak to zrobić.

Dziać się

Nie podoba ci się, jak standard KeyboardViewwygląda i zachowuje się? Ja na pewno nie. Wygląda na to, że nie był aktualizowany od czasu Androida 2.0. A co z tymi wszystkimi niestandardowymi klawiaturami w Sklepie Play? Nie wyglądają jak brzydka klawiatura powyżej.

Dobra wiadomość jest taka, że ​​możesz całkowicie dostosować wygląd i zachowanie własnej klawiatury. Będziesz musiał wykonać następujące czynności:

  1. Utwórz własny niestandardowy widok klawiatury, który obejmuje podklasy ViewGroup. Możesz wypełnić go Buttons lub nawet stworzyć własne niestandardowe widoki kluczy, które są podklasą View. Jeśli używasz widoków wyskakujących, zanotuj to .
  2. Dodaj niestandardowy interfejs nasłuchiwania zdarzeń na klawiaturze. Wywołaj jego metody dla rzeczy takich jak onKeyClicked(String text)lub onBackspace().
  3. Nie trzeba dodać keyboard_view.xml, key_preview.xmllub number_pad.xmlopisane w kierunkach wyżej, gdyż są to wszystko do normy KeyboardView. Zajmiesz się wszystkimi tymi aspektami interfejsu użytkownika w swoim niestandardowym widoku.
  4. W swojej MyInputMethodServiceklasie zaimplementuj niestandardowy odbiornik klawiatury zdefiniowany w klasie klawiatury. Jest to miejsce KeyboardView.OnKeyboardActionListener, które nie jest już potrzebne.
  5. W metodzie MyInputMethodServiceklasy onCreateInputView()utwórz i zwróć instancję klawiatury niestandardowej. Nie zapomnij ustawić niestandardowego nasłuchiwania klawiatury na this.

35

Klawiatura w aplikacji

Ta odpowiedź wyjaśnia, jak skonfigurować niestandardową klawiaturę do użytku wyłącznie w aplikacji. Jeśli chcesz stworzyć klawiaturę systemową, której można używać w dowolnej aplikacji, zobacz moją drugą odpowiedź .

Przykład będzie wyglądał następująco. Możesz go zmodyfikować dla dowolnego układu klawiatury.

wprowadź opis obrazu tutaj

1. Uruchom nowy projekt Android

Nazwałam swój projekt InAppKeyboard. Zadzwoń, jak chcesz.

2. Dodaj pliki układu

Układ klawiatury

Dodaj plik układu do res/layoutfolderu. Zadzwoniłem do mnie keyboard. Klawiatura będzie niestandardowym widokiem złożonym , który zostanie nadmuchany z tego pliku układu xml. Możesz użyć dowolnego układu do rozmieszczenia klawiszy, ale ja używam LinearLayout. Zwróć uwagę na mergetagi.

res / layout / keyboard.xml

<merge xmlns:android="http://schemas.android.com/apk/res/android">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <Button
                android:id="@+id/button_1"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="1"/>

            <Button
                android:id="@+id/button_2"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="2"/>

            <Button
                android:id="@+id/button_3"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="3"/>

            <Button
                android:id="@+id/button_4"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="4"/>

            <Button
                android:id="@+id/button_5"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="5"/>

        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <Button
                android:id="@+id/button_6"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="6"/>

            <Button
                android:id="@+id/button_7"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="7"/>

            <Button
                android:id="@+id/button_8"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="8"/>

            <Button
                android:id="@+id/button_9"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="9"/>

            <Button
                android:id="@+id/button_0"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="0"/>

        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <Button
                android:id="@+id/button_delete"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="2"
                android:text="Delete"/>

            <Button
                android:id="@+id/button_enter"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="3"
                android:text="Enter"/>

        </LinearLayout>
    </LinearLayout>

</merge>

Układ zajęć

Dla celów demonstracyjnych nasza aktywność ma jeden, EditTexta klawiatura jest na dole. Nazwałem niestandardowy widok klawiatury MyKeyboard. (Wkrótce dodamy ten kod, więc na razie zignoruj ​​błąd). Zaletą umieszczenia całego kodu klawiatury w jednym widoku jest to, że ułatwia on ponowne użycie w innym działaniu lub aplikacji.

res / layout / activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.inappkeyboard.MainActivity">

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#c9c9f1"
        android:layout_margin="50dp"
        android:padding="5dp"
        android:layout_alignParentTop="true"/>

    <com.example.inappkeyboard.MyKeyboard
        android:id="@+id/keyboard"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_alignParentBottom="true"/>

</RelativeLayout>

3. Dodaj plik Java Keyboard

Dodaj nowy plik Java. Zadzwoniłem do mnie MyKeyboard.

Najważniejszą rzeczą, na którą należy tutaj zwrócić uwagę, jest to, że nie ma stałego połączenia z żadnym EditTextlub Activity. Ułatwia to podłączenie go do dowolnej aplikacji lub działania, które tego potrzebuje. Ten niestandardowy widok klawiatury używa również znaku InputConnection, który naśladuje sposób, w jaki klawiatura systemowa komunikuje się z plikiem EditText. W ten sposób unikamy twardych linków.

MyKeyboard jest widokiem złożonym, który rozszerza układ widoku, który zdefiniowaliśmy powyżej.

MyKeyboard.java

public class MyKeyboard extends LinearLayout implements View.OnClickListener {

    // constructors
    public MyKeyboard(Context context) {
        this(context, null, 0);
    }

    public MyKeyboard(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

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

    // keyboard keys (buttons)
    private Button mButton1;
    private Button mButton2;
    private Button mButton3;
    private Button mButton4;
    private Button mButton5;
    private Button mButton6;
    private Button mButton7;
    private Button mButton8;
    private Button mButton9;
    private Button mButton0;
    private Button mButtonDelete;
    private Button mButtonEnter;

    // This will map the button resource id to the String value that we want to 
    // input when that button is clicked.
    SparseArray<String> keyValues = new SparseArray<>();

    // Our communication link to the EditText
    InputConnection inputConnection;

    private void init(Context context, AttributeSet attrs) {

        // initialize buttons
        LayoutInflater.from(context).inflate(R.layout.keyboard, this, true);
        mButton1 = (Button) findViewById(R.id.button_1);
        mButton2 = (Button) findViewById(R.id.button_2);
        mButton3 = (Button) findViewById(R.id.button_3);
        mButton4 = (Button) findViewById(R.id.button_4);
        mButton5 = (Button) findViewById(R.id.button_5);
        mButton6 = (Button) findViewById(R.id.button_6);
        mButton7 = (Button) findViewById(R.id.button_7);
        mButton8 = (Button) findViewById(R.id.button_8);
        mButton9 = (Button) findViewById(R.id.button_9);
        mButton0 = (Button) findViewById(R.id.button_0);
        mButtonDelete = (Button) findViewById(R.id.button_delete);
        mButtonEnter = (Button) findViewById(R.id.button_enter);

        // set button click listeners
        mButton1.setOnClickListener(this);
        mButton2.setOnClickListener(this);
        mButton3.setOnClickListener(this);
        mButton4.setOnClickListener(this);
        mButton5.setOnClickListener(this);
        mButton6.setOnClickListener(this);
        mButton7.setOnClickListener(this);
        mButton8.setOnClickListener(this);
        mButton9.setOnClickListener(this);
        mButton0.setOnClickListener(this);
        mButtonDelete.setOnClickListener(this);
        mButtonEnter.setOnClickListener(this);

        // map buttons IDs to input strings
        keyValues.put(R.id.button_1, "1");
        keyValues.put(R.id.button_2, "2");
        keyValues.put(R.id.button_3, "3");
        keyValues.put(R.id.button_4, "4");
        keyValues.put(R.id.button_5, "5");
        keyValues.put(R.id.button_6, "6");
        keyValues.put(R.id.button_7, "7");
        keyValues.put(R.id.button_8, "8");
        keyValues.put(R.id.button_9, "9");
        keyValues.put(R.id.button_0, "0");
        keyValues.put(R.id.button_enter, "\n");
    }

    @Override
    public void onClick(View v) {

        // do nothing if the InputConnection has not been set yet
        if (inputConnection == null) return;

        // Delete text or input key value
        // All communication goes through the InputConnection
        if (v.getId() == R.id.button_delete) {
            CharSequence selectedText = inputConnection.getSelectedText(0);
            if (TextUtils.isEmpty(selectedText)) {
                // no selection, so delete previous character
                inputConnection.deleteSurroundingText(1, 0);
            } else {
                // delete the selection
                inputConnection.commitText("", 1);
            }
        } else {
            String value = keyValues.get(v.getId());
            inputConnection.commitText(value, 1);
        }
    }

    // The activity (or some parent or controller) must give us 
    // a reference to the current EditText's InputConnection
    public void setInputConnection(InputConnection ic) {
        this.inputConnection = ic;
    }
}

4. Skieruj klawiaturę na EditText

W przypadku klawiatur systemowych system Android używa InputMethodManager, aby wskazać klawiaturę na fokus EditText. W tym przykładzie działanie zajmie jego miejsce, podając łącze z EditTextnaszej klawiatury niestandardowej do.

Ponieważ nie używamy klawiatury systemowej, musimy ją wyłączyć, aby nie pojawiała się po dotknięciu EditText. Po drugie, musimy pobrać go InputConnectionz EditTexti przekazać do naszej klawiatury.

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        EditText editText = (EditText) findViewById(R.id.editText);
        MyKeyboard keyboard = (MyKeyboard) findViewById(R.id.keyboard);

        // prevent system keyboard from appearing when EditText is tapped
        editText.setRawInputType(InputType.TYPE_CLASS_TEXT);
        editText.setTextIsSelectable(true);

        // pass the InputConnection from the EditText to the keyboard
        InputConnection ic = editText.onCreateInputConnection(new EditorInfo());
        keyboard.setInputConnection(ic);
    }
}

Jeśli Twoja aktywność ma wiele tekstów edycji, będziesz musiał napisać kod, aby przekazać odpowiednie teksty edycji InputConnectiondo klawiatury. (Możesz to zrobić, dodając OnFocusChangeListeneri OnClickListenerdo EditTexts. Zobacz ten artykuł, aby omówić ten temat). Możesz także chcieć ukryć lub pokazać klawiaturę w odpowiednim momencie.

Skończone

Otóż ​​to. Powinieneś móc teraz uruchomić przykładową aplikację i wprowadzić lub usunąć tekst zgodnie z potrzebami. Następnym krokiem jest zmodyfikowanie wszystkiego, aby dopasować je do własnych potrzeb. Na przykład w niektórych moich klawiaturach użyłem TextViews zamiast przycisków, ponieważ łatwiej jest je dostosować.

Uwagi

  • W pliku układu xml możesz również użyć TextViewraczej a, Buttonjeśli chcesz, aby klucze wyglądały lepiej. Następnie po prostu ustaw tło, które można narysować, a po naciśnięciu zmieni stan wyglądu.
  • Zaawansowane klawiatury niestandardowe: aby uzyskać większą elastyczność w wyglądzie i przełączaniu klawiatury, teraz tworzę niestandardowe widoki klawiszy, które są podklasami, Viewa niestandardowe klawiatury są podklasami ViewGroup. Klawiatura rozkłada wszystkie klawisze programowo. Klawisze wykorzystują interfejs do komunikacji z klawiaturą (podobnie jak fragmenty komunikują się z działaniem). Nie jest to konieczne, jeśli potrzebujesz tylko jednego układu klawiatury, ponieważ układ xml działa dobrze do tego. Ale jeśli chcesz zobaczyć przykład tego, nad czym pracowałem, sprawdź wszystkie Key*i Keyboard*zajęcia tutaj . Zauważ, że używam tam również widoku kontenera, którego funkcją jest włączanie i wyłączanie klawiatur.

Twoja odpowiedź jest świetna, ale jak możemy ustawić przełączanie między oryginalną klawiaturą a nową klawiaturą.
Kishan Donga

@KishanDonga, Na swojej klawiaturze możesz dodać klawisz do przełączania klawiatur. Gdy użytkownik naciśnie, zadzwoń InputMethodManager#showInputMethodPicker(). Jeśli jednak oryginalna klawiatura nie ma takiego klawisza, jedynym sposobem, w jaki użytkownicy mogą przełączyć się na klawiaturę, jest zrobienie tego ręcznie w ustawieniach systemu. Apple jest lepszy od Androida w tej dziedzinie, ponieważ Apple wymaga, aby wszystkie klawiatury miały klawisz przełączania klawiatury.
Suragch

@KishanDonga, właśnie zdałem sobie sprawę, że ta odpowiedź dotyczy klawiatury w aplikacji, a nie klawiatury systemowej. Jeśli chcesz przełączać się między dwiema niestandardowymi klawiaturami, możesz programowo zamieniać je w widoku kontenera i poza nim. Po prostu dodaj klawisz zamiany klawiatur na obu klawiaturach. Zobacz moją notatkę „zaawansowane klawiatury niestandardowe” i link w powyższej odpowiedzi.
Suragch

Jeśli chcesz przełączać się między klawiaturą a klawiaturą systemową, ukryj klawiaturę systemową i wyświetlaj ją w odpowiednich momentach (i odwrotnie).
Suragch

1
@MarekTakac, będziesz musiał wyłączyć klawiaturę systemową i dodać własną klawiaturę w każdej czynności. Jeśli działanie ma wiele EditTexts, będziesz musiał dodać onFocusChangedListenerdo nich znak, aby po uzyskaniu fokusu można było przypisać InputConnectionod bieżącego EditTextdo niestandardowej klawiatury.
Suragch

31

Zastosowanie KeyboardView:

KeyboardView kbd = new KeyboardView(context);
kbd.setKeyboard(new Keyboard(this, R.xml.custom));

kbd.setOnKeyboardActionListener(new OnKeyboardActionListener() {
    ....
}

teraz masz kbdco jest normalnym widokiem.

Fajną rzeczą w tym jest to, że R.xml.customodnosi się do /res/xml/custom.xml, który definiuje w xml układ klawiatury. Więcej informacji na temat tego pliku można znaleźć tutaj: Keyboard , Keyboard.Row , Keyboard.Key .


2
Używam klasy KeyboardView, ale od API 29 jest ona przestarzała.
Abhijit

14

Oto przykładowy projekt dla miękkiej klawiatury.

https://developer.android.com/guide/topics/text/creating-input-method.html

Twoje powinny znajdować się w tych samych wierszach z innym układem.

Edycja: Jeśli potrzebujesz klawiatury tylko w swojej aplikacji, jest to bardzo proste! Utwórz układ liniowy z orientacją pionową i utwórz w nim 3 układy liniowe z orientacją poziomą. Następnie umieść przyciski z każdego wiersza w każdym z tych poziomych układów liniowych i przypisz do przycisków właściwość wagi. Użyj android: layout_weight = 1 dla wszystkich, aby były równomiernie rozmieszczone.

To rozwiąże. Jeśli nie otrzymałeś tego, czego się spodziewałeś, prześlij kod tutaj, a my jesteśmy tutaj, aby Ci pomóc!


Edycja jest w rzeczywistości zła, ponieważ oznaczałoby to, że klawiatura jest zawsze wyświetlana i nie będzie zachowywać się jak standardowa klawiatura Androida.
m0skit0


4

Niedawno natknąłem się na ten post, gdy próbowałem zdecydować, jakiej metody użyć do stworzenia własnej niestandardowej klawiatury. Uznałem, że API systemu Android jest bardzo ograniczone, więc zdecydowałem się stworzyć własną klawiaturę w aplikacji. Wykorzystując odpowiedź Suragcha jako podstawę moich badań, przystąpiłem do zaprojektowania własnego komponentu klawiatury . Jest opublikowany na GitHub z licencją MIT. Miejmy nadzieję, że zaoszczędzi to komuś dużo czasu i bólu głowy.

Architektura jest dość elastyczna. Istnieje jeden widok główny (CustomKeyboardView), który można wstrzyknąć za pomocą dowolnego układu klawiatury i kontrolera.

Musisz tylko zadeklarować CustomKeyboardView w swoim pliku XML aktywności (możesz to również zrobić programowo):

    <com.donbrody.customkeyboard.components.keyboard.CustomKeyboardView
    android:id="@+id/customKeyboardView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true" />

Następnie zarejestruj w nim swój EditText i powiedz, jakiego typu klawiatury mają używać:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val numberField: EditText = findViewById(R.id.testNumberField)
    val numberDecimalField: EditText = findViewById(R.id.testNumberDecimalField)
    val qwertyField: EditText = findViewById(R.id.testQwertyField)

    keyboard = findViewById(R.id.customKeyboardView)
    keyboard.registerEditText(CustomKeyboardView.KeyboardType.NUMBER, numberField)
    keyboard.registerEditText(CustomKeyboardView.KeyboardType.NUMBER_DECIMAL, numberDecimalField)
    keyboard.registerEditText(CustomKeyboardView.KeyboardType.QWERTY, qwertyField)
}

CustomKeyboardView obsługuje resztę!

Mam piłkę za pomocą klawiatury Number, NumberDecimal i QWERTY. Zapraszam do pobrania i tworzenia własnych układów i kontrolerów. To wygląda tak:

Android niestandardowy krajobraz gif klawiatury

wprowadź opis obrazu tutaj

Nawet jeśli nie jest to architektura, na którą zdecydujesz się wybrać, miejmy nadzieję, że pomocne będzie zapoznanie się z kodem źródłowym działającej klawiatury w aplikacji.

Ponownie, oto link do projektu: Niestandardowa klawiatura w aplikacji


2

Cóż, Suragch udzielił jak dotąd najlepszej odpowiedzi, ale pominął pewne drobne rzeczy, które były ważne przy kompilacji aplikacji.

Mam nadzieję dać lepszą odpowiedź niż Suragch, poprawiając jego odpowiedź. Dodam wszystkie brakujące elementy, których nie umieścił.

Skompilowałem mój apk za pomocą aplikacji na Androida, APK Builder 1.1.0. Więc zacznijmy.

Aby zbudować aplikację na Androida, potrzebujemy kilku plików i folderów, które są uporządkowane w określonym formacie i odpowiednio pisane wielkimi literami.

res layout -> pliki xml przedstawiające wygląd aplikacji na telefonie. Podobnie jak HTML kształtuje wygląd strony internetowej w przeglądarce. Zezwalanie na odpowiednie dopasowanie aplikacji do ekranów.

wartości -> stałe dane, takie jak colors.xml, strings.xml, styles.xml. Te pliki muszą mieć poprawną pisownię.

do rysowania -> zdjęcia {jpeg, png, ...}; Nazwij je dowolnie.

mipmap -> więcej fotek. używany do ikony aplikacji?

xml -> więcej plików xml.

src -> działa jak JavaScript w html. Pliki układu zainicjują widok początkowy, a plik java będzie dynamicznie kontrolować elementy znaczników i zdarzenia wyzwalające. Zdarzenia można również aktywować bezpośrednio w pliku layout.xml, tak jak w html.

AndroidManifest.xml -> Ten plik rejestruje, o czym jest Twoja aplikacja. Nazwa aplikacji, typ programu, wymagane uprawnienia itp. To sprawia, że ​​Android jest raczej bezpieczny. Programy dosłownie nie mogą zrobić tego, o co nie poprosiły w Manifeście.

Obecnie istnieją 4 typy programów na Androida: aktywność, usługa, dostawca treści i odbiorca transmisji. Nasza klawiatura będzie usługą umożliwiającą jej działanie w tle. Nie pojawi się na liście aplikacji do uruchomienia; ale można go odinstalować.

Skompilowanie aplikacji obejmuje Gradle i podpisywanie APK. Możesz go zbadać lub użyć aplikacji APK Builder dla Androida. To bardzo proste.

Teraz, gdy rozumiemy rozwój Androida, stwórzmy pliki i foldery.

  1. Utwórz pliki i foldery, jak omówiłem powyżej. Mój katalog będzie wyglądał następująco:

    • NumPad
      • AndroidManifest.xml
      • src
        • Saragch
          • num_pad
            • MyInputMethodService.java
      • res
        • do rysowania
          • Suragch_NumPad_icon.png
        • układ
          • key_preview.xml
          • keyboard_view.xml
        • xml
          • method.xml
          • number_pad.xml
        • wartości
          • colors.xml
          • strings.xml
          • style.xml

Pamiętaj, że jeśli używasz ide, takiego jak Android Studio, może on zawierać plik projektu.

  1. Napisz pliki.

Odp .: NumPad / res / layout / key_preview.xml

<?xml version="1.0" encoding="utf-8"?>
   <TextView
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:gravity="center"
      android:background="@android:color/white"
      android:textColor="@android:color/black"
      android:textSize="30sp">
</TextView>

B: NumPad / res / layout / keyboard_view.xml

<?xml version="1.0" encoding="utf-8"?>
<android.inputmethodservice.KeyboardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/keyboard_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:keyPreviewLayout="@layout/key_preview"
    android:layout_alignParentBottom="true">

</android.inputmethodservice.KeyboardView>

C: NumPad / res / xml / method.xml

<?xml version="1.0" encoding="utf-8"?>
<input-method  xmlns:android="http://schemas.android.com/apk/res/android">
    <subtype  android:imeSubtypeMode="keyboard"/>
</input-method>

D: Numpad / res / xml / number_pad.xml

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyWidth="20%p"
    android:horizontalGap="5dp"
    android:verticalGap="5dp"
    android:keyHeight="60dp">

    <Row>
        <Key android:codes="49" android:keyLabel="1" android:keyEdgeFlags="left"/>
        <Key android:codes="50" android:keyLabel="2"/>
        <Key android:codes="51" android:keyLabel="3"/>
        <Key android:codes="52" android:keyLabel="4"/>
        <Key android:codes="53" android:keyLabel="5" android:keyEdgeFlags="right"/>
    </Row>

    <Row>
        <Key android:codes="54" android:keyLabel="6" android:keyEdgeFlags="left"/>
        <Key android:codes="55" android:keyLabel="7"/>
        <Key android:codes="56" android:keyLabel="8"/>
        <Key android:codes="57" android:keyLabel="9"/>
        <Key android:codes="48" android:keyLabel="0" android:keyEdgeFlags="right"/>
    </Row>

    <Row>
        <Key android:codes="-5"
             android:keyLabel="DELETE"
             android:keyWidth="40%p"
             android:keyEdgeFlags="left"
             android:isRepeatable="true"/>
        <Key android:codes="10"
             android:keyLabel="ENTER"
             android:keyWidth="60%p"
             android:keyEdgeFlags="right"/>
    </Row>

</Keyboard>

Oczywiście można to łatwo edytować według własnych upodobań. Możesz nawet użyć obrazów zamiast słów dla etykiety.

Suragch nie zademonstrował plików w folderze wartości i założył, że mamy dostęp do Android Studio; która automatycznie je tworzy. Dobrze, że mam APK Builder.

E: NumPad / res / values ​​/ colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>
</resources>

F: NumPad / res / values ​​/ strings.xml

<resources>
    <string name="app_name">Suragch NumPad</string>
</resources>

G: NumPad / res / values ​​/ styles.xml

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="android:Theme.Material.Light.DarkActionBar">
        <!-- Customize your theme here. -->
    </style>

</resources>

H: Numpad / AndroidManifest.xml

To jest plik, który naprawdę czekał na rywalizację. Tutaj poczułem, że nigdy nie skompiluję swojego programu. szloch. szloch. Jeśli zaznaczysz odpowiedź Suracgha, zobaczysz, że pozostawia pierwszy zestaw pól pustych i dodaje znacznik aktywności w tym pliku. Jak powiedziałem, istnieją cztery rodzaje programów na Androida. Aktywność to zwykła aplikacja z ikoną programu uruchamiającego. Ten numpad nie jest zajęciem! Ponadto nie podejmował żadnych działań.

Moi przyjaciele nie dołączają tagu aktywności. Twój program się skompiluje, a przy próbie uruchomienia ulegnie awarii! Jeśli chodzi o xmlns: android i uses-sdk; Nie mogę ci tam pomóc. Po prostu wypróbuj moje ustawienia, jeśli działają.

Jak widać, istnieje tag serwisowy, który rejestruje go jako usługę. Również service.android:name musi być nazwą usługi rozszerzającej klasę publiczną w naszym pliku java. MUSI być odpowiednio wielką literą. Pakiet jest również nazwą pakietu, który zadeklarowaliśmy w pliku java.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="Saragch.num_pad">

    <uses-sdk
        android:minSdkVersion="12"
        android:targetSdkVersion="27" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/Suragch_NumPad_icon"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <service
            android:name=".MyInputMethodService"
            android:label="Keyboard Display Name"
            android:permission="android.permission.BIND_INPUT_METHOD">

            <intent-filter>
                <action android:name="android.view.InputMethod"/>
            </intent-filter>

            <meta-data
                android:name="android.view.im"
                android:resource="@xml/method"/>

        </service>

    </application>
</manifest>

I: NumPad / src / Saragch / num_pad / MyInputMethodService.java

Uwaga: myślę, że java jest alternatywą dla src.

To był kolejny problem, ale nie tak sporny jak plik manifestu. Ponieważ znam Javę na tyle dobrze, że wiem, co jest czym, a co nie. Ledwo znam xml i jak to się wiąże z programowaniem na Androida!

Problem polegał na tym, że niczego nie importował! To znaczy, dał nam „kompletny” plik, który używa nazw, których nie można było rozwiązać! InputMethodService, Keyboard, itp. To zła praktyka, panie Suragch. Dziękuję za pomoc, ale jak spodziewałeś się kompilacji kodu, jeśli nazwy nie mogą zostać rozwiązane?

Poniżej znajduje się poprawnie zredagowana wersja. Po prostu natknąłem się na kilka wskazówek, które doprowadziły mnie we właściwe miejsce, aby dowiedzieć się, co dokładnie zaimportować.

package Saragch.num_pad;

import android.inputmethodservice.InputMethodService;
import android.inputmethodservice.KeyboardView;
import android.inputmethodservice.Keyboard;

import android.text.TextUtils;
import android.view.inputmethod.InputConnection;

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;


public class MyInputMethodService extends InputMethodService implements KeyboardView.OnKeyboardActionListener 
{
    @Override
    public View onCreateInputView() 
    {
     // get the KeyboardView and add our Keyboard layout to it
     KeyboardView keyboardView = (KeyboardView)getLayoutInflater().inflate(R.layout.keyboard_view, null);
     Keyboard keyboard = new Keyboard(this, R.xml.number_pad);
     keyboardView.setKeyboard(keyboard);
     keyboardView.setOnKeyboardActionListener(this);
     return keyboardView;
    }

    @Override
    public void onKey(int primaryCode, int[] keyCodes) 
    {

        InputConnection ic = getCurrentInputConnection();

        if (ic == null) return;

        switch (primaryCode)
        {
         case Keyboard.KEYCODE_DELETE:
            CharSequence selectedText = ic.getSelectedText(0);

            if (TextUtils.isEmpty(selectedText)) 
            {
             // no selection, so delete previous character
             ic.deleteSurroundingText(1, 0);
            }

            else 
            {
             // delete the selection
             ic.commitText("", 1);
            }

            ic.deleteSurroundingText(1, 0);
            break;

         default:
            char code = (char) primaryCode;
            ic.commitText(String.valueOf(code), 1);
        }
    }

    @Override
    public void onPress(int primaryCode) { }

    @Override
    public void onRelease(int primaryCode) { }

    @Override
    public void onText(CharSequence text) { }

    @Override
    public void swipeLeft() { }

    @Override
    public void swipeRight() { }

    @Override
    public void swipeDown() { }

    @Override
    public void swipeUp() { }
}
  1. Skompiluj i podpisz swój projekt.

    W tym miejscu nie mam pojęcia, jako początkujący programista Android. Chciałbym nauczyć się tego ręcznie, ponieważ uważam, że prawdziwi programiści mogą kompilować ręcznie.

Myślę, że gradle jest jednym z narzędzi do kompilowania i pakowania do apk. apk wygląda jak plik jar lub rar dla pliku zip. Istnieją zatem dwa rodzaje podpisów. klucz debugowania, który nie jest dozwolony w sklepie Play i klucz prywatny.

Pomóżmy panu Saragchowi. Dziękuję za obejrzenie mojego filmu. Polub, zasubskrybuj.


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.