如何自定义 安卓输入法 和 键盘

1.首先有几个关键类

1.InputMethodService 2.Keyboard 3.KeyboardView

1.1 InputMethodService

看下这个类的介绍

图片.png

InputMethodService provides a standard implementation of an InputMethod

作用 提供一个标准键盘实现 balabala.....

输入法生命周期.png

请参考 http://blog.csdn.net/weijinqian0/article/details/76906317

1.2.Keyboard 源码分析

图片.png

xmL 定义键盘的属性 : 键位宽/高/水平间距/垂直间距/按键文字图标/键值.....

键盘的UI样式就在这个类里面定义,准确的说 是在keyboard加载的xml文件中定义

构造方法

传入键盘布局文件id

/**

* Creates a keyboard from the given xml key layout file.

* @param context the application or service context

* @param xmlLayoutResId the resource file that contains the keyboard layout and keys.

*/

public Keyboard(Context context, int xmlLayoutResId) {

this(context, xmlLayoutResId, 0);

}

/**

* Creates a keyboard from the given xml key layout file. Weeds out rows

* that have a keyboard mode defined but don't match the specified mode.

* @param context the application or service context

* @param xmlLayoutResId the resource file that contains the keyboard layout and keys.

* @param modeId keyboard mode identifier

* @param width sets width of keyboard

* @param height sets height of keyboard

*/

public Keyboard(Context context, @XmlRes int xmlLayoutResId, int modeId, int width,

int height) {

mDisplayWidth = width;

mDisplayHeight = height;

mDefaultHorizontalGap = 0;

mDefaultWidth = mDisplayWidth / 10;

mDefaultVerticalGap = 0;

mDefaultHeight = mDefaultWidth;

mKeys = new ArrayList();

mModifierKeys = new ArrayList();

mKeyboardMode = modeId;

//加载键盘

loadKeyboard(context, context.getResources().getXml(xmlLayoutResId));

}

xml 解析键盘布局

private void loadKeyboard(Context context, XmlResourceParser parser) {

boolean inKey = false;

boolean inRow = false;

boolean leftMostKey = false;

int row = 0;

int x = 0;

int y = 0;

Key key = null;

Row currentRow = null;

Resources res = context.getResources();

boolean skipRow = false;

try {

int event;

while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) {

if (event == XmlResourceParser.START_TAG) {

String tag = parser.getName();

if (TAG_ROW.equals(tag)) {

inRow = true;

x = 0;

currentRow = createRowFromXml(res, parser);

rows.add(currentRow);

skipRow = currentRow.mode != 0 && currentRow.mode != mKeyboardMode;

if (skipRow) {

skipToEndOfRow(parser);

inRow = false;

}

} else if (TAG_KEY.equals(tag)) {

inKey = true;

key = createKeyFromXml(res, currentRow, x, y, parser);

mKeys.add(key);

if (key.codes[0] == KEYCODE_SHIFT) {

// Find available shift key slot and put this shift key in it

for (int i = 0; i < mShiftKeys.length; i++) {

if (mShiftKeys[i] == null) {

mShiftKeys[i] = key;

mShiftKeyIndices[i] = mKeys.size()-1;

break;

}

}

mModifierKeys.add(key);

} else if (key.codes[0] == KEYCODE_ALT) {

mModifierKeys.add(key);

}

currentRow.mKeys.add(key);

} else if (TAG_KEYBOARD.equals(tag)) {

parseKeyboardAttributes(res, parser);

}

} else if (event == XmlResourceParser.END_TAG) {

if (inKey) {

inKey = false;

x += key.gap + key.width;

if (x > mTotalWidth) {

mTotalWidth = x;

}

} else if (inRow) {

inRow = false;

y += currentRow.verticalGap;

y += currentRow.defaultHeight;

row++;

} else {

// TODO: error or extend?

}

}

}

} catch (Exception e) {

Log.e(TAG, "Parse error:" + e);

e.printStackTrace();

}

mTotalHeight = y - mDefaultVerticalGap;

}

1.3.KeyboardView :自定义键盘一般继承keyboardView 重写其方法

图片.png

作用:渲染按键 侦测按压

android:id="@+id/keyboardView"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_alignParentBottom="true"

android:background="#ECECEC"

//每一个按键的背景 (全部)

android:keyBackground="@drawable/btn_keyboard_key"

//预览的view 的高度

android:keyPreviewHeight="100dp"

//按键预览的布局

android:keyPreviewLayout="@layout/keyboard_preview"

//按键预览的pop的y轴偏移量

android:keyPreviewOffset="50dp"

android:keyTextColor="#4F4F4F"

