android 自定义数字软键盘,(笔记)Android自定义数字键盘
前言
最近Android开发中用到了自定义数字键盘,网上找的demo不能满足我的需求,比如删除和插入的时候只能在最后删除和插入,不能通过滑动键盘来移动光标。所以现在完成后把它总结写出来。
概述
主要实现以下功能:
(1)只有数字键,包括没有标点符号。
(2)可以在任意点插入和删除数字。
(3)可以通过手指左右滑动键盘来改变光标位置。
(4)输入框右边删除图标和按钮可随着内容有无变化。
(5)每三个数字空一格,输入框最多输入13个字符(包括空格)。
先上运行效果(请忽略UI -_-):
keyboard.gif
步骤:
1、新建一个KeyboardView.java文件。用来自定义所需要的键盘。
首先初始化绑定布局文件。
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
LayoutInflater.from(context).inflate(R.layout.layout_key_board, this);
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
rl_back=findViewById(R.id.rl_back);
rl_back.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) { // 点击关闭键盘
dismiss();
}
});
initData();
initView();
initAnimation();
}
填充数据(如果需要标点符号,则在i==9中填充即可)
private void initData() {
keyboardWords = new ArrayList<>();
for (int i = 0; i < 12; i++) {
if (i < 9) {
keyboardWords.add(String.valueOf(i + 1));
} else if (i == 9) {
keyboardWords.add("");
} else if (i == 10) {
keyboardWords.add("0");
} else {
keyboardWords.add("");
}
}
}
设置适配器
private void initView() {
int spanCount = 12;
recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 3));
recyclerView.setNestedScrollingEnabled(false);
recyclerView.addItemDecoration(new SpaceItemDecoration(spanCount));
adapter = new KeyboardAdapter(getContext(), keyboardWords);
recyclerView.setAdapter(adapter);
}
对键盘的操作
//判断软键盘的状态
public boolean isVisible() {
if (getVisibility() == VISIBLE) {
return true;
}
return false;
}
//弹出软键盘
public void show() {
startAnimation(animationIn);
setVisibility(VISIBLE);
}
//关闭软键盘
public void dismiss() {
if (isVisible()) {
startAnimation(animationOut);
setVisibility(GONE);
}
}
2、Adapter操作。
private Context context;
private List datas;
private OnKeyboardClickListener listener;
public KeyboardAdapter(Context context, List datas) {
this.context = context;
this.datas = datas;
}
@Override
public KeyboardHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.item_key_board, parent, false);
KeyboardHolder holder = new KeyboardHolder(view);
setListener(holder);
return holder;
}
private void setListener(final KeyboardHolder holder) {
holder.tvKey.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null) {
if (holder.getAdapterPosition() != 9) {
listener.onKeyClick(view, holder, holder.getAdapterPosition());
}
}
}
});
holder.rlDel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null) {
listener.onDeleteClick(view, holder, holder.getAdapterPosition());
}
}
});
}
@Override
public void onBindViewHolder(KeyboardHolder holder, int position) {
if (position == 9) {
holder.setVisibility(false);
} else if (position == 11) {
holder.rlDel.setVisibility(View.VISIBLE);
holder.tvKey.setVisibility(View.GONE);
} else {
holder.tvKey.setText(datas.get(position));
}
}
@Override
public int getItemCount() {
return datas == null ? 0 : datas.size();
}
class KeyboardHolder extends RecyclerView.ViewHolder {
public TextView tvKey;
public RelativeLayout rlDel;
private View convertView;
public KeyboardHolder(View itemView) {
super(itemView);
convertView = itemView;
tvKey = itemView.findViewById(R.id.tv_key);
rlDel = itemView.findViewById(R.id.rl_del);
}
public View getconvertView() {
return convertView;
}
public void setVisibility(boolean b) {
RecyclerView.LayoutParams param = (RecyclerView.LayoutParams) itemView.getLayoutParams();
if (b) {
param.height = LinearLayout.LayoutParams.WRAP_CONTENT;
param.width = LinearLayout.LayoutParams.MATCH_PARENT;
itemView.setVisibility(View.VISIBLE);
} else {
itemView.setVisibility(View.GONE);
param.height = 0;
param.width = 0;
}
itemView.setLayoutParams(param);
}
}
public interface OnKeyboardClickListener {
void onKeyClick(View view, RecyclerView.ViewHolder holder, int position);
void onDeleteClick(View view, RecyclerView.ViewHolder holder, int position);
}
public void setOnKeyboardClickListener(OnKeyboardClickListener listener) {
this.listener = listener;
}
}
3、在Activity中的运用。
关闭系统键盘
private void enableSystemKeyboard() {
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
try {
Class cls = EditText.class;
Method setShowSoftInputOnFocus = cls.getMethod("setShowSoftInputOnFocus", boolean.class);
setShowSoftInputOnFocus.setAccessible(true);
setShowSoftInputOnFocus.invoke(videoIdEt, false);
} catch (Exception e) {
e.printStackTrace();
}
}
键盘数字按钮的点击事件,并且获取输入当前光标位置
@SuppressLint("SetTextI18n")
@Override
public void onKeyClick(View view, RecyclerView.ViewHolder holder, int position) {
String editText = videoIdEt.getText().toString();
switch (position) {
case 9:
break;
default:
//获取当前光标位置
int index = videoIdEt.getSelectionStart();
if (index != videoIdEt.getText().length()) {
//在光标处插入数字
String inputEditText = keyboardNumbers.get(position);
Log.d(TAG, "inputEditText:" + inputEditText);
videoIdEt.getText().insert(index, inputEditText);
} else {
videoIdEt.setText(videoIdEt.getText().toString().trim() + keyboardNumbers.get(position));
videoIdEt.setSelection(videoIdEt.getText().length());
}
if (videoIdEt.getText().length() > 0) {
findViewById(R.id.ai_long_tv_confirm).setBackgroundResource(R.drawable.bg_determine_text);
Drawable drawable = getResources().getDrawable(R.drawable.ic_delete1);
//设置 ClickableEditText中只显示左边图标,删除图标可见
videoIdEt.setCompoundDrawablesWithIntrinsicBounds(mDrawable, null, drawable,null);
}
break;
}
}
手指触摸事件:获取手指按下和滑动停止的位置。将结果传给手势监听。
private View.OnTouchListener onTouchListener = new View.OnTouchListener() {
@RequiresApi(api = Build.VERSION_CODES.ECLAIR)
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
Log.d(TAG, "MotionEvent.ACTION_DOWN");
}
if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
Log.d(TAG, "MotionEvent.ACTION_UP");
refreshStartPoint = true;
}
if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
if (refreshStartPoint) {
startPointEvent = motionEvent.getX(0);
curatorIndex = videoIdEt.getSelectionStart();
}
refreshStartPoint = false;
stopPointEvent = motionEvent.getX();
Log.d(TAG, "MotionEvent.ACTION_MOVE");
}
return mDetector.onTouchEvent(motionEvent);
}
};
用户手势的监测。计算开始和停止滑动距离的大小(滑动前和滑动后的距离),通过计算滑动距离来计算光标移动多少,并通过距离的正负来判断滑动的方向,从而达到在键盘上滑动来控制光标移动的目的。
@RequiresApi(api = Build.VERSION_CODES.CUPCAKE)
private void initGestureDetector() {
mDetector = new GestureDetector(this, new GestureDetector.OnGestureListener() {
@Override
public boolean onDown(MotionEvent motionEvent) {
Log.d(TAG, "onDown");
return true;
}
@Override
public void onShowPress(MotionEvent motionEvent) {
Log.d(TAG, "onShowPress");
}
@Override
public boolean onSingleTapUp(MotionEvent motionEvent) {
Log.d(TAG, "onShowPress");
return false;
}
@Override
public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
mScreenWidth = displayMetrics.widthPixels;
float x = stopPointEvent - startPointEvent;
float newPercent = Math.abs(x) / mScreenWidth;
int range = (int) ((videoIdEt.getText().length()) * newPercent);
int newIndex;
if (x > 0) {
newIndex = curatorIndex + range;
if (curatorIndex == videoIdEt.getText().length()) {
videoIdEt.setSelection(curatorIndex);
}
if (newIndex > videoIdEt.getText().length()) {
videoIdEt.setSelection(videoIdEt.getText().length());
} else {
videoIdEt.setSelection(newIndex);
}
} else {
newIndex = curatorIndex - range;
if (curatorIndex == 0) {
videoIdEt.setSelection(curatorIndex);
}
if (newIndex < 0) {
videoIdEt.setSelection(0);
} else {
videoIdEt.setSelection(newIndex);
}
}
return false;
}
@Override
public void onLongPress(MotionEvent motionEvent) {
Log.d(TAG, "onLongPress");
}
@Override
public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
// startPointEvent=motionEvent1;
Log.d(TAG, "onFling: " + "motionEvent:" + motionEvent + "motionEvent1" + motionEvent1);
return false;
}
});
}
接着我们实现每三个数字输入一个空格。通过对ClickableEditText的监听来达到这一目的。
private TextWatcher watcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int start, int before, int i2) {
if (isTextChanging) {
isTextChanging = false;
return;
}
isTextChanging = true;
String result = "";
String newStr = charSequence.toString();
newStr = newStr.replace(" ", "");
int index = 0;
while ((index + 3) < newStr.length()) {
result += (newStr.substring(index, index + 3) + " ");
index += 3;
}
result += (newStr.substring(index, newStr.length()));
int i = videoIdEt.getSelectionStart();
videoIdEt.setText(result);
try {
if (i % 4 == 0 && before == 0) {
if (i + 1 <= result.length()) {
videoIdEt.setSelection(i + 1);
} else {
videoIdEt.setSelection(result.length());
}
} else if (before == 1 && i < result.length()) {
videoIdEt.setSelection(i);
} else if (before == 0 && i < result.length()) {
videoIdEt.setSelection(i);
} else {
videoIdEt.setSelection(result.length());
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void afterTextChanged(Editable editable) {
}
};
对右下角删除按钮的监听,只能删除一个一个删除,不能一下删除所输入的内容
@Override
public void onDeleteClick(View view, RecyclerView.ViewHolder holder, int position) {
int currentIndex = videoIdEt.getSelectionStart();
if (currentIndex > 0) {
videoIdEt.getText().delete(currentIndex - 1, currentIndex);
if (videoIdEt.getText().length() == 0) {
//设置 ClickableEditText中只显示左边图标,删除图标不可见
videoIdEt.setCompoundDrawablesWithIntrinsicBounds(mDrawable, null, null,null);
findViewById(R.id.ai_long_tv_confirm).setBackgroundResource(R.drawable.bg_determine_disable);
}
}
}
输入框右边删除按钮的点击事件,点击可消除所有输入的内容。
@Override
public void onDrawableRightClick(View view) {
switch (view.getId()) {
case R.id.ai_long_et_video_code:
videoIdEt.getText().clear();
//设置 ClickableEditText中只显示左边图标,删除图标不可见
videoIdEt.setCompoundDrawablesWithIntrinsicBounds(mDrawable, null, null,null);
findViewById(R.id.ai_long_tv_confirm).setBackgroundResource(R.drawable.bg_determine_disable);
break;
default:
break;
}
}
结论
以上就是整个项目的实现过程,注意一点,ClickableEditText是自定义的一个EditText,由于使用ConstraintLayout,在输入框的前后两端加按钮,是为了可以点击右边删除按钮能删除所有输入的内容所写。
android 自定义数字软键盘,(笔记)Android自定义数字键盘相关推荐
- android二级联动简书,笔记:Android二级联动---RecyclerView实现
做笔记免得以后有重写一边或者忘了,仅供自己学习(只实现功能,无动画实现,左边没做可见处理,有空再做吧): 1.左右两个RecyclerView, 2.左边RecyclerView点击某个item同时i ...
- android拓展笔记本,有道笔记Android版上线,拓展移动终端产品布局
在大家的翘首企盼下,有道笔记Android版今天终于上线了!广大G粉从今天起也可以在Android系统手机上使用有道笔记获得高效的个人知识管理体验. 有道笔记Android版拥有和桌面版.网页版一致的 ...
- python输入数字字符串_Python笔记—基本数据类型—数字字符串
数字 int #整型 所有的功能,都在int里 a = 123v= a.bit_length() #软件自带函数联想 print(v)-int 将字符串转换成数字 a= '123' print(typ ...
- 最小值c语言编写自定义函数,C语言笔记55:自定义函数[老九学堂]
函数定义 return_type function_name ([datetype1 arg1],[datype2 arg2,[...]){ //函数体 } 函数三要素返回值类型 函数名 参数列表 书 ...
- Android逆向文档阅读笔记-Android Application Fundamentals
Fundamentals Review Android应用程序是在APK格式的文件中的,APK是基于ZIP文件的(可以将APK后缀改成ZIP后缀,然后可以使用unzip去解压). APK文件内容: A ...
- Android日常开发 - FlexboxLayout学习笔记
Android日常开发 - FlexboxLayout学习笔记 Android日常开发使用FlexboxLayout实现流式布局的效果,FlexboxLayout与h5中的flex使用十分相似,都是将 ...
- Android开发笔记(一百四十八)自定义输入法软键盘
手机上输入文字,都是通过系统自带的软键盘,这个软键盘可以是Android自带的,也可以是第三方软键盘如搜狗输入法.多数情况下面,系统自带的软键盘已经够用了,可是总有少数情况,系统软键盘无法满足开发者的 ...
- android 自定义数字软键盘,Android自定义键盘的实现(数字键盘和字母键盘)
在项目中,产品对于输入方式会有特殊的要求,需要对输入方式增加特定的限制,这就需要采用自定义键盘.本文主要讲述数字键盘和字母键盘的自定义实现. 自定义键盘的实现步骤如下: 自定义CustomKeyboa ...
- Android自定义记账软键盘(仿鲨鱼记账的记账功能)
鲨鱼记账App效果: 本文实现的效果图: 本文 不是什么原理分析,属于使用工具,不再具体分析.直接贴图贴代码了 自定义软键盘的XML模版 注:android:codes的值,请参考ASCII < ...
- Android 自定义安全软键盘 SafeKeyboard 开发详细说明 2.0
Android 自定义安全软键盘 SafeKeyboard 开发详细说明 2.0 源码地址:GitHub: https://github.com/SValence/SafeKeyboard 注意 ...
最新文章
- IIS 不能重新启动,并且使用RUN-iisreset 也不能运行,错误提示:No Such Interface Supported (已解决)...
- asp.net core web mvc之异常
- matlab写字,Matlab实现鼠标写字代码
- python生成器用法_理解python中生成器用法
- OK335x mksd.sh hacking
- 编程实战:如何管理代码里的常量
- tomcat运行模式(bio,aio,apr)
- OSGB 倾斜摄影数据生产完成后裁剪模型问题
- 密码模块安全技术要求
- 有容云:梁胜-如何让Docker容器在企业中投产(上)
- 恶意软件隐身术:把可执行文件隐藏在注册表里
- 头条小程序,小游戏头像授权报错
- kepware rest服务器_KEPServerEX
- RAP2 API管理工具部署手册
- vscode的下载速度会特别慢问题处理
- 天龙八部 找怪物ID
- 快手2018年招聘算法笔试
- 滑块验证码通杀方案--python破解代码
- 输入字符串按ASCⅡ大小排序
- pycharm笔记-动手学深度学习(李沐)微积分课后习题
热门文章
- raspberry pi系统配置
- Transmission搭建BT下载服务器
- 知乎上 40 个有趣回复,很精辟很提神
- 小兔 —— 「 洛谷 」P2768 珍珠项链
- apifox设置全局header
- ubantu20.04 ros的安装
- hrbust 1699 矩阵游戏【枚举找规律】
- 130 个相见恨晚的超实用网站
- java myeclipse下载_MyEclipse,myeclipse 8.5 下载,myeclipse官网下载_多特软件站
- 我的世界java版和基岩版是什么意思_我的世界基岩版是什么意思