天天看点

android 自定义输入法研究(二)

  上一篇文章,介绍了自定义输入法的界面和布局,候选词列表采用的是GIF列表图片的形式。现在我把候选词列表改成正真的候选词列表,可以点击选词。如下图:

android 自定义输入法研究(二)

   候选词列表主要采用的Recyclerview来实现的(自己同时也学习了Recyclerview的使用方法)。候选词我存放到SQLite数据库中(网上下载的),常用单词可能不全。当输入某一个或者某一组字母的时候,候选词列表就会显示出当前的联想词来。用户可以左右滑动来选择单词,单击输入。

  以下是联想词的选择SQL语句:

String sql = "select english from t_words where english like ?";
Cursor cursor = mSQLiteDatabase.rawQuery(sql, new String[]{inputWord + "%"});
           

其实很简单,采用了SQL语句中的通配符来实现。直接上代码:

数据库操作类 DbUtils.java,比较简单,主要是以实现功能为目的。

package com.manboker.wb.momentcamime.db;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

import com.manboker.wb.momentcamime.R;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;

/**
 * Author: aaa
 * Date: 2016/11/15 16:07.
 */
public class DbUtils {
    private Context mContext;
    private volatile static DbUtils dbUtils;
    private static final String DATABASE_PATH = android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/dictionary";
    // 定义数据库的名字
    private final String DATABASE_FILENAME = "dictionary.db";
    private SQLiteDatabase mSQLiteDatabase;

    private DbUtils(Context context) {
        mContext = context;
    }

    public static DbUtils getInstance(Context context) {
        if (dbUtils == null) {
            synchronized (DbUtils.class) {
                if (dbUtils == null) {
                    dbUtils = new DbUtils(context);
                }
            }
        }
        return dbUtils;
    }

    // 打开数据库
    public SQLiteDatabase openDatabase() {
        try {
            // 获得dictionary.db文件的绝对路径
            String databaseFilename = DATABASE_PATH + "/" + DATABASE_FILENAME;
            File dir = new File(DATABASE_PATH);
            // 如果目录不存在,则创建这个目录
            if (!dir.exists()) {
                if (!dir.mkdir()) {
                    Log.i("aaa", "DATABASE_PATH = " + DATABASE_PATH + " Failed");
                }
            }
            // 如果在/sdcard/dictionary目录中不存在
            // dictionary.db文件,则从res\raw目录中复制这个文件到
            // SD卡的目录(/sdcard/dictionary)
            if (!(new File(databaseFilename)).exists()) {
                // 获得封装dictionary.db文件的InputStream对象
                InputStream is = mContext.getResources().openRawResource(R.raw.dictionary);
                FileOutputStream fos = new FileOutputStream(databaseFilename);
                byte[] buffer = new byte[];
                int count = ;
                // 开始复制dictionary.db文件
                while ((count = is.read(buffer)) > ) {
                    fos.write(buffer, , count);
                }
                // 关闭文件流
                fos.close();
                is.close();
            }
            // 打开/sdcard/dictionary目录中的dictionary.db文件
            mSQLiteDatabase = SQLiteDatabase.openOrCreateDatabase(databaseFilename, null);
            return mSQLiteDatabase;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public ArrayList<String> getCandidateWords(String inputWord) {
        ArrayList<String> arrayList = new ArrayList<String>();
        // 查询指定的单词
        String sql = "select english from t_words where english like ?";

        Cursor cursor = mSQLiteDatabase.rawQuery(sql, new String[]{inputWord + "%"});
        String result = "@@@";
        // 如果查找单词,显示其中文的意思
        while (cursor.moveToNext()) {
            result = cursor.getString(cursor.getColumnIndex("english"));
            arrayList.add(result);
        }
        cursor.close();
        return arrayList;
    }
}
           

候选词之间的间隔线 DividerItemDecoration.java

package com.manboker.wb.momentcamime.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;

/**
 * Author: aaa
 * Date: 2016/11/15 10:57.
 */
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
    private Context mContext;
    private Drawable mDivider;
    private int mOrientation;
    public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
    public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
    //我们通过获取系统属性中的listDivider来添加,在系统中的AppTheme中设置
    public static final int[] ATRRS = new int[]{
            android.R.attr.listDivider
    };


    public DividerItemDecoration(Context context, int orientation) {
        this.mContext = context;
        final TypedArray ta = context.obtainStyledAttributes(ATRRS);
        this.mDivider = ta.getDrawable();
        ta.recycle();
        setOrientation(orientation);
    }

    //设置屏幕的方向
    public void setOrientation(int orientation) {
        if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
            throw new IllegalArgumentException("invalid orientation");
        }
        mOrientation = orientation;
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDraw(c, parent, state);
        if (mOrientation == HORIZONTAL_LIST) {
            drawVerticalLine(c, parent, state);
        } else {
            drawHorizontalLine(c, parent, state);
        }
    }

