打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Android学习小Demo(22)带删除按钮的TextView

很多时候,会有一些很简单的需求,比如你利用一个Button弹出某个页面,选择了某个对象之后,你会将对象的某些属性,比如名称之类,显示在按钮上。

而紧跟着,又会想着,能不能把刚选择的对象给清掉,比如把按钮上的文字给去掉,这个时候,你就会希望,要是按钮后面还能够有多一个图标,一点击,就把当前控件的文字等清除掉就好了,并且还会对应的回调函数,让我们多处理一些事情,那多好。

很可惜,Android并没有提供现成的控件供我们这样使用,但换个角度想想,这又根本不可惜,因为我们可以自己来实现这样的效果呀,这是多有意思的一件事情啊。

即使有时候,实现很简单,只是做多一点点事情,但当我们把它实现了,满足的感觉依然会油然而生啊,对吧!

现在想做的事情就很简单,想自定义一个控件,实现功能如下:

1)实现像Button一样的点击效果

2)又能够在后面添加一个删除小图标,可删除此控件上的内容

3)还要有一个响应函数,能够在删除之后做一些操作。

我们知道,自定义控件有多种方式,我们可以直接继承View,自己去画各种各样的UI,也可以简单地继承已存在的控件,比如Button就是继承TextView的一个简单的控件。

提到Button就是继承TextView的,而TextView又有CompoundDrawable的概念,那很显然,我们就可以利用TextView来实现我们的功能了。

太啰嗦了,还是先上代码吧

  1. public class ClearableTextView extends TextView {  
  2.   
  3.     public interface OnTextClearListener {  
  4.         public void onTextClear(ClearableTextView v);  
  5.     }  
  6.   
  7.     private Context mContext;  
  8.     private Drawable mDrawableRight;  
  9.     private Rect mBounds;  
  10.   
  11.     private OnTextClearListener mOnTextClearListener;  
  12.   
  13.     public ClearableTextView(Context context) {  
  14.         super(context);  
  15.         initialize(context);  
  16.     }  
  17.   
  18.     public ClearableTextView(Context context, AttributeSet attrs) {  
  19.         super(context, attrs);  
  20.         initialize(context);  
  21.     }  
  22.   
  23.     private void initialize(Context context) {  
  24.         mContext = context;  
  25.         mDrawableRight = mContext.getResources().getDrawable(R.drawable.ic_delete);  
  26.         mDrawableRight.setBounds(00, mDrawableRight.getMinimumWidth(), mDrawableRight.getMinimumWidth());  
  27.         setClickable(true);  
  28.         setMinWidth(120);  
  29.         setGravity(Gravity.CENTER_VERTICAL);  
  30.         setPadding(8888);  
  31.         setCompoundDrawablePadding(8);  
  32.     }  
  33.   
  34.     @Override  
  35.     public void setCompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom) {  
  36.         if (right != null) {  
  37.             mDrawableRight = right;  
  38.         }  
  39.         super.setCompoundDrawables(left, top, mDrawableRight, bottom);  
  40.     }  
  41.   
  42.     public boolean onTouchEvent(MotionEvent event) {  
  43.   
  44.         if (event.getAction() == MotionEvent.ACTION_UP && mDrawableRight != null) {  
  45.   
  46.             mBounds = mDrawableRight.getBounds();  
  47.   
  48.             final int x = (int) event.getX();  
  49.             final int y = (int) event.getY();  
  50.   
  51.             if (x >= (this.getWidth() - mBounds.width()) && x <= (this.getWidth() - this.getPaddingRight())  
  52.                     && y >= this.getPaddingTop() && y <= (this.getHeight() - this.getPaddingBottom())) {  
  53.                 clear();  
  54.                 event.setAction(MotionEvent.ACTION_CANCEL);  
  55.             }  
  56.         }  
  57.   
  58.         return super.onTouchEvent(event);  
  59.     }  
  60.   
  61.     public void setTextClearable(CharSequence text) {  
  62.         setText(text);  
  63.         if (text == null || text.length() == 0) {  
  64.             super.setCompoundDrawables(nullnullnullnull);  
  65.         } else {  
  66.             super.setCompoundDrawables(nullnull, mDrawableRight, null);  
  67.         }  
  68.     }  
  69.   
  70.     private void clear() {  
  71.         setTextClearable("");  
  72.         if (mOnTextClearListener != null) {  
  73.             mOnTextClearListener.onTextClear(this);  
  74.         }  
  75.         super.setCompoundDrawables(nullnullnullnull);  
  76.     }  
  77.   
  78.     public void setOnTextClearListener(OnTextClearListener onTextClearListener) {  
  79.         mOnTextClearListener = onTextClearListener;  
  80.     }  
  81.   
  82.     public void finalize() throws Throwable {  
  83.         mDrawableRight = null;  
  84.         mBounds = null;  
  85.         super.finalize();  
  86.     }  
  87. }  

我们创建了一个ClearableTextView,继承于TextView,关键的代码如下:

1)设置CompoundDrawables。

我们知道在xml布局中,对于TextView,我们可以利用DrawableLeft, DrawableRight, DrawableTop, DrawableBottom等属性为TextView设置分别处于左右上下的图标,如下:

  1. <TextView  
  2.     android:layout_width="wrap_content"  
  3.     android:layout_height="wrap_content"  
  4.     android:drawableBottom="@drawable/ic_delete"  
  5.     android:drawableLeft="@drawable/ic_delete"  
  6.     android:drawableRight="@drawable/ic_delete"  
  7.     android:drawableTop="@drawable/ic_delete" />  

所以在我们的初始化中,我们可以自己先定义一个默认的图标,也可以从xml布局中获取。

