样式布局
要在Android中自定义键盘弹窗,先要创建一个新的XML布局文件,用于定义键盘弹窗的外观和布局。例如,创建一个名为key_alert_dialog.xml的文件,并在其中添加所需的按钮和其他UI元素。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/shape_alert_dialog"
android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="88dp"
android:orientation="horizontal">
<TextView
style="@style/key_board_title"
android:text="请输入管理员密码" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#BBBBBB" />
<LinearLayout
android:paddingTop="20dp"
android:paddingStart="48dp"
android:paddingEnd="48dp"
android:layout_width="fill_parent"
android:layout_height="84dp"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_pay1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:background="@drawable/key_password"
android:maxLength="1"
android:inputType="numberPassword"
android:textSize="32sp" />
<TextView
android:layout_marginStart="24dp"
android:id="@+id/tv_pay2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:background="@drawable/key_password"
android:layout_weight="1"
android:gravity="center"
android:maxLength="1"
android:inputType="numberPassword"
android:textSize="32sp" />
<TextView
android:layout_marginStart="24dp"
android:id="@+id/tv_pay3"
android:layout_width="0dp"
android:layout_height="match_parent"
android:background="@drawable/key_password"
android:layout_weight="1"
android:gravity="center"
android:maxLength="1"
android:inputType="numberPassword"
android:textSize="32sp" />
<TextView
android:id="@+id/tv_pay4"
android:layout_marginStart="24dp"
android:layout_width="0dp"
android:layout_height="match_parent"
android:background="@drawable/key_password"
android:layout_weight="1"
android:gravity="center"
android:maxLength="1"
android:inputType="numberPassword"
android:textSize="32sp" />
<TextView
android:id="@+id/tv_pay5"
android:layout_marginStart="24dp"
android:layout_width="0dp"
android:layout_height="match_parent"
android:background="@drawable/key_password"
android:layout_weight="1"
android:gravity="center"
android:maxLength="1"
android:inputType="numberPassword"
android:textSize="32sp" />
<TextView
android:id="@+id/tv_pay6"
android:layout_marginStart="24dp"
android:layout_width="0dp"
android:layout_height="match_parent"
android:background="@drawable/key_password"
android:layout_weight="1"
android:gravity="center"
android:maxLength="1"
android:inputType="numberPassword"
android:textSize="32sp" />
</LinearLayout>
<!-- 以下为键盘-->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#FFFFFF"
android:orientation="vertical">
<LinearLayout
android:paddingStart="48dp"
android:paddingEnd="48dp"
android:layout_width="fill_parent"
android:layout_height="71dp"
android:orientation="horizontal">
<TextView
android:id="@+id/num1"
style="@style/key_board_text"
android:background="@drawable/shape_key_board_bg"
android:text="1" />
<TextView
android:id="@+id/num2"
style="@style/key_board_text"
android:layout_marginLeft="60dp"
android:background="@drawable/shape_key_board_bg"
android:text="2" />
<TextView
android:id="@+id/num3"
style="@style/key_board_text"
android:layout_marginLeft="60dp"
android:background="@drawable/shape_key_board_bg"
android:text="3" />
</LinearLayout>
<!-- -->
<LinearLayout
android:paddingStart="48dp"
android:paddingEnd="48dp"
android:layout_width="fill_parent"
android:layout_height="71dp"
android:layout_marginTop="20dp"
android:orientation="horizontal">
<TextView
android:id="@+id/num4"
style="@style/key_board_text"
android:background="@drawable/shape_key_board_bg"
android:text="4" />
<TextView
android:id="@+id/num5"
style="@style/key_board_text"
android:layout_marginLeft="60dp"
android:background="@drawable/shape_key_board_bg"
android:text="5" />
<TextView
android:id="@+id/num6"
style="@style/key_board_text"
android:layout_marginLeft="60dp"
android:background="@drawable/shape_key_board_bg"
android:text="6" />
</LinearLayout>
<!-- -->
<LinearLayout
android:paddingStart="48dp"
android:paddingEnd="48dp"
android:layout_width="fill_parent"
android:layout_height="71dp"
android:layout_marginTop="20dp"
android:orientation="horizontal">
<TextView
android:id="@+id/num7"
style="@style/key_board_text"
android:background="@drawable/shape_key_board_bg"
android:text="7" />
<TextView
android:id="@+id/num8"
style="@style/key_board_text"
android:layout_marginLeft="60dp"
android:background="@drawable/shape_key_board_bg"
android:text="8" />
<TextView
android:id="@+id/num9"
style="@style/key_board_text"
android:layout_marginLeft="60dp"
android:background="@drawable/shape_key_board_bg"
android:text="9" />
</LinearLayout>
<!-- -->
<LinearLayout
android:paddingStart="48dp"
android:paddingEnd="48dp"
android:layout_width="fill_parent"
android:layout_height="71dp"
android:layout_marginTop="20dp"
android:orientation="horizontal">
<TextView
android:id="@+id/num0"
style="@style/key_board_text"
android:background="@drawable/shape_key_board_bg"
android:text="0" />
<ImageView
android:id="@+id/del"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_marginLeft="60dp"
android:background="@drawable/shape_key_board_bg"
android:src="@drawable/md_backspace" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="20dp"
android:background="#BBBBBB" />
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="88dp"
android:orientation="horizontal"
android:paddingStart="48dp"
android:paddingTop="14dp"
android:paddingEnd="48dp">
<TextView
android:id="@+id/cancel"
style="@style/key_board_text"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="@drawable/shape_key_board_bg"
android:text="取消" />
</RelativeLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
其中,数字键盘和背景的样式举例如下:
<style name="key_board_text">
<item name="android:textSize">32sp</item>
<item name="android:textColor">#333333</item>
<item name="android:gravity">center</item>
<item name="android:layout_weight">1</item>
<item name="android:layout_width">0dp</item>
<item name="android:textStyle">bold</item>
<item name="android:layout_height">match_parent</item>
</style>
shape_alert_dialog.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#ffffff"/>
<corners android:radius="16dp"/>
</shape>
密码输入框灰色:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="4dp" />
<solid android:color="#F5F5F5" />
</shape>
建立一个LinearLayout类为自定义键盘上的每个按钮设置点击事件监听器,以便在用户点击时执行相应的操作。你可以在布局文件中为每个按钮设置android:onClick属性,或者在代码中动态地为它们设置监听器,并设置text的显示,最后定义一个接口(onInputChanged)以便在输入满6位时通知实现者:
public class KeyBoardView extends LinearLayout implements View.OnClickListener {
View[] numberViews;
View delView;
private TextView tvFirst, tvSecond, tvThird, tvForth, tvFifth, tvSixth;
private StringBuilder mPassword;
public KeyBoardView(Context context) {
this(context, null);
}
public KeyBoardView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
InitView(context);
}
private void InitView(Context context) {
//绑定0-9
numberViews = new View[10];
View view = LayoutInflater.from(context).inflate(R.layout.key_alert_dialog, this);
Context viewContext = view.getContext();
for (int i = 0; i < numberViews.length; i++) {
int id = viewContext.getResources().getIdentifier("num" + i, "id", context.getPackageName());
numberViews[i] = findViewById(id);
numberViews[i].setOnClickListener(this);
}
//绑定删除
delView = findViewById(R.id.del);
delView.setOnClickListener(this);
initPayEditText(view);
}
private void initPayEditText(View view) {
mPassword = new StringBuilder();
tvFirst = view.findViewById(R.id.tv_pay1);
tvSecond = view.findViewById(R.id.tv_pay2);
tvThird = view.findViewById(R.id.tv_pay3);
tvForth = view.findViewById(R.id.tv_pay4);
tvFifth = view.findViewById(R.id.tv_pay5);
tvSixth = view.findViewById(R.id.tv_pay6);
}
@Override
public void onClick(View view) {
if (getNumberClicked(view) != -1) {
add(getNumberClicked(view));
}
if (view.getId() == R.id.del) {
remove();
}
}
/**
* 删除密码
*/
public void remove() {
if (mPassword != null && mPassword.length() > 0) {
if (mPassword.length() == 1) {
tvFirst.setText("");
} else if (mPassword.length() == 2) {
tvSecond.setText("");
} else if (mPassword.length() == 3) {
tvThird.setText("");
} else if (mPassword.length() == 4) {
tvForth.setText("");
} else if (mPassword.length() == 5) {
tvFifth.setText("");
} else if (mPassword.length() == 6) {
tvSixth.setText("");
}
mPassword.deleteCharAt(mPassword.length() - 1);
}
}
/**
* 输入密码
*
* @param valueInt
*/
public void add(int valueInt) {
String value = Integer.toString(valueInt);
if (mPassword != null && mPassword.length() < 6) {
mPassword.append(value);
if (mPassword.length() == 1) {
tvFirst.setText(value);
} else if (mPassword.length() == 2) {
tvSecond.setText(value);
} else if (mPassword.length() == 3) {
tvThird.setText(value);
} else if (mPassword.length() == 4) {
tvForth.setText(value);
} else if (mPassword.length() == 5) {
tvFifth.setText(value);
} else if (mPassword.length() == 6) {
tvSixth.setText(value);
//业务
inputCallback.onInputChanged(mPassword.toString());
}
}
}
public int getNumberClicked(View view) {
int result = -1;
for (int i = 0; i < numberViews.length; i++) {
if (view.equals(numberViews[i])) {
result = i;
break;
}
}
return result;
}
private InputCallback inputCallback;
public void setInputListener(InputCallback inputCallback) {
this.inputCallback = inputCallback;
}
public interface InputCallback {
void onInputChanged(String text);
}
}
自定义的弹窗
自定义PasswordDialog 继承 Dialog,将自定义布局加载到当前弹窗,并且将我们的取消按钮增加点击事件。最后,我们实现视图KeyBoardView的InputCallback接口完成数据接收:
public class PasswordDialog extends Dialog implements View.OnClickListener{
private Activity context;
TextView cancel;
public PasswordDialog(@NonNull Activity context) {
super(context);
this.context = context;
InitView();
}
private void InitView() {
// 设置自定义布局
KeyBoardView keyBoardView = new KeyBoardView(context);
setContentView(keyBoardView);
keyBoardView.setInputListener(text -> {
if (text.length() == 6) {
String dPwd = "666666";
if (!TextUtils.equals(text, dPwd)) {
Toast.makeText(context, "密码错误", Toast.LENGTH_SHORT).show();
} else {
//校验通过
dismiss();
}
}
});
cancel = findViewById(R.id.cancel);
cancel.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (view.getId() == R.id.cancel) {
dismiss();
}
}
}
调用弹窗中的视图
在你的Activity或Fragment中,使用AlertDialog或其他适当的方法来显示自定义键盘弹窗。首先,加载刚才创建的布局文件,并将其设置为弹窗的内容视图。
在Activity中调用方法,不如在点击事件中调用:
private PasswordDialog passwordDialog;
@Override
public void onClick(View view) {
if (view.getId() == R.id.button) {
showPasswordDialog(this);
}
}
/**
* @param context 上下文对象
*/
private void showPasswordDialog(Activity context) {
passwordDialog = new PasswordDialog(context);
passwordDialog.show();
}