改编自Trinea的CompoundDrawablesTextView,thanks

概述

在android的TextView中我们可以通过setCompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom)
或者android:drawableLeft系列属性
来给TextView的周围设置Drawable,省去了在旁边写一个ImageView而造成的多了一层布局.

但是,并没有对外提供触控事件,而有时我们却需要给这样一个drawable设置点击事件

实现原理

要实现这样一个需求,其实思路很简单,就是重写onTouchEvent,并判定点击区域是否在图标范围内,然后回调相应的点击事件即可.

核心代码:

 @Override public boolean onTouchEvent(MotionEvent event) {        // 在event为actionDown时标记用户点击是否在相应的图片范围内        if (event.getAction() == MotionEvent.ACTION_DOWN) {            resetTouchStatus();            if (mDrawableClickListener != null) {                mIsLeftTouched = touchLeftDrawable(event);                mIsTopTouched = touchTopDrawable(event);                mIsRightTouched = touchRightDrawable(event);                mIsBottomTouched = touchBottomDrawable(event);            }        }        return super.onTouchEvent(event);    }    @Override public void onClick(View v) {        /**         * 按照左上右下的顺序响应第一个点击范围内的Drawable         */        if (mDrawableClickListener != null) {            if (mIsLeftTouched) {                mDrawableClickListener.onClick(DrawableClickListener.DrawablePosition.LEFT);            } else if (mIsTopTouched) {                mDrawableClickListener.onClick(DrawableClickListener.DrawablePosition.TOP);            } else if (mIsRightTouched) {                mDrawableClickListener.onClick(DrawableClickListener.DrawablePosition.RIGHT);            } else if (mIsBottomTouched) {                mDrawableClickListener.onClick(DrawableClickListener.DrawablePosition.BOTTOM);            } else {                mDrawableClickListener.onClick(DrawableClickListener.DrawablePosition.TEXT);            }        }    }

本实例代码见:
CompoundDrawablesTextView@[Github]

原理剖析

rect对象所表示一个矩形区域,其有一个contains方法,只要我们把坐标传进去,就可以通过返回值来得到该坐标是否在该范围内 ,因此我们可以通过这个方法来进行判断我们所触摸的是哪一个Drawable或者是TextView的text

如下判断触摸的是否是左边的Drawable

   /** touch左边的Drawable     *     * @param event     * @return 是否在touch范围内     */    private boolean touchLeftDrawable(MotionEvent event) {        if (mLeftDrawable == null) {            return false;        }        // 计算图片点击可响应的范围,计算方法见        http://trinea.iteye.com/blog/1562388        int drawHeight = mLeftDrawable.getIntrinsicHeight();        int drawWidth = mLeftDrawable.getIntrinsicWidth();        int topBottomDis = (mTopDrawable == null ? 0 : mTopDrawable.getIntrinsicHeight())                - (mBottomDrawable == null ? 0 : mBottomDrawable.getIntrinsicHeight());        double imageCenterY = 0.5 * (this.getHeight() + topBottomDis);        Rect imageBounds = new Rect(this.getCompoundDrawablePadding() - mLazyX,                (int) (imageCenterY - 0.5 * drawHeight - mLazyY), this.getCompoundDrawablePadding()                + drawWidth + mLazyX,                (int) (imageCenterY + 0.5 * drawHeight + mLazyY));        return imageBounds.contains((int) event.getX(), (int) event.getY());    }

这里面有两个变量mLazyX,mLazyY,是用来扩大响应范围的,就是我们常说的热区。

Theme

这里我们通过theme来该改变控件的默认appearance,如果不了解通过theme改变控件属性可参考:
Android中的主题和样式

  • attrs.xml
    <attr name="Compound_Drawables_TextView_Style" format="reference" />
  • style.xml
<?xml version="1.0" encoding="utf-8"?><resources>   <style name="Theme.CompoundDrawablesTextViewStyleDefault" parent="android:Theme">        <item name="Compound_Drawables_TextView_Style">@style/Widget.cdtStyle   style>   <style name="Widget" />    <style name="Widget.cdtStyle">        <item name="android:gravity">centeritem>       <item name="android:textColor">#fabitem>    style>resources>
  • 应用
public CompoundDrawablesTextView(Context context, AttributeSet attrs) {        this(context, attrs, R.attr.Compound_Drawables_TextView_Style);    }

测试

  • customstyle.xml
<style name="AppTheme.NoActionBar.Compound_Default"><item name="Compound_Drawables_TextView_Style">@style/Widget.cdtStyle.CustomcdtStyle  style>  <style name="Widget.cdtStyle.CustomcdtStyle">      <item name="android:drawablePadding">10dpitem>       <item name="android:text">"CDT"item>      style>
  • manifes.xml && layout.xml
<activity android:name="com.bobomee.blogdemos.ui.activity.CompoundDrawablesTextViewActivity"android:theme="@style/AppTheme.NoActionBar.Compound_Default" />                      <?xml version="1.0" encoding="utf-8"?><com.bobomee.commonlibrary.widget.CompoundDrawablesTextView xmlns:android="http://schemas.android.com/apk/res/android"              android:layout_width="wrap_content"              android:id="@+id/textWithImage"              android:drawableLeft="@mipmap/ic_launcher"              android:layout_height="wrap_content"/>
  • java code
 @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.compound_drawables_textview_layout);        CompoundDrawablesTextView textWithImage = (CompoundDrawablesTextView)this.findViewById(R.id.textWithImage);        textWithImage.setDrawableClickListener(new ImageClickListener());    }    class ImageClickListener implements CompoundDrawablesTextView.DrawableClickListener {        @Override        public void onClick(DrawablePosition position) {            switch (position) {                case LEFT:                    // 左边图片被点击的响应                    Toast.makeText(CompoundDrawablesTextViewActivity.this, "left", Toast.LENGTH_SHORT).show();                    break;                case RIGHT:                    // 右边图片被点击的响应                    Toast.makeText(CompoundDrawablesTextViewActivity.this, "right", Toast.LENGTH_SHORT).show();                    break;                case BOTTOM:                    // 底部图片被点击的响应                    Toast.makeText(CompoundDrawablesTextViewActivity.this, "bottom", Toast.LENGTH_SHORT).show();                    break;                case TOP:                    // 上边图片被点击的响应                    Toast.makeText(CompoundDrawablesTextViewActivity.this, "top", Toast.LENGTH_SHORT).show();                    break;                case TEXT:                    Toast.makeText(CompoundDrawablesTextViewActivity.this, "TEXT", Toast.LENGTH_SHORT).show();                    break;                default:                    break;            }        }    }

效果图:

更多相关文章

  1. Android(安卓)按钮点击两次触发不同的事件
  2. android api 中文 (75)—— AdapterView.OnItemClickListener
  3. Android(安卓)中Layout实现点击水波纹特效
  4. 两种button点击后改变颜色的方法selectot和重写
  5. 81.s1-禁用checkBox点击事件
  6. Android入门一:Android(安卓)开发环境安装配置手册
  7. Android(安卓)环境搭建
  8. android studio调试c/c++代码
  9. 在Fragment中设置控件点击方法,执行失败。

随机推荐

  1. Android App Bundle
  2. android am start 启动某个apk
  3. Android Studio cmake和jni的一些坑
  4. Android常见内存泄漏以及优化方案
  5. Android 控件TextView的属性
  6. Android 打包时:.....is not translated i
  7. android 入门学习笔记 上传大文件
  8. EditText 随记
  9. Android onBackPressed() 里调用 setResu
  10. 自定义dialog样式