11

I'm working on a custom keyboard for Android, and I've run in to an issue where the keyboard seems to leave a white line/space at right, instead of filling the parent view... (don't mind the icons, it's simply placeholder graphic for now)

Screenshot from the simulator

Below you can see my layout...

<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyWidth="14%p"
    android:horizontalGap="0px"
    android:verticalGap="0px"
    android:keyHeight="60dp"
    >
    <Row>
        <Key android:codes="49" android:keyIcon="@drawable/rsz_emoji" android:horizontalGap="1%p" android:keyEdgeFlags="left"/>
        <Key android:codes="50" android:keyIcon="@drawable/rsz_emoji"/>
        <Key android:codes="51" android:keyIcon="@drawable/rsz_emoji"/>
        <Key android:codes="52" android:keyIcon="@drawable/rsz_emoji"/>
        <Key android:codes="53" android:keyIcon="@drawable/rsz_emoji"/>
        <Key android:codes="54" android:keyIcon="@drawable/rsz_emoji"/>
        <Key android:codes="48" android:keyIcon="@drawable/rsz_emoji" android:keyEdgeFlags="right"/>
    </Row>
    <Row>
        <Key android:codes="113" android:keyIcon="@drawable/rsz_emoji" android:horizontalGap="8%p" android:keyEdgeFlags="left"/>
        <Key android:codes="114" android:keyIcon="@drawable/rsz_emoji"/>
        <Key android:codes="116" android:keyIcon="@drawable/rsz_emoji"/>
        <Key android:codes="121" android:keyIcon="@drawable/rsz_emoji"/>
        <Key android:codes="111" android:keyIcon="@drawable/rsz_emoji"/>
        <Key android:codes="112" android:keyIcon="@drawable/rsz_emoji" android:keyEdgeFlags="right"/>
    </Row>
    <Row>
        <Key android:codes="1" android:keyIcon="@drawable/rsz_emoji" android:keyWidth="28%p" android:horizontalGap="8%p" android:keyEdgeFlags="left"/>
        <Key android:codes="46" android:keyIcon="@drawable/rsz_emoji" android:keyWidth="28%p"/>
        <Key android:codes="58" android:keyIcon="@drawable/rsz_emoji" android:keyWidth="28%p" android:keyEdgeFlags="right"/>
    </Row>
    <Row android:rowEdgeFlags="bottom">
        <Key android:codes="44" android:keyIcon="@drawable/globe" android:horizontalGap="8%p" android:keyEdgeFlags="left"/>
        <Key android:codes="47" android:keyIcon="@drawable/rsz_emoji"/>
        <Key android:codes="32" android:keyIcon="@drawable/rsz_emoji" android:keyWidth="28%p"/>
        <Key android:codes="1" android:keyIcon="@drawable/rsz_emoji"/>
        <Key android:codes="-5" android:keyIcon="@drawable/backspace" android:keyEdgeFlags="right"/>
    </Row>
</Keyboard>

As far as I can see, it's a matter of 1%p... But I'm a bit unsure how to fill it without messing up my alignments... E.g. changing the gap in the first row to 2 would fix it, but mess up the alignment.

Added extra code for you as requested...

My class extending InputMethodService:

    private KeyboardView kv;
    private Keyboard keyboard;

    @Override
    public View onCreateInputView() {
        kv = (KeyboardView)getLayoutInflater().inflate(R.layout.keyboard, null);
        keyboard = new Keyboard(this, R.xml.custom_keyboard);
        kv.setPreviewEnabled(false);
        kv.setKeyboard(keyboard);
        kv.setOnKeyboardActionListener(this);
        return kv;
    }

    @Override
    public void onPress(int primaryCode) {

    }

    @Override
    public void onRelease(int primaryCode) {

    }

    @Override
    public void onKey(int primaryCode, int[] keyCodes) {
        InputConnection ic = getCurrentInputConnection();

        if (primaryCode == Keyboard.KEYCODE_DELETE) {
            ic.deleteSurroundingText(1, 0);
        } else {
            Drawable mDrawable = ResourcesCompat.getDrawable(getResources(), R.drawable.rsz_emoji, null);
            Bitmap mBitmap = ((BitmapDrawable)mDrawable).getBitmap();
            String path = MediaStore.Images.Media.insertImage(getContentResolver(), mBitmap, "Emoticon", null);
            Uri fileUri = Uri.parse(path);

            Intent picMessageIntent = new Intent(Intent.ACTION_SEND);
            picMessageIntent.setPackage("com.android.mms");
            picMessageIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
            picMessageIntent.setType("image/png");
            picMessageIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(picMessageIntent);
        }
    }

    @Override
    public void onText(CharSequence text) {

    }

    @Override
    public void swipeLeft() {

    }

    @Override
    public void swipeRight() {

    }

    @Override
    public void swipeDown() {

    }

    @Override
    public void swipeUp() {

    }

My Keyboard.xml

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

Styles.xml

<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>
</resources>

