服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Android - Android自定义View实现微信支付密码输入框

Android自定义View实现微信支付密码输入框

2022-10-21 14:33AND_Devil Android

这篇文章主要为大家详细介绍了Android自定义View实现微信支付密码输入框,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了Android实现微信支付密码输入框的具体代码,供大家参考,具体内容如下

效果图

Android自定义View实现微信支付密码输入框

项目中使用到了支付密码功能,其实这类界面是比较常用的,涉及支付密码的输入的一般都会用到对的,所以单独地把这部分抽取出来,有需要的朋友可以拿去用哈!

效果就是支付,弹出密码框,输入密码,这个过程密码不可见,并且提供一个输入完毕的监听!

这个弹出层呢,其实就是一个DialogFragment,逻辑封装在其内部

一.弹出层进出动画 (anim文件)

push_bottom_in.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- 上下滑入式 -->
<set xmlns:android="http://schemas.android.com/apk/res/android"><translateandroid: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"><translateandroid: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

Android自定义View实现微信支付密码输入框

ic_input_del

Android自定义View实现微信支付密码输入框

icon_del.png

Android自定义View实现微信支付密码输入框

四.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">
<LinearLayoutandroid: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">
<RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content">
<TextViewandroid: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键--><ImageViewandroid: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  /><!--操作文字--><TextViewandroid:id="@+id/tv_content"android:layout_width="wrap_content"android:layout_height="@dimen/text_item_height"android:layout_gravity="center_horizontal"android:gravity="center"android:textStyle="bold" /><!--支付金额--><TextViewandroid:id="@+id/tv_content2"android:layout_width="wrap_content"android:layout_height="@dimen/text_item_height"android:layout_gravity="center_horizontal"android:gravity="center"android:textStyle="bold" /><!--额外扣除手续费--><TextViewandroid:id="@+id/tv_content3"android:layout_width="wrap_content"android:layout_height="@dimen/text_item_height2"android:layout_gravity="center_horizontal"android:gravity="center" /><!--密码输入框--><cn.xdeveloper.payui.PayPassWordViewandroid: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.PassWordInputViewandroid: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  />
<RelativeLayoutandroid:id="@+id/layout_hide"android:layout_width="match_parent"android:layout_height="25dp"android:background="@drawable/selector_item_pressed">
<ImageViewandroid:layout_width="30dp"android:layout_height="wrap_content"android:layout_centerInParent="true"android:src="@mipmap/ic_arrow_down" />
</RelativeLayout>
<LinearLayout >
<TextViewandroid:id="@+id/btn_1"android:layout_marginRight="@dimen/input_method_spacing"android:layout_marginTop="@dimen/input_method_spacing"android:onClick="onClick"android:tag="1"android:text="1" />
<TextViewandroid:id="@+id/btn_2"android:layout_marginRight="@dimen/input_method_spacing"android:layout_marginTop="@dimen/input_method_spacing"android:tag="2"android:text="2" />
<TextViewandroid:id="@+id/btn_3"android:layout_marginTop="@dimen/input_method_spacing"android:tag="3"android:text="3" /></LinearLayout>
<LinearLayout >
<TextViewandroid:id="@+id/btn_4"android:layout_marginRight="@dimen/input_method_spacing"android:tag="4"android:text="4" />
<TextViewandroid:id="@+id/btn_5"android:layout_marginRight="@dimen/input_method_spacing"android:tag="5"android:text="5" />
<TextViewandroid:id="@+id/btn_6"android:tag="6"android:text="6" /></LinearLayout>
<LinearLayout >
<TextViewandroid:id="@+id/btn_7"android:layout_marginRight="@dimen/input_method_spacing"android:tag="7"android:text="7" />
<TextViewandroid:id="@+id/btn_8"android:layout_marginRight="@dimen/input_method_spacing"android:tag="8"android:text="8" />
<TextViewandroid:id="@+id/btn_9"android:tag="9"android:text="9" /></LinearLayout>
<LinearLayout >
<TextViewandroid:layout_marginRight="@dimen/input_method_spacing"android:background="@color/gray_btn" />
<TextViewandroid:id="@+id/btn_0"android:layout_marginRight="@dimen/input_method_spacing"android:tag="0"android:text="0" />

<ImageViewandroid: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() {@Overridepublic void onClick(View v) {setVisibility(GONE);}});}
@Overridepublic 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一格//colormBorderPaint = 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);}
@Overrideprotected 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_contentreturn -1;}return wsize;}
private int measureHeight(int heightMeasureSpec) {//高度int hmode = MeasureSpec.getMode(heightMeasureSpec);int hsize = MeasureSpec.getSize(heightMeasureSpec);if (hmode == MeasureSpec.AT_MOST) {//wrap_contentreturn -1;}return hsize;}
@Overridepublic boolean onTouchEvent(MotionEvent event) {if (event.getAction() == MotionEvent.ACTION_DOWN) {//点击控件弹出输入键盘requestFocus();inputMethodView.setVisibility(VISIBLE);return true;}return true;}
@Overrideprotected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);if (gainFocus) {inputMethodView.setVisibility(VISIBLE);} else {inputMethodView.setVisibility(GONE);}}
@Overrideprotected 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);}}
@Overridepublic boolean onCheckIsTextEditor() {return true;}
@Overridepublic 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);}
@Overridepublic boolean commitText(CharSequence text, int newCursorPosition) {//这里是接受输入法的文本的,我们只处理数字,所以什么操作都不做return super.commitText(text, newCursorPosition);}
@Overridepublic 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() {@Overridepublic 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@Overridepublic 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);}
@Overridepublic 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;
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);findViewById(R.id.btn_pay).setOnClickListener(this);}
@Overridepublic 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;}}

@Overridepublic void onInputFinish(String result) {Toast.makeText(this, result, Toast.LENGTH_SHORT).show();fragment.dismiss();//窗口消失}
}

什么都没有,只有一个点击事件而已.

分享结束,这里面的代码可是有我造假的成分哦,不过,我就是喜欢将优秀的东西集成在一起,谢谢观看!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/qq_40543575/article/details/80028979

延伸 · 阅读

精彩推荐