android:shadowColor="#FFFFFF"

android:shadowRadius="0.0"

app:layout_constraintBottom_toBottomOf="parent"

app:layout_constraintStart_toStartOf="parent"/>

2. 具体实现

2.1 自定义键盘继承KeyboardView 当然也可以不定义 直接使用keyboardView

2.2 创建布局文件

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

xmlns:app="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:gravity="bottom"

android:orientation="vertical">

android:layout_width="match_parent"

android:layout_height="100dp"/>

android:id="@+id/keyboardView"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_alignParentBottom="true"

android:background="#ECECEC"

android:focusable="true"

android:focusableInTouchMode="true"

android:keyBackground="@drawable/btn_keyboard_key"

android:keyPreviewHeight="100dp"

android:keyPreviewLayout="@layout/keyboard_preview"

android:keyPreviewOffset="50dp"

android:keyTextColor="#4F4F4F"

android:shadowColor="#FFFFFF"

android:shadowRadius="0.0"

app:layout_constraintBottom_toBottomOf="parent"

app:layout_constraintStart_toStartOf="parent"/>

2.3 新建服务继承InputMethodService

public class MyInputMethodService extends InputMethodService {

@Override

public View onCreateInputView() {

View view = getLayoutInflater().

//键盘的布局文件

inflate(R.layout.keyboard_global, null);

return view;

}

}

清单文件

android:name="com.example.ableqing.androidkeyboardviewdemo.MyInputMethodService"

android:label="@string/keyboard_name"

android:permission="android.permission.BIND_INPUT_METHOD">

android:name="android.view.im"

android:resource="@xml/method"/>

2.4 xml 定义键盘的resource 文件 和 不同键盘布局文件

图片.png

字母键盘的布局

android:horizontalGap="0.9%p"

android:keyHeight="52dp"

android:keyWidth="9%p"

android:verticalGap="0px">

android:codes="113"

android:keyEdgeFlags="left"

android:keyLabel="q"/>

android:codes="119"

android:keyLabel="w"/>

android:codes="101"

android:keyLabel="e"/>

android:codes="114"

android:keyLabel="r"/>

android:codes="116"

android:keyLabel="t"/>

android:codes="121"

android:keyLabel="y"/>

android:codes="117"

android:keyLabel="u"/>

android:codes="105"

android:keyLabel="i"/>

android:codes="111"

android:keyLabel="o"/>

android:codes="112"

android:keyEdgeFlags="right"

android:keyLabel="p"/>

android:codes="97"

android:horizontalGap="6%p"

android:keyEdgeFlags="left"

android:keyLabel="a"/>

android:codes="115"

android:keyLabel="s"/>

android:codes="100"

android:keyLabel="d"/>

android:codes="102"

android:keyLabel="f"/>

android:codes="103"

android:keyLabel="g"/>

android:codes="104"

android:keyLabel="h"/>

android:codes="106"

android:keyLabel="j"/>

android:codes="107"

android:keyLabel="k"/>

android:codes="108"

android:keyLabel="l"/>

android:codes="-1"

android:isModifier="true"

android:isSticky="true"

android:keyEdgeFlags="left"

android:keyWidth="12.6%p"/>

android:codes="122"

android:horizontalGap="2.3%p"

android:keyLabel="z"

android:keyWidth="9%p"/>

android:codes="120"

android:keyLabel="x"

android:keyWidth="9%p"/>

android:codes="99"

android:keyLabel="c"

android:keyWidth="9%p"/>

android:codes="118"

android:keyLabel="v"

android:keyWidth="9%p"/>

android:codes="98"

android:keyLabel="b"

android:keyWidth="9%p"/>

android:codes="110"

android:keyLabel="n"

android:keyWidth="9%p"/>

android:codes="109"

android:keyLabel="m"

android:keyWidth="9%p"/>

android:codes="-5"

android:horizontalGap="2.3%p"

android:isRepeatable="true"

android:keyEdgeFlags="right"

android:keyIcon="@mipmap/key_back"

android:keyWidth="12.6%p"/>

android:codes="-101"

android:keyEdgeFlags="left"

android:keyLabel="123"

android:keyWidth="12.6%p"/>

android:codes="-105"

android:keyIcon="@mipmap/key_switch"

android:keyWidth="12.6%p"/>

android:codes="-100"

android:keyIcon="@mipmap/key_setting"

android:keyWidth="11%p"/>

android:codes="32"

android:isRepeatable="true"

android:keyLabel="space"

android:keyWidth="34.2%p"/>

android:codes="-4"

android:keyEdgeFlags="right"

android:keyLabel="return"

android:keyWidth="24%p"/>

