android 软键盘顶部加入工具条

时间:2021-04-02 23:39:43

先来个效果图:


android 软键盘顶部加入工具条


这个有点仿uc浏览器的,,,


直接上代码:

   

    新建一个工程,然后MainActivity的layou文件如下:

    

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
tools:context="com.muzi.keyboard.tool.MainActivity">

<EditText
android:id="@+id/edit_view"
android:hint="Hello World!"
android:inputType="text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>

  可以看到只有一个 Editext,没错,这个就是只需要一个输入框,弹起键盘


  首先,在软键盘顶部添加工具条,这个view势必会依赖软键盘,即:显示键盘->显示工具条,隐藏键盘->隐藏工具条

  因此,我们需要监听键盘的显示与隐藏

  同时,要在键盘的顶部添加view,也需要知道键盘的高度

  这里,可以通过监听视图树的布局改变来实现,具体如下


  这里先自定义类来实现ViewTreeObserver.OnGlobalLayoutListener接口

  

private class KeyboardOnGlobalChangeListener implements ViewTreeObserver.OnGlobalLayoutListener {

private int getScreenHeight() {
return ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay().getHeight();
}

private int getScreenWidth() {
return ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay().getWidth();
}

@Override
public void onGlobalLayout() {
Rect rect = new Rect();
// 获取当前页面窗口的显示范围
getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
int screenHeight = getScreenHeight();
int keyboardHeight = screenHeight - rect.bottom; // 输入法的高度
boolean preShowing = mIsSoftKeyBoardShowing;
if (Math.abs(keyboardHeight) > screenHeight / 5) {
// 超过屏幕五分之一则表示弹出了输入法
} else {
//隐藏输入法
}
}
}

   设置监听事件,这个可以放在onCreate方法里面

    

getWindow().getDecorView().getViewTreeObserver().addOnGlobalLayoutListener(new KeyboardOnGlobalChangeListener());

    到这一步,已经完成了对键盘弹起和消失的监听,以及键盘高度的获取

    接下来,就是要显示我们的工具条了

    这里使用的是PopupWindow,对,就是PopupWindow,而不是插入到输入法中的(捂脸)


    先贴一下PopupWindow的布局文件

     

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#808080"
android:orientation="vertical">

<LinearLayout
android:id="@+id/keyboard_top_view_tip_container"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_gravity="center"
android:gravity="center"
android:orientation="horizontal">

<TextView
android:id="@+id/keyboard_top_view_first_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:layout_weight="1"
android:text="www."
android:textColor="#ff000000"
android:textSize="14sp" />

<TextView
android:id="@+id/keyboard_top_view_second_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:layout_weight="1"
android:text="m."
android:textColor="#ff000000"
android:textSize="14sp" />

<Space
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />

<TextView
android:id="@+id/keyboard_top_view_third_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:layout_weight="1"
android:text="wap."
android:textColor="#ff000000"
android:textSize="14sp" />

<TextView
android:id="@+id/keyboard_top_view_fourth_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:layout_weight="1"
android:text=".cn"
android:textColor="#ff000000"
android:textSize="14sp" />
</LinearLayout>

<SeekBar
android:id="@+id/keyboard_top_view_seek_bar"
android:layout_width="@dimen/keyboard_top_view_seek_bar_min_width"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:max="50"
android:progress="25"/>
</FrameLayout>
     

     这里之所以把seekbar放外边,是为了做按住展开的动画


    好吧,贴一下完整的activity的代码吧

    

    

