本文得益于博主“Ruffian-痞子”的博文->Here,多谢大神分享。
一般当我们要实现文本旁边加一个图片的效果时(比如一般底部的导航栏都是这么个效果),经常会用一个TextView和一个ImageView组合来实现,当要改变状态时要显示不一样的背景或者颜色,同时Image也要变化。这样一来,效果是实现了,可是弊端在于,不只是xml端的代码很冗余(除了空间组合多,而且定义的用于状态切换的selector也多),而且代码端的更麻烦,你要在合适的时机去动态的改变,势必会频繁地setSelected()、setEnable(),想想就很乱。
所以,我们找到了drawableLeft、drawableRight、drawableTop、drawableBottom这几个属性,我们可以方便的在一个控件下实现图片为文本同时显示的效果,而且动态的改变变得更加简便和便于维护,可是并没有什么完美的东西,他的缺点就是,我们不能去改变他这个drawable的大小,所以当我们的drawable的宽度或者高度比TextView大的时候就会只显示一部分,我们能做的只有先把图片一开始就做成控件所能适应的大小,这样一来,UI会疯的,因为在一切落实之前,布局可能会频繁的改动的。如果你说我可以把UI的图拿过来自己用某软件缩成我需要的,那么你只是把UI的工作量挪到了自己这边,似不似傻,我就这么傻过(那是我刚工作的时候,一切为别人考虑...)。关键是即便是这样你在程序中显示出来的图片和UI给你的相比是失真的,你会看到一片片的朦胧美,然后我当时就懵逼了...
现在对于这个问题我们有了可以说是完美的解决方法:自定义View!
首先,定义我们自己的属性
其次,写一个继承自TextView的View,实现他的构造方法
public class DrawableTextView extends TextView { public static final String TAG = Contacts.TAG ; public static final int LEFT=1,TOP=2,RIGHT=3,BOTTOM=4 ; private Drawable src ; private int drawablePosition ; private int drawableWidth ; private int drawableHeight ; private Bitmap mBitmap; public DrawableTextView(Context context) { super(context); } public DrawableTextView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public DrawableTextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.DrawableTextView,defStyleAttr,0); //默认设置为“college”图片 src = array.getDrawable(R.styleable.DrawableTextView_drawableSrc); Log.d(TAG, "DrawableTextView: "+src); //默认设置为左边 drawablePosition = array.getInt(R.styleable.DrawableTextView_drawablePosition, LEFT); Log.d(TAG, "DrawableTextView: "+drawablePosition); //默认为20dp宽 drawableWidth = array.getDimensionPixelSize(R.styleable.DrawableTextView_drawableWidth,0); Log.d(TAG, "DrawableTextView: "+drawableWidth); //默认为20dp长 drawableHeight = array.getDimensionPixelSize(R.styleable.DrawableTextView_drawableHeight,0); Log.d(TAG, "DrawableTextView: " + drawableHeight); array.recycle(); drawDrawable(); } private void drawDrawable() { if (src != null) { Bitmap bitmap = ((BitmapDrawable)src).getBitmap(); Drawable drawable ; if (drawableWidth!=0&&drawableHeight!=0) { drawable = new BitmapDrawable(getResources(),getBitmap(bitmap,drawableWidth,drawableHeight)); }else { drawable = new BitmapDrawable(getResources(),Bitmap.createScaledBitmap(bitmap,bitmap.getWidth(),bitmap.getHeight(),true)); } switch (drawablePosition){ case LEFT: this.setCompoundDrawablesWithIntrinsicBounds(drawable,null,null,null); break; case TOP: this.setCompoundDrawablesWithIntrinsicBounds(null,drawable,null,null); break; case RIGHT: this.setCompoundDrawablesWithIntrinsicBounds(null,null,drawable,null); break; case BOTTOM: this.setCompoundDrawablesWithIntrinsicBounds(null,null,null,drawable); break; } } } public Bitmap getBitmap(Bitmap bitmap,int width,int height) { //实际的大小 int totalWidth = bitmap.getWidth(); int totalHeight = bitmap.getHeight(); // int a = width; // int b = height; //计算缩放比例 float scaleWidth = (float)width/totalWidth ; float scaleHeight = (float)height/totalHeight ; Matrix matrix = new Matrix(); //提交缩放 matrix.postScale(scaleWidth, scaleHeight); Log.d(TAG, "宽: " + totalWidth + "高:" + totalHeight); //得到缩放后的图片 Bitmap bitmapResult = Bitmap.createBitmap(bitmap,0,0,totalWidth,totalHeight,matrix,true); return bitmapResult ; } }大体就是getBitmap()方法是设置drawable的大小以适应我们在xml中设置好的大小,然后调用setCompoundDrawablesWithIntrinsicBounds()这个方法把设置好大小的drawable设置进去就ok了!
最后就是在xml中添加自定义View
<com.hardy.person.myself_view_test.views.DrawableTextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="自定义TextView(可以设置嵌入的图片大小,意味着我们再也不用费劲的去用ImageView和TextView组合去显示了)" android:gravity="center_vertical" android:drawablePadding="10dp" app:drawablePosition="bottom" app:drawableWidth="30dp" app:drawableHeight="30dp" app:drawableSrc="@drawable/major" />
其中的drawableSrc取代了drawableLeft等属性来设置drawable资源,用drawablePosition来设置图片在文本的哪个方向上,drawableWidth和drawableHeight可以设置图片的大小从而来适应TextView的大小。
No...感觉被坑了,上面说的优点顿时就没了,不能设置成selector的样式,会出现android.graphics.drawable.StateListDrawable cannot be cast to android.graphics.drawable.BitmapDrawable的错误,而且如果在代码中动态改变drawable,只能通过setCompoundDrawablesWithIntrinsicBounds()方法,然后还要像前面说的那样裁剪,EXM?这样一来比组合实现复杂多了好吗!可见这个控件只能适合写死的情况下,而且我觉得写死的情况用它只是少定义两个控件,但是自定义它自己的代码也多了不少好吗!所以我也不见得有什么优点了。。。好失望,如果能设置selector就好了,日后期待自己能完善这个问题。