Android 可显示左上右下Drawable的TextView

改编自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]

你可能感兴趣的:(android,textview,drawable,onclick)