Manifest:

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

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!-- Declares the input method service -->
        <service android:name=".CENSORED"
            android:label="@string/keyboard_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>

    <uses-permission android:name="android.permission.INTERNET" />
</manifest>
user969043
  • 756
  • 2
  • 13
  • 34

7 Answers7

7

I cannot reproduce the error, I have provided a screenshot, with a light background app and all my relevant code. I am not sure exactly where you are going wrong without seeing the whole project and directories, so I've posted the relevant xml. There is a service class also, I haven't included (as you obviously have it working).

The <Keyboard> code is in a file called qwerty.xml in the resources/xml folder, with a file called method.xml:

I used all your keyboard dimensions in the qwerty.xml, except I replaced the image.

method.xml

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

Two layout files:

keyboard.xml

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

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:background="#ffff00"
    android:gravity="center"
    android:textSize="30sp
    android:textStyle="bold">
</TextView>

Styles:

<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>
</resources>

In the manifest, within application:

<service
    android:name=".SimpleIME"
    android:label="@string/simple_ime"
    android:permission="android.permission.BIND_INPUT_METHOD"
    >
    <meta-data
        android:name="android.view.im"
        android:resource="@xml/method"/>
    <intent-filter>
        <action android:name="android.view.InputMethod"/>
    </intent-filter>
</service>

I've left the image so large so you can clearly see there is no gap. enter image description here

This link here also steps through this code:

http://code.tutsplus.com/tutorials/create-a-custom-keyboard-on-android--cms-22615

edit 1

After discussion in the comments, I would suggest checking your background style as there are issues/changes with the default background color may be showing for the keyboard window. This is addressed in detail issue in this answer https://stackoverflow.com/a/33052648/3956566. I won't reiterate the details, as the link is unlikely to rot, being an upvoted SO post.

edit 2

Ok Adding the difference in the input method service:

@Override
public void onKey(int primaryCode, int[] keyCodes) {
    InputConnection ic = getCurrentInputConnection();

    switch(primaryCode){
        case Keyboard.KEYCODE_DELETE :
            ic.deleteSurroundingText(1, 0);
            break;
        case Keyboard.KEYCODE_SHIFT:
            caps = !caps;
            keyboard.setShifted(caps);
            kv.invalidateAllKeys();
            break;
        case Keyboard.KEYCODE_DONE:
            ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
            break;
        default:
            char code = (char)primaryCode;
            if(Character.isLetter(code) && caps){
                code = Character.toUpperCase(code);
            }
            ic.commitText(String.valueOf(code),1);
    }
}

edit 3

Create a blank project, no activity for your keyboard, to test and run it as a separate app. You are using android:theme="@style/AppTheme.NoActionBar" In your launcher activity and there may be an issue with background opacity and your windows/views.

Community
  • 1
  • 1
  • I actually followed the tutorial you posted a link to when doing the keyboard, but my keyboard and method.xml's are the same as yours, except I don't use a preview for my keyboard... So I'm thinking the error somehow is in the Keyboard layout xml file, that I posted in my question... I'm not sure, why you can't reproduce is, as the tutorial is the exact one I followed and my only difference is my layout... For now, I've solved it by changing the button sizes a bit, but it's not really how I wanted to solve it... – user969043 Nov 18 '15 at 12:28
  • I'll take a look at the theme thing you're talking about... Seems like that could be the issue – user969043 Nov 18 '15 at 18:06
  • Yeah, it did seem to be a theme issue – user969043 Nov 24 '15 at 09:40
  • 1
    Nice answer . Happy coding – IntelliJ Amiya Nov 24 '15 at 10:08
3

In you case: 7 (keys) x 14% = 98% + 1% gap (firstkeyś horizontalGap) = 99%.

Put the '%1' in horizontalGap in last key as you did in first key.

<Row>
        <Key android:codes="49" 
             android:keyIcon="@drawable/rsz_emoji" 
             android:horizontalGap="1%p" 
             android:keyEdgeFlags="left"/>
        <Key android:codes="50" android:keyIcon="@drawable/rsz_emoji"/>
        <Key android:codes="51" android:keyIcon="@drawable/rsz_emoji"/>
        <Key android:codes="52" android:keyIcon="@drawable/rsz_emoji"/>
        <Key android:codes="53" android:keyIcon="@drawable/rsz_emoji"/>
        <Key android:codes="54" android:keyIcon="@drawable/rsz_emoji"/>
        <Key android:codes="48" 
             android:keyIcon="@drawable/rsz_emoji" 
             android:horizontalGap="1%p"
             android:keyEdgeFlags="right"/>
</Row>
Christian
  • 7,062
  • 9
  • 53
  • 79
  • Yes, but a gap to the left of the last key will ruin the ui... as the gap is supposed to be on the right... this will add an ugly space between the 2nd last and the last button on the first line... – user969043 Nov 18 '15 at 09:58
  • I don't get it... this is why keyEdgeFlags suposed to be set to right... The gap should be placed to right (not to left) from last key... So, then try removing `android:keyEdgeFlags="right"` from the last key and set `android:horizontalGap="1%p"` as mentioned and see what happens. – Christian Nov 18 '15 at 11:16
  • @MrsEd: according to docs: **Default horizontal gap between keys**. So, I think it is. – Christian Nov 18 '15 at 16:06
  • OK. But why do you think is not correctly using it twice? – Christian Nov 18 '15 at 23:28
