改编自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来该改变控件的默认appearance,如果不了解通过theme改变控件属性可参考:
Android中的主题和样式
<attr name="Compound_Drawables_TextView_Style" format="reference" />
<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);
}
<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>
<activity android:name="com.bobomee.blogdemos.ui.activity.CompoundDrawablesTextViewActivity"
android:theme="@style/AppTheme.NoActionBar.Compound_Default" />
<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"/>
@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;
}
}
}