自定义键盘(二)[通俗易懂]

自定义键盘(二)[通俗易懂]自定义键盘(二)

大家好,又见面了,我是你们的朋友全栈君。

一引言

上一篇文章只是自定义了一个键盘的样式,并未和任何的输入框进行关联。只有和输入框进行关联才能是一个有用的键盘。不知道你有没有注意到应用市场上有这样一类app:第三方输入法app,比如讯飞输入法,搜狗输入法;

第三方输入法app:设置完成之后,手机上所有的输入框都会弹出第三方键盘。它们实现都是通过系统的InputMethodManager类去做的扩展。安装第三方输入法的手机,可以在设置–高级设置-语言和输入法中找到。—-系统级别的输入法

那么有没有app级别的输入法扩展呢?

如果有的话会让关于键盘的开发变得更加容易,于是,笔者就去下载一些炒股app,它们都是实现了类似app级别的键盘,发现设置中并未找到他们关于键盘的定义。笔者也没有google到关于app级别的键盘。笔者认定炒股app中的自定义键盘的实现思路应该也是封装然后关联输入框。

二需求

我们如何能封装一个没有耦合性的自定义键盘,笔者能想到的需求如下:

  • 动态添加到任何布局中
  • 解决和系统键盘显示冲突
  • 动态绑定系统输入框
  • 有show和hide动画,让键盘显示更加优雅
  • 没有耦合,使用方便,尽可能让原生属性有效
  • 键盘特殊按钮监听
  • 解决键盘覆盖输入框的问题
  • 点击非键盘,非输入框区域,让键盘消失。

三实现需求

3.1动态添加到任何布局中

android中每个页面布局都有一个DecorView包裹着,我们可以获取这个DecorView,然后把我们的键盘布局文件添加到这个跟布局下:

(activity.getWindow().getDecorView().findViewById(android.R.id.content));复制代码

但是这样会有一个问题,假如有这样一种布局,页面嵌套ViewPager,ViewPager中嵌套多个Fragment,而他们共同拥有一个DecorView。如果把键盘挂载到这样一个布局中,势必会造成页面之间互相影响。于是,笔者就提供方法让挂载键盘的根布局通过外部传入,至于你是传递DecorView还是传递一个fragment的根布局,由外部决定。

3.2解决和系统键盘显示冲突

这就需要我们把页面中所有的EditText传递到封装的工具类中,调用这个方法隐藏系统键盘

/**
 * 隐藏系统键盘
 *
 * @param editText
 */
public static void hideSystemSoftKeyboard(EditText editText) {
    int sdkInt = Build.VERSION.SDK_INT;
    if (sdkInt >= 11) {
        try {
            Class<EditText> cls = EditText.class;
            Method setShowSoftInputOnFocus;
            setShowSoftInputOnFocus = cls.getMethod("setShowSoftInputOnFocus", boolean.class);
            setShowSoftInputOnFocus.setAccessible(true);
            setShowSoftInputOnFocus.invoke(editText, false);
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    } else {
        editText.setInputType(InputType.TYPE_NULL);
    }
}复制代码

然后对应的页面清单文件设置

android:windowSoftInputMode="stateHidden|stateUnchanged"复制代码

让系统键盘不弹出来

3.3动态绑定输入框

系统的输入框是当EditText获取焦点的时候会弹出来,所以这里我们要给传递进来的EditText设置焦点改变监听,通过焦点改变来显示键盘。

key.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View view, boolean b) {
        if (b) {
            currentEditText = (EditText) view;
            showSoftKeyboard();
        }
    }
});复制代码

里有一点需要注意,我们点击确定按钮的时候,当前获取焦点的EditText仍然在获取焦点,再次点击这个EditText,键盘并未弹出。因为焦点没有改变。这就需要我们在我们传递过来的布局文件中添加一个宽高是0的EditText。让用户点击完成的时候,这个EditText获取焦点。

FrameLayout.LayoutParams params2 = new FrameLayout.LayoutParams(0, 0, Gravity.BOTTOM);
rootView.addView(frameLayout, params);
focusReplace = new EditText(context);
rootView.addView(focusReplace, params2);复制代码