    //画横线, 这里的parent其实是显示在屏幕显示的这部分
    public void drawHorizontalLine(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int left = parent.getPaddingLeft();
        int right = parent.getWidth() - parent.getPaddingRight();
        final int childCount = parent.getChildCount();
        for (int i = ; i < childCount; i++) {
            final View child = parent.getChildAt(i);

            //获得child的布局信息
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            final int top = child.getBottom() + params.bottomMargin;
            final int bottom = top + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    //由于Divider也有长宽高,每一个Item需要向下或者向右偏移
    //画竖线
    public void drawVerticalLine(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int top = parent.getPaddingTop();
        int bottom = parent.getHeight() - parent.getPaddingBottom();
        final int childCount = parent.getChildCount();
        for (int i = ; i < childCount; i++) {
            final View child = parent.getChildAt(i);

            //获得child的布局信息
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            final int left = child.getRight() + params.rightMargin;
            final int right = left + mDivider.getIntrinsicWidth();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        if (mOrientation == HORIZONTAL_LIST) {
            //画横线,就是往下偏移一个分割线的高度
            outRect.set(, , , mDivider.getIntrinsicHeight());
        } else {
            //画竖线,就是往右偏移一个分割线的宽度
            outRect.set(, , mDivider.getIntrinsicWidth(), );
        }
    }
}
           

回调接口

package com.manboker.wb.momentcamime.interf;

import android.view.View;

/**
 * Author: aaa
 * Date: 2016/11/15 11:40.
 */
public interface IRecyclerItemClickListener {
    public void onItemClick(View view, String text);
}
           

修改之后的 MomentCamIME.java

package com.manboker.wb.momentcamime;

import android.inputmethodservice.InputMethodService;
import android.view.KeyEvent;
import android.view.View;

import com.manboker.wb.momentcamime.db.DbUtils;
import com.manboker.wb.momentcamime.interf.IKeyBoard;
import com.manboker.wb.momentcamime.interf.IRecyclerItemClickListener;
import com.manboker.wb.momentcamime.view.CandidateView;
import com.manboker.wb.momentcamime.view.MyKeyboardView;

import java.util.ArrayList;


/**
 * Author: aaa
 * Date: 2016/11/8 15:58.
 */
public class MomentCamIME extends InputMethodService {

    private MyKeyboardView mMyKeyboardView;
    private CandidateView mCandidateView;

    private IKeyBoard mIKeyBoard = new IKeyBoard() {
        @Override
        public void setInputText(String text, boolean b) {
            if (!b) {
                getCurrentInputConnection().commitText(text, );
            } else {
                getCurrentInputConnection().setComposingText(mMyKeyboardView.mInputWord, );
            }
        }

        @Override
        public void deleteInputOne() {
            if (mMyKeyboardView.mInputWord.length() >= ) {
                getCurrentInputConnection().setComposingText(mMyKeyboardView.mInputWord, );
            }

            if (mMyKeyboardView.mInputWord.length() == ) {
                getCurrentInputConnection().deleteSurroundingText(, );
            }
        }

        @Override
        public void enter() {
            getCurrentInputConnection().sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
        }

        @Override
        public void done() {
            requestHideSelf();
        }

        @Override
        public void setCondiateShow(boolean b, ArrayList<String> words) {
            setCandidatesViewShown(b);
            if (b) {
                mCandidateView.refreshWords(words);
            }
        }
    };

    private IRecyclerItemClickListener mIRecyclerItemClickListener = new IRecyclerItemClickListener() {
        @Override
        public void onItemClick(View view, String text) {
            getCurrentInputConnection().commitText(text, );

            mMyKeyboardView.mInputWord = "";
            setCandidatesViewShown(false);
        }
    };

    @Override
    public void onInitializeInterface() {
        super.onInitializeInterface();
        DbUtils.getInstance(this).openDatabase();
    }

    @Override
    public View onCreateInputView() {
        mMyKeyboardView = new MyKeyboardView(this);
        mMyKeyboardView.setInterface(mIKeyBoard);

        return mMyKeyboardView;
    }

    @Override
    public View onCreateCandidatesView() {
        mCandidateView = new CandidateView(this);
        mCandidateView.setOnRecyclerItemClickListener(mIRecyclerItemClickListener);

        return mCandidateView;
    }

    @Override
    public void showWindow(boolean showInput) {
        if (mMyKeyboardView != null) {
            mMyKeyboardView.mInputWord = "";
            setCandidatesViewShown(false);
        }
        super.showWindow(showInput);
    }
}
           

修改之后的 MyKeyboardView.java

package com.manboker.wb.momentcamime.view;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout;

import com.manboker.wb.momentcamime.R;
import com.manboker.wb.momentcamime.db.DbUtils;
import com.manboker.wb.momentcamime.interf.IKeyBoard;

import java.util.ArrayList;
import java.util.Arrays;


/**
 * Author: aaa
 * Date: 2016/11/8 16:14.
 */
public class MyKeyboardView extends LinearLayout {
    private final int LETTER_NUM = ;//字母数量

    private Context mContext;
    private IKeyBoard mIKeyBoard;

    private Button mButtonA, mButtonB, mButtonC, mButtonD, mButtonE, mButtonF, mButtonG, mButtonH, mButtonI, mButtonJ, mButtonK, mButtonL,
            mButtonM, mButtonN, mButtonO, mButtonP, mButtonQ, mButtonR, mButtonS, mButtonT, mButtonU, mButtonV, mButtonW, mButtonX, mButtonY, mButtonZ;
    private Button[] mLetterButtons = new Button[]{mButtonA, mButtonB, mButtonC, mButtonD, mButtonE, mButtonF, mButtonG, mButtonH, mButtonI, mButtonJ, mButtonK,
            mButtonL, mButtonM, mButtonN, mButtonO, mButtonP, mButtonQ, mButtonR, mButtonS, mButtonT, mButtonU, mButtonV, mButtonW, mButtonX, mButtonY, mButtonZ};

    private Integer[] mLetterButtonIds = new Integer[]{
            R.id.keyboard_a, R.id.keyboard_b, R.id.keyboard_c, R.id.keyboard_d, R.id.keyboard_e, R.id.keyboard_f, R.id.keyboard_g, R.id.keyboard_h,
            R.id.keyboard_i, R.id.keyboard_j, R.id.keyboard_k, R.id.keyboard_l, R.id.keyboard_m, R.id.keyboard_n, R.id.keyboard_o, R.id.keyboard_p,
            R.id.keyboard_q, R.id.keyboard_r, R.id.keyboard_s, R.id.keyboard_t, R.id.keyboard_u, R.id.keyboard_v, R.id.keyboard_w, R.id.keyboard_x,
            R.id.keyboard_y, R.id.keyboard_z};

    private String mLowerletters;//字母小写
    private String mUpperletters;//字母大写

    private String mLowerNumber;//数字小写
    private String mUpperNumber;//数字大写

    private ImageButton mIBtnShift, mIBtnDelete, mIBtnDone, mIBtnSpace, mIBtnReturn;
    private Button mBtnDot, mBtnComma;
    private Button mBtnChange123;
    private boolean mCapsLock, mNumberCapsLock;// true - 大写锁定

    private View mLetterLayout, mNumberLayout;

    public String mInputWord = "";//保存输入法输入的内容

    public MyKeyboardView(Context context) {
        super(context);
        mContext = context;
        init();
        initABC();
        init123();

        showLetterLayout(true);
        showNumberLayout(false);

    }

    private void init() {
        // 加载布局
        LayoutInflater.from(mContext).inflate(R.layout.main, this);
        mLetterLayout = findViewById(R.id.main_letter);
        mNumberLayout = findViewById(R.id.main_number);

        mCapsLock = false;
        mNumberCapsLock = false;
        mLowerletters = "abcdefghijklmnopqrstuvwxyz";
        mUpperletters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

        mLowerNumber = "1234567890@#$%&*-=()!\"':;/?";
        mUpperNumber = "~±×÷•°`´{}©£€^®¥_+[]¡<>¢|\\¿";
    }

    /**
     * 初始化ABC布局
     */
    private void initABC() {
        for (int i = ; i < LETTER_NUM; i++) {
            mLetterButtons[i] = (Button) findViewById(mLetterButtonIds[i]);
            mLetterButtons[i].setOnClickListener(new MyOnClickListener());
        }

        mBtnDot = (Button) findViewById(R.id.keyboard_dot);
        mBtnDot.setOnClickListener(new MyOnClickListener());
        mBtnComma = (Button) findViewById(R.id.keyboard_comma);
        mBtnComma.setOnClickListener(new MyOnClickListener());

        mIBtnShift = (ImageButton) findViewById(R.id.keyboard_shift);
        mIBtnDelete = (ImageButton) findViewById(R.id.keyboard_delete);
        mIBtnDone = (ImageButton) findViewById(R.id.keyboard_done);
        mIBtnSpace = (ImageButton) findViewById(R.id.keyboard_space);
        mIBtnReturn = (ImageButton) findViewById(R.id.keyboard_return);
        mIBtnShift.setOnClickListener(new MyOnClickListener());
        mIBtnDelete.setOnClickListener(new MyDeleteClickListener());
        mIBtnDelete.setOnTouchListener(new MyDeleteClickListener());
        mIBtnDone.setOnClickListener(new MyOnClickListener());
        mIBtnSpace.setOnClickListener(new MyOnClickListener());
        mIBtnReturn.setOnClickListener(new MyOnClickListener());

        mBtnChange123 = (Button) findViewById(R.id.keyboard_change_123);
        mBtnChange123.setOnClickListener(new MyOnClickListener());
    }

    private class MyOnClickListener implements OnClickListener {

        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.keyboard_a:
                case R.id.keyboard_b:
                case R.id.keyboard_c:
                case R.id.keyboard_d:
                case R.id.keyboard_e:
                case R.id.keyboard_f:
                case R.id.keyboard_g:
                case R.id.keyboard_h:
                case R.id.keyboard_i:
                case R.id.keyboard_j:
                case R.id.keyboard_k:
                case R.id.keyboard_l:
                case R.id.keyboard_m:
                case R.id.keyboard_n:
                case R.id.keyboard_o:
                case R.id.keyboard_p:
                case R.id.keyboard_q:
                case R.id.keyboard_r:
                case R.id.keyboard_s:
                case R.id.keyboard_t:
                case R.id.keyboard_u:
                case R.id.keyboard_v:
                case R.id.keyboard_w:
                case R.id.keyboard_x:
                case R.id.keyboard_y:
                case R.id.keyboard_z:
                    clickLetter(view.getId());
                    break;
                case R.id.keyboard_shift:
                    clickShift();
                    break;
                case R.id.keyboard_num_shift:
                    clickNumberShift();
                    break;

                case R.id.keyboard_done:
                case R.id.keyboard_num_done:
                    mIKeyBoard.done();
                    break;
                case R.id.keyboard_space://空格
                    showCandidateView(mInputWord);
                case R.id.keyboard_num_space:
                    mIKeyBoard.setInputText(mInputWord + " ", false);
                    mInputWord = "";
                    break;
                case R.id.keyboard_return:
                    mInputWord = "";
                    showCandidateView(mInputWord);
                case R.id.keyboard_num_return:
                    mIKeyBoard.enter();
                    break;
                case R.id.keyboard_dot://点
                    showCandidateView(mInputWord);
                case R.id.keyboard_num_dot:
                    mIKeyBoard.setInputText(mInputWord + ".", false);
                    mInputWord = "";
                    break;
                case R.id.keyboard_comma://逗号
                    showCandidateView(mInputWord);
                case R.id.keyboard_num_comma:
                    mIKeyBoard.setInputText(mInputWord + ",", false);
                    mInputWord = "";
                    break;
                case R.id.keyboard_change_123://切换数字键盘
                    mIKeyBoard.setInputText(mInputWord, false);
                    mInputWord = "";
                    showCandidateView(mInputWord);
                    showLetterLayout(false);
                    showNumberLayout(true);
                    if (mNumberCapsLock) {//大写转换成小写
                        clickNumberShift();
                    }
                    break;

                case R.id.keyboard_num_1:
                case R.id.keyboard_num_2:
                case R.id.keyboard_num_3:
                case R.id.keyboard_num_4:
                case R.id.keyboard_num_5:
                case R.id.keyboard_num_6:
                case R.id.keyboard_num_7:
                case R.id.keyboard_num_8:
                case R.id.keyboard_num_9:
                case R.id.keyboard_num_10:
                case R.id.keyboard_num_11:
                case R.id.keyboard_num_12:
                case R.id.keyboard_num_13:
                case R.id.keyboard_num_14:
                case R.id.keyboard_num_15:
                case R.id.keyboard_num_16:
                case R.id.keyboard_num_17:
                case R.id.keyboard_num_18:
                case R.id.keyboard_num_19:
                case R.id.keyboard_num_20:
                case R.id.keyboard_num_21:
                case R.id.keyboard_num_22:
                case R.id.keyboard_num_23:
                case R.id.keyboard_num_24:
                case R.id.keyboard_num_25:
                case R.id.keyboard_num_26:
                case R.id.keyboard_num_27:
                    clickNumber(view.getId());
                    break;

                case R.id.keyboard_num_change_abc://切换字母键盘
                    showNumberLayout(false);
                    showLetterLayout(true);
                    if (mCapsLock) {//如果是大写,则转换成小写
                        clickShift();
                    }
                    break;
            }
        }
    }

    public void setInterface(IKeyBoard iKeyBoard) {
        mIKeyBoard = iKeyBoard;
    }

    /**
     * 点击Shift
     */
    private void clickShift() {
        mCapsLock = !mCapsLock;
        if (mCapsLock) {//大写锁定
            mIBtnShift.setImageResource(R.mipmap.sym_keyboard_shift_click);
            for (int i = ; i < LETTER_NUM; i++) {
                mLetterButtons[i].setText(String.valueOf(mUpperletters.charAt(i)));
            }
        } else {
            mIBtnShift.setImageResource(R.mipmap.sym_keyboard_shift);
            for (int i = ; i < LETTER_NUM; i++) {
                mLetterButtons[i].setText(String.valueOf(mLowerletters.charAt(i)));
            }
        }
    }

    /**
     * 点击字母按键
     */
    private void clickLetter(int id) {
        int idx = Arrays.asList(mLetterButtonIds).indexOf(id);
        if (idx == -) {
            return;
        }
        String word = "";
        if (mCapsLock) {
            word = String.valueOf(mUpperletters.charAt(idx));
        } else {
            word = String.valueOf(mLowerletters.charAt(idx));
        }

        mInputWord += word;
        mIKeyBoard.setInputText(mInputWord, true);

        showCandidateView(mInputWord);

    }

    private Handler mHandler = new Handler();
    private CheckForLongPress mPendingCheckForLongPress = null;

    /**
     * 删除按钮事件监听
     */
    private class MyDeleteClickListener implements OnClickListener, OnTouchListener {

        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.keyboard_delete:
                    if (mInputWord.length() > ) {
                        mInputWord = mInputWord.substring(, mInputWord.length() - );
                        showCandidateView(mInputWord);
                    }
                case R.id.keyboard_num_delete:
                    mIKeyBoard.deleteInputOne();
                    break;
            }
        }

        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            if (view.getId() == R.id.keyboard_delete || view.getId() == R.id.keyboard_num_delete) {
                if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
                    removeLongPressCallback();
                    showCandidateView(mInputWord);
                } else if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
                    checkForLongClick();
                }
            }
            return false;
        }
    }

    private void checkForLongClick() {
        if (mPendingCheckForLongPress == null) {
            mPendingCheckForLongPress = new CheckForLongPress();
        }
        mHandler.postDelayed(mPendingCheckForLongPress, );
    }

    class CheckForLongPress implements Runnable {
        int currentKeycode = ;

        public void run() {
            longPressDelete(currentKeycode);
            mHandler.postDelayed(this, );
        }
    }

    private void longPressDelete(int keycode) {
        mIKeyBoard.deleteInputOne();
        if (mInputWord.length() > ) {
            mInputWord = mInputWord.substring(, mInputWord.length() - );
        }
    }

    private void removeLongPressCallback() {
        if (mPendingCheckForLongPress != null) {
            mHandler.removeCallbacks(mPendingCheckForLongPress);
            mPendingCheckForLongPress = null;
        }
    }

    private final int NUMBER_NUM = ;//数字数量
    private Button mButton1, mButton2, mButton3, mButton4, mButton5, mButton6, mButton7, mButton8, mButton9, mButton10, mButton11, mButton12,
            mButton13, mButton14, mButton15, mButton16, mButton17, mButton18, mButton19, mButton20, mButton21, mButton22, mButton23, mButton24,
            mButton25, mButton26, mButton27;
    private Button[] mNumberButtons = new Button[]{mButton1, mButton2, mButton3, mButton4, mButton5, mButton6, mButton7, mButton8, mButton9, mButton10, mButton11,
            mButton12, mButton13, mButton14, mButton15, mButton16, mButton17, mButton18, mButton19, mButton20, mButton21, mButton22, mButton23, mButton24,
            mButton25, mButton26, mButton27};

    private Integer[] mNumberButtonIds = new Integer[]{
            R.id.keyboard_num_1, R.id.keyboard_num_2, R.id.keyboard_num_3, R.id.keyboard_num_4, R.id.keyboard_num_5, R.id.keyboard_num_6, R.id.keyboard_num_7,
            R.id.keyboard_num_8, R.id.keyboard_num_9, R.id.keyboard_num_10, R.id.keyboard_num_11, R.id.keyboard_num_12, R.id.keyboard_num_13, R.id.keyboard_num_14,
            R.id.keyboard_num_15, R.id.keyboard_num_16, R.id.keyboard_num_17, R.id.keyboard_num_18, R.id.keyboard_num_19, R.id.keyboard_num_20, R.id.keyboard_num_21,
            R.id.keyboard_num_22, R.id.keyboard_num_23, R.id.keyboard_num_24, R.id.keyboard_num_25, R.id.keyboard_num_26, R.id.keyboard_num_27};
    private Button mNumberBtnDot, mNumberBtnComma;
    private ImageButton mNumberIBtnShift, mNumberIBtnDelete, mNumberIBtnDone, mNumberIBtnSpace, mNumberIBtnReturn;
    private Button mNumberBtnChangeabc;

    /**
     * 初始化数字键盘
     */
    private void init123() {
        for (int i = ; i < NUMBER_NUM; i++) {
            mNumberButtons[i] = (Button) findViewById(mNumberButtonIds[i]);
            mNumberButtons[i].setOnClickListener(new MyOnClickListener());
        }

        mNumberBtnDot = (Button) findViewById(R.id.keyboard_num_dot);
        mNumberBtnDot.setOnClickListener(new MyOnClickListener());
        mNumberBtnComma = (Button) findViewById(R.id.keyboard_num_comma);
        mNumberBtnComma.setOnClickListener(new MyOnClickListener());

        mNumberIBtnShift = (ImageButton) findViewById(R.id.keyboard_num_shift);
        mNumberIBtnDelete = (ImageButton) findViewById(R.id.keyboard_num_delete);
        mNumberIBtnDone = (ImageButton) findViewById(R.id.keyboard_num_done);
        mNumberIBtnSpace = (ImageButton) findViewById(R.id.keyboard_num_space);
        mNumberIBtnReturn = (ImageButton) findViewById(R.id.keyboard_num_return);
        mNumberIBtnShift.setOnClickListener(new MyOnClickListener());
        mNumberIBtnDelete.setOnClickListener(new MyDeleteClickListener());
        mNumberIBtnDelete.setOnTouchListener(new MyDeleteClickListener());
        mNumberIBtnDone.setOnClickListener(new MyOnClickListener());
        mNumberIBtnSpace.setOnClickListener(new MyOnClickListener());
        mNumberIBtnReturn.setOnClickListener(new MyOnClickListener());

        mNumberBtnChangeabc = (Button) findViewById(R.id.keyboard_num_change_abc);
        mNumberBtnChangeabc.setOnClickListener(new MyOnClickListener());
    }

    /**
     * 点击字母按键
     */
    private void clickNumber(int id) {
        int idx = Arrays.asList(mNumberButtonIds).indexOf(id);
        if (idx == -) {
            return;
        }
        if (mNumberCapsLock) {
            mIKeyBoard.setInputText(String.valueOf(mUpperNumber.charAt(idx)), false);
        } else {
            mIKeyBoard.setInputText(String.valueOf(mLowerNumber.charAt(idx)), false);
        }
    }

    /**
     * 点击Shift
     */
    private void clickNumberShift() {
        mNumberCapsLock = !mNumberCapsLock;
        if (mNumberCapsLock) {//大写锁定
            mNumberIBtnShift.setImageResource(R.mipmap.sym_keyboard_shift_click);
            for (int i = ; i < NUMBER_NUM; i++) {
                mNumberButtons[i].setText(String.valueOf(mUpperNumber.charAt(i)));
            }
        } else {
            mNumberIBtnShift.setImageResource(R.mipmap.sym_keyboard_shift);
            for (int i = ; i < NUMBER_NUM; i++) {
                mNumberButtons[i].setText(String.valueOf(mLowerNumber.charAt(i)));
            }
        }
    }

    /**
     * 隐藏字母键盘布局
     *
     * @param b
     */
    private void showLetterLayout(boolean b) {
        int show = View.VISIBLE;
        if (!b) {
            show = View.GONE;
        }
        mLetterLayout.setVisibility(show);
    }

    /**
     * 隐藏数字键盘布局
     *
     * @param b
     */
    private void showNumberLayout(boolean b) {
        int show = View.VISIBLE;
        if (!b) {
            show = View.GONE;
        }
        mNumberLayout.setVisibility(show);
    }

    ArrayList<String> words = null;//从数据库中找到的单词列表

    /*
     * 显示候选词列表
     */
    private void showCandidateView(final String word) {
        Log.i("aaa", "word=" + word + " size:" + word.length());
        if (word.length() <= ) {
            mIKeyBoard.setCondiateShow(false, null);
        } else {
            final Handler handler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    switch (msg.what) {
                        case :
                            if (words.size() >  && mInputWord.length() > ) {
                                mIKeyBoard.setCondiateShow(true, words);
                            }
                            break;
                        default:
                            break;
                    }
                }
            };
            new Thread() {
                @Override
                public void run() {
                    super.run();
                    words = DbUtils.getInstance(mContext).getCandidateWords(word);
                    Message msg = new Message();
                    msg.obj = ;
                    msg.what = ;
                    handler.sendMessage(msg);
                }
            }.start();
        }
    }
}
           

