如何将已弃用的 KeyboardView.java 和 Keyboard.java 正确复制到 android 项目?
How to properly copy deprecated KeyboardView.java and Keyboard.java to android project?
我正在尝试遵循 Google 关于 KeyboardView.java 的建议:https://developer.android.com/reference/android/inputmethodservice/KeyboardView
我已经复制并调整了 KeyboardView.java、Keyboard.java 和 com.android.internal.R 中标记为已弃用的部分,并创建了一个新的 res/values/styles.xml 包含样式定义的文件。
一切都构建得很好,但是当它到达显示自定义键盘的地步时,
我得到一个空指针异常。我可以看到问题出在此处复制的 KeyboardView 代码中(a.getIndexCount() 的计数为 0,因此 mKeyBackground 永远不会设置并在调用“[=38= 时导致空异常](mPadding)").我不知道我错过了什么?:
public KeyboardView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a =
context.obtainStyledAttributes(
attrs, R.styleable.KeyboardView, defStyle, 0);
LayoutInflater inflate =
(LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
int previewLayout = 0;
int keyTextSize = 0;
// n is set to 0
int n = a.getIndexCount();
// since n = 0, the loop is never entered
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.KeyboardView_keyBackground:
// mKeyBackground is supposed to be set but isn't because n = 0
mKeyBackground = a.getDrawable(attr);
break;
case R.styleable.KeyboardView_verticalCorrection:
mVerticalCorrection = a.getDimensionPixelOffset(attr, 0);
break;
case R.styleable.KeyboardView_keyPreviewLayout:
previewLayout = a.getResourceId(attr, 0);
break;
case R.styleable.KeyboardView_keyPreviewOffset:
mPreviewOffset = a.getDimensionPixelOffset(attr, 0);
break;
case R.styleable.KeyboardView_keyPreviewHeight:
mPreviewHeight = a.getDimensionPixelSize(attr, 80);
break;
case R.styleable.KeyboardView_keyTextSize:
mKeyTextSize = a.getDimensionPixelSize(attr, 18);
break;
case R.styleable.KeyboardView_keyTextColor:
mKeyTextColor = a.getColor(attr, 0xFF000000);
break;
case R.styleable.KeyboardView_labelTextSize:
mLabelTextSize = a.getDimensionPixelSize(attr, 14);
break;
case R.styleable.KeyboardView_popupLayout:
mPopupLayout = a.getResourceId(attr, 0);
break;
}
}
// Get the settings preferences
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
mVibrateOn = sp.getBoolean(PREF_VIBRATE_ON, mVibrateOn);
mSoundOn = sp.getBoolean(PREF_SOUND_ON, mSoundOn);
mProximityCorrectOn = sp.getBoolean(PREF_PROXIMITY_CORRECTION, true);
mPreviewPopup = new PopupWindow(context);
if (previewLayout != 0) {
mPreviewText = (TextView) inflate.inflate(previewLayout, null);
mPreviewTextSizeLarge = (int) mPreviewText.getTextSize();
mPreviewPopup.setContentView(mPreviewText);
mPreviewPopup.setBackgroundDrawable(null);
} else {
mShowPreview = false;
}
mPreviewPopup.setTouchable(false);
mPopupKeyboard = new PopupWindow(context);
mPopupKeyboard.setBackgroundDrawable(null);
//mPopupKeyboard.setClippingEnabled(false);
mPopupParent = this;
//mPredicting = true;
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setTextSize(keyTextSize);
mPaint.setTextAlign(Align.CENTER);
mPadding = new Rect(0, 0, 0, 0);
mMiniKeyboardCache = new HashMap<Key,View>();
// Program crashes here from null pointer since mKeyBackground isn't set
mKeyBackground.getPadding(mPadding);
resetMultiTap();
initGestureDetector();
}
这是 styles.xml 文件:
styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="KeyboardView" parent="android:Widget">
<item name="android:background">@color/black</item>
<item name="keyBackground">@drawable/background</item>
<item name="keyTextSize">22sp</item>
<item name="keyTextColor">@color/white</item>
<item name="keyPreviewLayout">@layout/preview</item>
<item name="keyPreviewOffset">-12dp</item>
<item name="keyPreviewHeight">80dp</item>
<item name="labelTextSize">14sp</item>
<item name="popupLayout">@layout/preview</item>
<item name="verticalCorrection">-10dp</item>
<!-- <item name="shadowColor">@android:color/transparent</item> -->
<!-- <item name="shadowRadius">2.75</item> -->
</style>
</resources>
这是我的原件com.android.internal.R(在values/attrs.xml)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="KeyboardView">
<!-- Default KeyboardView style. -->
<attr name="keyboardViewStyle" format="reference" />
<!-- Image for the key. This image needs to be a StateListDrawable, with the following
possible states: normal, pressed, checkable, checkable+pressed, checkable+checked,
checkable+checked+pressed. -->
<attr name="keyBackground" format="reference" />
<!-- Size of the text for character keys. -->
<attr name="keyTextSize" format="dimension" />
<!-- Size of the text for custom keys with some text and no icon. -->
<attr name="labelTextSize" format="dimension" />
<!-- Color to use for the label in a key. -->
<attr name="keyTextColor" format="color" />
<!-- Layout resource for key press feedback. -->
<attr name="keyPreviewLayout" format="reference" />
<!-- Vertical offset of the key press feedback from the key. -->
<attr name="keyPreviewOffset" format="dimension" />
<!-- Height of the key press feedback popup. -->
<attr name="keyPreviewHeight" format="dimension" />
<!-- Amount to offset the touch Y coordinate by, for bias correction. -->
<attr name="verticalCorrection" format="dimension" />
<!-- Layout resource for popup keyboards. -->
<attr name="popupLayout" format="reference" />
<!-- <attr name="shadowColor" /> -->
<!-- <attr name="shadowRadius" /> -->
</declare-styleable>
<declare-styleable name="KeyboardViewPreviewState">
<!-- State for {@link android.inputmethodservice.KeyboardView KeyboardView}
key preview background. -->
<attr name="state_long_pressable" format="boolean" />
</declare-styleable>
<declare-styleable name="Keyboard">
<!-- Default width of a key, in pixels or percentage of display width. -->
<attr name="keyWidth" format="dimension|fraction" />
<!-- Default height of a key, in pixels or percentage of display width. -->
<attr name="keyHeight" format="dimension|fraction" />
<!-- Default horizontal gap between keys. -->
<attr name="horizontalGap" format="dimension|fraction" />
<!-- Default vertical gap between rows of keys. -->
<attr name="verticalGap" format="dimension|fraction" />
</declare-styleable>
<declare-styleable name="Keyboard_Row">
<!-- Row edge flags. -->
<attr name="rowEdgeFlags">
<!-- Row is anchored to the top of the keyboard. -->
<flag name="top" value="4" />
<!-- Row is anchored to the bottom of the keyboard. -->
<flag name="bottom" value="8" />
</attr>
<!-- Mode of the keyboard. If the mode doesn't match the
requested keyboard mode, the row will be skipped. -->
<attr name="keyboardMode" format="reference" />
</declare-styleable>
<declare-styleable name="Keyboard_Key">
<!-- The unicode value or comma-separated values that this key outputs. -->
<attr name="codes" format="integer|string" />
<!-- The XML keyboard layout of any popup keyboard. -->
<attr name="popupKeyboard" format="reference" />
<!-- The characters to display in the popup keyboard. -->
<attr name="popupCharacters" format="string" />
<!-- Key edge flags. -->
<attr name="keyEdgeFlags">
<!-- Key is anchored to the left of the keyboard. -->
<flag name="left" value="1" />
<!-- Key is anchored to the right of the keyboard. -->
<flag name="right" value="2" />
</attr>
<!-- Whether this is a modifier key such as Alt or Shift. -->
<attr name="isModifier" format="boolean" />
<!-- Whether this is a toggle key. -->
<attr name="isSticky" format="boolean" />
<!-- Whether long-pressing on this key will make it repeat. -->
<attr name="isRepeatable" format="boolean" />
<!-- The icon to show in the popup preview. -->
<attr name="iconPreview" format="reference" />
<!-- The string of characters to output when this key is pressed. -->
<attr name="keyOutputText" format="string" />
<!-- The label to display on the key. -->
<attr name="keyLabel" format="string" />
<!-- The icon to display on the key instead of the label. -->
<attr name="keyIcon" format="reference" />
<!-- Mode of the keyboard. If the mode doesn't match the
requested keyboard mode, the key will be skipped. -->
<attr name="keyboardMode" />
</declare-styleable>
</resources>
未使用包含默认值的 KeyboardView
style
。
虽然您可以在 XML layout
中手动设置每个值(如您在评论中所述),但像这样
<your.package.name.KeyboardView
…
app:keyBackground="@drawable/bg_container"
…
/>
或者直接设置整个style
,像这样
<your.package.name.KeyboardView
…
style="@style/KeyboardView"
…
/>
两者都需要在每次使用 View
时设置这些值。
更好的方法是在 KeyboardView.java
:
中设置默认值
public KeyboardView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.KeyboardView,
R.attr.keyboardViewStyle,
R.style.KeyboardView);
// …
}
我正在尝试遵循 Google 关于 KeyboardView.java 的建议:https://developer.android.com/reference/android/inputmethodservice/KeyboardView
我已经复制并调整了 KeyboardView.java、Keyboard.java 和 com.android.internal.R 中标记为已弃用的部分,并创建了一个新的 res/values/styles.xml 包含样式定义的文件。
一切都构建得很好,但是当它到达显示自定义键盘的地步时, 我得到一个空指针异常。我可以看到问题出在此处复制的 KeyboardView 代码中(a.getIndexCount() 的计数为 0,因此 mKeyBackground 永远不会设置并在调用“[=38= 时导致空异常](mPadding)").我不知道我错过了什么?:
public KeyboardView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a =
context.obtainStyledAttributes(
attrs, R.styleable.KeyboardView, defStyle, 0);
LayoutInflater inflate =
(LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
int previewLayout = 0;
int keyTextSize = 0;
// n is set to 0
int n = a.getIndexCount();
// since n = 0, the loop is never entered
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.KeyboardView_keyBackground:
// mKeyBackground is supposed to be set but isn't because n = 0
mKeyBackground = a.getDrawable(attr);
break;
case R.styleable.KeyboardView_verticalCorrection:
mVerticalCorrection = a.getDimensionPixelOffset(attr, 0);
break;
case R.styleable.KeyboardView_keyPreviewLayout:
previewLayout = a.getResourceId(attr, 0);
break;
case R.styleable.KeyboardView_keyPreviewOffset:
mPreviewOffset = a.getDimensionPixelOffset(attr, 0);
break;
case R.styleable.KeyboardView_keyPreviewHeight:
mPreviewHeight = a.getDimensionPixelSize(attr, 80);
break;
case R.styleable.KeyboardView_keyTextSize:
mKeyTextSize = a.getDimensionPixelSize(attr, 18);
break;
case R.styleable.KeyboardView_keyTextColor:
mKeyTextColor = a.getColor(attr, 0xFF000000);
break;
case R.styleable.KeyboardView_labelTextSize:
mLabelTextSize = a.getDimensionPixelSize(attr, 14);
break;
case R.styleable.KeyboardView_popupLayout:
mPopupLayout = a.getResourceId(attr, 0);
break;
}
}
// Get the settings preferences
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
mVibrateOn = sp.getBoolean(PREF_VIBRATE_ON, mVibrateOn);
mSoundOn = sp.getBoolean(PREF_SOUND_ON, mSoundOn);
mProximityCorrectOn = sp.getBoolean(PREF_PROXIMITY_CORRECTION, true);
mPreviewPopup = new PopupWindow(context);
if (previewLayout != 0) {
mPreviewText = (TextView) inflate.inflate(previewLayout, null);
mPreviewTextSizeLarge = (int) mPreviewText.getTextSize();
mPreviewPopup.setContentView(mPreviewText);
mPreviewPopup.setBackgroundDrawable(null);
} else {
mShowPreview = false;
}
mPreviewPopup.setTouchable(false);
mPopupKeyboard = new PopupWindow(context);
mPopupKeyboard.setBackgroundDrawable(null);
//mPopupKeyboard.setClippingEnabled(false);
mPopupParent = this;
//mPredicting = true;
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setTextSize(keyTextSize);
mPaint.setTextAlign(Align.CENTER);
mPadding = new Rect(0, 0, 0, 0);
mMiniKeyboardCache = new HashMap<Key,View>();
// Program crashes here from null pointer since mKeyBackground isn't set
mKeyBackground.getPadding(mPadding);
resetMultiTap();
initGestureDetector();
}
这是 styles.xml 文件:
styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="KeyboardView" parent="android:Widget">
<item name="android:background">@color/black</item>
<item name="keyBackground">@drawable/background</item>
<item name="keyTextSize">22sp</item>
<item name="keyTextColor">@color/white</item>
<item name="keyPreviewLayout">@layout/preview</item>
<item name="keyPreviewOffset">-12dp</item>
<item name="keyPreviewHeight">80dp</item>
<item name="labelTextSize">14sp</item>
<item name="popupLayout">@layout/preview</item>
<item name="verticalCorrection">-10dp</item>
<!-- <item name="shadowColor">@android:color/transparent</item> -->
<!-- <item name="shadowRadius">2.75</item> -->
</style>
</resources>
这是我的原件com.android.internal.R(在values/attrs.xml)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="KeyboardView">
<!-- Default KeyboardView style. -->
<attr name="keyboardViewStyle" format="reference" />
<!-- Image for the key. This image needs to be a StateListDrawable, with the following
possible states: normal, pressed, checkable, checkable+pressed, checkable+checked,
checkable+checked+pressed. -->
<attr name="keyBackground" format="reference" />
<!-- Size of the text for character keys. -->
<attr name="keyTextSize" format="dimension" />
<!-- Size of the text for custom keys with some text and no icon. -->
<attr name="labelTextSize" format="dimension" />
<!-- Color to use for the label in a key. -->
<attr name="keyTextColor" format="color" />
<!-- Layout resource for key press feedback. -->
<attr name="keyPreviewLayout" format="reference" />
<!-- Vertical offset of the key press feedback from the key. -->
<attr name="keyPreviewOffset" format="dimension" />
<!-- Height of the key press feedback popup. -->
<attr name="keyPreviewHeight" format="dimension" />
<!-- Amount to offset the touch Y coordinate by, for bias correction. -->
<attr name="verticalCorrection" format="dimension" />
<!-- Layout resource for popup keyboards. -->
<attr name="popupLayout" format="reference" />
<!-- <attr name="shadowColor" /> -->
<!-- <attr name="shadowRadius" /> -->
</declare-styleable>
<declare-styleable name="KeyboardViewPreviewState">
<!-- State for {@link android.inputmethodservice.KeyboardView KeyboardView}
key preview background. -->
<attr name="state_long_pressable" format="boolean" />
</declare-styleable>
<declare-styleable name="Keyboard">
<!-- Default width of a key, in pixels or percentage of display width. -->
<attr name="keyWidth" format="dimension|fraction" />
<!-- Default height of a key, in pixels or percentage of display width. -->
<attr name="keyHeight" format="dimension|fraction" />
<!-- Default horizontal gap between keys. -->
<attr name="horizontalGap" format="dimension|fraction" />
<!-- Default vertical gap between rows of keys. -->
<attr name="verticalGap" format="dimension|fraction" />
</declare-styleable>
<declare-styleable name="Keyboard_Row">
<!-- Row edge flags. -->
<attr name="rowEdgeFlags">
<!-- Row is anchored to the top of the keyboard. -->
<flag name="top" value="4" />
<!-- Row is anchored to the bottom of the keyboard. -->
<flag name="bottom" value="8" />
</attr>
<!-- Mode of the keyboard. If the mode doesn't match the
requested keyboard mode, the row will be skipped. -->
<attr name="keyboardMode" format="reference" />
</declare-styleable>
<declare-styleable name="Keyboard_Key">
<!-- The unicode value or comma-separated values that this key outputs. -->
<attr name="codes" format="integer|string" />
<!-- The XML keyboard layout of any popup keyboard. -->
<attr name="popupKeyboard" format="reference" />
<!-- The characters to display in the popup keyboard. -->
<attr name="popupCharacters" format="string" />
<!-- Key edge flags. -->
<attr name="keyEdgeFlags">
<!-- Key is anchored to the left of the keyboard. -->
<flag name="left" value="1" />
<!-- Key is anchored to the right of the keyboard. -->
<flag name="right" value="2" />
</attr>
<!-- Whether this is a modifier key such as Alt or Shift. -->
<attr name="isModifier" format="boolean" />
<!-- Whether this is a toggle key. -->
<attr name="isSticky" format="boolean" />
<!-- Whether long-pressing on this key will make it repeat. -->
<attr name="isRepeatable" format="boolean" />
<!-- The icon to show in the popup preview. -->
<attr name="iconPreview" format="reference" />
<!-- The string of characters to output when this key is pressed. -->
<attr name="keyOutputText" format="string" />
<!-- The label to display on the key. -->
<attr name="keyLabel" format="string" />
<!-- The icon to display on the key instead of the label. -->
<attr name="keyIcon" format="reference" />
<!-- Mode of the keyboard. If the mode doesn't match the
requested keyboard mode, the key will be skipped. -->
<attr name="keyboardMode" />
</declare-styleable>
</resources>
未使用包含默认值的 KeyboardView
style
。
虽然您可以在 XML layout
中手动设置每个值(如您在评论中所述),但像这样
<your.package.name.KeyboardView
…
app:keyBackground="@drawable/bg_container"
…
/>
或者直接设置整个style
,像这样
<your.package.name.KeyboardView
…
style="@style/KeyboardView"
…
/>
两者都需要在每次使用 View
时设置这些值。
更好的方法是在 KeyboardView.java
:
public KeyboardView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.KeyboardView,
R.attr.keyboardViewStyle,
R.style.KeyboardView);
// …
}