3.4有show和hide动画,让键盘显示更加优雅

这无非是系统的View动画,实现起来比较简单

3.5没有耦合,使用方便,尽可能让原生属性有效

这就需要我们用EditText,获取他的属性,然后根据属性去设置键盘的变换

3.6键盘特殊按钮监听

我们写一个外部回调方法即可实现这个需求。

3.7键盘遮挡

这里就需要首先判断是否已经被遮挡,如果被遮挡,需要算出来整个布局需要移动多少,当然键盘布局不能移动。移动方式可以通过属性动画或者scrollBy方法。这里我选择属性动画。

在键盘show出的时候:

//获取传递过来的跟布局的宽高
Rect rect = new Rect();
frameLayout.getWindowVisibleDisplayFrame(rect);
//计算当前获取焦点的输入框在屏幕中的位置
int[] vLocation = new int[2];
currentEditText.getLocationOnScreen(vLocation);
int keyboardTop = vLocation[1] + currentEditText.getHeight() / 2 + currentEditText.getPaddingBottom() + currentEditText.getPaddingTop();
//输入框或基线View的到屏幕的距离 + 键盘高度 如果 超出了屏幕的承载范围, 就需要移动.
int moveHeight = rect.bottom - keyboardTop - keyboardView.getHeight();
moveHeight = moveHeight > 0 ? 0 : moveHeight;
if (moveHeight != 0) {
    rootView.setTag("move");
    //遍历所有的子View,让其向上移动改移动的高度
    for (int i = 0; i < rootView.getChildCount(); i++) {
        if (rootView.getChildAt(i) != frameLayout) {
            rootView.getChildAt(i).setTranslationY(moveHeight);
            ObjectAnimator.ofFloat(rootView.getChildAt(i), "translationY", 0, moveHeight).setDuration(400).start();
        }
    }
}复制代码

在键盘隐藏的时候:

Object tag = rootView.getTag();
if (tag != null) {
    //遍历所有的子View,让其向上移动改移动的高度
    for (int i = 0; i < rootView.getChildCount(); i++) {
        if (rootView.getChildAt(i) != frameLayout) {
            ObjectAnimator.ofFloat(rootView.getChildAt(i), "translationY", 0).setDuration(400).start();
        }
    }
}复制代码

基本使用:

keyboardViewManager = KeyboardViewManager
        .builder()
        .bindEditText(edit1, edit2, edit3)//需要使用自定义键盘的控件
        .showSystemKeyboard(edit4)//需要使用系统键盘的控件
        .bindEditTextCallBack(edit1, new KeyboardViewManager.onSureClickListener() {
            @Override
            public void onSureClick() {

            }
        })//自定义键盘确定回调
        .bindEditTextCallBack(edit2, new KeyboardViewManager.onSureClickListener() {
            @Override
            public void onSureClick() {

            }
        })//自定义键盘确定回调
        .build(this)
        .addKeyboardView(rootView);//需要传入的跟布局复制代码

四.细节使用

4.1键盘默认情况下弹出,我们可以设置输入框的父布局添加一下属性:

android:focusable="true"
android:focusableInTouchMode="true"复制代码

4.2我们可以设置这个输入框只输入数字。模式是输入英文字母

android:inputType="number" 复制代码

4.3点击非键盘和焦点区域,让键盘消失

重写activity的方法,然后调用隐藏键盘方法

@Override
public boolean onTouchEvent(MotionEvent event) {
    keyboardViewManager.hideSoftKeyboard();
    return super.onTouchEvent(event);
}复制代码

假如在Fragment中,在Fragment的onCreateView方法中调用Activity中的onTouchEvent方法:

public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.frag_home_tab, container, false);
    //点击空白区域系统软键盘消失 
    view.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            getActivity().onTouchEvent(motionEvent);
            return false;
        }
    });
    return view;
}复制代码

到此,关于自定义键盘的算是结束,

最后奉上源码

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/107292.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号