修改后候选词View CandidateView.java

package com.manboker.wb.momentcamime.view;

import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.manboker.wb.momentcamime.R;
import com.manboker.wb.momentcamime.interf.IRecyclerItemClickListener;

import java.util.ArrayList;

/**
 * Author: aaa
 * Date: 2016/11/11 09:17.
 */
public class CandidateView extends LinearLayout {
    private Context mContext;
    private RecyclerView mRecyclerView;
    private ArrayList<String> mDatas;
    private MyAdapter mMyAdapter;

    private IRecyclerItemClickListener mIRecyclerItemClickListener;

    public CandidateView(Context context) {
        super(context);
        mContext = context;
        initData();
        init();
    }

    private void initData() {
        mDatas = new ArrayList<String>();

        mMyAdapter = new MyAdapter();
    }

    private void init() {
        LayoutInflater.from(mContext).inflate(R.layout.candidate, this);
        mRecyclerView = (RecyclerView) findViewById(R.id.candiate_rv);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false));//水平放置
        mRecyclerView.setAdapter(mMyAdapter);
        //这句就是添加我们自定义的分隔线
        mRecyclerView.addItemDecoration(new DividerItemDecoration(mContext, DividerItemDecoration.HORIZONTAL_LIST));
    }

    public void refreshWords(ArrayList<String> words) {
        mMyAdapter.setWords(words);
    }

    public void setOnRecyclerItemClickListener(IRecyclerItemClickListener iRecyclerItemClickListener) {
        mIRecyclerItemClickListener = iRecyclerItemClickListener;
    }

    private class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {

        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(mContext).inflate(R.layout.recylerview_item, parent, false);
            MyViewHolder viewHolder = new MyViewHolder(view);
            return viewHolder;
        }

        @Override
        public void onBindViewHolder(MyViewHolder holder, final int position) {
            if (mDatas.size() <= ) {
                return;
            }
            holder.mItemTextView.setText(mDatas.get(position));
            holder.mItemTextView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mIRecyclerItemClickListener.onItemClick(view, mDatas.get(position));
                }
            });
        }

        public void setWords(ArrayList<String> words) {
            mDatas = words;
            notifyDataSetChanged();
        }

        @Override
        public int getItemCount() {
            return mDatas.size();
        }

        public class MyViewHolder extends RecyclerView.ViewHolder {
            public TextView mItemTextView;

            public MyViewHolder(View itemView) {
                super(itemView);
                mItemTextView = (TextView) itemView.findViewById(R.id.recyclerview_item_tv);
            }
        }
    }
}
           

  以上实现了后输入法的只要功能,基本逻辑也是没有问题的,但是由于没有严格的测试,也许会有部分逻辑问题或者BUG,希望各位朋友仔细测试使用。以上代码仅供参考。