经常在项目中我们会看到一个按钮采用图片及文字结合的方式来显示界面,我们如何设计布局了?
第一种方法:使用一个ViewGroup,在ViewGroup中添加一个ImageView和一个TextView组合来达到这种效果。
第二种方式使用Textview的drawableLeft,drawableTop,drawableRight,drawableRight来达到这种效果,但是这又有一个问题,就是不能指定drawable的大小和位置。
系统默认是显示图片的加载大小,可在TextView源码中的
public void setCompoundDrawablesWithIntrinsicBounds(@Nullable Drawable left, @Nullable Drawable top, @Nullable Drawable right, @Nullable Drawable bottom) { if (left != null) { left.setBounds(0, 0, left.getIntrinsicWidth(), left.getIntrinsicHeight()); } if (right != null) { right.setBounds(0, 0, right.getIntrinsicWidth(), right.getIntrinsicHeight()); } if (top != null) { top.setBounds(0, 0, top.getIntrinsicWidth(), top.getIntrinsicHeight()); } if (bottom != null) { bottom.setBounds(0, 0, bottom.getIntrinsicWidth(), bottom.getIntrinsicHeight()); } setCompoundDrawables(left, top, right, bottom); }这个方法中看到,这个方法在其构造函数中调用。
最后是把这4个变量存在其内部类Drawables中,api23之前是存在Drawables中的4个成员变量中,之后是存在其mShowing中。
在api23的源码中,Textview的ondraw()方法中可以看到,
if (dr.mShowing[Drawables.LEFT] != null) { canvas.save(); canvas.translate(scrollX + mPaddingLeft + leftOffset, scrollY + compoundPaddingTop + (vspace - dr.mDrawableHeightLeft) / 2); dr.mShowing[Drawables.LEFT].draw(canvas); canvas.restore(); }所以我们通过反射可以,改变Drawable中的mBounds变量,以left为例:
try { Class> calss = Class.forName("android.widget.TextView"); Field draw = calss.getDeclaredField("mDrawables"); draw.setAccessible(true); Object obj=draw.get(mbtn); if(obj != null){ calss = obj.getClass(); if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.M){ draw = calss.getDeclaredField("mShowing"); draw.setAccessible(true); Object song = draw.get(obj); if(song != null){ Object[] objs = (Object[]) song; if(objs[1] != null){ Drawable top = (Drawable) objs[1]; top.setBounds(0,0,50,50); } } }else{ draw = calss.getDeclaredField("mDrawableTop"); draw.setAccessible(true); Object song = draw.get(obj); if(song != null){ Drawable top = (Drawable) song; top.setBounds(0,0,50,50); } } } draw = calss.getDeclaredField("mDrawableWidthTop"); draw.setAccessible(true); draw.set(obj,50); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); }最后还要反射Drawables的mDrawableWidthTop变量来让图片居中