package com.muzi.keyboard.tool;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Rect;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.PopupWindow;
import android.widget.SeekBar;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity implements TextWatcher, View.OnClickListener, SeekBar.OnSeekBarChangeListener{

private static final String KEYBOARD_TOP_VIEW_FIRST_TIP_NULL = "www.";
private static final String KEYBOARD_TOP_VIEW_SECOND_TIP_NULL = "m.";
private static final String KEYBOARD_TOP_VIEW_THIRD_TIP_NULL = "wap.";
private static final String KEYBOARD_TOP_VIEW_FOURTH_TIP_NULL = ".cn";
private static final String KEYBOARD_TOP_VIEW_FIRST_TIP = ".";
private static final String KEYBOARD_TOP_VIEW_SECOND_TIP = "/";
private static final String KEYBOARD_TOP_VIEW_THIRD_TIP = ".com";
private static final String KEYBOARD_TOP_VIEW_FOURTH_TIP = ".cn";

private View mContainer;
private EditText mEditText;
private TextView mKeyboardTopViewFirstTxt;
private TextView mKeyboardTopViewSecondTxt;
private TextView mKeyboardTopViewThirdTxt;
private TextView mKeyboardTopViewFourthTxt;
private View mKeyboardTopViewTipContainer;
private boolean mInputViewIsNull = true;

private SeekBar mKeyboardTopViewSeekBar;
private ValueAnimator mExtendSeekBarAnimator;
private ValueAnimator mShrinkSeekBarAnimator;
private boolean mIsCanMoveCursor = false;
private int mLastSeekBarProgress = 25;

private PopupWindow mSoftKeyboardTopPopupWindow;
private boolean mIsSoftKeyBoardShowing = false;

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

mContainer = findViewById(R.id.container);
mEditText = (EditText) findViewById(R.id.edit_view);
mEditText.addTextChangedListener(this);

//监听视图树的布局改变(弹出/隐藏软键盘会触发)
getWindow().getDecorView().getViewTreeObserver().addOnGlobalLayoutListener(new KeyboardOnGlobalChangeListener());
}

@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {

}

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {

}

@Override
public void afterTextChanged(Editable s) {
String text = s.toString();
updateKeyboardTopViewTips(TextUtils.isEmpty(text));
}

@Override
public void onClick(View v) {
String txt = "";
switch (v.getId()) {
case R.id.keyboard_top_view_first_txt:
txt = mKeyboardTopViewFirstTxt.getText().toString();
break;
case R.id.keyboard_top_view_second_txt:
txt = mKeyboardTopViewSecondTxt.getText().toString();
break;
case R.id.keyboard_top_view_third_txt:
txt = mKeyboardTopViewThirdTxt.getText().toString();
break;
case R.id.keyboard_top_view_fourth_txt:
txt = mKeyboardTopViewFourthTxt.getText().toString();
break;
}
insertTextToEditText(txt);
}

@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (mIsCanMoveCursor) {
moveEditViewCursor(mLastSeekBarProgress > progress);
}
mLastSeekBarProgress = progress;
}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {
mIsCanMoveCursor = false;
extendSeekBarAnimator();
}

@Override
public void onStopTrackingTouch(SeekBar seekBar) {
mIsCanMoveCursor = false;
shrinkSeekBarAnimator();
}

private void extendSeekBarAnimator() {
if (mShrinkSeekBarAnimator != null && mShrinkSeekBarAnimator.isRunning()) {
mShrinkSeekBarAnimator.cancel();
mShrinkSeekBarAnimator = null;
}

int screenWidth = ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay().getWidth();
final int seekBarWidth = mKeyboardTopViewSeekBar.getWidth();
mExtendSeekBarAnimator = ValueAnimator.ofInt(screenWidth - seekBarWidth);
mExtendSeekBarAnimator.setDuration(300);
mExtendSeekBarAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
if (mKeyboardTopViewSeekBar == null) return;
Integer value = (Integer) animation.getAnimatedValue();
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) mKeyboardTopViewSeekBar.getLayoutParams();
layoutParams.width = value + seekBarWidth;
mKeyboardTopViewSeekBar.setLayoutParams(layoutParams);
}
});
mExtendSeekBarAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {}

@Override
public void onAnimationEnd(Animator animation) {
if (mKeyboardTopViewTipContainer != null) {
mKeyboardTopViewTipContainer.setVisibility(View.INVISIBLE);
mIsCanMoveCursor = true;
}
}

@Override
public void onAnimationCancel(Animator animation) {}

