闲来无聊研究了下微信支付键盘,大致有三种实现方式
第一种
-
自定义view实现,主要用到onDraw和onTouchEvent这两个,这种实现起来是真的烦,很少有人用这种方式,不推荐(大屌除外)
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
int height = getHeight();
mCanvas = canvas;
Log.d(TAG, "onDraw: width=" + width + "\theight=" + height);
// 画竖线
mPaint.setColor(Color.BLACK);
mAvgWidth = width / WIDTH_LINES;
for (int i = 1; i < WIDTH_LINES; i++) {
canvas.drawLine(mAvgWidth * i, 0, mAvgWidth * i, height, mPaint);
}
// 画横线
mAvgHeight = height / HEIGHT_LINES;
for (int i = 0; i < HEIGHT_LINES; i++) {
canvas.drawLine(0, mAvgHeight * i, width, mAvgHeight * i, mPaint);
}
// 画数字
mPaint.setTextSize(40);
Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt();
// 画1-3
drawNum(1, 1, "1", fontMetrics);
drawNum(1, 2, "2", fontMetrics);
drawNum(1, 3, "3", fontMetrics);
// 画4-6
drawNum(2, 1, "4", fontMetrics);
drawNum(2, 2, "5", fontMetrics);
drawNum(2, 3, "6", fontMetrics);
// 画7-9
drawNum(3, 1, "7", fontMetrics);
drawNum(3, 2, "8", fontMetrics);
drawNum(3, 3, "9", fontMetrics);
// 画底部
drawNum(4, 2, "0", fontMetrics);
mPaint.setColor(Color.GRAY);
// canvas.drawRect(0, mAvgHeight * 3, mAvgWidth, mAvgHeight * 4, mPaint);
// canvas.drawRect(mAvgWidth * 2, mAvgHeight * 3, mAvgWidth * 3, mAvgHeight * 4, mPaint);
// Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.back);
// int bWidth = bitmap.getWidth();
// int bHeight = bitmap.getHeight();
// canvas.drawBitmap(bitmap, (float) (mAvgWidth * 2.5 - bWidth / 2), (float) (mAvgHeight * 3.5 - bHeight / 2), mPaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mStartX = event.getX();
mStartY = event.getY();
if (mStartX <= mAvgWidth) {
if (mStartY <= mAvgHeight) {
Log.d(TAG, "onTouchEvent: " + "1");
} else if (mStartY > mAvgHeight && mStartY <= mAvgHeight * 2) {
Log.d(TAG, "onTouchEvent: " + "4");
} else if (mStartY > mAvgHeight * 2 && mStartY <= mAvgHeight * 3) {
Log.d(TAG, "onTouchEvent: " + "7");
} else {
Log.d(TAG, "onTouchEvent: " + " ");
}
} else if (mStartX > mAvgWidth && mStartX <= mAvgWidth * 2) {
if (mStartY <= mAvgHeight) {
Log.d(TAG, "onTouchEvent: " + "2");
} else if (mStartY > mAvgHeight && mStartY <= mAvgHeight * 2) {
Log.d(TAG, "onTouchEvent: " + "5");
} else if (mStartY > mAvgHeight * 2 && mStartY <= mAvgHeight * 3) {
Log.d(TAG, "onTouchEvent: " + "8");
} else {
Log.d(TAG, "onTouchEvent: " + "0");
}
} else {
if (mStartY <= mAvgHeight) {
Log.d(TAG, "onTouchEvent: " + "3");
} else if (mStartY > mAvgHeight && mStartY <= mAvgHeight * 2) {
Log.d(TAG, "onTouchEvent: " + "6");
} else if (mStartY > mAvgHeight * 2 && mStartY <= mAvgHeight * 3) {
Log.d(TAG, "onTouchEvent: " + "9");
} else {
Log.d(TAG, "onTouchEvent: " + "删除");
}
}
// invalidate();
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
mStartX = 0;
mStartY = 0;
// invalidate();
break;
}
return true;
}
第二种
-
用keyboard和keyboardview实现,这种的缺陷是,你按住4,然后移动到1或者7,他显示的是1或者7,很显然不符合微信这种,微信是移动到1或7的时候直接取消当前这个,不推荐(你个渣渣,肯定没找到相应的API)
-
在res下面创建xml包
- 创建keyboard.xml文件
<?xml version="1.0" encoding="utf-8"?>
<Keyboard
xmlns:android="http://schemas.android.com/apk/res/android"
android:horizontalGap="1dp"
android:keyHeight="8%p"
android:keyWidth="33.3333%p"
android:verticalGap="1dp">
<Row>
<Key
android:keyLabel="1"/>
<Key
android:keyLabel="2"/>
<Key
android:keyLabel="3"/>
</Row>
<Row>
<Key
android:keyLabel="4"/>
<Key
android:keyLabel="5"/>
<Key
android:keyLabel="6"/>
</Row>
<Row>
<Key
android:keyLabel="7"/>
<Key
android:keyLabel="8"/>
<Key
android:keyLabel="9"/>
</Row>
<Row>
<Key
android:codes="-10"
android:keyLabel=""
/>
<Key
android:keyLabel="0"/>
<Key
android:codes="-5"
android:isRepeatable="true"/>
</Row>
</Keyboard>
- 自定义view继承KeyboardView
-
绘制空格键和删除键
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
List<Keyboard.Key> keys = getKeyboard().getKeys();
for (Keyboard.Key key : keys) {
//绘制空白键
if (key.codes[0] == KEYCODE_EMPTY) {
drawKeyBackGround(key, canvas);
} else if (key.codes[0] == Keyboard.KEYCODE_DELETE) {
//绘制删除键背景
drawKeyBackGround(key, canvas);
// //绘制按键图片
drawkeyDelete(key, canvas);
}
}
mCanvas = canvas;
}
private void drawKeyBackGround(Keyboard.Key key, Canvas canvas) {
Drawable drawable = mContext.getResources().getDrawable(R.drawable.keyboard_empty);
// 选择器效果
int[] state = key.getCurrentDrawableState();
drawable.setState(state);
// TODO: 2017/12/21 减去key的间距,很难控制,而且有按键问题
// drawable.setBounds(key.x, key.y, key.x + key.width, key.y + key.height);
drawable.setBounds(key.x, key.y + mSpace, key.x + key.width, key.y + key.height + mSpace);
drawable.draw(canvas);
}
private void drawkeyDelete(Keyboard.Key key, Canvas canvas) {
DisplayMetrics dm = getResources().getDisplayMetrics();
int width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30, dm);
int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 11, dm);
int[] state = key.getCurrentDrawableState();
mDeleteDrawable.setState(state);
mDeleteDrawable.setBounds(key.x + width, key.y + height, key.x + key.width - width, key.y + key.height - height);
mDeleteDrawable.draw(canvas);
}
-
key的回调
@Override
public void onKey(int primaryCode, int[] keyCodes) {
Log.d(TAG, "onKey: " + primaryCode);
if (primaryCode == Keyboard.KEYCODE_DELETE && mOnkeyPressListener != null) {
if (mOnkeyPressListener != null) {
mOnkeyPressListener.onDeleteKey();
}
} else if (primaryCode != KEYCODE_EMPTY) {
if (mOnkeyPressListener != null) {
Log.d(TAG, "数字: " + Character.toString((char) primaryCode));
mOnkeyPressListener.onInertKey(Character.toString((char) primaryCode));
}
}
}
- xml中布局
<cn.gongwebo.payview.widget.KeyView
android:id="@+id/keyview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:keyBackground="@drawable/keyboard_num"
android:keyTextColor="@android:color/black"
android:shadowColor="@color/white"
android:shadowRadius="0.0"
app:keyView_delete="@drawable/keyboard_delete"/>
需要注意的如果没有在KeyView设置以下两行代码,会导致字体模糊
第三种
-
用ViewGroup添加,我认为是三种里面最符合微信的,推荐
- item的布局
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rl"
android:layout_width="match_parent"
android:layout_height="60dp">
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:gravity="center"
android:textColor="@color/black"
android:textSize="18sp"
tools:text="1"/>
<!--头部的黑边-->
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/black"/>
<!--右边的黑边-->
<View
android:id="@+id/view_right"
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:background="@color/black"/>
<ImageView
android:id="@+id/iv_delete"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerInParent="true"
android:visibility="gone"
tools:src="@drawable/delete_normal"/>
</RelativeLayout>
- 对item的操作
@Override
public void onBindViewHolder(KeyBoardViewHolder holder, int position) {
final Integer code = mList.get(position);
// 数字
TextView tv = holder.tv;
// 点击
View view = holder.view;
// 删除
ImageView iv_delete = holder.iv_delete;
iv_delete.setVisibility(code == DELETE ? View.VISIBLE : View.GONE);
if (code == EMPTY) {
view.setBackgroundResource(R.drawable.keyboard_empty);
} else if (code == DELETE) {
view.setBackgroundResource(R.drawable.keyboard_empty);
iv_delete.setBackgroundResource(R.drawable.keyboard_delete);
} else {
view.setBackgroundResource(R.drawable.keyboard_num);
tv.setText(mList.get(position) + "");
}
// 最右边的不显示
if (holder.getPosition() % 3 == 2) {
holder.view_right.setVisibility(View.GONE);
}
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mKeyBoardAdapterListener != null) {
mKeyBoardAdapterListener.click(code);
}
}
});
}
- 动画效果
@OnClick({R.id.iv_close, R.id.fl_close, R.id.payview})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.iv_close:
dismiss();
break;
case R.id.fl_close:
if (!keyHide) {
Animation exit = AnimationUtils.loadAnimation(getActivity(), R.anim.exit_anim);
mLlKey.setAnimation(exit);
mLlKey.startAnimation(exit);
exit.setFillAfter(true);
keyHide = true;
// 影藏的时候要等动画执行完
exit.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
// 因为是补间动画所以把控件隐藏
mRv.setVisibility(View.GONE);
mFlClose.setVisibility(View.GONE);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
break;
case R.id.payview:
if (keyHide) {
Animation enter = AnimationUtils.loadAnimation(getActivity(), R.anim.enter_anim);
mLlKey.setAnimation(enter);
mLlKey.startAnimation(enter);
enter.setFillAfter(true);
keyHide = false;
// 因为是补间动画所以把控件显示
mRv.setVisibility(View.VISIBLE);
mFlClose.setVisibility(View.VISIBLE);
}
break;
}
}