Android关于TextView 宽度过大导致Drawable无法居中问题

在做项目的时候,很多时候我们都要用到文字和图片一起显示,一般设置TextView的DrawableLeft、DrawableRight、DrawableTop、DrawableBottom就行了。但是有一种情况是当TextView的熟悉是fill_parent或者使用权重的时候并且设置了起Gravity的ceter的时候,Drawable图片是无法一起居中的,为了解决其,我们一般再套一层布局,然后设置TextView的熟悉是wrap_content,但是有时候嵌套过多的布局的时候,有可能发生StackOverFlow,所以必须要优化,下面说一下其中的一个解决方案。先上图

Android关于TextView 宽度过大导致Drawable无法居中问题_第1张图片

这个解决方案很粗糙,局限性很大,文字不能换行,换行之后就不准了,下面是源码:

[java]  view plain copy
  1. package com.example.testandroid;  
  2.   
  3. import java.lang.ref.WeakReference;  
  4.   
  5. import android.content.Context;  
  6. import android.graphics.Bitmap;  
  7. import android.graphics.BitmapFactory;  
  8. import android.graphics.Canvas;  
  9. import android.graphics.Color;  
  10. import android.graphics.Rect;  
  11. import android.util.AttributeSet;  
  12. import android.view.MotionEvent;  
  13. import android.widget.TextView;  
  14.   
  15. public class DrawableTextView extends TextView {  
  16.   
  17.     private WeakReference<Bitmap> normalReference;  
  18.     private WeakReference<Bitmap> pressReference;  
  19.     private WeakReference<Bitmap> showReference;  
  20.   
  21.     private int normalColor = Color.WHITE, pressColor = Color.WHITE;  
  22.   
  23.     private String text;  
  24.     private int textWidth = 0;  
  25.     private int textHeight = 0;  
  26.   
  27.     public DrawableTextView(Context context) {  
  28.         super(context);  
  29.     }  
  30.   
  31.     public DrawableTextView(Context context, AttributeSet attrs) {  
  32.         super(context, attrs);  
  33.     }  
  34.   
  35.     public DrawableTextView(Context context, AttributeSet attrs, int defStyle) {  
  36.         super(context, attrs, defStyle);  
  37.     }  
  38.   
  39.     @Override  
  40.     protected void onFinishInflate() {  
  41.         super.onFinishInflate();  
  42.         initText();  
  43.     }  
  44.   
  45.     private void initText() {  
  46.         text = super.getText().toString();  
  47.         initVariable();  
  48.     }  
  49.   
  50.     /** 
  51.      * 初始化,测量Textview内容的长度,高度 
  52.      */  
  53.     private void initVariable() {  
  54.         textWidth = (int) (getPaint().measureText(text));  
  55.         final Rect rect = new Rect();  
  56.         getPaint().getTextBounds(text, 01, rect);  
  57.         textHeight = rect.height();  
  58.     }  
  59.   
  60.     /** 
  61.      * 设置TextView的内容 
  62.      * @param text 
  63.      */  
  64.     public void setText(String text) {  
  65.         this.text = text;  
  66.         initVariable();  
  67.         invalidate();  
  68.     }  
  69.   
  70.     /** 
  71.      * 获取TextView内容 
  72.      */  
  73.     public String getText() {  
  74.         return text;  
  75.     }  
  76.   
  77.     /** 
  78.      * 设置TextView的Drawable内容,目前仅支持DrawableLeft 
  79.      * @param normalDrawableId 
  80.      *              DrawableLeft的normal状态Id 
  81.      * @param pressDrawableId 
  82.      *              DrawableLeft的press状态的Id(没有press状态,请传-1) 
  83.      */  
  84.     public void setDrawableLeftId(final int normalDrawableId, final int pressDrawableId) {  
  85.         normalReference = new WeakReference<Bitmap>(BitmapFactory.decodeResource(getResources(), normalDrawableId));  
  86.         if (pressDrawableId != -1) {  
  87.             pressReference = new WeakReference<Bitmap>(BitmapFactory.decodeResource(getResources(), pressDrawableId));  
  88.         }  
  89.         showReference = normalReference;  
  90.         invalidate();  
  91.     }  
  92.   
  93.     /** 
  94.      * 设置TextView的Color 
  95.      * @param normalColor 
  96.      *              TextView normal状态的Color值 
  97.      * @param pressDrawableId 
  98.      *              TextView press状态的Color值(如果没有press状态,请传与normal状态的值) 
  99.      */  
  100.     public void setTextColor(final int normalColor, final int pressColor) {  
  101.         this.normalColor = normalColor;  
  102.         this.pressColor = pressColor;  
  103.         getPaint().setColor(normalColor);  
  104.         initVariable();  
  105.     }  
  106.   
  107.     @Override  
  108.     protected void onDraw(Canvas canvas) {  
  109.         if (showReference != null && showReference.get() != null) {  
  110.             final int bitmapWidth = showReference.get().getWidth();  
  111.             final int bitmapHeight = showReference.get().getHeight();  
  112.             final int viewHeight = getHeight();  
  113.             final int drawablePadding = getCompoundDrawablePadding();  
  114.             final int start = (getWidth() - (bitmapWidth + drawablePadding + textWidth)) >> 1;  
  115.             canvas.drawBitmap(showReference.get(), start, (viewHeight >> 1) - (bitmapHeight >> 1), getPaint());  
  116.               
  117.             /** 
  118.              * 注意改方法,第三个参数y,本人也被误导了好久,原来在画文字的时候,y表示文字最后的位置(不是下笔点的起始位置) 
  119.              * 所以为什么 是TextView高度的一半(中间位置) + 文字高度的一半 = 文字居中 
  120.              */  
  121.             canvas.drawText(text, start + drawablePadding + bitmapWidth, (viewHeight >> 1) + (textHeight >> 1), getPaint());  
  122.         }  
  123.     }  
  124.   
  125.     @Override  
  126.     public boolean onTouchEvent(MotionEvent event) {  
  127.         if (event.getAction() == MotionEvent.ACTION_DOWN) {  
  128.             if (pressReference != null && pressReference.get() != null) {  
  129.                 showReference = pressReference;  
  130.             }  
  131.             getPaint().setColor(pressColor);  
  132.         } else if (event.getAction() == MotionEvent.ACTION_UP) {  
  133.             if (normalReference != null && normalReference.get() != null) {  
  134.                 showReference = normalReference;  
  135.             }  
  136.             getPaint().setColor(normalColor);  
  137.         }  
  138.         invalidate();  
  139.         return super.onTouchEvent(event);  
  140.     }  
  141.   
  142. }  