@Override
public void onAnimationRepeat(Animator animation) {}
});
mExtendSeekBarAnimator.start();
}

private void shrinkSeekBarAnimator() {
if (mExtendSeekBarAnimator != null && mExtendSeekBarAnimator.isRunning()) {
mExtendSeekBarAnimator.cancel();
mExtendSeekBarAnimator = null;
}

final int seekBarWidth = mKeyboardTopViewSeekBar.getWidth();
final int minWidth = getResources().getDimensionPixelOffset(R.dimen.keyboard_top_view_seek_bar_min_width);
mShrinkSeekBarAnimator = ValueAnimator.ofInt(seekBarWidth - minWidth);
mShrinkSeekBarAnimator.setDuration(300);
mShrinkSeekBarAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
if (mKeyboardTopViewSeekBar == null) return;
Integer value = (Integer) animation.getAnimatedValue();
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) mKeyboardTopViewSeekBar.getLayoutParams();
layoutParams.width = seekBarWidth - value;
mKeyboardTopViewSeekBar.setLayoutParams(layoutParams);
int normalProgress = mKeyboardTopViewSeekBar.getMax() / 2;
int progress = (mKeyboardTopViewSeekBar.getProgress() - normalProgress) * (value / (seekBarWidth - minWidth)) + normalProgress;
mKeyboardTopViewSeekBar.setProgress(progress);
}
});
mShrinkSeekBarAnimator.start();

if (mKeyboardTopViewTipContainer != null) {
mKeyboardTopViewTipContainer.setVisibility(View.VISIBLE);
}
}

private void insertTextToEditText(String txt) {
if (TextUtils.isEmpty(txt)) return;
int start = mEditText.getSelectionStart();
int end = mEditText.getSelectionEnd();
Editable edit = mEditText.getEditableText();//获取EditText的文字
if (start < 0 || start >= edit.length()) {
edit.append(txt);
} else {
edit.replace(start, end, txt);//光标所在位置插入文字
}
}

private void moveEditViewCursor(boolean isMoveLeft) {
int index = mEditText.getSelectionStart();
if (isMoveLeft) {
if (index <= 0) return;
mEditText.setSelection(index - 1);
} else {
Editable edit = mEditText.getEditableText();//获取EditText的文字
if (index >= edit.length()) return;
mEditText.setSelection(index + 1);
}
}

private void showKeyboardTopPopupWindow(int x, int y) {
if (mSoftKeyboardTopPopupWindow != null && mSoftKeyboardTopPopupWindow.isShowing()) {
updateKeyboardTopPopupWindow(x, y); //可能是输入法切换了输入模式,高度会变化(比如切换为语音输入)
return;
}

View popupView = getLayoutInflater().inflate(R.layout.soft_keyboard_top_tool_view, null);

mKeyboardTopViewFirstTxt = (TextView) popupView.findViewById(R.id.keyboard_top_view_first_txt);
mKeyboardTopViewSecondTxt = (TextView) popupView.findViewById(R.id.keyboard_top_view_second_txt);
mKeyboardTopViewThirdTxt = (TextView) popupView.findViewById(R.id.keyboard_top_view_third_txt);
mKeyboardTopViewFourthTxt = (TextView) popupView.findViewById(R.id.keyboard_top_view_fourth_txt);
mKeyboardTopViewSeekBar = (SeekBar) popupView.findViewById(R.id.keyboard_top_view_seek_bar);
mKeyboardTopViewTipContainer = popupView.findViewById(R.id.keyboard_top_view_tip_container);

mKeyboardTopViewFirstTxt.setOnClickListener(this);
mKeyboardTopViewSecondTxt.setOnClickListener(this);
mKeyboardTopViewThirdTxt.setOnClickListener(this);
mKeyboardTopViewFourthTxt.setOnClickListener(this);
mKeyboardTopViewSeekBar.setOnSeekBarChangeListener(this);

mSoftKeyboardTopPopupWindow = new PopupWindow(popupView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
mSoftKeyboardTopPopupWindow.setTouchable(true);
mSoftKeyboardTopPopupWindow.setOutsideTouchable(false);
mSoftKeyboardTopPopupWindow.setFocusable(false);
mSoftKeyboardTopPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED); //解决遮盖输入法
mSoftKeyboardTopPopupWindow.showAtLocation(mContainer, Gravity.BOTTOM, x, y);
updateKeyboardTopViewTips(TextUtils.isEmpty(mEditText.getText()));
}

