1.效果圖
2.實現方式
dialog_confirm_order.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"
android:background="#ffffff">
<LinearLayout
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="40dp">
<TextView
android:textColor="#000000"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:text="在線支付"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tv_close"
android:textColor="#000000"
android:text="X"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="30dp">
<TextView
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:text="支付金額"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:text="¥50.00"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="30dp">
<TextView
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:text="訂單信息"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:text="某某某購買了十桶泡麪"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="30dp">
<TextView
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:text="付款方式"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:text="賬戶餘額"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<TextView
android:layout_gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="40dp" />
<Button
android:id="@+id/btn_confirmorder"
android:background="#9bbdf2"
android:text="立即支付"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
3.dialog_input_password.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"
android:background="#ffffff">
<LinearLayout
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="40dp">
<TextView
android:id="@+id/tv_close"
android:text="X"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:layout_marginLeft="10dp"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:text="請輸入支付密碼"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:paddingLeft="40dp"
android:paddingRight="40dp"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.example.mama.paydemo.widget.PayPsdInputView
android:inputType="number"
android:id="@+id/et_password"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_gravity="right"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:paddingRight="40dp"
android:gravity="right"
android:text="忘記密碼?"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
4.自定義輸入框PayPsdInputView.java
package com.example.mama.paydemo.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.text.InputFilter;
import android.util.AttributeSet;
import android.widget.EditText;
import com.example.mama.paydemo.R;
import static android.graphics.Paint.ANTI_ALIAS_FLAG;
/**
* Created by mama on 2017/12/5.
*/
public class PayPsdInputView extends EditText {
private Context mContext;
/**
* 第一個圓開始繪製的圓心座標
*/
private float startX;
private float startY;
private float cX;
/**
* 實心圓的半徑
*/
private int radius = 10;
/**
* view的高度
*/
private int height;
private int width;
/**
* 當前輸入密碼位數
*/
private int textLength = 0;
private int bottomLineLength;
/**
* 最大輸入位數
*/
private int maxCount = 6;
/**
* 圓的顏色 默認BLACK
*/
private int circleColor = Color.BLACK;
/**
* 底部線的顏色 默認GRAY
*/
private int bottomLineColor = Color.GRAY;
/**
* 分割線的顏色
*/
private int borderColor = Color.GRAY;
/**
* 分割線的畫筆
*/
private Paint borderPaint;
/**
* 分割線開始的座標x
*/
private int divideLineWStartX;
/**
* 分割線的寬度 默認2
*/
private int divideLineWidth = 2;
/**
* 豎直分割線的顏色
*/
private int divideLineColor = Color.GRAY;
private int focusedColor = Color.RED;
private RectF rectF = new RectF();
private RectF focusedRecF = new RectF();
private int psdType = 0;
private final static int psdType_weChat = 0;
private final static int psdType_bottomLine = 1;
/**
* 矩形邊框的圓角
*/
private int rectAngle = 0;
/**
* 豎直分割線的畫筆
*/
private Paint divideLinePaint;
/**
* 圓的畫筆
*/
private Paint circlePaint;
/**
* 底部線的畫筆
*/
private Paint bottomLinePaint;
/**
* 當前輸入的位置索引
*/
private int position = 0;
private onPasswordListener mListener;
public PayPsdInputView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
getAtt(attrs);
initPaint();
this.setBackgroundColor(Color.TRANSPARENT);
this.setCursorVisible(false);
this.setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxCount)});
}
private void getAtt(AttributeSet attrs) {
TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.PayPsdInputView);
maxCount = typedArray.getInt(R.styleable.PayPsdInputView_maxCount, maxCount);
circleColor = typedArray.getColor(R.styleable.PayPsdInputView_circleColor, circleColor);
bottomLineColor = typedArray.getColor(R.styleable.PayPsdInputView_bottomLineColor, bottomLineColor);
radius = typedArray.getDimensionPixelOffset(R.styleable.PayPsdInputView_radius, radius);
divideLineWidth = typedArray.getDimensionPixelSize(R.styleable.PayPsdInputView_divideLineWidth, divideLineWidth);
divideLineColor = typedArray.getColor(R.styleable.PayPsdInputView_divideLineColor, divideLineColor);
psdType = typedArray.getInt(R.styleable.PayPsdInputView_psdType, psdType);
rectAngle = typedArray.getDimensionPixelOffset(R.styleable.PayPsdInputView_rectAngle, rectAngle);
focusedColor = typedArray.getColor(R.styleable.PayPsdInputView_focusedColor, focusedColor);
typedArray.recycle();
}
/**
* 初始化畫筆
*/
private void initPaint() {
circlePaint = getPaint(5, Paint.Style.FILL, circleColor);
bottomLinePaint = getPaint(2, Paint.Style.FILL, bottomLineColor);
borderPaint = getPaint(3, Paint.Style.STROKE, borderColor);
divideLinePaint = getPaint(divideLineWidth, Paint.Style.FILL, borderColor);
}
/**
* 設置畫筆
*
* @param strokeWidth 畫筆寬度
* @param style 畫筆風格
* @param color 畫筆顏色
* @return
*/
private Paint getPaint(int strokeWidth, Paint.Style style, int color) {
Paint paint = new Paint(ANTI_ALIAS_FLAG);
paint.setStrokeWidth(strokeWidth);
paint.setStyle(style);
paint.setColor(color);
paint.setAntiAlias(true);
return paint;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
height = h;
width = w;
divideLineWStartX = w / maxCount;
startX = w / maxCount / 2;
startY = h / 2;
bottomLineLength = w / (maxCount + 2);
rectF.set(0, 0, width, height);
}
@Override
protected void onDraw(Canvas canvas) {
//不刪除的畫會默認繪製輸入的文字
// super.onDraw(canvas);
switch (psdType) {
case psdType_weChat:
drawWeChatBorder(canvas);
drawItemFocused(canvas, position);
break;
case psdType_bottomLine:
drawBottomBorder(canvas);
break;
}
drawPsdCircle(canvas);
}
/**
* 畫微信支付密碼的樣式
*
* @param canvas
*/
private void drawWeChatBorder(Canvas canvas) {
canvas.drawRoundRect(rectF, rectAngle, rectAngle, borderPaint);
for (int i = 0; i < maxCount - 1; i++) {
canvas.drawLine((i + 1) * divideLineWStartX,
0,
(i + 1) * divideLineWStartX,
height,
divideLinePaint);
}
}
private void drawItemFocused(Canvas canvas, int position) {
if (position > maxCount - 1) {
return;
}
focusedRecF.set(position * divideLineWStartX, 0, (position + 1) * divideLineWStartX,
height);
canvas.drawRoundRect(focusedRecF, rectAngle, rectAngle, getPaint(3, Paint.Style.STROKE, focusedColor));
}
/**
* 畫底部顯示的分割線
*
* @param canvas
*/
private void drawBottomBorder(Canvas canvas) {
for (int i = 0; i < maxCount; i++) {
cX = startX + i * 2 * startX;
canvas.drawLine(cX - bottomLineLength / 2,
height,
cX + bottomLineLength / 2,
height, bottomLinePaint);
}
}
/**
* 畫密碼實心圓
*
* @param canvas
*/
private void drawPsdCircle(Canvas canvas) {
for (int i = 0; i < textLength; i++) {
canvas.drawCircle(startX + i * 2 * startX,
startY,
radius,
circlePaint);
}
}
@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
super.onTextChanged(text, start, lengthBefore, lengthAfter);
this.position = start + lengthAfter;
textLength = text.toString().length();
if (textLength>0&&textLength == maxCount) {
mListener.getInput(getPasswordString());
}
invalidate();
}
@Override
protected void onSelectionChanged(int selStart, int selEnd) {
super.onSelectionChanged(selStart, selEnd);
//保證光標始終在最後
if (selStart == selEnd) {
setSelection(getText().length());
}
}
/**
* 獲取輸入的密碼
*
* @return
*/
public String getPasswordString() {
return getText().toString().trim();
}
public void getComparePassword(onPasswordListener listener) {
mListener = listener;
}
/**
* 密碼監聽
*/
public interface onPasswordListener {
void getInput(String data);
}
}
5.調用 MainActivity
package com.example.mama.paydemo;
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Display;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.example.mama.paydemo.widget.PayPsdInputView;
/**
* Created by dingkangkang on 2017/12/5.
*/
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void zhifu(View view){
final AlertDialog dialog = new AlertDialog.Builder(this).create();
Window w = dialog.getWindow();
w.setGravity(Gravity.BOTTOM);
//給彈窗加滑出動畫
w.setWindowAnimations(R.style.DialogAnimation);
//設置外圍點擊消失
dialog.setCanceledOnTouchOutside(true);
//加上會去掉邊界
dialog.getWindow().setBackgroundDrawable(new ColorDrawable());
dialog.show();
//以下必須寫在show之後,不然會失效
WindowManager wm = w.getWindowManager();
Display d = wm.getDefaultDisplay();//屏幕
WindowManager.LayoutParams p = w.getAttributes();
p.width = (int)(d.getWidth()*1);//設置彈窗寬度爲屏幕的寬度
w.setAttributes(p);
View v = LayoutInflater.from(this).inflate(R.layout.dialog_confirm_order,null);
dialog.setContentView(v);//給彈窗加載佈局
TextView tv_close = (TextView)v.findViewById(R.id.tv_close);
Button btn_confirmorder = (Button)v.findViewById(R.id.btn_confirmorder);
btn_confirmorder.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
showPayDialog();
}
});
tv_close.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
}
//輸入密碼彈窗
public void showPayDialog(){
final AlertDialog dialog = new AlertDialog.Builder(this).create();
Window w = dialog.getWindow();
w.setGravity(Gravity.BOTTOM);
//給彈窗加滑出動畫
w.setWindowAnimations(R.style.DialogAnimation);
//設置外圍點擊消失
dialog.setCanceledOnTouchOutside(true);
//加上會去掉邊界
dialog.getWindow().setBackgroundDrawable(new ColorDrawable());
dialog.show();
//以下必須寫在show之後,不然會失效
WindowManager wm = w.getWindowManager();
Display d = wm.getDefaultDisplay();//屏幕
WindowManager.LayoutParams p = w.getAttributes();
p.width = (int)(d.getWidth()*1);//設置彈窗寬度爲屏幕的寬度
w.setAttributes(p);
View v = LayoutInflater.from(this).inflate(R.layout.dialog_input_password,null);
dialog.setContentView(v);//給彈窗加載佈局
TextView tv_close = (TextView)v.findViewById(R.id.tv_close);
PayPsdInputView payPsdInputView = (PayPsdInputView)v.findViewById(R.id.et_password);
//彈出軟鍵盤, AlertDialog中一般的顯示方法不起作用
dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,0);
payPsdInputView.getComparePassword(new PayPsdInputView.onPasswordListener() {
@Override
public void getInput(String data) {
//此步驟要在 dialog.dismiss(); 之前執行,不然會失效
if (imm.isActive()){
hideSoft();
}
dialog.dismiss();
Toast.makeText(getApplication(),"密碼:::::"+data, Toast.LENGTH_SHORT).show();
}
});
tv_close.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//此步驟要在 dialog.dismiss(); 之前執行,不然會失效
if (imm.isActive()){
hideSoft();
}
dialog.dismiss();
}
});
}
//隱藏軟鍵盤
private void hideSoft() {
//隱藏鍵盤,AlertDialog中一般的隱藏方法不起作用
InputMethodManager imm2 = (InputMethodManager) getSystemService(MainActivity.INPUT_METHOD_SERVICE);
imm2.toggleSoftInput(InputMethodManager.HIDE_NOT_ALWAYS, 0);
}
}
6.彈窗動畫 請看
7.自定義動畫屬性 在values下新建 attr.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 支付屬性 -->
<declare-styleable name="PayPsdInputView">
<attr name="maxCount" format="integer" />
<attr name="circleColor" format="color" />
<attr name="bottomLineColor" format="color" />
<attr name="radius" format="reference" />
<attr name="divideLineWidth" format="dimension" />
<attr name="divideLineColor" format="color" />
<attr name="rectAngle" format="dimension" />
<attr name="focusedColor" format="color"/>
<attr name="psdType" format="enum">
<enum name="weChat" value="0" />
<enum name="bottomLine" value="1" />
</attr>
</declare-styleable>
<declare-styleable name="CircleProgressBarView">
<attr name="circleBgStrokeWidth" format="dimension" />
<attr name="progressStrokeWidth" format="dimension" />
<attr name="circleBgColor" format="color" />
<attr name="progressColor" format="color" />
<attr name="circleAnimationDuration" format="integer" />
<attr name="isDrawCenterProgressText" format="boolean" />
<attr name="centerProgressTextColor" format="color"/>
<attr name="centerProgressTextSize" format="dimension"/>
</declare-styleable>
<declare-styleable name="RadarWaveView">
<attr name="waveColor" format="color" />
<attr name="waveAmplitude" format="dimension" />
<attr name="waveSpeed" format="float" />
<attr name="waveStartPeriod" format="float" />
<attr name="waveStart" format="boolean" />
<attr name="waveFillTop" format="boolean" />
<attr name="waveFillBottom" format="boolean" />
<attr name="waveFillType" format="enum">
<enum name="top" value="0" />
<enum name="bottom" value="1" />
</attr>
<attr name="waveType" format="enum">
<enum name="sin" value="0" />
<enum name="cos" value="1" />
</attr>
</declare-styleable>
</resources>
9.特別感謝