2

Have you tried adding this to the keyboard tag in your xml file?

android:layout_height="fill_parent"
android:layout_width="fill_parent"
Andreas Louv
  • 46,145
  • 13
  • 104
  • 123
sayan
  • 1,520
  • 17
  • 33
1

add a row with 100 percent width and zero heigh before first row. like this. add this code before first row

<Row android:horizontalGap="0%p" android:keyHeight="0.01%p">
        <Key android:codes="32" android:keyLabel=""
            android:keyWidth="100%p"
            />

    </Row>
Masoud
  • 535
  • 3
  • 19
0

I had this problem too. I never found a good solution.

Android's Keyboard layout API sucks. If I were doing this all over again I would not have used it and instead created my own UI from scratch interfacing with InputMethod directly.

In any case, my solution was to add an extra key at the bottom of the layout with a 100% width and only 1dp height.

The button does absolutely nothing and the height is so small the user doesn't see it. But the width of the key fixes the gap issue.

Micho
  • 3,929
  • 13
  • 37
  • 40
trans
  • 1,411
  • 1
  • 13
  • 13
0

If the keyboardview is in a layout, make sure the padding parameters are set to 0dp.

Fred
  • 51
  • 5
0

In your keys some problems of keywidth and horizontal gape. First thing first you have 100%p widht. Secondly give each key width according to 100%p. Fill 100%p your keys will never show gape. Now make sure horizontalgap should be keyboard tag not in keys. Just remember 100%p width I am sharing numbers keys

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
app:horizontalGap="1.7%p"
app:keyHeight="@dimen/key_height"
app:keyWidth="10%p"
app:verticalGap="1.7%p">

    <Row  app:rowEdgeFlags="top"
        app:keyHeight="@dimen/key_for_digit">
        <Key app:codes="49" app:keyLabel="1" app:keyWidth="8%p" 
        app:keyEdgeFlags="left"/>
        <Key app:codes="50" app:keyLabel="2" app:keyWidth="8%p"  />
        <Key app:codes="51" app:keyLabel="3" app:keyWidth="8%p"  />
        <Key app:codes="52" app:keyLabel="4" app:keyWidth="8%p"  />
        <Key app:codes="53" app:keyLabel="5" app:keyWidth="8%p"  />
        <Key app:codes="54" app:keyLabel="6" app:keyWidth="8%p"  />
        <Key app:codes="55" app:keyLabel="7" app:keyWidth="8%p"  />
        <Key app:codes="56" app:keyLabel="8" app:keyWidth="8%p"  />
        <Key app:codes="57" app:keyLabel="9" app:keyWidth="8%p"  />
        <Key app:codes="48" app:keyLabel="0" app:keyWidth="8%p"  app:keyEdgeFlags="right"/>
    </Row>
<Row >
    <Key
        app:codes="113"
        app:keyEdgeFlags="left"
        app:keyLabel="q"
        app:keyWidth="8%p"
        app:popupCharacters="1"
        app:popupKeyboard="@xml/keyboard_popup" />
    <Key
        app:codes="119"
        app:keyLabel="w"
        app:keyWidth="8%p"
        app:popupCharacters="2"
        app:popupKeyboard="@xml/keyboard_popup"
        />
    <Key
        app:codes="101"
        app:keyLabel="e"
        app:keyWidth="8%p"
        app:popupCharacters="3"
        app:popupKeyboard="@xml/keyboard_popup"
        />
    <Key
        app:codes="114"
        app:keyLabel="r"
        app:keyWidth="8%p"
        app:popupCharacters="4"
        app:popupKeyboard="@xml/keyboard_popup"
        />
    <Key
        app:codes="116"
        app:keyLabel="t"
        app:keyWidth="8%p"
        app:popupCharacters="5"
        app:popupKeyboard="@xml/keyboard_popup"
        />
    <Key
        app:codes="121"
        app:keyLabel="y"
        app:keyWidth="8%p"
        app:popupCharacters="6"
        app:popupKeyboard="@xml/keyboard_popup"
        />
    <Key
        app:codes="117"
        app:keyLabel="u"
        app:keyWidth="8%p"
        app:popupCharacters="7"
        app:popupKeyboard="@xml/keyboard_popup"
        />
    <Key
        app:codes="105"
        app:keyLabel="i"
        app:keyWidth="8%p"
        app:popupCharacters="8" />
    <Key
        app:codes="111"
        app:keyLabel="o"
        app:keyWidth="8%p"
        app:popupCharacters="9" />
    <Key
        app:codes="112"
        app:keyEdgeFlags="right"
        app:keyLabel="p"
        app:keyWidth="8%p"
        app:popupCharacters="0" />
</Row>
Adil Khan
  • 1
  • 1
  • 2