当在xml布局中设置了上面对应的属性之后,函数setCompoundDrawables就会被调用,我们可在里面处理重新设置我们的mDrawableRight。

  1. @Override  
  2. public void setCompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom) {  
  3.     if (right != null) {  
  4.         mDrawableRight = right;  
  5.     }  
  6.     super.setCompoundDrawables(left, top, mDrawableRight, bottom);  
  7. }  

2)必须重载onTouchEvent方法。

这是因为在TextView中设置四边的图标时,并没有提供其对应的点击事件,所以这就需要我们自己去拦截用户的点击事件,判断用户的点击区域,人工的去做对应的处理,如下:

  1. public boolean onTouchEvent(MotionEvent event) {  
  2.   
  3.     if (event.getAction() == MotionEvent.ACTION_UP && mDrawableRight != null) {  
  4.   
  5.         mBounds = mDrawableRight.getBounds();  
  6.   
  7.         final int x = (int) event.getX();  
  8.         final int y = (int) event.getY();  
  9.   
  10.         if (x >= (this.getWidth() - mBounds.width()) && x <= (this.getWidth() - this.getPaddingRight())  
  11.                 && y >= this.getPaddingTop() && y <= (this.getHeight() - this.getPaddingBottom())) {  
  12.             clear();  
  13.             event.setAction(MotionEvent.ACTION_CANCEL);  
  14.         }  
  15.     }  
  16.   
  17.     return super.onTouchEvent(event);  
  18. }  

逻辑很简单,首先要获取图标的矩形区域,同时获取用户点击的点,只要此点落在此矩形区域内,我们就可以认为用户点击了这个按钮,进行我们自己的逻辑处理,然后将此事件的Action设置为Cancel,再利用系统onTouchEvent去处理这个Cancel事件。

代码中的clear方法就是我们自己去处理的逻辑,这个时候,我们就要考虑了,只是单纯做一些操作就可以,还是需要跟外部进行交互呢?

3)定义一个接口,用来由外部实现,可在图标点击事件时触发

  1. public interface OnTextClearListener {  
  2.     public void onTextClear(ClearableTextView v);  
  3. }  
  4.   
  5.   
  6. private void clear() {  
  7.     setTextClearable("");  
  8.     if (mOnTextClearListener != null) {  
  9.         mOnTextClearListener.onTextClear(this);  
  10.     }  
  11.     super.setCompoundDrawables(nullnullnullnull);  
  12. }  

所以,我们在clear方法里面,要判断有没有这样一个接口被实现并传给当前控件,如果存在,我们要调用其方法。

4)为了让文字不存在的时候,删除按钮不出现,我们可以自己定义一个setTextClearable方法,里面包装了TextView的setText方法,但是我们会根据参数内容来判断,要不要显示删除图标。

  1. public void setTextClearable(CharSequence text) {  
  2.     setText(text);  
  3.     if (text == null || text.length() == 0) {  
  4.         super.setCompoundDrawables(nullnullnullnull);  
  5.     } else {  
  6.         super.setCompoundDrawables(nullnull, mDrawableRight, null);  
  7.     }  
  8. }  

5)当然,最后,在按钮不再存在上下文,即被销毁的时候,我们需要将对应的资源也清空,如下:

  1. public void finalize() throws Throwable {  
  2.     mDrawableRight = null;  
  3.     mBounds = null;  
  4.     super.finalize();  
  5. }  

到这里,整个的实现就讲解完了,虽然很简单,但是还是有学习的地方的,比如接口定义,很多方法的交互,我们可以通过消息传递,也可以通过回调函数来实现,具体就得考虑工作场景了。

好,接下来,就是在外面放置这样一个控件,来看看效果了。

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:paddingBottom="@dimen/activity_vertical_margin"  
  6.     android:paddingLeft="@dimen/activity_horizontal_margin"  
  7.     android:paddingRight="@dimen/activity_horizontal_margin"  
  8.     android:paddingTop="@dimen/activity_vertical_margin"  
  9.     tools:context="com.example.clearabletextviewdemo.MainActivity$PlaceholderFragment" >  
  10.   
  11.     <com.example.clearabletextviewdemo.ClearableTextView  
  12.         android:id="@+id/ctvTest"  
  13.         android:layout_width="wrap_content"  
  14.         android:layout_height="wrap_content"  
  15.         android:text="@string/hello_world" />  
  16.   
  17. </RelativeLayout>  

MainActivity中的代码:

  1.     public View onCreateView(LayoutInflater inflater, ViewGroup container,  
  2.             Bundle savedInstanceState) {  
  3.         View rootView = inflater.inflate(R.layout.fragment_main, container,  
  4.                 false);  
  5.         mCtvTest = (ClearableTextView) rootView.findViewById(R.id.ctvTest);  
  6.         mCtvTest.setTextClearable("Hello World");  
  7.           
  8.         mCtvTest.setOnClickListener(new OnClickListener() {  
  9.               
  10.             @Override  
  11.             public void onClick(View v) {  
  12.                 mCtvTest.setTextClearable("Hello World!");  
  13.             }  
  14.         });  
  15.           
  16.         mCtvTest.setOnTextClearListener(new OnTextClearListener() {  
  17.               
  18.             @Override  
  19.             public void onTextClear(ClearableTextView v) {  
  20.                 Toast.makeText(getActivity(), "On Text Cleared ", Toast.LENGTH_SHORT).show();  
  21.             }  
  22.         });  
  23.           
  24.         return rootView;  
  25.     }  
  26. }  

最后,当然就是效果图了,如下:


结束!

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
Android自定义查看更多TextView
Android 自定义EditText输入框 带清空按钮
新手啊请求帮助,在自定义适配器里面设置数据的时候都是报错,读不到listDate数据
ArrayAdapter和BaseAdapter介绍
Android开发网上的一些重要知识点
Android一些常用知识和代码(不断更新)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服