Android开发案例 - 自定义虚拟键盘

所有包含IM功能的App(如微信, 微博, QQ, 支付宝等)都提供了Emoji表情之类的虚拟键盘,  如下图:

  

本文只着重介绍如何实现输入法键盘和自定义虚拟键盘的流畅切换, 而不介绍如何实现虚拟键盘, 因为后者实现相对容易, 而前者若实现不好, 则会出现体验的问题, 比如输入区域的视图在切换时会跳动等问题.

知识要点:

  • AndroidManifest.xml: activity属性 android:windowSoftInputMode 
  • InputMethodManager
  • Window 管理机制
  • View 管理机制

基本思路:

  • 假设最外层视图为LinearLayout
  • 虚拟键盘以layout形式直接添加到页面layout-xml中, 进入上述图中页面时, 默认是隐藏该虚拟键盘布局的, 输入法键盘也是默认收起的
  • 虚拟键盘高度应该为输入法键盘的高度, 因此, 输入法弹出时需要保存其高度值, 另外, 如果弹出虚拟键盘前未弹出过输入法键盘, 那么这时是不知道其高度值的, 因此需要预设一个高度值
  • 在切换键盘时, 动态调整内容区域(如聊天内容列表)的高度, 当虚拟键盘弹出时, 设置内容区域的高度为固定高度值, 而当虚拟键盘隐藏时, 还原内容区域的高度, 这样就可以实现键盘间的流畅切换了

实现代码:

具体用法:

> 页面布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1.0" />

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:src="@drawable/divider_vertical" />

    <LinearLayout
        android:id="@android:id/inputArea"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/white"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:paddingLeft="5dp"
        android:paddingRight="5dp">

        <EditText
            android:id="@android:id/input"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1.0"
            android:inputType="textMultiLine"
            android:maxLines="4">

            <requestFocus />
        </EditText>

        <ImageView
            android:id="@+id/emoji"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:contentDescription="@null"
            android:paddingBottom="5dp"
            android:paddingTop="5dp"
            android:src="@mipmap/ic_launcher" />
    </LinearLayout>

    <FrameLayout
        android:id="@+id/emoji_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:background="#aaa"
        android:minHeight="200dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="Hello, Emoji!" />
    </FrameLayout>
</LinearLayout>

layout-xml: activity_main.xml

> 页面代码

public class MainActivity extends AppCompatActivity
        implements View.OnTouchListener, View.OnClickListener {

    private ListView mListView;
    private EditText mEditText;
    private ImageView mEmojiImage;

    private View mEmojiLayout;

    private VirtualKeyboardController mVirtualKeyboardController;
    private LayoutManager mLayoutManager;
    private SoftKeyboardCompat mSoftKeyboardCompat;

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

        mListView = (ListView) findViewById(android.R.id.list);
        mListView.setOnTouchListener(this);
        initListAdapter();

        mEditText = (EditText) findViewById(android.R.id.input);
        mEditText.setOnClickListener(this);

        mEmojiImage = (ImageView) findViewById(R.id.emoji);
        mEmojiImage.setOnClickListener(this);

        mEmojiLayout = findViewById(R.id.emoji_layout);

        mVirtualKeyboardController = new VirtualKeyboardController(this);
        mSoftKeyboardCompat = new SoftKeyboardCompat(this);
        mLayoutManager = new LinearLayoutManager(this, mSoftKeyboardCompat);
        mLayoutManager.setContentView(mListView);
        mLayoutManager.setSoftInputFocusView(mEditText);
        mLayoutManager.setEmojiKeyboardView(mEmojiLayout);
        mVirtualKeyboardController.setLayoutManager(mLayoutManager);
    }

    // 略, 详见github
    ...
}

扩展用法:

如果页面布局的最外层视图不是LinearLayout, 扩展 VirtualKeyboardController.LayoutManager 接口即可, 可参考 LinearLayoutManager 实现代码.

相关:

END.

时间: 2024-11-04 19:37:55

Android开发案例 - 自定义虚拟键盘的相关文章

android开发(45) 自定义软键盘(输入法)