xml布局:

[html]  view plain copy
  1. <com.example.testandroid.DrawableTextView  
  2.         android:id="@+id/my_textview"  
  3.         android:layout_width="fill_parent"  
  4.         android:layout_marginTop="20dp"  
  5.         android:background="@drawable/text_selector"  
  6.         android:drawablePadding="8dp"  
  7.         android:textColor="@color/standard_orange"  
  8.         android:layout_height="wrap_content"  
  9.         android:padding="15dp"  
  10.         android:textSize="16sp"  
  11.         android:text="有Drawable的TextView" />  
调用代码:

[java]  view plain copy
  1. DrawableTextView drawableTextView = (DrawableTextView) getView().findViewById(R.id.my_textview);  
  2. drawableTextView.setDrawableLeftId(R.drawable.bg_btn_delete_normal, R.drawable.bg_btn_delete_pressed);  
  3. drawableTextView.setTextColor(getResources().getColor(R.color.standard_orange), getResources().getColor(R.color.standard_white));  
  4. drawableTextView.setText("我在动态修改Text啦");  

其实还有更加方便的方法,下面朋友借鉴某个网友的代码(地址我就不知道了):

[java]  view plain copy
  1. @Override  
  2. protected void onDraw(Canvas canvas) {  
  3.     Drawable[] drawables = getCompoundDrawables();  
  4.     if (drawables != null) {  
  5.         Drawable drawableLeft = drawables[0];  
  6.         if (drawableLeft != null) {  
  7.             final float textWidth = getPaint().measureText(getText().toString());  
  8.             final int drawablePadding = getCompoundDrawablePadding();  
  9.             final int drawableWidth = drawableLeft.getIntrinsicWidth();  
  10.             final float bodyWidth = textWidth + drawableWidth + drawablePadding;  
  11.             canvas.translate((getWidth() - bodyWidth) / 20);  
  12.         }  
  13.     }  
  14.     super.onDraw(canvas);  
  15. }  

xml布局:

[html]  view plain copy
  1. <com.example.testandroid.DrawableTextView  
  2.         android:id="@+id/my_textview"  
  3.         android:layout_width="fill_parent"  
  4.         android:layout_marginTop="20dp"  
  5.         android:background="@drawable/text_selector"  
  6.         android:drawablePadding="8dp"  
  7.         android:drawableLeft="@drawable/clear_edittext_selector"  
  8.         android:textColor="@color/text_color_selector"  
  9.         android:layout_height="wrap_content"  
  10.         android:padding="15dp"  
  11.         android:textSize="16sp"  
  12.         android:text="有Drawable的TextView" />  


