最近项目中用到了文字图标的按钮,需要居中显示,如果用textview实现的方式,必须同时设置padding和drawablepadding。如下:
<androidx.appcompat.widget.appcompattextview android:layout_width="200dp" android:layout_height="wrap_content" android:drawableleft="@drawable/ic_xxx" android:drawablepadding="-60dp" android:minheight="48dp" android:gravity="center" android:padding="80dp" />
这种方式需要自己做精确计算。比较麻烦。另外还有一种方式就是用线性布局包裹imageview和textview,但这样会增加布局层级。于是自己封装了一个控件drawablecentertextview。
attrs.xml文件中定义属性:
<declare-styleable name="drawablecentertextview"> <attr name="android:text" /> <attr name="android:textcolor" /> <attr name="android:textsize" /> <attr name="android:textstyle" /> <attr name="android:drawablepadding" /> <attr name="android:drawableleft" /> <attr name="android:drawabletop" /> <attr name="android:drawableright" /> <attr name="android:drawablebottom" /> </declare-styleable>
对应的java代码如下:
public class drawablecentertextview extends view {
static final int left = 0;
static final int top = 1;
static final int right = 2;
static final int bottom = 3;
private charsequence mtext;
private colorstatelist mtextcolor;
private float mtextsize;
private int mtextstyle;
private int mdrawablepadding;
private drawable[] mcompounddrawables;
private rect mtextbounds;
private rect mdrawableleftbounds;
private rect mdrawabletopbounds;
private rect mdrawablerightbounds;
private rect mdrawablebottombounds;
private textpaint mtextpaint;
public drawablecentertextview(context context) {
this(context, null);
}
public drawablecentertextview(context context, attributeset attrs) {
this(context, attrs, 0);
}
public drawablecentertextview(context context, attributeset attrs, int defstyleattr) {
super(context, attrs, defstyleattr);
drawable drawableleft = null, drawabletop = null, drawableright = null, drawablebottom = null;
typedarray ta = context.obtainstyledattributes(attrs, r.styleable.drawablecentertextview, defstyleattr, 0);
mtext = ta.gettext(r.styleable.drawablecentertextview_android_text);
mtextcolor = ta.getcolorstatelist(r.styleable.drawablecentertextview_android_textcolor);
mtextsize = ta.getdimensionpixelsize(r.styleable.drawablecentertextview_android_textsize, 15);
mtextstyle = ta.getint(r.styleable.drawablecentertextview_android_textstyle, 0);
drawableleft = ta.getdrawable(r.styleable.drawablecentertextview_android_drawableleft);
drawabletop = ta.getdrawable(r.styleable.drawablecentertextview_android_drawabletop);
drawableright = ta.getdrawable(r.styleable.drawablecentertextview_android_drawableright);
drawablebottom = ta.getdrawable(r.styleable.drawablecentertextview_android_drawablebottom);
mdrawablepadding = ta.getdimensionpixelsize(r.styleable.drawablecentertextview_android_drawablepadding, 0);
ta.recycle();
if (mtextcolor == null) {
mtextcolor = colorstatelist.valueof(0xff000000);
}
mtextpaint = new textpaint(paint.anti_alias_flag);
mtextpaint.density = getresources().getdisplaymetrics().density;
mtextpaint.settextsize(mtextsize);
settypeface(typeface.create(typeface.default, mtextstyle));
setcompounddrawableswithintrinsicbounds(drawableleft, drawabletop, drawableright, drawablebottom);
}
@override
protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
int widthmode = measurespec.getmode(widthmeasurespec);
int heightmode = measurespec.getmode(heightmeasurespec);
int widthsize = measurespec.getsize(widthmeasurespec);
int heightsize = measurespec.getsize(heightmeasurespec);
int width;
int height;
//计算文本范围
calctextbounds();
if (widthmode == measurespec.exactly) {
width = widthsize;
} else {
width = mtextbounds.width();
if (mcompounddrawables != null) {
if (mcompounddrawables[top] != null) {
width = math.max(width, mdrawabletopbounds.width());
}
if (mcompounddrawables[bottom] != null) {
width = math.max(width, mdrawablebottombounds.width());
}
//加上左右内边距及drawable宽度和drawable间距
width += getcompoundpaddingleft() + getcompoundpaddingright();
width = math.max(width, getsuggestedminimumwidth());
if (widthmode == measurespec.at_most) {
width = math.min(widthsize, width);
}
}
}
if (heightmode == measurespec.exactly) {
height = heightsize;
} else {
height = mtextbounds.height();
if (mcompounddrawables != null) {
if (mcompounddrawables[left] != null) {
height = math.max(height, mdrawableleftbounds.height());
}
if (mcompounddrawables[right] != null) {
height = math.max(height, mdrawablerightbounds.height());
}
//加上上下内边距及drawable高度和drawable间距
height += getcompoundpaddingtop() + getcompoundpaddingbottom();
height = math.max(height, getsuggestedminimumheight());
if (heightmode == measurespec.at_most) {
height = math.min(heightsize, height);
}
}
}
setmeasureddimension(width, height);
}
public int getcompoundpaddingtop() {
if (mcompounddrawables == null || mcompounddrawables[top] == null) {
return getpaddingtop();
} else {
rect rect = new rect();
mcompounddrawables[top].copybounds(rect);
return getpaddingtop() + mdrawablepadding + rect.height();
}
}
public int getcompoundpaddingbottom() {
if (mcompounddrawables == null || mcompounddrawables[bottom] == null) {
return getpaddingbottom();
} else {
rect rect = new rect();
mcompounddrawables[bottom].copybounds(rect);
return getpaddingbottom() + mdrawablepadding + rect.height();
}
}
public int getcompoundpaddingleft() {
if (mcompounddrawables == null || mcompounddrawables[left] == null) {
return getpaddingleft();
} else {
rect rect = new rect();
mcompounddrawables[left].copybounds(rect);
return getpaddingleft() + mdrawablepadding + rect.width();
}
}
public int getcompoundpaddingright() {
if (mcompounddrawables == null || mcompounddrawables[right] == null) {
return getpaddingright();
} else {
rect rect = new rect();
mcompounddrawables[right].copybounds(rect);
return getpaddingright() + mdrawablepadding + rect.width();
}
}
@override
protected void ondraw(canvas canvas) {
super.ondraw(canvas);
int vspace = getbottom() - gettop() - getcompoundpaddingbottom() - getcompoundpaddingtop(); //剩余垂直可绘制文本空间大小
int hspace = getright() - getleft() - getcompoundpaddingright() - getcompoundpaddingleft(); //剩余水平可绘制文本空间大小
if (mcompounddrawables != null) {
if (mcompounddrawables[left] != null) {
canvas.save();
canvas.translate((hspace - mtextbounds.width()) / 2.0f + getpaddingleft(),
getcompoundpaddingtop() + (vspace - mdrawableleftbounds.height()) / 2.0f);
mcompounddrawables[left].draw(canvas);
canvas.restore();
}
if (mcompounddrawables[right] != null) {
canvas.save();
canvas.translate(getright() - getleft() - getpaddingright() - (hspace - mtextbounds.width()) / 2.0f - mdrawablerightbounds.width(),
getcompoundpaddingtop() + (vspace - mdrawablerightbounds.height()) / 2.0f);
mcompounddrawables[right].draw(canvas);
canvas.restore();
}
if (mcompounddrawables[top] != null) {
canvas.save();
canvas.translate(getcompoundpaddingleft()
+ (hspace - mdrawabletopbounds.width()) / 2.0f, (vspace - mtextbounds.height()) / 2.0f + getpaddingtop());
mcompounddrawables[top].draw(canvas);
canvas.restore();
}
if (mcompounddrawables[bottom] != null) {
canvas.save();
canvas.translate(getcompoundpaddingleft()
+ (hspace - mdrawablebottombounds.width()) / 2.0f,
getbottom() - gettop() - getpaddingbottom() - (vspace - mtextbounds.height()) / 2.0f - mdrawablebottombounds.height());
mcompounddrawables[bottom].draw(canvas);
canvas.restore();
}
}
if (!textutils.isempty(mtext)) {
float startx = (hspace - mtextbounds.width()) / 2.0f + getcompoundpaddingleft();
//因为drawtext以baseline为基准,因此需要向下移ascent
float starty = (vspace - mtextbounds.height()) / 2.0f + getcompoundpaddingtop() - mtextpaint.getfontmetrics().ascent;
mtextpaint.setcolor(mtextcolor.getcolorforstate(getdrawablestate(), 0));
canvas.drawtext(mtext, 0, mtext.length(), startx, starty, mtextpaint);
}
}
@override
protected void drawablestatechanged() {
super.drawablestatechanged();
if (mtextcolor != null && mtextcolor.isstateful()) {
mtextpaint.setcolor(mtextcolor.getcolorforstate(getdrawablestate(), 0));
}
if (mcompounddrawables != null) {
final int[] state = getdrawablestate();
for (drawable dr : mcompounddrawables) {
if (dr != null && dr.isstateful() && dr.setstate(state)) {
invalidatedrawable(dr);
}
}
}
}
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);
}
public void setcompounddrawables(@nullable drawable left, @nullable drawable top,
@nullable drawable right, @nullable drawable bottom) {
if (mcompounddrawables == null) {
mcompounddrawables = new drawable[4];
} else {
if (mcompounddrawables[left] != null && mcompounddrawables[left] != left) {
mcompounddrawables[left].setcallback(null);
}
if (mcompounddrawables[top] != null && mcompounddrawables[top] != top) {
mcompounddrawables[top].setcallback(null);
}
if (mcompounddrawables[right] != null && mcompounddrawables[right] != right) {
mcompounddrawables[right].setcallback(null);
}
if (mcompounddrawables[bottom] != null && mcompounddrawables[bottom] != bottom) {
mcompounddrawables[bottom].setcallback(null);
}
}
if (left != null) {
mdrawableleftbounds = new rect();
left.copybounds(mdrawableleftbounds);
left.setcallback(this);
mcompounddrawables[left] = left;
} else {
mcompounddrawables[left] = null;
}
if (top != null) {
mdrawabletopbounds = new rect();
top.copybounds(mdrawabletopbounds);
top.setcallback(this);
mcompounddrawables[top] = top;
} else {
mcompounddrawables[top] = null;
}
if (right != null) {
mdrawablerightbounds = new rect();
right.copybounds(mdrawablerightbounds);
right.setcallback(this);
mcompounddrawables[right] = right;
} else {
mcompounddrawables[right] = null;
}
if (bottom != null) {
mdrawablebottombounds = new rect();
bottom.copybounds(mdrawablebottombounds);
bottom.setcallback(this);
mcompounddrawables[bottom] = bottom;
} else {
mcompounddrawables[bottom] = null;
}
invalidate();
requestlayout();
}
public void settext(charsequence text) {
this.mtext = text;
invalidate();
requestlayout();
}
public void settextsize(float textsize) {
this.mtextsize = typedvalue.applydimension(typedvalue.complex_unit_sp, textsize, getresources().getdisplaymetrics());
invalidate();
requestlayout();
}
public void settextcolor(@colorint int textcolor) {
this.mtextcolor = colorstatelist.valueof(textcolor);
invalidate();
}
public void settypeface(@nullable typeface tf) {
if (mtextpaint.gettypeface() != tf) {
mtextpaint.settypeface(tf);
requestlayout();
invalidate();
}
}
private void calctextbounds() {
mtextbounds = new rect();
if (textutils.isempty(mtext)) return;
if (build.version.sdk_int > build.version_codes.q) {
mtextpaint.gettextbounds(mtext, 0, mtext.length(), mtextbounds);
} else {
int width = (int) math.ceil(mtextpaint.measuretext(mtext.tostring()));
paint.fontmetrics fontmetrics = mtextpaint.getfontmetrics();
int height = (int) math.ceil(fontmetrics.descent - fontmetrics.ascent);
mtextbounds.set(0, 0, width, height);
}
}
}
感谢大家的支持,如有错误请指正。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
_内