Android自定义View实现微信支付密码输入框
程序员文章站
2023-11-25 17:17:10
本文实例为大家分享了android实现微信支付密码输入框的具体代码,供大家参考,具体内容如下
效果图
项目中使用到了支付密码功能,其实这类界面是比较常用的,涉及支付...
本文实例为大家分享了android实现微信支付密码输入框的具体代码,供大家参考,具体内容如下
效果图
项目中使用到了支付密码功能,其实这类界面是比较常用的,涉及支付密码的输入的一般都会用到对的,所以单独地把这部分抽取出来,有需要的朋友可以拿去用哈!
效果就是支付,弹出密码框,输入密码,这个过程密码不可见,并且提供一个输入完毕的监听!
这个弹出层呢,其实就是一个dialogfragment,逻辑封装在其内部
一.弹出层进出动画 (anim文件)
push_bottom_in.xml
<?xml version="1.0" encoding="utf-8"?> <!-- 上下滑入式 --> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="200" android:fromydelta="100%p" android:toydelta="0" /> </set>
push_bottom_out.xml
<?xml version="1.0" encoding="utf-8"?> <!-- 上下滑出式 --> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="200" android:fromydelta="0" android:toydelta="100%p" /> </set>
二.drawable资源
selector_item_pressed.xml
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@color/gray_bg" android:state_pressed="true" /> <item android:drawable="@color/white" android:state_activated="false" /> <item android:drawable="@color/white" /> </selector>
键盘的点击效果
shape_dialog.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="@android:color/white" /> <corners android:radius="10dp" /> </shape>
弹出框样式
三.mipmap资源
ic_arrow_down
ic_input_del
icon_del.png
四.layout布局
fragment_pay.xml
支付弹出层布局
<?xml version="1.0" encoding="utf-8"?> <relativelayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <linearlayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginleft="40dp" android:layout_marginright="40dp" android:layout_margintop="100dp" android:background="@drawable/shape_dialog" android:orientation="vertical" android:paddingbottom="@dimen/spacing_large"> <relativelayout android:layout_width="match_parent" android:layout_height="wrap_content"> <textview style="@style/style_black_normal_text" android:layout_width="wrap_content" android:layout_height="@dimen/text_item_height" android:layout_centerinparent="true" android:gravity="center" android:text="请输入支付密码" android:textsize="20sp" android:textstyle="bold" /> <!--cancel键--> <imageview android:id="@+id/iv_close" android:clickable="true" android:layout_width="28dp" android:layout_height="28dp" android:layout_alignparentleft="true" android:layout_centervertical="true" android:layout_marginleft="@dimen/spacing_tiny" android:src="@mipmap/icon_del" /> </relativelayout> <view style="@style/style_separate_line" /> <!--操作文字--> <textview android:id="@+id/tv_content" style="@style/style_black_normal_text" android:layout_width="wrap_content" android:layout_height="@dimen/text_item_height" android:layout_gravity="center_horizontal" android:gravity="center" android:textstyle="bold" /> <!--支付金额--> <textview android:id="@+id/tv_content2" style="@style/style_black_money_text" android:layout_width="wrap_content" android:layout_height="@dimen/text_item_height" android:layout_gravity="center_horizontal" android:gravity="center" android:textstyle="bold" /> <!--额外扣除手续费--> <textview android:id="@+id/tv_content3" style="@style/style_black_normal_text" android:layout_width="wrap_content" android:layout_height="@dimen/text_item_height2" android:layout_gravity="center_horizontal" android:gravity="center" /> <!--密码输入框--> <cn.xdeveloper.payui.paypasswordview android:id="@+id/paypwdview" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginleft="@dimen/spacing_large" android:layout_marginright="@dimen/spacing_large" android:background="@color/white" /> </linearlayout> <!--键盘--> <cn.xdeveloper.payui.passwordinputview android:id="@+id/inputmethodview" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignparentbottom="true" /> </relativelayout>
自定义键盘布局
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/table_num" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="6" android:background="@color/gray_line" android:orientation="vertical"> <view style="@style/style_separate_line" /> <relativelayout android:id="@+id/layout_hide" android:layout_width="match_parent" android:layout_height="25dp" android:background="@drawable/selector_item_pressed"> <imageview android:layout_width="30dp" android:layout_height="wrap_content" android:layout_centerinparent="true" android:src="@mipmap/ic_arrow_down" /> </relativelayout> <linearlayout style="@style/layout_input_amount_style"> <textview android:id="@+id/btn_1" style="@style/btn_input_num_style" android:layout_marginright="@dimen/input_method_spacing" android:layout_margintop="@dimen/input_method_spacing" android:onclick="onclick" android:tag="1" android:text="1" /> <textview android:id="@+id/btn_2" style="@style/btn_input_num_style" android:layout_marginright="@dimen/input_method_spacing" android:layout_margintop="@dimen/input_method_spacing" android:tag="2" android:text="2" /> <textview android:id="@+id/btn_3" style="@style/btn_input_num_style" android:layout_margintop="@dimen/input_method_spacing" android:tag="3" android:text="3" /> </linearlayout> <linearlayout style="@style/layout_input_amount_style"> <textview android:id="@+id/btn_4" style="@style/btn_input_num_style" android:layout_marginright="@dimen/input_method_spacing" android:tag="4" android:text="4" /> <textview android:id="@+id/btn_5" style="@style/btn_input_num_style" android:layout_marginright="@dimen/input_method_spacing" android:tag="5" android:text="5" /> <textview android:id="@+id/btn_6" style="@style/btn_input_num_style" android:tag="6" android:text="6" /> </linearlayout> <linearlayout style="@style/layout_input_amount_style"> <textview android:id="@+id/btn_7" style="@style/btn_input_num_style" android:layout_marginright="@dimen/input_method_spacing" android:tag="7" android:text="7" /> <textview android:id="@+id/btn_8" style="@style/btn_input_num_style" android:layout_marginright="@dimen/input_method_spacing" android:tag="8" android:text="8" /> <textview android:id="@+id/btn_9" style="@style/btn_input_num_style" android:tag="9" android:text="9" /> </linearlayout> <linearlayout style="@style/layout_input_amount_style"> <textview style="@style/btn_input_num_style" android:layout_marginright="@dimen/input_method_spacing" android:background="@color/gray_btn" /> <textview android:id="@+id/btn_0" style="@style/btn_input_num_style" android:layout_marginright="@dimen/input_method_spacing" android:tag="0" android:text="0" /> <imageview android:id="@+id/btn_del" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:scaletype="center" android:src="@mipmap/ic_input_del" android:tag="-1" /> </linearlayout> </linearlayout>
五.color资源
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorprimary">#3f51b5</color> <color name="colorprimarydark">#303f9f</color> <color name="coloraccent">#ff4081</color> <color name="gray_text">#919191</color> <color name="gray_btn">#ebebeb</color> <color name="gray_bg">#f0eff5</color> <color name="gray_line">#d5d1d1</color> <color name="white">#ffffff</color> <color name="black">#000000</color> <color name="black_text">#212121</color> </resources>
六.dimen资源
<?xml version="1.0" encoding="utf-8"?> <resources> <!-- 字体大小 --> <dimen name="font_larger">40sp</dimen> <dimen name="font_large">18sp</dimen> <dimen name="font_normal">15sp</dimen> <dimen name="font_small">12sp</dimen> <dimen name="font_tiny">10sp</dimen> <!-- 控件之间的距离 --> <dimen name="spacing_large">20dp</dimen> <dimen name="spacing_normal">15dp</dimen> <dimen name="spacing_small">10dp</dimen> <dimen name="spacing_tiny">10dp</dimen> <dimen name="divider_height">0.5dp</dimen> <dimen name="spacing_layout_padding">10dp</dimen> <dimen name="spacing_layout_margin">10dp</dimen> <!-- 描述性文字item项的高 --> <dimen name="text_item_height">50dp</dimen> <dimen name="text_item_height2">25dp</dimen> <dimen name="input_method_spacing">2px</dimen> </resources>
七.styles样式
<resources> <!-- base application theme. --> <style name="apptheme" parent="theme.appcompat.light.darkactionbar"> <!-- customize your theme here. --> <item name="colorprimary">@color/colorprimary</item> <item name="colorprimarydark">@color/colorprimarydark</item> <item name="coloraccent">@color/coloraccent</item> </style> <!--底部弹框--> <style name="bottomdialog" parent="@style/theme.appcompat"> <item name="android:layout_width">match_parent</item> <item name="android:layout_height">wrap_content</item> <item name="android:windowisfloating">true</item> <item name="android:backgrounddimenabled">true</item> </style> <style name="animbottom" parent="@android:style/animation"> <item name="android:windowenteranimation">@anim/push_bottom_in</item> <item name="android:windowexitanimation">@anim/push_bottom_out</item> </style> <!-- 提示文字样式 --> <style name="style_black_normal_text"> <item name="android:textcolor">@color/black_text</item> <item name="android:textsize">@dimen/font_normal</item> <item name="android:includefontpadding">false</item> </style> <!-- 输入金额样式 --> <style name="style_black_money_text"> <item name="android:textcolor">@color/black_text</item> <item name="android:textsize">@dimen/font_larger</item> <item name="android:includefontpadding">false</item> </style> <!-- 分割线样式 --> <style name="style_separate_line"> <item name="android:layout_width">match_parent</item> <item name="android:layout_height">@dimen/divider_height</item> <item name="android:background">@color/gray_line</item> </style> <!--密码弹出框--> <declare-styleable name="paypasswordview"> <attr name="count" format="integer" /> <attr name="border_color" format="color" /> <attr name="dot_color" format="color" /> </declare-styleable> <!--输入样式--> <style name="layout_input_amount_style"> <item name="android:layout_width">match_parent</item> <item name="android:layout_height">55dp</item> <item name="android:layout_marginbottom">2px</item> <item name="android:gravity">center</item> <item name="android:orientation">horizontal</item> </style> <!--键盘数字--> <style name="btn_input_num_style"> <item name="android:layout_width">0dp</item> <item name="android:layout_height">match_parent</item> <item name="android:layout_weight">1</item> <item name="android:gravity">center</item> <item name="android:textsize">25sp</item> <item name="android:textcolor">@color/black_text</item> <item name="android:background">@drawable/selector_item_pressed</item> </style> </resources>
八.输入键盘view
public class passwordinputview extends linearlayout implements view.onclicklistener { private inputreceiver inputreceiver; public passwordinputview(context context, @nullable attributeset attrs) { super(context, attrs); layoutinflater.from(context).inflate(r.layout.view_password_input, this); initview(); } private void initview() { findviewbyid(r.id.btn_1).setonclicklistener(this); findviewbyid(r.id.btn_2).setonclicklistener(this); findviewbyid(r.id.btn_3).setonclicklistener(this); findviewbyid(r.id.btn_4).setonclicklistener(this); findviewbyid(r.id.btn_5).setonclicklistener(this); findviewbyid(r.id.btn_6).setonclicklistener(this); findviewbyid(r.id.btn_7).setonclicklistener(this); findviewbyid(r.id.btn_8).setonclicklistener(this); findviewbyid(r.id.btn_9).setonclicklistener(this); findviewbyid(r.id.btn_0).setonclicklistener(this); findviewbyid(r.id.btn_del).setonclicklistener(this); findviewbyid(r.id.layout_hide).setonclicklistener(new onclicklistener() { @override public void onclick(view v) { setvisibility(gone); } }); } @override public void onclick(view v) { string num = (string) v.gettag(); this.inputreceiver.receive(num); } /** * 设置接收器 * * @param receiver */ public void setinputreceiver(inputreceiver receiver) { this.inputreceiver = receiver; } /** * 输入接收器 */ public interface inputreceiver { void receive(string num); } }
九.密码框view
public class paypasswordview extends view { private arraylist<string> result;//输入结果保存 private int count;//密码位数 private int size;//默认每一格的大小 private paint mborderpaint;//边界画笔 private paint mdotpaint;//掩盖点的画笔 private int mbordercolor;//边界颜色 private int mdotcolor;//掩盖点的颜色 private rectf mroundrect;//外面的圆角矩形 private int mroundradius;//圆角矩形的圆角程度 public paypasswordview(context context) { super(context); init(null);//初始化 } private inputcallback inputcallback;//输入完成的回调 private passwordinputview inputmethodview; //输入键盘 public interface inputcallback { void oninputfinish(string result); } public paypasswordview(context context, attributeset attrs) { super(context, attrs); init(attrs); } public paypasswordview(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); init(attrs); } /** * 初始化相关参数 */ void init(attributeset attrs) { final float dp = getresources().getdisplaymetrics().density; this.setfocusable(true); this.setfocusableintouchmode(true); result = new arraylist<>(); if (attrs != null) { typedarray ta = getcontext().obtainstyledattributes(attrs, r.styleable.paypasswordview); mbordercolor = ta.getcolor(r.styleable.paypasswordview_border_color, color.ltgray); mdotcolor = ta.getcolor(r.styleable.paypasswordview_dot_color, color.black); count = ta.getint(r.styleable.paypasswordview_count, 6); ta.recycle(); } else { mbordercolor = color.ltgray; mdotcolor = color.gray; count = 6;//默认6位密码 } size = (int) (dp * 30);//默认30dp一格 //color mborderpaint = new paint(paint.anti_alias_flag); mborderpaint.setstrokewidth(3); mborderpaint.setstyle(paint.style.stroke); mborderpaint.setcolor(mbordercolor); mdotpaint = new paint(paint.anti_alias_flag); mdotpaint.setstrokewidth(3); mdotpaint.setstyle(paint.style.fill); mdotpaint.setcolor(mdotcolor); mroundrect = new rectf(); mroundradius = (int) (5 * dp); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { int w = measurewidth(widthmeasurespec); int h = measureheight(heightmeasurespec); int wsize = measurespec.getsize(widthmeasurespec); int hsize = measurespec.getsize(heightmeasurespec); //宽度没指定,但高度指定 if (w == -1) { if (h != -1) { w = h * count;//宽度=高*数量 size = h; } else {//两个都不知道,默认宽高 w = size * count; h = size; } } else {//宽度已知 if (h == -1) {//高度不知道 h = w / count; size = h; } } setmeasureddimension(math.min(w, wsize), math.min(h, hsize)); } private int measurewidth(int widthmeasurespec) { //宽度 int wmode = measurespec.getmode(widthmeasurespec); int wsize = measurespec.getsize(widthmeasurespec); if (wmode == measurespec.at_most) {//wrap_content return -1; } return wsize; } private int measureheight(int heightmeasurespec) { //高度 int hmode = measurespec.getmode(heightmeasurespec); int hsize = measurespec.getsize(heightmeasurespec); if (hmode == measurespec.at_most) {//wrap_content return -1; } return hsize; } @override public boolean ontouchevent(motionevent event) { if (event.getaction() == motionevent.action_down) {//点击控件弹出输入键盘 requestfocus(); inputmethodview.setvisibility(visible); return true; } return true; } @override protected void onfocuschanged(boolean gainfocus, int direction, rect previouslyfocusedrect) { super.onfocuschanged(gainfocus, direction, previouslyfocusedrect); if (gainfocus) { inputmethodview.setvisibility(visible); } else { inputmethodview.setvisibility(gone); } } @override protected void ondraw(canvas canvas) { super.ondraw(canvas); final int width = getwidth() - 2; final int height = getheight() - 2; //先画个圆角矩形 mroundrect.set(0, 0, width, height); canvas.drawroundrect(mroundrect, 0, 0, mborderpaint); //画分割线 for (int i = 1; i < count; i++) { final int x = i * size; canvas.drawline(x, 0, x, height, mborderpaint); } //画掩盖点, // 这是前面定义的变量 private arraylist<integer> result;//输入结果保存 int dotradius = size / 8;//圆圈占格子的三分之一 for (int i = 0; i < result.size(); i++) { final float x = (float) (size * (i + 0.5)); final float y = size / 2; canvas.drawcircle(x, y, dotradius, mdotpaint); } } @override public boolean oncheckistexteditor() { return true; } @override public inputconnection oncreateinputconnection(editorinfo outattrs) { outattrs.inputtype = inputtype.type_class_number;//输入类型为数字 outattrs.imeoptions = editorinfo.ime_action_done; return new myinputconnection(this, false); } public void setinputcallback(inputcallback inputcallback) { this.inputcallback = inputcallback; } public void clearresult() { result.clear(); invalidate(); } private class myinputconnection extends baseinputconnection { public myinputconnection(view targetview, boolean fulleditor) { super(targetview, fulleditor); } @override public boolean committext(charsequence text, int newcursorposition) { //这里是接受输入法的文本的,我们只处理数字,所以什么操作都不做 return super.committext(text, newcursorposition); } @override public boolean deletesurroundingtext(int beforelength, int afterlength) { //软键盘的删除键 del 无法直接监听,自己发送del事件 if (beforelength == 1 && afterlength == 0) { return super.sendkeyevent(new keyevent(keyevent.action_down, keyevent.keycode_del)) && super.sendkeyevent(new keyevent(keyevent.action_up, keyevent.keycode_del)); } return super.deletesurroundingtext(beforelength, afterlength); } } /** * 设置输入键盘view * * @param inputmethodview */ public void setinputmethodview(passwordinputview inputmethodview) { this.inputmethodview = inputmethodview; this.inputmethodview.setinputreceiver(new passwordinputview.inputreceiver() { @override public void receive(string num) { if (num.equals("-1")) { if (!result.isempty()) { result.remove(result.size() - 1); invalidate(); } } else { if (result.size() < count) { result.add(num); invalidate(); ensurefinishinput(); } } } }); } /** * 判断是否输入完成,输入完成后调用callback */ void ensurefinishinput() { if (result.size() == count && inputcallback != null) {//输入完成 stringbuffer sb = new stringbuffer(); for (string i : result) { sb.append(i); } inputcallback.oninputfinish(sb.tostring()); } } /** * 获取输入文字 * * @return */ public string getinputtext() { if (result.size() == count) { stringbuffer sb = new stringbuffer(); for (string i : result) { sb.append(i); } return sb.tostring(); } return null; } }
十.支付弹出层
public class payfragment extends dialogfragment implements view.onclicklistener { public static final string extra_content = "extra_content"; //提示框内容 public static final string extra_content2 = "extra_content2"; //提示框内容 public static final string extra_content3 = "extra_content3"; //提示框内容 private paypasswordview psw_input; private paypasswordview.inputcallback inputcallback; @nonnull @override public dialog oncreatedialog(bundle savedinstancestate) { // 使用不带theme的构造器, 获得的dialog边框距离屏幕仍有几毫米的缝隙。 dialog dialog = new dialog(getactivity(), r.style.bottomdialog); dialog.requestwindowfeature(window.feature_no_title); // 设置content前设定 dialog.setcontentview(r.layout.fragment_pay); dialog.setcanceledontouchoutside(true); //外部点击取消 // 设置宽度为屏宽, 靠近屏幕底部。 final window window = dialog.getwindow(); window.setwindowanimations(r.style.animbottom); window.setbackgrounddrawable(new colordrawable(color.transparent)); final windowmanager.layoutparams lp = window.getattributes(); lp.width = windowmanager.layoutparams.match_parent; // 宽度持平 lp.gravity = gravity.top; window.setattributes(lp); initview(dialog); return dialog; } private void initview(dialog dialog) { bundle bundle = getarguments(); if (bundle != null) { textview tv_content = (textview) dialog.findviewbyid(r.id.tv_content); textview tv_content2 = (textview) dialog.findviewbyid(r.id.tv_content2); textview tv_content3 = (textview) dialog.findviewbyid(r.id.tv_content3); tv_content.settext(bundle.getstring(extra_content)); tv_content2.settext(bundle.getstring(extra_content2)); tv_content3.settext(bundle.getstring(extra_content3)); } psw_input = (paypasswordview) dialog.findviewbyid(r.id.paypwdview); passwordinputview inputmethodview = (passwordinputview) dialog.findviewbyid(r.id.inputmethodview); psw_input.setinputmethodview(inputmethodview); psw_input.setinputcallback(inputcallback); dialog.findviewbyid(r.id.iv_close).setonclicklistener(this); } @override public void onclick(view v) { switch (v.getid()) { case r.id.iv_close: dismiss(); break; } } /** * 设置输入回调 * * @param inputcallback */ public void setpaysuccesscallback(paypasswordview.inputcallback inputcallback) { this.inputcallback = inputcallback; } }
十一.逻辑代码中直接引用
public class mainactivity extends appcompatactivity implements paypasswordview.inputcallback, view.onclicklistener { private payfragment fragment; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); findviewbyid(r.id.btn_pay).setonclicklistener(this); } @override public void onclick(view v) { switch (v.getid()) { case r.id.btn_pay: bundle bundle = new bundle(); bundle.putstring(payfragment.extra_content, "提现"); bundle.putstring(payfragment.extra_content2, "¥" + 1.00); bundle.putstring(payfragment.extra_content3, "额外扣除0.1手续费"); fragment = new payfragment();//创建支付弹出框实例 fragment.setarguments(bundle);//传递信息 fragment.setpaysuccesscallback(mainactivity.this);//设置回调 fragment.show(getsupportfragmentmanager(), "pay"); break; } } @override public void oninputfinish(string result) { toast.maketext(this, result, toast.length_short).show(); fragment.dismiss();//窗口消失 } }
什么都没有,只有一个点击事件而已.
分享结束,这里面的代码可是有我造假的成分哦,不过,我就是喜欢将优秀的东西集成在一起,谢谢观看!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。