輸入法修改記錄 ui修改 主題

android studio 運行LatinIME工程

網上找了篇 https://www.jianshu.com/p/5278addbf99c

  1. 從android源碼裏copy下這個app需要的部分代碼
    路徑:源碼目錄/frameworks/opt/inputmethodcommon/java/com/android/inputmethodcommon
    把上邊的java下的目錄copy到LatinIME的java下的src目錄裏

  2. LatinIME目錄下新建build.gradle文件,如下

buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:4.2.1"

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28

    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 28
        versionCode 1
        versionName = "1.0"
        
        externalNativeBuild {
            cmake {
                cppFlags "-std=c++11"
            }
        }
    }
    sourceSets {
        main {
            manifest.srcFile 'java/AndroidManifest.xml'
            java.srcDirs = ['java/src', 'java-overridable/src', 'common/src', 'inputmethodcommon/java']
            res.srcDirs = ['java/res']
        }
    }
    externalNativeBuild {
        cmake {
            path 'native/CMakeLists.txt'
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    lintOptions {
        htmlReport false
        abortOnError false
        disable 'MissingTranslation'
        disable 'ExtraTranslation'
    }
}

dependencies {
    implementation 'com.android.support:appcompat-v7:28.0.0'
    
    implementation "com.google.code.findbugs:jsr305:3.0.1"
}

gradle的版本可以改成自己本地有的,就不用下載了,如果提示gradle版本不匹配啥的,可以自己copy下對應的gradle文件夾到工程目錄下,如下圖紅框


  1. 在源碼的native目錄下新建 CMakeLists.txt文件,加入cmake的配置

cmake_minimum_required(VERSION 3.4.1)

# 二進制碼剝除
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s")

add_library(jni_latinime SHARED
            jni/com_android_inputmethod_keyboard_ProximityInfo.cpp
            jni/com_android_inputmethod_latin_BinaryDictionary.cpp
            jni/com_android_inputmethod_latin_BinaryDictionaryUtils.cpp
            jni/com_android_inputmethod_latin_DicTraverseSession.cpp
            jni/jni_common.cpp
            jni/src/dictionary/header/header_policy.cpp
            jni/src/dictionary/header/header_read_write_utils.cpp
            jni/src/dictionary/property/ngram_context.cpp
            jni/src/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp
            jni/src/dictionary/structure/backward/v402/ver4_dict_buffers.cpp
            jni/src/dictionary/structure/backward/v402/ver4_dict_constants.cpp
            jni/src/dictionary/structure/backward/v402/ver4_patricia_trie_node_reader.cpp
            jni/src/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.cpp
            jni/src/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp
            jni/src/dictionary/structure/backward/v402/ver4_patricia_trie_reading_utils.cpp
            jni/src/dictionary/structure/backward/v402/ver4_patricia_trie_writing_helper.cpp
            jni/src/dictionary/structure/backward/v402/ver4_pt_node_array_reader.cpp
            jni/src/dictionary/structure/backward/v402/bigram/ver4_bigram_list_policy.cpp
            jni/src/dictionary/structure/backward/v402/content/bigram_dict_content.cpp
            jni/src/dictionary/structure/backward/v402/content/probability_dict_content.cpp
            jni/src/dictionary/structure/backward/v402/content/shortcut_dict_content.cpp
            jni/src/dictionary/structure/backward/v402/content/sparse_table_dict_content.cpp
            jni/src/dictionary/structure/backward/v402/content/terminal_position_lookup_table.cpp
            jni/src/dictionary/structure/pt_common/dynamic_pt_gc_event_listeners.cpp
            jni/src/dictionary/structure/pt_common/dynamic_pt_reading_helper.cpp
            jni/src/dictionary/structure/pt_common/dynamic_pt_reading_utils.cpp
            jni/src/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp
            jni/src/dictionary/structure/pt_common/dynamic_pt_writing_utils.cpp
            jni/src/dictionary/structure/pt_common/patricia_trie_reading_utils.cpp
            jni/src/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.cpp
            jni/src/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.cpp
            jni/src/dictionary/structure/v2/patricia_trie_policy.cpp
            jni/src/dictionary/structure/v2/ver2_patricia_trie_node_reader.cpp
            jni/src/dictionary/structure/v2/ver2_pt_node_array_reader.cpp
            jni/src/dictionary/structure/v4/ver4_dict_buffers.cpp
            jni/src/dictionary/structure/v4/ver4_dict_constants.cpp
            jni/src/dictionary/structure/v4/ver4_patricia_trie_node_reader.cpp
            jni/src/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp
            jni/src/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
            jni/src/dictionary/structure/v4/ver4_patricia_trie_reading_utils.cpp
            jni/src/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp
            jni/src/dictionary/structure/v4/ver4_pt_node_array_reader.cpp
            jni/src/dictionary/structure/v4/content/dynamic_language_model_probability_utils.cpp
            jni/src/dictionary/structure/v4/content/language_model_dict_content.cpp
            jni/src/dictionary/structure/v4/content/language_model_dict_content_global_counters.cpp
            jni/src/dictionary/structure/v4/content/shortcut_dict_content.cpp
            jni/src/dictionary/structure/v4/content/sparse_table_dict_content.cpp
            jni/src/dictionary/structure/v4/content/terminal_position_lookup_table.cpp
            jni/src/dictionary/utils/buffer_with_extendable_buffer.cpp
            jni/src/dictionary/utils/byte_array_utils.cpp
            jni/src/dictionary/utils/dict_file_writing_utils.cpp
            jni/src/dictionary/utils/file_utils.cpp
            jni/src/dictionary/utils/forgetting_curve_utils.cpp
            jni/src/dictionary/utils/format_utils.cpp
            jni/src/dictionary/utils/mmapped_buffer.cpp
            jni/src/dictionary/utils/multi_bigram_map.cpp
            jni/src/dictionary/utils/probability_utils.cpp
            jni/src/dictionary/utils/sparse_table.cpp
            jni/src/dictionary/utils/trie_map.cpp
            jni/src/suggest/core/suggest.cpp
            jni/src/suggest/core/dicnode/dic_node.cpp
            jni/src/suggest/core/dicnode/dic_node_utils.cpp
            jni/src/suggest/core/dicnode/dic_nodes_cache.cpp
            jni/src/suggest/core/dictionary/dictionary.cpp
            jni/src/suggest/core/dictionary/dictionary_utils.cpp
            jni/src/suggest/core/dictionary/digraph_utils.cpp
            jni/src/suggest/core/dictionary/error_type_utils.cpp
            jni/src/suggest/core/layout/additional_proximity_chars.cpp
            jni/src/suggest/core/layout/proximity_info.cpp
            jni/src/suggest/core/layout/proximity_info_params.cpp
            jni/src/suggest/core/layout/proximity_info_state.cpp
            jni/src/suggest/core/layout/proximity_info_state_utils.cpp
            jni/src/suggest/core/policy/weighting.cpp
            jni/src/suggest/core/result/suggestion_results.cpp
            jni/src/suggest/core/result/suggestions_output_utils.cpp
            jni/src/suggest/core/session/dic_traverse_session.cpp
            jni/src/suggest/policyimpl/gesture/gesture_suggest_policy_factory.cpp
            jni/src/suggest/policyimpl/typing/scoring_params.cpp
            jni/src/suggest/policyimpl/typing/typing_scoring.cpp
            jni/src/suggest/policyimpl/typing/typing_suggest_policy.cpp
            jni/src/suggest/policyimpl/typing/typing_traversal.cpp
            jni/src/suggest/policyimpl/typing/typing_weighting.cpp
            jni/src/utils/autocorrection_threshold_utils.cpp
            jni/src/utils/char_utils.cpp
            jni/src/utils/jni_data_utils.cpp
            jni/src/utils/log_utils.cpp
            jni/src/utils/time_keeper.cpp)

include_directories(jni/src/)

target_link_libraries(jni_latinime
                      android
                      log
                      z)

ok,這時候工程應該可以正常運行了。對了,就像帖子裏說的,你的studio需要下載配置好ndk

ui修改

目前只考慮英文的,我這裏測試的是平板,所以只修改了xml-sw600dp 這個文件夾下相關的資源文件,如果是給手機用的,那修改默認的xml下的文件即可

  1. 默認的英文字母界面 rows_kwerty.xml
    總共有4個Row也就是4行,最後一行通過include引用了另外一個通用的文件 row_kwerty4.xml
    比如想刪除一個key,添加一個key都可以,不過需要注意按鍵的總寬度不能大於100,否則有的按鈕就不顯示了

我這裏是把刪除按鍵和action按鍵放到最後兩行了


默認界面左下角點擊那個123的按鍵,會跳到 數字符號界面

  1. 數字符號界面 rows_symbols.xml

在這個界面點擊第三行第一個按鈕,切換到更多符號界面

  1. 對應的就是rows_symbols_shift.xml
    如下最後兩行的代碼,
        <Key
            latin:keySpec="&#x00BF;" />
        <Key //替換原來和左側一樣的鍵爲刪除鍵
            latin:keyStyle="deleteKeyStyle"
            latin:keyWidth="fillRight" />
    </Row>
    <Row
        latin:keyWidth="9.0%p"
        latin:backgroundType="functional"
    >
        <Key
            latin:keyStyle="toAlphaKeyStyle"
            latin:keyWidth="10%p" />
        <include
            latin:keyboardLayout="@xml/row_symbols_shift4" />
<!--        <include-->
<!--            latin:keyboardLayout="@xml/key_emoji" />-->
        <Key  //新加的
            latin:keyStyle="enterKeyStyle"
            latin:keyWidth="fillRight" />
    </Row>

佈局修改

這裏只測試英文的,rows_qwerty.xml
table上測試,用的是default屬性
修改keyWidth爲10%p ,這裏的百分比是除去key之間的間隔的,10個key平分,所以就是10%

    <Row>
        <switch>
            <!-- Split keyboard layout for the first row -->
            <case
                latin:isSplitLayout="true"
            >
//...
            <default>
                <include
                    latin:keyboardLayout="@xml/rowkeys_qwerty1"
                    latin:keyWidth="10%p" />
<!--                <Key-->
<!--                    latin:keyStyle="deleteKeyStyle"-->
<!--                    latin:keyWidth="fillRight" />-->
            </default>
        </switch>
    </Row>

第二行,這個和我想的效果差距太大,我這百分比是加上間隔算的,現在發現不對

                <include
                    latin:keyboardLayout="@xml/rowkeys_qwerty2"
                    latin:keyXPos="6.275%p"
                    latin:keyWidth="8.57%p" />

測試結果發現這裏的百分比是出去間隔的,所以上邊第二行修改如下
9個字母佔90%,每個10%,剩下兩邊各5%,也就是默認起始x偏移5%,效果如下

                <include
                    latin:keyboardLayout="@xml/rowkeys_qwerty2"
                    latin:keyXPos="5%p"
                    latin:keyWidth="10%p" />

rows_qwerty.xml 修改字母界面沒啥問題,
修改數字界面,應該是rows_symbols.xm,l結果發現改完沒變化,那就是改錯了。

我測試的是橫屏板子輸入法,所以最先找的是 xml-sw600dp-land 沒找到,我就去xml下去找了,
現在想起來還有個xml-sw600dp文件夾,land下沒有應該先找這個的。這次修改完就生效了,如下


數字界面切換符號界面
rows_symboles_shift.xml
簡單修改完成,目前只是把key的位置修改完了。


接下來找下咋修改按鈕背景圖,最後再修改鍵盤高度

鍵盤高度修改

我們的需求是鍵盤高度增大了,所以根據下邊的邏輯,我就修改了下最小高度,最後使用的就是這個值了。
在config.xml 下看到這個名字,需要注意下,你要適配的大小,找對應的,這個文件有很多個,找對應的修改

    <dimen name="config_default_keyboard_height">365.4dp</dimen>
    <fraction name="config_min_keyboard_height">55%p</fraction>

搜下哪裏用到了ResourceUtils.java

    public static int getDefaultKeyboardHeight(final Resources res) {
        final DisplayMetrics dm = res.getDisplayMetrics();
        final String keyboardHeightInDp = getDeviceOverrideValue(
                res, R.array.keyboard_heights, null /* defaultValue */);
        final float keyboardHeight;
        if (TextUtils.isEmpty(keyboardHeightInDp)) {//目前數組是空的,所以會走這裏了
            keyboardHeight = res.getDimension(R.dimen.config_default_keyboard_height);
        } else {
            keyboardHeight = Float.parseFloat(keyboardHeightInDp) * dm.density;
        }
        final float maxKeyboardHeight = res.getFraction(//最大高度
                R.fraction.config_max_keyboard_height, dm.heightPixels, dm.heightPixels);
        float minKeyboardHeight = res.getFraction(//最小高度
                R.fraction.config_min_keyboard_height, dm.heightPixels, dm.heightPixels);
        if (minKeyboardHeight < 0.0f) {//如果是負的,弄成正的
            // Specified fraction was negative, so it should be calculated against display
            // width.
            minKeyboardHeight = -res.getFraction(
                    R.fraction.config_min_keyboard_height, dm.widthPixels, dm.widthPixels);
        }
        // Keyboard height will not exceed maxKeyboardHeight and will not be less than
        // minKeyboardHeight. 首先固定高度和最大高度取最小值,然後再和最小高度比較取最大值,所以我們修改下最小高度就行了.
        return (int)Math.max(Math.min(keyboardHeight, maxKeyboardHeight), minKeyboardHeight);
    }

主題

我用的8.0的源碼,這個有提供4種主題,如下


修改的時候要找到對應的主題修改,別修改錯了地方,源碼裏主題都在這了

看到light和dark,那麼
themes-lxx-dark 對應的 Material Dark
themes-lxx-light 對應的 Material Light
themes-lxx 是上邊兩個通用的部分
themes-klp 是 Holo White
themes-ics 是Holo Blue(區分很簡單,這裏的顏色有藍色的)
themes-holo 是上邊兩個通用的
themes-common 是所有主題通用的部分
目前我以holo white 爲默認的做修改,其他幾種先不管

    <style
        name="KeyboardView.KLP"
        parent="KeyboardView.Holo"
    >
        <item name="android:background">#F2F2F2</item>//鍵盤背景,不包括上邊提示那部分
        <item name="keyBackground">@drawable/btn_keyboard_key_klp_test</item>//默認按鍵的背景,就是那些字母數字
        <item name="functionalKeyBackground">@drawable/btn_keyboard_key_klp_test</item>//功能性的按鍵,xml裏的Key有聲明的
        <item name="spacebarBackground">@drawable/btn_keyboard_key_klp_test</item>//空格鍵的背景
        <item name="keyTextColor">@color/key_text_color_holo</item>// key上字母的顏色
        <item name="keyTextInactivatedColor">@color/key_text_inactivated_color_holo</item>
        <item name="functionalTextColor">@color/key_text_color_holo</item>//功能性按鍵上的文字顏色
        <item name="keyHintLetterColor">@color/key_hint_letter_color_holo</item>//第一行字母右上角那數字的顏色
        <item name="keyHintLabelColor">@color/key_hint_label_color_holo</item>//最後一行按鈕右下角三個點的顏色
        <item name="keyShiftedLetterHintInactivatedColor">@color/key_shifted_letter_hint_inactivated_color_holo</item>
        <item name="keyShiftedLetterHintActivatedColor">@color/key_shifted_letter_hint_activated_color_holo</item>
        <item name="keyPreviewTextColor">@color/key_text_color_holo</item>
    </style>

按鍵的背景系統默認的有3種, 普通按鈕,功能性的按鍵,空格鍵
根據需求我們把這三種顏色修改成我們要的.然後還得增加一種深色的,如下圖。


默認最地下一行除了空格都是functional背景的,如果不需要,可以修改下latin:backgroundType即可

    <Key
        latin:backgroundType="normal"
        latin:keySpec="/" />

查看attrs.xml 下定義的 latin:backgroundType="functional"

<declare-styleable name="Keyboard_Key">
        <attr name="backgroundType" format="enum">
            <!-- This should be aligned with
                 {@link com.android.inputmethod.keyboard.Key#BACKGROUND_TYPE_NORMAL} etc. -->
            <enum name="empty" value="0" />
            <enum name="normal" value="1" />
            <enum name="functional" value="2" />
            <enum name="stickyOff" value="3" />
            <enum name="stickyOn" value="4" />
            <enum name="action" value="5" />
            <enum name="spacebar" value="6" />
        </attr>

// 系統默認就定義了三種background,我們在下邊加一種新的

 <declare-styleable name="KeyboardView">
        <!-- Background image for the key. This image needs to be a
            {@link android.graphics.drawable.StateListDrawable}, with the following possible states:
             normal, pressed, checkable, checkable+pressed, checkable+checked,
             checkable+checked+pressed. -->
        <attr name="keyBackground" format="reference" />
        <!-- Background image for the functional key. This image needs to be a
             {@link android.graphics.drawable.StateListDrawable}, with the following possible
             states: normal, pressed. -->
        <attr name="functionalKeyBackground" format="reference" />
        <!-- Background image for the spacebar.  This image needs to be a
             {@link android.graphics.drawable.StateListDrawable}, with the following possible
             states: normal, pressed. -->
        <attr name="spacebarBackground" format="reference" />

先看下背景哪裏用到了
Key.java
可以看到,就分了3種情況,

    public final Drawable selectBackgroundDrawable(@Nonnull final Drawable keyBackground,
            @Nonnull final Drawable functionalKeyBackground,
            @Nonnull final Drawable spacebarBackground) {
        final Drawable background;
        if (mBackgroundType == BACKGROUND_TYPE_FUNCTIONAL) {
            background = functionalKeyBackground;
        } else if (mBackgroundType == BACKGROUND_TYPE_SPACEBAR) {
            background = spacebarBackground;
        } else {
            background = keyBackground;
        }
        final int[] state = KeyBackgroundState.STATES[mBackgroundType].getState(mPressed);
        background.setState(state);
        return background;
    }

圖片是在KeyboardView.java 里加載的,所以需要去主題裏設置

    public KeyboardView(final Context context, final AttributeSet attrs, final int defStyle) {
        super(context, attrs, defStyle);

        final TypedArray keyboardViewAttr = context.obtainStyledAttributes(attrs,
                R.styleable.KeyboardView, defStyle, R.style.KeyboardView);
        mKeyBackground = keyboardViewAttr.getDrawable(R.styleable.KeyboardView_keyBackground);
        mKeyBackground.getPadding(mKeyBackgroundPadding);
        final Drawable functionalKeyBackground = keyboardViewAttr.getDrawable(
                R.styleable.KeyboardView_functionalKeyBackground);
        mFunctionalKeyBackground = (functionalKeyBackground != null) ? functionalKeyBackground
                : mKeyBackground;
        final Drawable spacebarBackground = keyboardViewAttr.getDrawable(
                R.styleable.KeyboardView_spacebarBackground);
        mSpacebarBackground = (spacebarBackground != null) ? spacebarBackground : mKeyBackground;

現在假設增加了一種attrs.xml下添加

<declare-styleable name="KeyboardView">
<attr name="functionalKeyBackground2" format="reference" /> //for dark blue action key

theme裏添加
多個主題的話就都加,或者加載默認的主題下邊,我這裏就只處理一種主題

        <item name="functionalKeyBackground">@drawable/btn_keyboard_key_functional_klp</item>
        <item name="functionalKeyBackground2">@drawable/btn_keyboard_key_functional_klp2</item>

KeyboardView裏獲取圖片

        // newly added
        final Drawable functionalKeyBackground2 = keyboardViewAttr.getDrawable(
                R.styleable.KeyboardView_functionalKeyBackground2);
        mFunctionalKeyBackground2 = (functionalKeyBackground2 != null) ? functionalKeyBackground2
                : mKeyBackground;

那麼哪裏用這圖片了?先給Key增加一種類型

        <attr name="backgroundType" format="enum">
            <!-- This should be aligned with
                 {@link com.android.inputmethod.keyboard.Key#BACKGROUND_TYPE_NORMAL} etc. -->
            <enum name="empty" value="0" />
            <enum name="normal" value="1" />
            <enum name="functional" value="2" />
            <enum name="stickyOff" value="3" />
            <enum name="stickyOn" value="4" />
            <enum name="action" value="5" />
            <enum name="spacebar" value="6" />
<enum name="functional2" value="7" />
        </attr>

然後修改下Key的latin:backgroundType屬性

                <Key
                    latin:backgroundType="functional2"
                    latin:keyStyle="enterKeyStyle"
                    latin:keyWidth="fillRight" />

好了,在key.java裏處理下
如下,下個方法增加一個參數,從KeyboardView裏傳過來的, 多加個if條件

//
    public static final int BACKGROUND_TYPE_FUNCTIONAL2 = 7;
//
        case BACKGROUND_TYPE_SPACEBAR: return "spacebar";
        case BACKGROUND_TYPE_FUNCTIONAL2:return "functional2";

public final Drawable selectBackgroundDrawable(@Nonnull final Drawable keyBackground,
            @Nonnull final Drawable functionalKeyBackground,
            @Nonnull final Drawable spacebarBackground,@Nonnull final Drawable functionalKeyBackground2) {
        final Drawable background;
        if (mBackgroundType == BACKGROUND_TYPE_FUNCTIONAL) {
            background = functionalKeyBackground;
        }else if(mBackgroundType == BACKGROUND_TYPE_FUNCTIONAL2){
            background = functionalKeyBackground2;
        }else if (mBackgroundType == BACKGROUND_TYPE_SPACEBAR) {
            background = spacebarBackground;
        } else {
            background = keyBackground;
        }
        final int[] state = KeyBackgroundState.STATES[mBackgroundType].getState(mPressed);
        background.setState(state);
        return background;
    }

想着ok了,運行了下掛了,下邊這行掛了,數組越界,
java.lang.ArrayIndexOutOfBoundsException: length=7; index=7

final int[] state = KeyBackgroundState.STATES[mBackgroundType].getState(mPressed);

點進去一看,果然,這個忘了處理了,如下,最後位置添加一個新的

        public static final KeyBackgroundState[] STATES = {
            // 0: BACKGROUND_TYPE_EMPTY
            new KeyBackgroundState(android.R.attr.state_empty),
            // 1: BACKGROUND_TYPE_NORMAL
            new KeyBackgroundState(),
            // 2: BACKGROUND_TYPE_FUNCTIONAL
            new KeyBackgroundState(),
            // 3: BACKGROUND_TYPE_STICKY_OFF
            new KeyBackgroundState(android.R.attr.state_checkable),
            // 4: BACKGROUND_TYPE_STICKY_ON
            new KeyBackgroundState(android.R.attr.state_checkable, android.R.attr.state_checked),
            // 5: BACKGROUND_TYPE_ACTION
            new KeyBackgroundState(android.R.attr.state_active),
            // 6: BACKGROUND_TYPE_SPACEBAR
            new KeyBackgroundState(),
                // 7: BACKGROUND_TYPE_FUNCTIONAL2
                new KeyBackgroundState(),
        };

這次就ok拉

刪除頂部的提示view

@layout/main_keyboard_frame
在這個佈局裏,我以爲把提示的view設置爲gone就完事了,結果沒效果。然後搜了下這個控件用到的地方,發現java代碼裏有控制它的可見性

    <com.android.inputmethod.latin.suggestions.SuggestionStripView
        android:id="@+id/suggestion_strip_view"
        android:layoutDirection="ltr"
        android:layout_width="match_parent"
        android:layout_height="@dimen/config_suggestions_strip_height"
        android:visibility="gone"
        android:gravity="center_vertical"
        style="?attr/suggestionStripViewStyle" />

LatinIME.java裏有

        final boolean shouldShowImportantNotice =
                ImportantNoticeUtils.shouldShowImportantNotice(this, currentSettingsValues);
        final boolean shouldShowSuggestionCandidates =
                currentSettingsValues.mInputAttributes.mShouldShowSuggestions
                && currentSettingsValues.isSuggestionsEnabledPerUserSettings();
        final boolean shouldShowSuggestionsStripUnlessPassword = shouldShowImportantNotice
                || currentSettingsValues.mShowsVoiceInputKey
                || shouldShowSuggestionCandidates
                || currentSettingsValues.isApplicationSpecifiedCompletionsOn();
        final boolean shouldShowSuggestionsStrip = shouldShowSuggestionsStripUnlessPassword
                && !currentSettingsValues.mInputAttributes.mIsPasswordField;
        mSuggestionStripView.updateVisibility(shouldShowSuggestionsStrip, isFullscreenMode());

//go on

    public void updateVisibility(final boolean shouldBeVisible, final boolean isFullscreenMode) {
        final int visibility = shouldBeVisible ? VISIBLE : (isFullscreenMode ? GONE : INVISIBLE);
        setVisibility(visibility);
        final SettingsValues currentSettingsValues = Settings.getInstance().getCurrent();
        //mVoiceKey.setVisibility(currentSettingsValues.mShowsVoiceInputKey ? VISIBLE : INVISIBLE);
        mVoiceKey.setVisibility(View.GONE);
    }

主要就是setting裏有個設置是否提示【第一個參數】,以及當前是否全屏【第二個參數】
我們不需要顯示這個佈局,那麼上邊代碼直接改成如下即可

mSuggestionStripView.updateVisibility(false,true);

如果需要修改顏色啥的,那去主題裏修改下,應該是以suggestion開頭的一些屬性

    <style
        name="SuggestionWord.KLP"
        parent="SuggestionWord"
    >
        <item name="android:background">@drawable/btn_suggestion_klp</item>
        <item name="android:textColor">@color/highlight_color_klp</item>
    </style>

長按有彈框的,處理下彈框顏色

    <style
        name="MoreKeysKeyboardView.KLP"
        parent="KeyboardView.KLP"
    >
        <item name="android:background">#F2F2F2</item>//彈框整體背景
        <item name="keyBackground">@drawable/btn_keyboard_key_popup_klp</item>//每個key的背景
        <item name="divider">@drawable/more_keys_divider</item>//
        <item name="keyTypeface">normal</item>
        <item name="verticalCorrection">@dimen/config_more_keys_keyboard_vertical_correction_holo</item>
    </style>

字體style修改

默認是bold,改下

        <item name="keyTypeface">normal</item>

折騰到現在長這樣,現在問題就是圖標看起來有點小


圖標大小如何修改

先來回顧下之前研究的,這些Key的內容咋定義的

  1. 普通的字母
    第一種是第一行那種長按可以選擇數字的,第二種是第二行那普通的字母
    <Key
        latin:keySpec="!text/keyspec_q"
        latin:keyHintLabel="1"
        latin:additionalMoreKeys="1"
        latin:moreKeys="!text/morekeys_q" />

    <Key
        latin:keySpec="k" />
  1. 功能按鍵
    這些一般都是簡單寫個KeyStyle,具體的屬性在 <include latin:keyboardLayout="@xml/key_styles_common" />
                <Key
                    latin:keyStyle="deleteKeyStyle"
                    latin:keyWidth="fillRight" />
//key_styles_common 裏找到styleName一樣的
    <key-style
        latin:styleName="deleteKeyStyle"
        latin:keySpec="!icon/delete_key|!code/key_delete"
        latin:keyActionFlags="isRepeatable|noKeyPreview"
        latin:backgroundType="functional" />

有的還帶有parent屬性的

            <key-style
                latin:styleName="shiftKeyStyle"
                latin:keySpec="!icon/shift_key|!code/key_shift"
                latin:backgroundType="stickyOff"
                latin:parentStyle="baseForShiftKeyStyle" />

    <key-style
        latin:styleName="baseForShiftKeyStyle"
        latin:keyActionFlags="noKeyPreview"
        latin:keyLabelFlags="preserveCase"
        latin:moreKeys="!noPanelAutoMoreKey!, |!code/key_capslock" />

其實可以看到key的內容是定義在keySpec裏的
目前有以下幾種

!icon/shift_key|!code/key_shift
!text/keyspec_q

去Key.java裏看下咋解析這些值的

 final String keySpec = keyStyle.getString(keyAttr, R.styleable.Keyboard_Key_keySpec);

 public Key(@Nullable final String keySpec, @Nonnull final TypedArray keyAttr,
            @Nonnull final KeyStyle style, @Nonnull final KeyboardParams params,
            @Nonnull final KeyboardRow row) {

mIconId = KeySpecParser.getIconId(keySpec);

final int code = KeySpecParser.getCode(keySpec);
 final String label = KeySpecParser.getLabel(keySpec);
String outputText = KeySpecParser.getOutputText(keySpec);

看下這些方法,可以得出一些結論
1.1. keySpec可以有多個,以豎槓分開
1.2. 如果有icon的話,icon必須放在首位
1.3. 文字圖片都是根據前綴來區分的
1.4. 解析出對應的名字,比如shift_key,這個是icon,那麼會去KeyboardIconsSet這個類裏找,這裏有初始化所有的icon

    public static final String PREFIX_ICON = "!icon/";
    private static final char BACKSLASH = Constants.CODE_BACKSLASH; // 反斜槓 \ 
    private static final char VERTICAL_BAR = Constants.CODE_VERTICAL_BAR; //豎槓 |
    private static final String PREFIX_HEX = "0x";


   private static boolean hasIcon(@Nonnull final String keySpec) {
        return keySpec.startsWith(KeyboardIconsSet.PREFIX_ICON);
    }

    public static int getIconId(@Nullable final String keySpec) {
        if (keySpec == null) {
            // TODO: Throw {@link KeySpecParserError} once Key.keyLabel attribute becomes mandatory.
            return KeyboardIconsSet.ICON_UNDEFINED;
        }
        if (!hasIcon(keySpec)) {
            return KeyboardIconsSet.ICON_UNDEFINED;
        }
        final int labelEnd = indexOfLabelEnd(keySpec);
        final String iconName = getBeforeLabelEnd(keySpec, labelEnd)
                .substring(KeyboardIconsSet.PREFIX_ICON.length());
//iconName取的就是 
        return KeyboardIconsSet.getIconId(iconName);
    }

//code

        if (text.startsWith(KeyboardCodesSet.PREFIX_CODE)) {
            return KeyboardCodesSet.getCode(text.substring(KeyboardCodesSet.PREFIX_CODE.length()));
        }
// 有icon的話,lable直接返回null了
    public static String getLabel(@Nullable final String keySpec) {
        if (keySpec == null) {
            // TODO: Throw {@link KeySpecParserError} once Key.keyLabel attribute becomes mandatory.
            return null;
        }
        if (hasIcon(keySpec)) {
            return null;
        }
//有code的話 text就返回null了

    public static String getOutputText(@Nullable final String keySpec) {
        if (keySpec == null) {
            // TODO: Throw {@link KeySpecParserError} once Key.keyLabel attribute becomes mandatory.
            return null;
        }
        final int labelEnd = indexOfLabelEnd(keySpec);
        if (hasCode(keySpec, labelEnd)) {
            return null;
        }

看下已定義的icon有哪些 KeyboardIconsSet.java
看名字大概就知道是哪些按鍵了,每個key都對應一個style的,我們去查下style

    public static final String PREFIX_ICON = "!icon/";
    private static final String NAME_UNDEFINED = "undefined";
    public static final String NAME_SHIFT_KEY = "shift_key";//
    public static final String NAME_SHIFT_KEY_SHIFTED = "shift_key_shifted";//
    public static final String NAME_DELETE_KEY = "delete_key";//
    public static final String NAME_SETTINGS_KEY = "settings_key";
    public static final String NAME_SPACE_KEY = "space_key";
    public static final String NAME_SPACE_KEY_FOR_NUMBER_LAYOUT = "space_key_for_number_layout";
    public static final String NAME_ENTER_KEY = "enter_key";
    public static final String NAME_GO_KEY = "go_key";
    public static final String NAME_SEARCH_KEY = "search_key";
    public static final String NAME_SEND_KEY = "send_key";
    public static final String NAME_NEXT_KEY = "next_key";
    public static final String NAME_DONE_KEY = "done_key";
    public static final String NAME_PREVIOUS_KEY = "previous_key";
    public static final String NAME_TAB_KEY = "tab_key";
    public static final String NAME_SHORTCUT_KEY = "shortcut_key";
    public static final String NAME_SHORTCUT_KEY_DISABLED = "shortcut_key_disabled";
    public static final String NAME_LANGUAGE_SWITCH_KEY = "language_switch_key";
    public static final String NAME_ZWNJ_KEY = "zwnj_key";
    public static final String NAME_ZWJ_KEY = "zwj_key";
    public static final String NAME_EMOJI_ACTION_KEY = "emoji_action_key";
    public static final String NAME_EMOJI_NORMAL_KEY = "emoji_normal_key";

    private static final Object[] NAMES_AND_ATTR_IDS = {
        NAME_UNDEFINED,                   ATTR_UNDEFINED,
        NAME_SHIFT_KEY,                   R.styleable.Keyboard_iconShiftKey,
        NAME_DELETE_KEY,                  R.styleable.Keyboard_iconDeleteKey,
        NAME_SETTINGS_KEY,                R.styleable.Keyboard_iconSettingsKey,
        NAME_SPACE_KEY,                   R.styleable.Keyboard_iconSpaceKey,
        NAME_ENTER_KEY,                   R.styleable.Keyboard_iconEnterKey,
        NAME_GO_KEY,                      R.styleable.Keyboard_iconGoKey,
        NAME_SEARCH_KEY,                  R.styleable.Keyboard_iconSearchKey,
        NAME_SEND_KEY,                    R.styleable.Keyboard_iconSendKey,
        NAME_NEXT_KEY,                    R.styleable.Keyboard_iconNextKey,
        NAME_DONE_KEY,                    R.styleable.Keyboard_iconDoneKey,
        NAME_PREVIOUS_KEY,                R.styleable.Keyboard_iconPreviousKey,
        NAME_TAB_KEY,                     R.styleable.Keyboard_iconTabKey,
        NAME_SHORTCUT_KEY,                R.styleable.Keyboard_iconShortcutKey,
        NAME_SPACE_KEY_FOR_NUMBER_LAYOUT, R.styleable.Keyboard_iconSpaceKeyForNumberLayout,
        NAME_SHIFT_KEY_SHIFTED,           R.styleable.Keyboard_iconShiftKeyShifted,
        NAME_SHORTCUT_KEY_DISABLED,       R.styleable.Keyboard_iconShortcutKeyDisabled,
        NAME_LANGUAGE_SWITCH_KEY,         R.styleable.Keyboard_iconLanguageSwitchKey,
        NAME_ZWNJ_KEY,                    R.styleable.Keyboard_iconZwnjKey,
        NAME_ZWJ_KEY,                     R.styleable.Keyboard_iconZwjKey,
        NAME_EMOJI_ACTION_KEY,            R.styleable.Keyboard_iconEmojiActionKey,
        NAME_EMOJI_NORMAL_KEY,            R.styleable.Keyboard_iconEmojiNormalKey,
    };

//加載主題裏的圖片
    public void loadIcons(final TypedArray keyboardAttrs) {
        final int size = ATTR_ID_TO_ICON_ID.size();
        for (int index = 0; index < size; index++) {
            final int attrId = ATTR_ID_TO_ICON_ID.keyAt(index);
            try {
                final Drawable icon = keyboardAttrs.getDrawable(attrId);
                setDefaultBounds(icon);
                final Integer iconId = ATTR_ID_TO_ICON_ID.get(attrId);
                mIcons[iconId] = icon;
                mIconResourceIds[iconId] = keyboardAttrs.getResourceId(attrId, 0);
            } catch (Resources.NotFoundException e) {
                Log.w(TAG, "Drawable resource for icon #"
                        + keyboardAttrs.getResources().getResourceEntryName(attrId)
                        + " not found");
            }
        }
    }

現在分析下主題
有這麼一個KeyboardTheme類的,這裏就包含了4種主題了,自己用的哪種,去對應下邊找就行了

    static final KeyboardTheme[] KEYBOARD_THEMES = {
        new KeyboardTheme(THEME_ID_ICS, "ICS", R.style.KeyboardTheme_ICS,
                // This has never been selected because we support ICS or later.
                VERSION_CODES.BASE),
        new KeyboardTheme(THEME_ID_KLP, "KLP", R.style.KeyboardTheme_KLP,
                // Default theme for ICS, JB, and KLP.
                VERSION_CODES.ICE_CREAM_SANDWICH),
        new KeyboardTheme(THEME_ID_LXX_LIGHT, "LXXLight", R.style.KeyboardTheme_LXX_Light,
                // Default theme for LXX.
                Build.VERSION_CODES.LOLLIPOP),
        new KeyboardTheme(THEME_ID_LXX_DARK, "LXXDark", R.style.KeyboardTheme_LXX_Dark,
                // This has never been selected as default theme.
                VERSION_CODES.BASE),
    };

如下圖片定義在這裏

    <style name="KeyboardIcons.Holo">
        <!-- Keyboard icons -->
        <item name="iconShiftKey">@drawable/sym_keyboard_shift_holo_dark</item>
        <item name="iconDeleteKey">@drawable/sym_keyboard_delete_holo_dark</item>
        <item name="iconSettingsKey">@drawable/sym_keyboard_settings_holo_dark</item>
        <item name="iconSpaceKey">@null</item>
        <item name="iconEnterKey">@drawable/sym_keyboard_return_holo_dark</item>
        <item name="iconSearchKey">@drawable/sym_keyboard_search_holo_dark</item>
        <item name="iconTabKey">@drawable/sym_keyboard_tab_holo_dark</item>
        <item name="iconShortcutKey">@drawable/sym_keyboard_voice_holo_dark</item>
        <item name="iconSpaceKeyForNumberLayout">@drawable/sym_keyboard_space_holo_dark</item>
        <item name="iconShiftKeyShifted">@drawable/sym_keyboard_shift_locked_holo_dark</item>
        <item name="iconShortcutKeyDisabled">@drawable/sym_keyboard_voice_off_holo_dark</item>
        <item name="iconLanguageSwitchKey">@drawable/sym_keyboard_language_switch_dark</item>
        <item name="iconZwnjKey">@drawable/sym_keyboard_zwnj_holo_dark</item>
        <item name="iconZwjKey">@drawable/sym_keyboard_zwj_holo_dark</item>
        <item name="iconEmojiActionKey">@drawable/sym_keyboard_smiley_holo_dark</item>
        <item name="iconEmojiNormalKey">@drawable/sym_keyboard_smiley_holo_dark</item>
    </style>

結果發現ics和klp主題下的圖片不全,少5個,lxx主題下的圖片是全的,這樣的話klp主題下那5個缺失的圖片咋獲取?少的那5個是動態變化的那個enter key

<Key
                    latin:backgroundType="functional2"
                    latin:keyStyle="enterKeyStyle"
                    latin:keyWidth="fillRight" />

然後去key_styles_common裏找了下,沒有styleName叫enterKeyStyle的,不可能啊,沒有的話會掛的,完事全局搜了下,發現這東西定義在另外一個文件裏,然後這個key_styles_common裏include進來

    <include
        latin:keyboardLayout="@xml/key_styles_enter" />

如下,簡單複製了幾個action,根據imeAction區分,parentStyle裏定義了其他信息,也是include的其他文件

        <case
            latin:imeAction="actionGo"
        >
            <key-style
                latin:styleName="enterKeyStyle"
                latin:parentStyle="goActionKeyStyle" />
        </case>
        <case
            latin:imeAction="actionNext"
        >
            <key-style
                latin:styleName="enterKeyStyle"
                latin:parentStyle="nextActionKeyStyle" />
        </case>

注意一下,這個幾個action的code名字都是key_enter
可以看到,兩種case ,第一個先判斷icon在不在 latin:isIconDefined,不在就走下邊那種,那種裏邊定義了text了,

    <!-- Go key -->
    <switch>
        <case latin:isIconDefined="go_key">
            <key-style
                latin:styleName="goActionKeyStyle"
                latin:keySpec="!icon/go_key|!code/key_enter"
                latin:parentStyle="defaultEnterKeyStyle" />
        </case>
        <default>
            <key-style
                latin:styleName="goActionKeyStyle"
                latin:keySpec="!text/label_go_key|!code/key_enter"
                latin:parentStyle="defaultEnterKeyStyle" />
        </default>
    </switch>
    <!-- Next key -->
    <switch>
        <case latin:isIconDefined="next_key">
            <key-style
                latin:styleName="nextActionKeyStyle"
                latin:keySpec="!icon/next_key|!code/key_enter"
                latin:parentStyle="defaultEnterKeyStyle" />
        </case>
        <default>
            <key-style
                latin:styleName="nextActionKeyStyle"
                latin:keySpec="!text/label_next_key|!code/key_enter"
                latin:parentStyle="defaultEnterKeyStyle" />
        </default>
    </switch>

最終測試了,因爲沒定義這5個圖片,所以在這種主題下,輸入法的action確實不顯示圖片,顯示的是文字
go ,send ,next,prev,done 這種 ,
資源文件裏有

<resources xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <string name="label_go_key" msgid="4033615332628671065">"Go"</string>
    <string name="label_next_key" msgid="5586407279258592635">"Next"</string>
    <string name="label_previous_key" msgid="1421141755779895275">"Prev"</string>
    <string name="label_done_key" msgid="7564866296502630852">"Done"</string>
    <string name="label_send_key" msgid="482252074224462163">"Send"</string>
    <string name="label_search_key" msgid="7965186050435796642">"Search"</string>
    <string name="label_pause_key" msgid="2225922926459730642">"Pause"</string>
    <string name="label_wait_key" msgid="5891247853595466039">"Wait"</string>
</resources>

和KeyboardIconsSet一樣也有一個KeyboardTextsSet 的類來解析文字

public final class KeyboardTextsSet {
    public static final String PREFIX_TEXT = "!text/";
    private static final String PREFIX_RESOURCE = "!string/";

text獲取還得另外一個類

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章