xml 中定义布局的 属性

keyLabel 按键显示的内容

keyIcon 按键显示的图标内容

keyWidth 按键的宽度

keyHeight 按键的高度

horizontalGap 代表按键前的间隙水平方向上的

isSticky 按键是否是sticky的,就像shift 键 具有两种状态

isModifier 按键是不是功能键

keyOutputText 指定按键输出的内容是字符串

isRepeatable 按键是可重复的,如果长按键可以触发重复按键事件则为true,else为false

keyEdgeFlags 指定按键的对齐指令,取值为left或者right

设置和选择输入法

跳转输入法设置界面:

Intent intent = new Intent();

intent.setAction( Settings.ACTION_INPUT_METHOD_SETTINGS);

SoftDemoActivity.this.startActivity(intent);

设置输入法.png

弹出输入法选择框

((InputMethodManager) service.getSystemService(Context.INPUT_METHOD_SERVICE)).showInputMethodPicker();

选择输入法.png

Kapture 2018-02-02 at 15.08.06.gif

3问题处理

3.1 第一排按键预览位置错误

图片.png

对比下讯飞输入法

图片.png

可以看出讯飞输入法上面还有一个透明布局

按键的预览本质是一个popupwindow

图片.png

在keyboardViwe 源码中可以看到按键预览的实现方式,按键预览的pop的位置不会超过给 InputMethodService 的布局的范围

更证: 其实onCreateCandidatesView 中设置candidatesView也可以

override fun onCreateCandidatesView(): View {

// return super.onCreateCandidatesView()

return 自定义的view

}

问题解决: 只要给InputMethodService 设置的布局的高度大于布局中的keyboardView的高度,那么就可以显示正常

图片.png

3.2 给不同按键设置不同背景

keyboardView 可以给按键设置背景 但是是给所有的按键设置

这个地方不是在xml 资源文件中设置按键的keyIcon 而是重写keyboardView的Ondraw 根据不同keycode重新绘制

3.3 禁止部分按键的按键预览

1.在 keyboardView的监听 OnKeyboardActionListener 回调的onPress()中处理

@Override

public void onPress(int primaryCode) {

//设置某些按键不显示预览的view

LogUtil.d(TAG, "-->Keyboard: onPress at >>" + primaryCode);

KeyboardUtils.vibrate(20);

if (primaryCode == Keyboard.KEYCODE_SHIFT || primaryCode == Keyboard.KEYCODE_DELETE //

|| primaryCode == Keyboard.KEYCODE_DONE || primaryCode == VipKeyboardCode.CODE_SPACE //

|| primaryCode == VipKeyboardCode.CODE_TYPE_QWERTY || primaryCode == VipKeyboardCode.CODE_TYPE_NUM //

|| primaryCode == VipKeyboardCode.CODE_TYPE_SYMBOL || primaryCode == VipKeyboardCode.CODE_OPEN_VIP //

|| primaryCode == VipKeyboardCode.CODE_TYPE_SWITCH_INPUT || primaryCode == Keyboard.KEYCODE_MODE_CHANGE) {

setPreviewEnabled(false);

} else {

setPreviewEnabled(true);

}

}

2.上面处理了点击是没问题了 但是在键盘上滑动时,滑动到每个按键还是会显示preView

所以可以重写KeyboardView的OnTouchEvent方法处理

/**

* 处理滑动时 回车等键位的 按键预览 出现问题

*/

@Override

public boolean onTouchEvent(MotionEvent me) {

float x = me.getX();

float y = me.getY();

switch (me.getAction()) {

case MotionEvent.ACTION_DOWN:

mDownX = x;

mDownY = y;

break;

case MotionEvent.ACTION_UP:

case MotionEvent.ACTION_CANCEL:

//取消预览

setPreviewEnabled(false);

setPopupOffset(0, ScreenUtil.dp2px(0));

break;

case MotionEvent.ACTION_MOVE:

setPreviewEnabled(false);

//滑动距离小于10dp时不隐藏键盘预览 大于10dp时隐藏键盘按键预览

if (Math.abs(x - mDownX) > ScreenUtil.dp2px(10) || Math.abs(y - mDownY) > ScreenUtil

.dp2px(10)) {

//取消预览

setPopupOffset(0, ScreenUtil.dp2px(0));

}

break;

}

return super.onTouchEvent(me);

}