概述 在项目开发中遇到一个需求,”只要数字键盘的输入,仅仅有大写字母的输入,某些输入法总是会提示更新,弹出广告等“,使得我们需要自定义输入. 关联到的知识 KeyboardView      一个视图对象,展示了键盘.它需要关联到一个 Keyboard对象才能展示. Keyboard              键盘对象,通过加载xml的配置获得键盘的排列. xml 文件键盘描述     一个xml文件,放置在 xml 资源文件夹下,描述了 显示的键盘按钮,和排列,键盘宽度和高度等. 具体实现 准

Android使用xml自定义软键盘效果(附源码)

Android使用xml自定义软键盘效果原理: 1,软键盘其实是个控件,使用android.inputmethodserver.KeyboardView类定义. 2,主布局中使用帧布局,当我们需要显示软键盘时设置为可见,不需要时设置为不可见. 3,编写xml文件,定义键盘内容.使用xml文件填充KeyBoardView布局 4,设置EditText的监听事件. 完成键盘开发. 上效果图: 1,源码研究android.inputmethodserver.KeyboardView: /* * Cop

Android开发之自定义View-可动画展开收缩View的实现

有时候需要点击一个view可以动画展开和收缩折叠一个View这样的效果,这样就可以直接自定义View来实现. 本例中,采用继承FrameLayout来实现自定义的ExpandView.下面将详细介绍各个部分来实现该类以及如何使用该自定义视图. 效果图如下: 未展开效果: 正在向上折叠收缩中的效果: 已经展开效果: 自定义展开类:ExpandView的实现: package com.czm.customview; import android.content.Context; import and

Android开发之自定义TabHost文字及背景(源代码分享)

使用TabHost 可以在一个屏幕间进行不同版面的切换,而系统自带的tabhost界面较为朴素,我们应该如何进行自定义修改优化呢 MainActivity的源代码 package com.dream.ledong; import android.app.TabActivity; import android.content.Intent; import android.graphics.Color; import android.os.Bundle; import android.view.Gr

Android开发:自定义GridView/ListView数据源

http://mobile.51cto.com/android-259861.htm 在开发中,我们常常会遇到比较复杂的GridView/ListView的布局,重新实现BaseAdapter不但能帮助我们实现我们想要的布局效果,并且在绑定大数据量时也不会感觉有卡壳现象.记得以前用一个ListView直接去绑定手机内的联系人Cursor(一百多号人),滑动的时候就会有卡的感觉.今天决定写个Demo是因为在项目中可能会要实现这样的一个效果:一个GridView中绑定4个ImageButton,有些

Android开发之自定义Dialog二次打开报错问题解决

之前自定义了一个AlertDialog对话框,第一次点击时正常,但第二次调用时会出现错误:java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first. 关于这个错误纠结了我好久,在网上百度了也不少,但感觉解决效果都达不到自己想要的效果.网上的解释说是一个子视图指定了多个父视图.由此可以推断出,在第二

Android开发之自定义HorizontalScrollView视图实现仿ViewPager效果

开发过程中,需要达到 HorizontalScrollView和ViewPager的效果,于是直接重写了HorizontalScrollView来达到实现ViewPager的效果. 实际效果图如下: (1)自定义HorizontalScrollView类:AppHorizontalScrollView实现: package com.czm.ui.view; import java.util.ArrayList; import android.content.Context; import and

Android开发之自定义Spinner样式的效果实现(源代码实现)

android系统自带的Spinner样式是远远满足不了我们实际开发过程中对Spinner UI风格的要求,因此我们肯定需要为了切合整个应用的风格,修改我们的Spinner样式.系统给我们提供了两种常见的修改方式,一个是用XML方式静态,另一个就是Java代码动态来修改啦,我们这篇文章呢主要就是介绍如何动态修改Spinner的样式.我的实现方法呢,是自己构造一个SpinnerAdapter,继承来自ArrayAdapter,重写getDropDownView(),getView()这两个方法就好

Android开发之自定义圆角矩形图片ImageView的实现

android中的ImageView只能显示矩形的图片,这样一来不能满足我们其他的需求,比如要显示圆角矩形的图片,这个时候,我们就需要自定义ImageView了,其原理就是首先获取到图片的Bitmap,然后进行裁剪对应的圆角矩形的bitmap,然后在onDraw()进行绘制圆角矩形图片输出. 效果图如下: 自定义的圆形的ImageView类的实现代码如下: package com.xc.xcskin.view; import android.content.Context; import and