嗯,自己写这个东西,也学到了一些东西,大家有什么更好的方法,大家可以讨论一下。


另外的解决思路:

自定义控件让TextView、Button的drawableLeft和drawableRight与文本一起居中显示

http://blog.csdn.net/catoop/article/details/23947345

TextView的drawableLeft、drawableRight和drawableTop是一个常用、好用的属性,可以在文本的上下左右放置一个图片,而不使用更加复杂布局就能达到,我也常常喜欢用RadioButton的这几个属性实现很多效果,但是苦于不支持让drawbleLeft与文本一起居中,设置gravity为center也无济于事,终于有空研究了一下,这里与大家一起分享。


布局XML

[html]  view plain copy
  1. <com.assistant.expand.customview.DrawableCenterButton  
  2.                         android:gravity="left|center_vertical"  
  3.                         android:drawableLeft="@drawable/icon_erweima"  
  4.                         android:drawablePadding="5dp"  
  5.                 android:id="@+id/btn_scale"  
  6.                 android:layout_width="fill_parent"  
  7.                 android:layout_height="fill_parent"  
  8.                 android:background="@android:color/transparent"  
  9.                 android:singleLine="true"  
  10.                 android:text="扫描二维码签到"  
  11.                 android:textColor="@color/color_button2"  
  12.                 android:textSize="17sp" />  



[java]  view plain copy
  1. /** 
  2.  * drawableLeft与文本一起居中显示 
  3.  *  
  4.  *  
  5.  */  
  6. public class DrawableCenterTextView extends TextView {  
  7.   
  8.     public DrawableCenterTextView(Context context, AttributeSet attrs,  
  9.             int defStyle) {  
  10.         super(context, attrs, defStyle);  
  11.     }  
  12.   
  13.     public DrawableCenterTextView(Context context, AttributeSet attrs) {  
  14.         super(context, attrs);  
  15.     }  
  16.   
  17.     public DrawableCenterTextView(Context context) {  
  18.         super(context);  
  19.     }  
  20.   
  21.     @Override  
  22.     protected void onDraw(Canvas canvas) {  
  23.         Drawable[] drawables = getCompoundDrawables();  
  24.         if (drawables != null) {  
  25.             Drawable drawableLeft = drawables[0];  
  26.             if (drawableLeft != null) {  
  27.                 float textWidth = getPaint().measureText(getText().toString());  
  28.                 int drawablePadding = getCompoundDrawablePadding();  
  29.                 int drawableWidth = 0;  
  30.                 drawableWidth = drawableLeft.getIntrinsicWidth();  
  31.                 float bodyWidth = textWidth + drawableWidth + drawablePadding;  
  32.                 canvas.translate((getWidth() - bodyWidth) / 20);  
  33.             }  
  34.         }  
  35.         super.onDraw(canvas);  
  36.     }  
  37. }  


下面是用Button的Right 例子

[java]  view plain copy
  1. /** 
  2.  * drawableRight与文本一起居中显示 
  3.  *  
  4.  *  
  5.  */  
  6. public class DrawableCenterButton extends Button {  
  7.   
  8.     public DrawableCenterButton(Context context) {  
  9.         super(context);  
  10.         // TODO Auto-generated constructor stub  
  11.     }  
  12.   
  13.     public DrawableCenterButton(Context context, AttributeSet attrs,  
  14.     int defStyle) {  
  15.         super(context, attrs, defStyle);  
  16.     }  
  17.   
  18.     public DrawableCenterButton(Context context, AttributeSet attrs) {  
  19.         super(context, attrs);  
  20.     }  
  21.   
  22.   
  23.     @Override  
  24.     protected void onDraw(Canvas canvas) {  
  25.         Drawable[] drawables = getCompoundDrawables();  
  26.         if (drawables != null) {  
  27.             Drawable drawableLeft = drawables[2];  
  28.                 if (drawableLeft != null) {  
  29.               
  30.                 float textWidth = getPaint().measureText(getText().toString());  
  31.                 int drawablePadding = getCompoundDrawablePadding();  
  32.                 int drawableWidth = 0;  
  33.                 drawableWidth = drawableLeft.getIntrinsicWidth();  
  34.                 float bodyWidth = textWidth + drawableWidth + drawablePadding;  
  35.                 setPadding(00, (int)(getWidth() - bodyWidth), 0);  
  36.                 canvas.translate((getWidth() - bodyWidth) / 20);  
  37.             }  
  38.         }  
  39.         super.onDraw(canvas);  
  40.     }  
  41. }  

你可能感兴趣的:(Android关于TextView 宽度过大导致Drawable无法居中问题)