android 自定义输入法布局,Android InputMethodService|KeyboardView 自定义输入法和键盘 01...相关推荐

  1. android 自定义输入法布局,Android自定义输入法使用方法

    Android自定义输入法使用方法 时间:2017-04-21     来源:Android开发学习网 对于Android用户而言,一般都会使用第三方的输入法.可是在输入密码时(尤其是支付相关的密码) ...

  2. android 自定义输入法布局,Android 解决沉浸式状态栏下,输入法弹出,布局不会自动调整的BUG...

    一.前言 在开发中,如果输入框在布局的底部.在弹出输入发时,为了使输入法不遮挡输入框通常有两种做法: 1.将布局压缩(Activity的android:windowSoftInputMode属性设置为 ...

  3. android 输入法更换_详解安卓手机输入法和键盘切换方式的教程

    说道键盘也许大家都非常的熟悉,键盘有软键盘和硬键盘,如今大部分智能机上的就是软键盘,还有个别好几年前的手机呢使用的硬键盘,现在我们简单介绍一下键盘,键盘是用于操作设备运行的一种指令和数据输入装置,也指 ...

  4. android 自定义键盘字体大小,android.inputmethodservice.KeyboardView 自定义键盘 字体大小设置...

    KeyboardView 设置自定义键盘上文本的属性,其中字体的设置用:android:keyTextSize    android:labelTextSize 即可实现!! 亲测! android: ...

  5. Android自定义组合布局,Android 流式布局 + 自定义组合控件

    自定义组合控件 package yanjupeng.bawei.com.day09.two; import android.content.Context; import android.util.A ...

  6. android仿qq布局,Android自定义布局实现仿qq侧滑部分代码

    自定义布局实现仿qq侧滑部分android代码,供大家参考,具体内容如下 实现说明: 通过自定义布局实现: slidinglayout继承于 horizontalscrollview /** * cr ...

  7. android 开发打赏布局,Android自定义View模仿虎扑直播界面的打赏按钮功能

    Android自定义View模仿虎扑直播界面的打赏按钮功能 发布时间:2020-09-28 12:15:53 来源:脚本之家 阅读:77 作者:shenhuniurou 前言 作为一个资深篮球爱好者, ...

  8. android win8风格布局,Android仿Win8界面开发

    本文将要模仿Win8界面的一个设计,一个一个的方块.方法很简单.这里自己把图片改改就可以成为自己想要的界面了. 1.首先来看看自定义的MyImageView: package com.example. ...

  9. android 动态绘制布局,Android代码和绘制曲线中按钮和绘图板的动态布局

    时间: 2019年1月11日 本文向您介绍Android代码中的按钮和绘图板的动态布局和绘制曲线,主要包括示例android 动态绘制曲线,应用技巧,基本知识和知识android 动态绘制曲线,包括A ...

最新文章

  1. Java项目接口安全_ESAPI安全开发实战
  2. 003 通过内存关系找万能按键call
  3. B端设计指南 —— 弹窗 究竟应该如何设计
  4. opencv 图片叠加_OpenCVSharp学习之——ROI与图像叠加
  5. 在SQL Server 2000中使用Transact-SQL建立数据库
  6. java设计模式----简单工厂
  7. 【观点讨论与支撑】明星和成功人士真的就只有成功的一面吗?背后的心酸和痛苦的经历我感觉更重要!
  8. 翻译:生产中的机器学习:为什么你应该关心数据和概念漂移
  9. 腾讯首款区块链AR游戏上线《一起来捉妖》,风物志里的奇珍异兽
  10. Excel - Office Excel 多表无法多窗口问题
  11. 手机端,网站页面被浏览器转码
  12. 可该变某一属性的GAN:Hijack-GAN
  13. Typora 0.11.18 beta版不能使用解决方法
  14. 再生龙linux多挂载点备份,利用Clonezilla(再生龙)对Linux系统备份与恢复
  15. windows防火墙是干什么的_windows防火墙作用介绍
  16. 《流浪方舟》- 废土世界的冒险之旅
  17. Oracle语句(持续更新)
  18. 【有料】Java线程池实现原理及其在美团业务中的实践
  19. 如何用redis设计一个运动步数排行榜?
  20. 关于010editor

热门文章

  1. 使用GAE建立免费静态网站
  2. Unreal Engine4开篇
  3. 多尺度结构元素形态学边缘检测算法的研究-含Matlab代码
  4. Stm32之RTC时钟(2021-07-26)
  5. TransactionTemplate编程式事务
  6. 我最喜欢的一节计算机课400字,我和计算机的故事作文400字
  7. 《黑暗之光》RPG游戏案例学习(2)——第一章(1)搭建游戏场景
  8. 关于FPV图传系统时延讨论
  9. 兴安雪学运维之:CentOS用户组管理groupadd,groupdel...
  10. 世外桃源六python_求活在金朝末年_第六章:世外桃源-笔趣阁