Android深入浅出自定义控件(三)
16lz
2021-01-26
在我的上两篇博文Android深入浅出自定义控件(一)、Android深入浅出自定义控件(二)中介绍了如何自定义View以及ViewGroup,自定义控件的话是从零写起,从无到有,但有时候我们还可以通过简单地重写系统自带的控件,来实现属于自己的控件,比如定义一个自己的弹框,定义一个个性化进度条等等,都是可以直接继承系统控件来重写。
其中要注意的两个点:
setCompoundDrawablesWithIntrinsicBounds(Drawable left,Drawable top,Drawable right,Drawable bottom);
这个方法表示将图标设置在EditText的哪个位置,里面有4个参数,分别表示设置在左上右下四个角落,由于我们的最终效果是将查询图标设置在靠左,所以调用setCompoundDrawablesWithIntrinsicBounds(search, null, null, null);
在监听文本更改事件中,我们选择在afterTextChanged中去判断,即表示在文本更改完成后,系统再判断文本框是否有内容:
记住,定义完之后还要在构造方法中调用init():
代码中注释得很清楚了,大概的思路就是:当用户手指触碰屏幕时,根据所触碰的点是否在删除图标所在的区域内,来判断用户是否点击了删除图标。
上面基本已经完成了我们的自定义控件的定义,我们再给它加个圆角边框:
在drawable文件夹中定义一个xml文件,作为EditText的背景【这里我命名为border_edit.xml】:
最后,在activity_main.xml文件中使用:
最终效果:
本文主要通过自定义一个带删除功能的EditText来学习如何重写系统控件,我们都知道,Android自带的文本框是没有删除功能,但是在许多时候,用户由于输入错误,想要删除内容,只能连续多次点击软键盘的删除按钮,为了简便用户的操作,我们可以为文本框加上一个删除的小按钮,让用户只需点击这个按钮便能实现将文本框内容一键清空,如图:
那么接下来我们来定义这样的一个EditText
1.既然要重写,肯定要继承EditText类,重写其中的构造方法,这一步相信都很熟悉了:
public class EditTextWithDel extends EditText{public EditTextWithDel(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}public EditTextWithDel(Context context, AttributeSet attrs) {super(context, attrs);}public EditTextWithDel(Context context) {super(context);}}
2.由于我们的EditText要有一个查找的图标和一个删除的图标,所以需要定义两个Drawable属性,待会用来添加到控件上,另外还要传入一个上下文对象:
public class EditTextWithDel extends EditText{//上下文private Context context;//删除图标private Drawable del;//查找图标private Drawable search;public EditTextWithDel(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);this.context = context;}public EditTextWithDel(Context context, AttributeSet attrs) {super(context, attrs);this.context = context;}public EditTextWithDel(Context context) {super(context);this.context = context;}}
3.接下来就可以开始写我们个性化的部分了,定义一个init方法,在里面定义我们需要的功能:
public void init(){//通过上下文获得查询的Drawable对象search = (Drawable)context.getResources().getDrawable(R.drawable.search);//将查询图标设置在EditText的左边setCompoundDrawablesWithIntrinsicBounds(search, null, null, null);//通过上下文获得删除的Drawable对象del = (Drawable)context.getResources().getDrawable(R.drawable.delete_icon);//添加文本更改监听事件,一旦EditText中文本更改了,马上进行判断addTextChangedListener(new TextWatcher() {@Overridepublic void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {// TODO Auto-generated method stub}@Overridepublic void beforeTextChanged(CharSequence arg0, int arg1, int arg2,int arg3) {// TODO Auto-generated method stub}@Overridepublic void afterTextChanged(Editable arg0) {// TODO Auto-generated method stubif(arg0.length()>0){//如果有内容,就将查询图标设置在左,删除图标设置在右setCompoundDrawablesWithIntrinsicBounds(search, null, del, null);}else{//如果空了,查询图标在左依旧不变,删除图标需要隐藏setCompoundDrawablesWithIntrinsicBounds(search, null, null, null);}}});}
其中要注意的两个点:
setCompoundDrawablesWithIntrinsicBounds(Drawable left,Drawable top,Drawable right,Drawable bottom);
这个方法表示将图标设置在EditText的哪个位置,里面有4个参数,分别表示设置在左上右下四个角落,由于我们的最终效果是将查询图标设置在靠左,所以调用setCompoundDrawablesWithIntrinsicBounds(search, null, null, null);
在监听文本更改事件中,我们选择在afterTextChanged中去判断,即表示在文本更改完成后,系统再判断文本框是否有内容:
@Overridepublic void afterTextChanged(Editable arg0) {// TODO Auto-generated method stubif(arg0.length()>0){//如果有内容,就将查询图标设置在左,删除图标设置在右setCompoundDrawablesWithIntrinsicBounds(search, null, del, null);}else{//如果空了,查询图标在左依旧不变,删除图标需要隐藏setCompoundDrawablesWithIntrinsicBounds(search, null, null, null);}}
记住,定义完之后还要在构造方法中调用init():
4.上面的步骤已经完成了基本的外形,但是删除图标的功能我们还没实现,需要重写onTouchEvent:
@Overridepublic boolean onTouchEvent(MotionEvent event) {// TODO Auto-generated method stubif(event.getAction()==MotionEvent.ACTION_UP){//获得手指触碰的坐标int eventX = (int)event.getRawX();int eventY = (int)event.getRawY();//建立一个矩形区域,表示删除图标所在的范围Rect rect = new Rect();//获得EditText在屏幕中所处的矩形区域,赋给rectgetGlobalVisibleRect(rect);//将该rect的右边缘减去60,赋给左边缘,此时rect的区域缩小成了删除图标所在的区域rect.left = rect.right-60;//如果触碰的点属于rect(即删除图标所在的范围)就清空EditText内容if(rect.contains(eventX,eventY)){setText("");}}return super.onTouchEvent(event);}
代码中注释得很清楚了,大概的思路就是:当用户手指触碰屏幕时,根据所触碰的点是否在删除图标所在的区域内,来判断用户是否点击了删除图标。
上面基本已经完成了我们的自定义控件的定义,我们再给它加个圆角边框:
在drawable文件夹中定义一个xml文件,作为EditText的背景【这里我命名为border_edit.xml】:
<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android" > <stroke android:width="2dp" android:color="#2684C2"/><size android:height="14dp"/><corners android:radius="20dp"/></shape>
最后,在activity_main.xml文件中使用:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <com.example.view.EditTextWithDel android:layout_width="fill_parent" android:layout_height="36dp" android:layout_marginTop="30dp" android:layout_marginLeft="35dp" android:layout_marginRight="35dp" android:background="@drawable/border_edit" /> </LinearLayout>
最终效果:
本文demo所用到的材料和源码:点我下载
希望本文能够对你自定义个性化系统控件有初步的了解,我会在以后的博文中继续通过实战demo来加强对这一块的理解。更多相关文章
- Android(安卓)Studio 使用 ImageAsset 生成 ic_launcher 产生边
- 【Android】实现桌面清理内存简单Widget小控件
- Android中的布局方式(一)
- 浅谈Android系统的图标设计规范
- android 仿IOS实现SegmentControl
- 巧用android 控件—CheckBox + 状态选择器
- Android多分辨率支持以及各种类型图标尺寸大小
- android自学总结
- Android简单实现屏幕下方Tab菜单的方法