Android 自定義軟鍵盤遇到的問題
首先來分析一下軟鍵盤的基本屬性
- 軟鍵盤的實現
- 點選輸入框從底部彈出軟鍵盤
- 彈出軟鍵盤後焦點在輸入框
- 彈出軟鍵盤不遮擋輸入框
軟鍵盤的實現
可以使用KeyboardView也可以自己寫佈局寫點選事件(除特殊情況不推薦)
KeyboardView的簡單實現方法
一、在res下新建xml資料夾,在xml資料夾中新建keyboard.xml檔案
<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:keyWidth="33.3333%p" android:horizontalGap="0px"
android:verticalGap="0px" android:keyHeight="80dp">
<Row>
<Key android:codes="55" android:keyLabel="7" />
<Key android:codes="56" android:keyLabel="8" />
<Key android:codes="57" android:keyLabel="9" android:keyEdgeFlags="right"/>
</Row>
<Row>
<Key android:codes="52" android:keyLabel="4" />
<Key android:codes="53" android:keyLabel="5" />
<Key android:codes="54" android:keyLabel="6" android:keyEdgeFlags="right"/>
</Row >
<Row>
<Key android:codes="49" android:keyLabel="1" />
<Key android:codes="50" android:keyLabel="2" />
<Key android:codes="51" android:keyLabel="3" android:keyEdgeFlags="right"/>
</Row>
<Row>
<Key android:codes="46" android:keyLabel="." />
<Key android:codes="48" android:keyLabel="0" />
<Key android:codes="-3" android:keyEdgeFlags="right" android:keyLabel="OK"/>
</Row>
</Keyboard>
二、這個地方有的實現有點不一樣,一般來說不應該在每一個佈局裡都加入KeyboardViw,比如我使用的在MainActivity,Main裡面全是fragment所以就直接在佈局裡面了
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/img_bg">
<FrameLayout
android:id="@+id/frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="50dp">
</FrameLayout>
<android.inputmethodservice.KeyboardView
android:id="@+id/keyboardview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/write"
android:layout_alignParentBottom="true"
android:focusable="true"
android:usableInTouchMode="true"
android:visibility="invisible"/>
</RelativeLayout>
然後
import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.Context;
import android.inputmethodservice.InputMethodService;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.media.AudioManager;
import android.text.Editable;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.InputConnection;
import android.widget.EditText;
import com.kubu.terminal.R;
import java.util.List;
import static android.content.Context.AUDIO_SERVICE;
/**
* Created by steven on 2017/7/31.
*/
public class KeyBoradUtil extends InputMethodService implements KeyboardView.OnKeyboardActionListener
{
private Context mContext;//上下文物件
private KeyboardView mKeyboardView;
private Keyboard mKeyboard;
private EditText mEdit;
/**
* 必須activity作為上下文對像 *
*
* @param context
*/
public KeyBoradUtil(Context context)
{
mContext = context;
//初始化鍵盤佈局,下面在放進 KeyBoardView裡面去。
mKeyboard = new Keyboard(mContext, R.xml.keyboard);
//配置keyBoardView
try
{
mKeyboardView = (KeyboardView) ((Activity)mContext).findViewById(R.id.keyboardview);
mKeyboardView.setKeyboard(mKeyboard); //設定鍵盤
mKeyboardView.setEnabled(true);
mKeyboardView.setPreviewEnabled(false); //這個是,效果圖按住是出來的預覽圖。
//設定監聽,不設定的話會報錯。監聽放下面了。
mKeyboardView.setOnKeyboardActionListener(this);
} catch (Exception e)
{
Log.e("sun", "keyview初始化失敗");
}
}
public void setEdit(EditText mEdit)
{
this.mEdit = mEdit;
}
@Override
public void onPress(int primaryCode)
{
}
@Override
public void onRelease(int primaryCode)
{
}
@Override
public void onKey(int primaryCode, int[] keyCodes)
{
Editable editable = mEdit.getText();
int start = mEdit.getSelectionStart();
if (primaryCode == Keyboard.KEYCODE_CANCEL)
{// 完成
hideKeyboard();
} else if (primaryCode == Keyboard.KEYCODE_DELETE)
{// 回退
if (editable != null && editable.length() > 0)
{
if (start > 0)
{
editable.delete(start - 1, start);
}
}
} else if (primaryCode == 57419)
{ // go left
if (start > 0)
{
mEdit.setSelection(start - 1);
}
} else if (primaryCode == 57421)
{ // go right
if (start < mEdit.length())
{
mEdit.setSelection(start + 1);
}
} else
{
editable.insert(start, Character.toString((char) primaryCode));
}
}
@Override
public void onText(CharSequence text)
{
}
@Override
public void swipeLeft()
{
}
@Override
public void swipeRight()
{
}
@Override
public void swipeDown()
{
}
@Override
public void swipeUp()
{
}
//顯示軟鍵盤
public void showKeyboard()
{
int visibility = mKeyboardView.getVisibility();
if (visibility == View.GONE || visibility == View.INVISIBLE)
{
mKeyboardView.setVisibility(View.VISIBLE);
int hight = mKeyboardView.getHeight();
Log.d("TAG",hight+"");
ObjectAnimator bad = ObjectAnimator.ofFloat(mKeyboardView, "translationY", hight, 0);
bad.setDuration(300);
bad.start();
}
}
//關閉軟鍵盤
public void hideKeyboard()
{
int visibility = mKeyboardView.getVisibility();
if (visibility == View.VISIBLE)
{
int hight = mKeyboardView.getHeight();
ObjectAnimator bad = ObjectAnimator.ofFloat(mKeyboardView, "translationY", 0, hight);
bad.setDuration(300);
bad.start();
bad.addListener(new Animator.AnimatorListener()
{
@Override
public void onAnimationStart(Animator animation)
{
}
@Override
public void onAnimationEnd(Animator animation)
{
mKeyboardView.setVisibility(View.INVISIBLE);
}
@Override
public void onAnimationCancel(Animator animation)
{
}
@Override
public void onAnimationRepeat(Animator animation)
{
}
});
}
}
}
注意在佈局裡KeyboardView的android:visibility=”invisible”不能為gone,否則getHeight()為空 ,然後初始化 mKeyBoard = new KeyBoradUtil(getActivity()),並在editText的setOnTouchListener裡面顯示軟鍵盤。
@Override
public boolean onTouch(View v, MotionEvent event)
{
switch (v.getId())
{
case R.id.et_phone:
//隱藏系統軟鍵盤
setInputType(et_phone);
mKeyBoard.setEdit(et_phone);
break;
case R.id.et_password:
//隱藏系統軟鍵盤
setInputType(et_password);
mKeyBoard.setEdit(et_password);
break;
}
mKeyBoard.showKeyboard();
return false;
}
private void setInputType(EditText editText)
{
if (android.os.Build.VERSION.SDK_INT <= 10)
{//4.0以下 danielinbiti
editText.setInputType(InputType.TYPE_NULL);
} else
{
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
try
{
Class<EditText> cls = EditText.class;
Method setShowSoftInputOnFocus = cls.getMethod("setShowSoftInputOnFocus", boolean.class);
setShowSoftInputOnFocus.setAccessible(true);
setShowSoftInputOnFocus.invoke(editText, false);
} catch (Exception e)
{
e.printStackTrace();
}
}
}
像我上面說的整個工程就一個Activity,初始化以及顯示都在那一個Activity裡面,那麼如果不是這樣的呢,額…,想過使用PopupWindows,但是PopupWindows彈出後,輸入框的游標沒有了(⊙﹏⊙),而且點返回按鈕的時候只是僅僅關閉彈窗(跟實際軟鍵盤效果不符,可能有其他處理方法,感覺沒意義),然後又想到用addView的方式加進去,又發現不同佈局可能最外層可能不一樣,沒法統一處理,目前沒找到好的解決辦法。
最後不遮擋輸入框的做法,很簡單,我們知道了軟鍵盤的高度,那麼通過一系列的計算通過view.scrollTo(0,editH-keyboardH+10);移動佈局就行了,具體看程式碼
為了拿到View,我在KeyBoradUtil中加了個setView()
public void setView(View view){
this.view = view;
}
public void showKeyboard()
{
//計算輸入框底部到父佈局頂部的距離,有50dp的padding
int editH = mEdit.getBottom()+DisplayUtil.dip2px(mContext,50);
//計算軟鍵盤頂部到父佈局頂部的距離
int keyboardH = mKeyboardView.getTop();
//移動佈局
if (editH>keyboardH)
{
if (view != null)
{
//加了10的偏移,看個人愛好,可以不加
view.scrollTo(0,editH-keyboardH+10);
}
}
int visibility = mKeyboardView.getVisibility();
if (visibility == View.GONE || visibility == View.INVISIBLE)
{
mKeyboardView.setVisibility(View.VISIBLE);
int hight = mKeyboardView.getHeight();
Log.d("TAG",hight+"");
ObjectAnimator bad = ObjectAnimator.ofFloat(mKeyboardView, "translationY", hight, 0);
bad.setDuration(200);
bad.start();
}
}
public void hideKeyboard()
{
int visibility = mKeyboardView.getVisibility();
if (visibility == View.VISIBLE)
{
if (view != null)
{
//佈局恢復
view.scrollTo(0,0);
}
int hight = mKeyboardView.getHeight();
ObjectAnimator bad = ObjectAnimator.ofFloat(mKeyboardView, "translationY", 0, hight);
bad.setDuration(200);
bad.start();
bad.addListener(new Animator.AnimatorListener()
{
@Override
public void onAnimationStart(Animator animation)
{
}
@Override
public void onAnimationEnd(Animator animation)
{
mKeyboardView.setVisibility(View.INVISIBLE);
}
@Override
public void onAnimationCancel(Animator animation)
{
}
@Override
public void onAnimationRepeat(Animator animation)
{
}
});
}
}