此文接着《Android快速自定义控件+实战演示(一)新手进阶必看!》的教程接着讲解。
这一次会讲到知识点有:
1.自定义数字按键view
2.结合数字按键和圆盘按键
3.如何思考设计以及使用回调
已经学会一的同学可以直接跳到标题-结合数字按键和圆盘按键-处接着往下看。
第一讲讲了如何自定义圆盘按键,现在我们来实现白色的数字按键(上面是数字,下面是字母)。
如果看了第一讲,跟着步骤做,就非常简单了。
布局很明显是上下结构的,可以用LinearLayout,上面一个Button,用来放数字,下面一个TextView,用来放字母。布局文件取名为custom_keyboard_item_num.xml
然后新建一个类,取名为CustomNumKeyboardItem.java,继承LinearLayout,重写它的构造方法:
public final class CustomNumKeyboardItem extends LinearLayout {
public CustomNumKeyboardItem(final Context context) {
super(context);
load();
}
public CustomNumKeyboardItem(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
load();
}
public CustomNumKeyboardItem(final Context context, final AttributeSet attrs) {
super(context, attrs);
load();
}
}
依旧只是再原有的构造方法上加上了我们自己的扩展方法load()
private void load() {
if (isInEditMode()) {
return;
}
inflateLayout();
initUI();
initData();
}
load方法里面也是和之前教程定义圆盘按键的方法一模一样,然后在inflateLayout里面引入定义好的xml。有不会的请看第一个教程。
因为圆盘按键和数字按键的数据都是一样的,所以我们让setData()方法里面加入同一种数据类型对象。
/** * @Description 设置数据 * @param data 自定义键盘item实体类 */
public void setData(final CustomKeyboardItemEntity data) {
mData = data;
mNumButton.setText(data.getNumText());
mLetterTextView.setText(data.getLettersText());
}
那么在CustomKeyboardItemEntity实体类并没有NumText和LettersText数据,所以我们就要在返回数据方法里做特殊处理了:
/** * @Description 得到数字键的数字 * @return 数字 */
public String getNumText() {
return mCenterText;
}
/** * @Description 得到数字键下面的字母 * @return 字母集 */
public String getLettersText() {
String str;
str = mLeftText + mTopText + mRightText;
if (mBottomText != null) {
str += mBottomText;
}
return str;
}
可以看到,其实NumText,就是一开始设置的CenterText,而下面则是根据传入数据顺序进行叠加,因为有的数字,比如2下面只有三个字母(ABC),而有的有4个(比如9 WXYZ),所以初始化数据的时候也有两种情况,如果只有三个字母的,mBottomText就被设置为空,这里要进行特别判断一下。
CustomKeyboardItemEntity的两种构造方法:
/** * @Description initialize the entity * @param center 中间 * @param left 左 * @param top 上 * @param right 右 * @param bottom 下 */
public CustomKeyboardItemEntity(
final String center, final String left,
final String top, final String right, final String bottom) {
mCenterText = center;
mLeftText = left;
mTopText = top;
mRightText = right;
mBottomText = bottom;
}
/** * @Description initialize the entity * @param center 中间 * @param left 左 * @param top 上 * @param right 右 */
public CustomKeyboardItemEntity(
final String center, final String left,
final String top, final String right) {
this(center, left, top, right, null);
}
好了设置数据方法写完了,最后在main.xml布局里面加入
<com.azz.customkeyboard.viewmodel.CustomNumKeyboardItem
android:id="@+id/custom_number_keyboard_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
然后在main里面随便加入数据试试
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
customNumKeyBoardItemView = (CustomNumKeyboardItem) findViewById(R.id.custom_num_keyboard_item);
CustomKeyboardItemEntity data = new CustomKeyboardItemEntity("9", "W", "X", "Y", "Z");
//CustomKeyboardItemEntity data = new CustomKeyboardItemEntity("5", "L", "J", "K");
customNumKeyBoardItemView.setData(data);
}
运行
现在数字按键和圆盘按键我们都写好了,该把它们结合起来了!其实用到的还是前面的知识!组合技!思路是:再定义一个自定义view,这个自定义view又包含了圆盘按键和数字按键两个自定义view,当点击数字按键view时,出现圆盘按键view,当圆盘按键下按返回时,出现数字按键view!
取名为custom_keyboard_item.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" >
<!-- 数字按键 --> <com.azz.customkeyboard.viewmodel.CustomNumKeyboardItem android:id="@+id/custom_number_keyboard_item" android:layout_width="wrap_content" android:layout_height="wrap_content" />
<!-- 圆盘按键 --> <com.azz.customkeyboard.viewmodel.CustomCircleKeyboardItem android:id="@+id/custom_circle_keyboard_item" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone"/>
</FrameLayout>
自定义布局里面就是又加入了两个自定义布局!这两个就是我刚刚定义的圆盘按键和数字按键!然后新建类CustomKeyboardItem继承FrameLayout,和自定义圆盘按键|数字按键的步骤一模一样,重写构造函数,引入布局,初始化UI和数据
initUI():
/** * @Description initialize the ui */
private void initUI() {
circleKeyboardItem = (CustomCircleKeyboardItem) findViewById(R.id.custom_circle_keyboard_item);
numKeyboardItem = (CustomNumKeyboardItem) findViewById(R.id.custom_number_keyboard_item);
}
setData()方法就是把得到的数据往下传:
/** * @Description 设置数据 * @param data 自定义键盘item实体类 */
public void setData(final CustomKeyboardItemEntity data) {
mData = data; //在对象中保存一份
circleKeyboardItem.setData(data);
numKeyboardItem.setData(data);
}
很明显,监听点击的是数字按键,那我们监听事件要写在数字按键的类里面,但是显示的圆盘按键在混合按键类里面才能得到,所以显示圆盘按键的方法写在混合按键类里面,那么要如何做才能使数字按键类里面的方法去调用外面的包含它的混合按键的方法呢?
遇到这种问题就应该想到回调!
思路:我们自定义一个监听器(姑且叫OnKeyWorkListener),提供一个抽象方法void onDpadCenter(View view);
public interface OnKeyWorkListener {
/** * @Description 按中心键的时候 * @param view 监听事件的view */
void onDpadCenter(View view);
让CustomNumKeyboardItem类里拥有这个监听器的属性并加上setter方法
/** * @Field @mOnKeyWorkListener : onKey监听器 */
private OnKeyWorkListener mOnKeyWorkListener;
/** * @param onKeyWorkListener the mOnKeyWorkListener to set */
public void setOnKeyWorkListener(final OnKeyWorkListener onKeyWorkListener) {
this.mOnKeyWorkListener = onKeyWorkListener;
}
然后在onKey监听OK键事件中,加入判断
case KeyEvent.KEYCODE_DPAD_CENTER:
if (mOnKeyWorkListener != null) {
mOnKeyWorkListener.onDpadCenter(this);
}
break;
在CustomKeyboardItem中定义具体onDpadCenter()里面的实现。CustomKeyboardItem可以自己充当这个代理,实现(implements)OnKeyWorkListener
/** * @Description initialize the data */
private void initData() {
circleKeyboardItem.setOnKeyWorkListener(this); //设置监听器,监听OK键点击
numKeyboardItem.setOnKeyWorkListener(this); //设置监听器,监听Back键点击
}
/* (非 Javadoc) * Description: * @see com.azz.customkeyboard.listener.OnKeyWorkListener#onDpadCenter() */
@Override
public void onDpadCenter(final View view) {
Log.d(TAG, "onDpadCenter");
if (view == numKeyboardItem
&& numKeyboardItem.isShown()
&& !circleKeyboardItem.isShown()) {
circleKeyboardItem.appearWithAnimation(showAnim); //显示圆盘按键
numKeyboardItem.disappearWithAnimation(showAnim); //数字按键消失
}
}
在OnKeyWorkListener中再加入一个虚方法boolean onBack(View view);
public interface OnKeyWorkListener {
/** * @Description 按中心键的时候 * @param view 监听事件的view */
void onDpadCenter(View view);
/** * @Description 按返回的时候 * @param view 监听事件的view * @return 返回true,停止返回事件,false,继续传返回事件到下一层 */
boolean onBack(View view);
}
让CustomCircleKeyboardItem也拥有这个监听器的属性,并在onKey监听返回事件中加入
case KeyEvent.KEYCODE_BACK:
mDataBackup = mData.backup();
if (mOnKeyWorkListener != null) {
return mOnKeyWorkListener.onBack(this);
}
break;
在CustomKeyboardItem中具体实现:
/* (非 Javadoc) * Description: * @see com.azz.customkeyboard.listener.OnKeyWorkListener#onBack() */
@Override
public boolean onBack(final View view) {
if (view == circleKeyboardItem
&& circleKeyboardItem.isShown()
&& !numKeyboardItem.isShown()) {
numKeyboardItem.appearWithAnimation(showAnim);
circleKeyboardItem.disappearWithAnimation(showAnim);
return true;
}
return false;
}
下一节会讲
1.如何组合成完整的键盘
2.如何连环回调。
转下一节:《Android快速自定义控件+实战演示(三)完整键盘和组合回调!》
如果你有任何问题,请留言告诉我!