教你写一个Android可快速复用的小键盘输入控件
引子
在Android项目开发中特别是一些稍大型的项目,面对需求文档的时候你经常会发现很多地方用到了同样的组件,但是又略有不同。比如这个:
- 写一个小键盘的布局单独存为一个layout文件
- 在用到这个小键盘的activity/fragment中的layout布局中include这个小键盘布局文件
- 在activity/fragment中监听每小键盘的按钮来改变输入框的内容
- 同样include这个布局文件
- 同样拷贝按钮逻辑处理代码
- 小键盘的布局可能不是这个样子的,其他地方布局万一有变化呢
- 小键盘的每个按钮按下后输入的效果或者说内容是不一样的
- 小键盘针对哪个输入框(比如EditText)起作用也是不定的
我们第一步需要把这个组件的共性和区别给抽象出来,通过仔细考虑,发现下列地方是可以公用:
- 小键盘的各种布局中的每个按钮(0~9、小数点、删除)的view id是可以相同的
- 小键盘中每个按钮按下后的效果是可以有一个共同操作的,比如按下1就出来一个1,按下删除就删除最后一个数字
- 小键盘起作用的时候,影响的输入框在作用的时候引用是不变的(除非用户点击了另一个输入框期望对这个输入框操作)
- 提供默认的布局,同时提供接口让使用者自定义布局
- 提供默认的按钮操作,同时提供接口让使用者自定义按钮操作(比如某个奇葩用户希望按下1键后打出来a)
- 提供接口,可以设置正在作用的输入框
首先我们这个自定义view继承自LinearLayout,我们把它命名为NumericPad类,首先是写一个默认的布局,这里很简单,花点时间即可:
// filename : custom_numeric_pad.xml <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
android:weightSum="3"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/pad_1"
android:layout_width="0dp"
android:layout_height="65dp"
android:layout_weight="1"
android:textSize="26sp"
android:layout_margin="10dp"
android:gravity="center"
android:background="@drawable/bg_cal_btn_selector"
android:textColor="@color/btn_text_color"
android:text="1"/>
<Button
android:id="@+id/pad_2"
android:layout_width="0dp"
android:layout_height="65dp"
android:layout_weight="1"
android:textSize="26sp"
android:layout_margin="10dp"
android:gravity="center"
android:background="@drawable/bg_cal_btn_selector"
android:textColor="@color/btn_text_color"
android:text="2"/>
<Button
android:id="@+id/pad_3"
android:layout_width="0dp"
android:layout_height="65dp"
android:layout_weight="1"
android:textSize="26sp"
android:layout_margin="10dp"
android:gravity="center"
android:background="@drawable/bg_cal_btn_selector"
android:textColor="@color/btn_text_color"
android:text="3"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:weightSum="3"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/pad_4"
android:layout_width="0dp"
android:layout_height="65dp"
android:layout_weight="1"
android:textSize="26sp"
android:layout_margin="10dp"
android:gravity="center"
android:background="@drawable/bg_cal_btn_selector"
android:textColor="@color/btn_text_color"
android:text="4"/>
<Button
android:id="@+id/pad_5"
android:layout_width="0dp"
android:layout_height="65dp"
android:layout_weight="1"
android:textSize="26sp"
android:layout_margin="10dp"
android:gravity="center"
android:background="@drawable/bg_cal_btn_selector"
android:textColor="@color/btn_text_color"
android:text="5"/>
<Button
android:id="@+id/pad_6"
android:layout_width="0dp"
android:layout_height="65dp"
android:layout_weight="1"
android:textSize="26sp"
android:layout_margin="10dp"
android:gravity="center"
android:background="@drawable/bg_cal_btn_selector"
android:textColor="@color/btn_text_color"
android:text="6"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:weightSum="3"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/pad_7"
android:layout_width="0dp"
android:layout_height="65dp"
android:layout_weight="1"
android:textSize="26sp"
android:layout_margin="10dp"
android:gravity="center"
android:background="@drawable/bg_cal_btn_selector"
android:textColor="@color/btn_text_color"
android:text="7"/>
<Button
android:id="@+id/pad_8"
android:layout_width="0dp"
android:layout_height="65dp"
android:layout_weight="1"
android:textSize="26sp"
android:layout_margin="10dp"
android:gravity="center"
android:background="@drawable/bg_cal_btn_selector"
android:textColor="@color/btn_text_color"
android:text="8"/>
<Button
android:id="@+id/pad_9"
android:layout_width="0dp"
android:layout_height="65dp"
android:layout_weight="1"
android:textSize="26sp"
android:layout_margin="10dp"
android:gravity="center"
android:background="@drawable/bg_cal_btn_selector"
android:textColor="@color/btn_text_color"
android:text="9"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:weightSum="3"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content">
<Button
android:id="@+id/pad_dot"
android:layout_width="0dp"
android:layout_height="65dp"
android:layout_weight="1"
android:textSize="26sp"
android:layout_margin="10dp"
android:gravity="center"
android:background="@drawable/bg_cal_btn_selector"
android:textColor="@color/btn_text_color"
android:text="."/>
<Button
android:id="@+id/pad_0"
android:layout_width="0dp"
android:layout_height="65dp"
android:layout_weight="1"
android:textSize="26sp"
android:layout_margin="10dp"
android:gravity="center"
android:background="@drawable/bg_cal_btn_selector"
android:textColor="@color/btn_text_color"
android:text="0"/>
<ImageButton
android:id="@+id/pad_del"
android:layout_width="0dp"
android:layout_height="65dp"
android:layout_weight="1"
android:layout_margin="10dp"
android:scaleType="center"
android:background="@drawable/bg_cal_btn_selector"
android:textColor="@color/btn_text_color"
android:src="@drawable/cal_del_selector"/>
</LinearLayout>
</LinearLayout>
public NumericPad(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mRoot = (LinearLayout) mInflater.inflate(R.layout.custom_numeric_pad, this);
}
public void setLayout(@LayoutRes int layoutId) {
if (layoutId != 0) {
// use customized layout from parameter
mRoot = (LinearLayout) mInflater.inflate(layoutId, this);
} }
因为每个小键盘按钮都是个button,那么这里首先我们要处理的是点击事件的监听,这里我们不需要创建出来button,只需要依次迭代每个ViewID对他findviewbyid出来,同时设置setonclicklistener或者setonlongclicklistener即可:
public class NumericPad extends LinearLayout implements View.OnClickListener, View.OnLongClickListener{
... }
//initView方法需要在NumericPad的构造函数和setLayout方法中调用 private void initView() {
mViewsId = new ArrayList<>();
mViewsId.add(R.id.pad_0);
mViewsId.add(R.id.pad_1);
mViewsId.add(R.id.pad_2);
mViewsId.add(R.id.pad_3);
mViewsId.add(R.id.pad_4);
mViewsId.add(R.id.pad_5);
mViewsId.add(R.id.pad_6);
mViewsId.add(R.id.pad_7);
mViewsId.add(R.id.pad_8);
mViewsId.add(R.id.pad_9);
mViewsId.add(R.id.pad_dot);
mViewsId.add(R.id.pad_del);
for (int viewId : mViewsId) {
findViewById(viewId).setOnClickListener(this);
findViewById(viewId).setOnLongClickListener(this);
}
}
@Override
public boolean onLongClick(View v) {
switch (v.getId()) {
case R.id.pad_del:
if (mInputView != null) {
mInputView.setText("");
}
break;
}
return true;
}
@Override
public void onClick(View v) {
int result_param = PAD_ERR;
switch (v.getId()) {
case R.id.pad_0:
result_param = PAD_ZERO;
break;
case R.id.pad_1:
result_param = PAD_ONE;
break;
case R.id.pad_2:
result_param = PAD_TWO;
break;
case R.id.pad_3:
result_param = PAD_THREE;
break;
case R.id.pad_4:
result_param = PAD_FOUR;
break;
case R.id.pad_5:
result_param = PAD_FIVE;
break;
case R.id.pad_6:
result_param = PAD_SIX;
break;
case R.id.pad_7:
result_param = PAD_SEVEN;
break;
case R.id.pad_8:
result_param = PAD_EIGHT;
break;
case R.id.pad_9:
result_param = PAD_NINE;
break;
case R.id.pad_dot:
result_param = PAD_DOT;
break;
case R.id.pad_del:
result_param = PAD_DEL;
break;
}
L.d("click button type : " + result_param); // do the default action
doDefaultNumericAction(result_param);
}
既然是用户自己想定制按钮输入逻辑,那么这个逻辑代码应该是放在含有NumericPad的activity/fragment中的,所以我们在NumericPad里面写一个interface:
public interface NumericPadButtonClickListener {
/**
* 当按下数字键盘某个按钮后的回调
* @param type 检查返回值是否为PAD_ERR(错误),否者就是正常按下了某个值,根据值来判断做对应的界面响应
*/
void onNumericPadButtonClicked(int type);
}
/**
* 设置键盘按钮响应回调方法
* @param mListener
*/
public void setNumericPadButtonClickListener(NumericPadButtonClickListener mListener) {
this.mListener = mListener;
}
@Override
public void onNumericPadButtonClicked(int type) { }
@Override
public void onClick(View v) {
int result_param = PAD_ERR;
switch (v.getId()) {
case R.id.pad_0:
result_param = PAD_ZERO;
break;
case R.id.pad_1:
result_param = PAD_ONE;
break;
case R.id.pad_2:
result_param = PAD_TWO;
break;
case R.id.pad_3:
result_param = PAD_THREE;
break;
case R.id.pad_4:
result_param = PAD_FOUR;
break;
case R.id.pad_5:
result_param = PAD_FIVE;
break;
case R.id.pad_6:
result_param = PAD_SIX;
break;
case R.id.pad_7:
result_param = PAD_SEVEN;
break;
case R.id.pad_8:
result_param = PAD_EIGHT;
break;
case R.id.pad_9:
result_param = PAD_NINE;
break;
case R.id.pad_dot:
result_param = PAD_DOT;
break;
case R.id.pad_del:
result_param = PAD_DEL;
break;
}
L.d("click button type : " + result_param);
if (mListener != null) {
// 新添加的代码
// do the custom action
mListener.onNumericPadButtonClicked(result_param);
} else {
L.d("button click listener is null, will call the default action");
// do the default action
doDefaultNumericAction(result_param);
}
}
设置正在操作的输入框
这里很简单,就是一个设置的接口:
public void setInputView(@NonNull TextView view) {
this.mInputView = view;
}
至此,一个完整的可以快速复用定制的小键盘输入组件就搞定了
教你写一个Android可快速复用的小键盘输入控件的更多相关文章
- Android 高仿微信支付密码输入控件
像微信支付密码控件,在app中是一个多么司空见惯的功能.最近,项目需要这个功能,于是乎就实现这个功能. 老样子,投篮需要找准角度,变成需要理清思路.对于这个"小而美"的控件,我们思 ...
- Android 图片混排富文本编辑器控件
概述 一个Android 图片混排富文本编辑器控件(仿兴趣部落) 详细 代码下载:http://www.demodashi.com/demo/12032.html 一.一个Android 图片混排富文 ...
- 只有20行Javascript代码!手把手教你写一个页面模板引擎
http://www.toobug.net/article/how_to_design_front_end_template_engine.html http://barretlee.com/webs ...
- 半个小时教你写一个装(bi)逼(she)之地图搜租房
半个小时教你写一个装(bi)逼(she)之地图搜租房 首先需要一个Python3环境,怎么准备我就不多说了,实在不会的出门右转看一下廖雪峰老师的博客. HTML部分 代码来自:高德API+Python ...
- 写一个Android输入法01——最简步骤
本文演示用Android Studio写一个最简单的输入法.界面和交互都很简陋,只为剔肉留骨,彰显写一个Android输入法的要点. 1.打开Android Studio创建项目,该项目和普通APP的 ...
- 为PhoneGap写一个android插件
为PhoneGap写一个android插件,要怎么做? 其实这句话应该反过来说,为android写一个PhoneGap插件,要怎么做? 这里以最简单的Hello World!为例,做个说明: 1.第一 ...
- 【vps】教你写一个属于自己的随机图API
[vps]教你写一个自己的随机图API 前言 刚刚开始使用halo博客的时候,我就发现halo博客系统是可以使用随机图当背景的,所以也是使用了网上一些比较火的随机图API. 在上次发现了各种图片API ...
- 写一个Android输入法02——候选窗、转换
上一篇介绍了完成Android输入法的最小化步骤,它只能将按键对应的字符上屏.一般的东亚语言都有一个转换的过程,比如汉语输入拼音,需要由拼音转成汉字再上屏.本文将在前文基础上加入完成转换过程所必需的候 ...
- Android 自定义支持快速搜索筛选的选择控件(一)
Android 自定义支持快速搜索筛选的选择控件 项目中遇到选择控件选项过多,需要快速查找匹配的情况. 做了简单的Demo,效果图如下: 源码地址:https://github.com/whieenz ...
随机推荐
- Go对OO的选择
Go摒弃了许多OO的概念,但是还是很好的继承了OO的精髓——消息传递.我猜这个是学了Smalltalk的.通常我们说OO,我们会说这三大特性:对象,继承,多态. 1,Go中的对象 对于GO来说他的类型 ...
- j-query应用---鼠标悬停不同文字显示不同背景图片banner动画
源代码部分:注意事项:样式表的引用的路径要一致. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ...
- MyEclipse下创建的项目导入到Eclipse中详细的图文配置方法
一.情景再现. 有些人比较喜欢用Myeclipse开发,有些人却比较喜欢用eclipse开发.但是其中有一个问题,Myeclipse里面的项目导入的时候出现了一个小小的问题. 如下: 二.说明问题 导 ...
- python 发送邮件函数模块
发送邮件函数功能 #!/usr/bin/env python # -*- coding:utf-8 -*- import smtplib from email.mime.text import MIM ...
- Android中Spanner获取选中内容和选中位置,根据位置选择对象
作为一名菜鸟,关于spanner获取选中的内容文字代码,网上后很多 但是根据给出的位置来自动选择对象,这个代码一直没找到 后来找人问了问,才知道就一句话的事,特意在这里记录下 array.xml X ...
- scons使用
1.概述 scons是一个Python写的自动化构建工具,和GNU make相比优点明显: A.移植性:python能运行的地方,就能运行scons B. 扩展性:理论上scons只是提供 ...
- 如何在TFS的过程模板中添加报表
在新建团队项目的过程中,TFS的"新建团队项目向导"会根据用户选择的过程模板类型(CMMI, Scrum,Agile等)自动为团队项目创建一个SSRS(SQL Server Rep ...
- POJ 1990 MooFest --树状数组
题意:牛的听力为v,两头牛i,j之间交流,需要max(v[i],v[j])*dist(i,j)的音量.求所有两两头牛交谈时音量总和∑(max(v[i],v[j])*abs(x[j]-x[i])) ,x ...
- POJ 2823 Sliding Window 再探单调队列
重新刷这个经典题,感觉跟以前不一样了,变得更加容易理解了,不讲解了,看代码.注意:要用C++提交,用G++会超时.. 代码: #include <iostream> #include &l ...
- bootstrap学习总结-js组件(四)
这次我们来看下js组件的使用,本篇文章会有点长,希望大家可以耐心看,相信收获会有不少.不少园友加我好友,表示喜欢我写文字的风格,简单明了,这里,再次谢谢你们的支持.一方面,博主自身技术有限,写的东西都 ...