更新:介于很多人问我在兑换框中不能显示的问题和不能直接弹出软件盘的问题,在这里我添加了对话框模式并且在对话框中会直接弹出软键盘,CSDN不能更新, 最新的代码和demo在GitHub上面,大家可以下载看看哦。
*****我的视频课程:FFmpeg打造Android万能音频播放器*****
现在很多应用都会集成支付功能,不管是直接调用支付SDK还是自己平台的虚拟货币,支付密码都是很重要的。一般的应用会直接使用Edittext作为密码输入框,这个看着就有点low了,高大上一点的就会自定义一个支付界面,然后输入效果也会有相应的设计,比如我们看到的支付宝和微信支付就是这样的。因为常用所以我也就简单的写了一个类似的支付密码输入控件,望以后不再纠结于此事,哈哈哈,先来张效果图:
控件就是这样的,具体和怎样的支付界面或对话框搭配,就可以灵活使用了。
编程写代码的快慢和Bug的多少都取决于编程思路和思想,所谓编程的思路想法才是最重要的,即:算法是灵魂。所以我们先说说实现思想是怎么回事,当思想懂了,写代码就可以有一千种方式了。
一、实现思想如下:
分析效果图我们可以发现要能输入类容还要得到内容的值,所以首先得有Edittext。第一种尝试:密码个数是多少个,就写多少个Edittext,然后监听每个的值,最后组合到一起就是输入的密码。这个方式可以简单的实现顺序输入效果,但是就没有那么灵活了,会考虑当前输入框前后输入框的值是否有,是否需要跳转指针等等麻烦的事,而且代码也比较多,所以这种方式就pass掉了;第二种尝试:就是一个Edittext,然后在它上面覆盖密码个数的TextView,随时监听Edittext的内容变化实时反馈到TextView中,就可以达到这种效果了,而且只有一个Edittext,长按退格键可以删除完内容,还可以直接清空类容都很方便。这里有个技巧就是,输入框Edittext的大小应该和TextView组合起来的整体大小一致,点击效果才能更完美,然后Edittext的字体大小应该尽量小(0或者1),才能保证每次获取焦点时都是在内容最末尾处。这样就可以实现这种支付密码效果了。
二、封装过程
思路大家已经知道了,根据思路来如果每次用xml布局的话,那还是很麻烦的,要写那么多Textview和布局,这是我们不能忍受的,贴别是应用中多个地方都用到了支付功能,那就GG了。所以我把这些操作都封装到了一个控件里面,然后暴露出相应的方法来设置属性(这里不是很全,可根据自己的需求添加相应的属性方法来达到自己的效果),使用时就当做一个简单的控件使用就行(本人不是很喜欢自定义属性,感觉有点拖泥带水的,所以都是用方法来实现的)。
(1)因为有控件重叠效果,所以首先集成RelativeLayout来达到这个效果。
/**
* Created by ywl on 2016/7/10.
*/
public class PayPwdEditText extends RelativeLayout{
private EditText editText; //文本编辑框
private Context context;
private LinearLayout linearLayout; //文本密码的文本
private TextView[] textViews; //文本数组
private int pwdlength = 6; //密码长度, 默认6
private OnTextFinishListener onTextFinishListener;
public PayPwdEditText(Context context) {
this(context, null);
}
public PayPwdEditText(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public PayPwdEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
}
}
(2)分析要用到的属性,有密码框的背景布局、密码长度、每个密码直接的分割线宽度和颜色、密码字体颜色和大小(还可以密码设置显示的字符效果,这里没有添加,使用的默认效果)
(3)初始化Edittext
/**
* 初始化编辑框
* @param bgcolor
*/
private void initEdit(int bgcolor)
{
editText = new EditText(context);
editText.setBackgroundResource(bgcolor);
editText.setCursorVisible(false);
editText.setTextSize(0);
editText.setInputType(InputType.TYPE_NUMBER_VARIATION_PASSWORD | InputType.TYPE_CLASS_NUMBER);
editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(pwdlength)});
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
Editable etext = editText.getText();
Selection.setSelection(etext, etext.length());
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
initDatas(s);
if(s.length() == pwdlength)
{
if(onTextFinishListener != null)
{
onTextFinishListener.onFinish(s.toString().trim());
}
}
}
});
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
lp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
addView(editText, lp);
}
这里可以对输入框的类型进行定制,只能输入数字还是数字字母混合等,然后监听每次输入的类容,并添加回调接口,方便使用时得到数据。
(4)初始化TextView显示框
/**
* @param bgcolor 背景drawable
* @param pwdlength 密码长度
* @param slpilinewidth 分割线宽度
* @param splilinecolor 分割线颜色
* @param pwdcolor 密码字体颜色
* @param pwdsize 密码字体大小
*/
public void initShowInput(int bgcolor, int pwdlength, float slpilinewidth, int splilinecolor, int pwdcolor, int pwdsize)
{
//添加密码框父布局
linearLayout = new LinearLayout(context);
linearLayout.setBackgroundResource(bgcolor);
LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
linearLayout.setLayoutParams(layoutParams);
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
addView(linearLayout);
//添加密码框
textViews = new TextView[pwdlength];
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,LayoutParams.MATCH_PARENT);
params.weight = 1;
params.gravity = Gravity.CENTER;
LinearLayout.LayoutParams params2 = new LinearLayout.LayoutParams(dip2px(context, slpilinewidth),LayoutParams.MATCH_PARENT);
for(int i = 0; i < textViews.length; i++)
{
final int index = i;
TextView textView = new TextView(context);
textView.setGravity(Gravity.CENTER);
textViews[i] = textView;
textViews[i].setTextSize(pwdsize);
textViews[i].setTextColor(context.getResources().getColor(pwdcolor));
textViews[i].setInputType(InputType.TYPE_NUMBER_VARIATION_PASSWORD | InputType.TYPE_CLASS_NUMBER);
linearLayout.addView(textView, params);
if(i < textViews.length - 1)
{
View view = new View(context);
view.setBackgroundColor(context.getResources().getColor(splilinecolor));
linearLayout.addView(view, params2);
}
}
}
这个也是初始化TextView的显示效果,然后根据密码长度动态添加到布局中,并保存每个TextView的引用,方便以后对它门进行操作。
(5)然后是根据Edittext的输入内容设置Textview的值
/**
* 根据输入字符,显示密码个数
* @param s
*/
public void initDatas(Editable s)
{
if(s.length() > 0)
{
int length = s.length();
for(int i = 0; i < pwdlength; i++)
{
if(i < length)
{
for(int j = 0; j < length; j++)
{
char ch = s.charAt(j);
textViews[j].setText(String.valueOf(ch));
}
}
else
{
textViews[i].setText("");
}
}
}
else
{
for(int i = 0; i < pwdlength; i++)
{
textViews[i].setText("");
}
}
}
这个方法添加到Edittext的TextWatcher监听中即可,就能动态显示密码效果了。
核心思路和实现就是这样的,然后提供一个初始化入口:
/**
* @param bgdrawable 背景drawable
* @param pwdlength 密码长度
* @param splilinewidth 分割线宽度
* @param splilinecolor 分割线颜色
* @param pwdcolor 密码字体颜色
* @param pwdsize 密码字体大小
*/
public void initStyle(int bgdrawable, int pwdlength, float splilinewidth, int splilinecolor, int pwdcolor, int pwdsize)
{
this.pwdlength = pwdlength;
initEdit(bgdrawable);
initShowInput(bgdrawable, pwdlength, splilinewidth, splilinecolor, pwdcolor, pwdsize);
}
其他属性方法如下:
/**
* 是否显示明文
* @param showPwd
*/
public void setShowPwd(boolean showPwd) {
int length = textViews.length;
for(int i = 0; i < length; i++) {
if (showPwd) {
textViews[i].setTransformationMethod(PasswordTransformationMethod.getInstance());
} else {
textViews[i].setTransformationMethod(HideReturnsTransformationMethod.getInstance());
}
}
}
/**
* 设置显示类型
* @param type
*/
public void setInputType(int type)
{
int length = textViews.length;
for(int i = 0; i < length; i++) {
textViews[i].setInputType(type);
}
}
/**
* 清除文本框
*/
public void clearText()
{
editText.setText("");
for(int i = 0; i < pwdlength; i++)
{
textViews[i].setText("");
}
}
public void setOnTextFinishListener(OnTextFinishListener onTextFinishListener) {
this.onTextFinishListener = onTextFinishListener;
}
/**
得到输入内容
*/
public String getPwdText()
{
if(editText != null)
return editText.getText().toString().trim();
return "";
}
public static int dip2px(Context context, float dipValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
}
public interface OnTextFinishListener
{
void onFinish(String str);
}
这样就全部写完了,还是不多是吧,哈哈哈。
项目源码免费下载地址:
1、CSDN:PayPwdEditText
2、Github:PayPwdEditText(添加对话框实例)
欢迎下载和start