欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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);
  }
 }
}

感谢大家的支持,如有错误请指正。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。