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

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

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

一引言

上一篇文章只是自定义了一个键盘的样式,并未和任何的输入框进行关联。只有和输入框进行关联才能是一个有用的键盘。不知道你有没有注意到应用市场上有这样一类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;
}复制代码

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

最后奉上源码

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 浅谈一个网页打开的全过程(涉及DNS、CDN、Nginx负载均衡等)

    浅谈一个网页打开的全过程(涉及DNS、CDN、Nginx负载均衡等)

    2021年10月31日
    35
  • 基于单片机的八路抢答器的设计与实现_基于单片机的三路抢答器设计

    基于单片机的八路抢答器的设计与实现_基于单片机的三路抢答器设计1.设计要求:1.以单片机为核心,设计一个八位竞赛抢答器:同时供八名选手或八个代表队比赛,分别用八个按钮S0~S7表示。2.设置一个系统清除和抢答控制开关S,开关由主持人控制。3.抢答器具有锁存与显示功能。即选手按按钮,锁存相应的编号,并在优先抢答选手的编号一直保持到主持人将系统清除为止。4.抢答器具有定时抢答功能,且一次抢答的时间由主持人设定(如30秒)。5.当主持人启动“开始”键后,定时器进行减计时,同时扬声器发出短暂的声响,声响持续的时间为0.5s左右。6.参赛选手在设定的时间

    2022年10月9日
    0
  • 解开Android应用程序组件Activity的”singleTask”之谜

    解开Android应用程序组件Activity的”singleTask”之谜在Android应用程序中,可以配置Activity以四种方式来启动,其中最令人迷惑的就是”singleTask”这种方式了,官方文档称以这种方式启动的Activity总是属于一个任务的根Activity。果真如此吗?本文将为你解开Activity的”singleTask”之谜。     在解开这个谜之前,我们先来简单了解一下在Android应用程序中,任务(Task)是个什么样的概念。我们

    2022年6月26日
    21
  • linux 7 bond0,Centos 7 配置多网卡bond0 及网桥br0

    《Centos7配置多网卡bond0及网桥br0》由会员分享,可在线阅读,更多相关《Centos7配置多网卡bond0及网桥br0(2页珍藏版)》请在人人文库网上搜索。1、Centos7配置多网卡bond0及网桥br0一配置多网卡bonding1手动添加bond0配置,如:vim/etc/sysconfig/network-scripts/ifcfg-bond0DEVICE=b…

    2022年4月7日
    104
  • thinkphp开发微信公众号时,验证基本配置提示请求url超时

    thinkphp开发微信公众号时,验证基本配置提示请求url超时

    2021年9月24日
    51
  • JVM内存结构和Java内存模型别再傻傻分不清了

    JVM内存结构和Java内存模型别再傻傻分不清了JVM内存结构和Java内存模型都是面试的热点问题,名字看感觉都差不多,网上有些博客也都把这两个概念混着用,实际上他们之间差别还是挺大的。通俗点说,JVM内存结构是与JVM的内部存储结构相关,而Java内存模型是与多线程编程相关,本文针对这两个总是被混用的概念展开讲解。文章目录JVM内存结构JVM构成JVM内存结构程序计数器虚拟机栈本地方法栈堆方法区GC垃圾回收机制1.垃圾判别方法引用计数算法可达性分析算法2.垃圾回收算法标记清除法标记整理法复制算法3.分代垃圾回收机制4.垃圾回收器5.四种引

    2022年4月28日
    43

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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