Android图文居中显示控件使用方法详解
程序员文章站
2022-06-25 08:10:17
最近项目中用到了文字图标的按钮,需要居中显示,如果用textview实现的方式,必须同时设置padding和drawablepadding。如下:
最近项目中用到了文字图标的按钮,需要居中显示,如果用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); } } }
感谢大家的支持,如有错误请指正。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: canvas 绘制双线技巧
下一篇: CI框架简单分页类用法示例
推荐阅读
-
Android控件AppWidgetProvider使用方法详解
-
Android常用控件ImageSwitcher使用方法详解
-
Android垂直滚动控件ScrollView使用方法详解
-
Android进度条控件progressbar使用方法详解
-
Android中ToggleButton开关状态按钮控件使用方法详解
-
Android中CheckBox复选框控件使用方法详解
-
Android中SeekBar拖动条控件使用方法详解
-
Android垂直滚动控件ScrollView使用方法详解
-
Android进度条控件progressbar使用方法详解
-
Android中ToggleButton开关状态按钮控件使用方法详解