改编自Trinea的CompoundDrawablesTextView,thanks

概述

在android的TextView中为我们提供了很方便的在TextView的周围画Drawable

setCompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom)
或者
android:drawableLeft=””
android:drawableTop=””
android:drawableRight=””
android:drawableBottom=”“

但是,并没有对外提供触控事件,而我们需要其点击事件,对于这种情况,就需要了解Android的事件分发机制了

Android事件分发

参考:(Trinea)https://github.com/android-cn/android-open-project-analysis/tree/master/tech/touch-event

事件传递过程Activity.dispatchTouchEvent() -> ViewGroup.dispatchTouchEvent() -> View.onTouchEvent()

因此我们只需要重写onTouchEvent()即可。

   /** * 设置OnClickListener为当前的listener,即调用{@link CompoundDrawablesTextView#onClick(View)}函数 **/    private void init() {        super.setOnClickListener(this);    } @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);            }        }    }

实现原理

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

ps:left drawale

/** * 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,是用来扩大响应范围的。
这里用了一个自定义的接口来处理点击事件 的回调

  /** * 图片点击的监听器 * * @author Trinea 2012-5-3 下午11:45:41 */    public interface DrawableClickListener {        /** * 图片的位置 */        enum DrawablePosition {            /** * 图片在TextView的左部 **/            LEFT,            /** * 图片在TextView的上部 **/            TOP,            /** * 图片在TextView的右部 **/            RIGHT,            /** * 图片在TextView的底部 **/            BOTTOM,            /** * 点击的是文字 */            TEXT        }

Theme

这里我们通过theme来该改变控件的默认appearance,如果不了解通过theme改变控件属性可参见:
深入解析Android declare-styleable attr style theme(中)

  • attrs.xml
 <!--CompoundDrawablesTextView的style-->   <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</item> </style>   <style name="Widget" /> <style name="Widget.cdtStyle"> <item name="android:gravity">center</item> <item name="android:textColor">#fab</item> </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</item> </style>  <style name="Widget.cdtStyle.CustomcdtStyle"> <item name="android:drawablePadding">10dp</item> <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" />           <!--layout.xml-->           <?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;            }        }    }

效果图:
Android 可显示左上右下Drawable的TextView_第1张图片

CompoundDrawablesTextView.java@[Github]

完整demo :
CompoundDrawablesTextViewActivity.java@[Github]

更多相关文章

  1. Android事件处理之监听事件
  2. android photoview 图片放大缩放功能 ImageView
  3. Android图片太大导致无法正常显示
  4. 不停地切换两张图片ViewFlipper
  5. android一些不常用的事件
  6. Android实现图片缩放与旋转
  7. Android Studio点击按钮更换背景图片
  8. android图片放大 缩小 旋转

随机推荐

  1. Android 简单EventBus登录界面与传值(粘性
  2. Android软键盘遮挡布局的那些事
  3. 理解MeasureSpec
  4. Android群英传笔记
  5. android中执行线程的部分代码
  6. 一句话源码
  7. android 实现视频缓存
  8. Android仿微信activity滑动关闭效果
  9. Android 日历方式显示的日期选择组件
  10. Android实现百度地图两点画弧线