private void updateKeyboardTopPopupWindow(int x, int y) {
if (mSoftKeyboardTopPopupWindow != null && mSoftKeyboardTopPopupWindow.isShowing()) {
mSoftKeyboardTopPopupWindow.update(x, y, mSoftKeyboardTopPopupWindow.getWidth(), mSoftKeyboardTopPopupWindow.getHeight());
}
}

private void closePopupWindow() {
if (mSoftKeyboardTopPopupWindow != null && mSoftKeyboardTopPopupWindow.isShowing()) {
mSoftKeyboardTopPopupWindow.dismiss();
mSoftKeyboardTopPopupWindow = null;
mKeyboardTopViewFirstTxt = null;
mKeyboardTopViewSecondTxt = null;
mKeyboardTopViewThirdTxt = null;
mKeyboardTopViewFourthTxt = null;
mKeyboardTopViewSeekBar = null;
mInputViewIsNull = true;
}
}

private void updateKeyboardTopViewTips(boolean isNull) {
if (mInputViewIsNull == isNull) {
return;
}

if (isNull) {
if (mKeyboardTopViewFirstTxt != null) {
mKeyboardTopViewFirstTxt.setText(KEYBOARD_TOP_VIEW_FIRST_TIP_NULL);
}
if (mKeyboardTopViewSecondTxt != null) {
mKeyboardTopViewSecondTxt.setText(KEYBOARD_TOP_VIEW_SECOND_TIP_NULL);
}
if (mKeyboardTopViewThirdTxt != null) {
mKeyboardTopViewThirdTxt.setText(KEYBOARD_TOP_VIEW_THIRD_TIP_NULL);
}
if (mKeyboardTopViewFourthTxt != null) {
mKeyboardTopViewFourthTxt.setText(KEYBOARD_TOP_VIEW_FOURTH_TIP_NULL);
}
mInputViewIsNull = true;
} else {
if (mKeyboardTopViewFirstTxt != null) {
mKeyboardTopViewFirstTxt.setText(KEYBOARD_TOP_VIEW_FIRST_TIP);
}
if (mKeyboardTopViewSecondTxt != null) {
mKeyboardTopViewSecondTxt.setText(KEYBOARD_TOP_VIEW_SECOND_TIP);
}
if (mKeyboardTopViewThirdTxt != null) {
mKeyboardTopViewThirdTxt.setText(KEYBOARD_TOP_VIEW_THIRD_TIP);
}
if (mKeyboardTopViewFourthTxt != null) {
mKeyboardTopViewFourthTxt.setText(KEYBOARD_TOP_VIEW_FOURTH_TIP);
}
mInputViewIsNull = false;
}
}

private class KeyboardOnGlobalChangeListener implements ViewTreeObserver.OnGlobalLayoutListener {

private int getScreenHeight() {
return ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay().getHeight();
}

private int getScreenWidth() {
return ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay().getWidth();
}

@Override
public void onGlobalLayout() {
Rect rect = new Rect();
// 获取当前页面窗口的显示范围
getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
int screenHeight = getScreenHeight();
int keyboardHeight = screenHeight - rect.bottom; // 输入法的高度
boolean preShowing = mIsSoftKeyBoardShowing;
if (Math.abs(keyboardHeight) > screenHeight / 5) {
mIsSoftKeyBoardShowing = true; // 超过屏幕五分之一则表示弹出了输入法
showKeyboardTopPopupWindow(getScreenWidth() / 2, keyboardHeight);
} else {
if (preShowing) {
closePopupWindow();
}
mIsSoftKeyBoardShowing = false;
}
}
}
}

     代码下载