当前位置: 移动技术网 > 移动技术>移动开发>Android > Android图文居中显示控件使用方法详解

Android图文居中显示控件使用方法详解

2020年09月06日  | 移动技术网移动技术  | 我要评论
最近项目中用到了文字图标的按钮,需要居中显示,如果用textview实现的方式,必须同时设置padding和drawablepadding。如下:<androidx.appcompat.widg

最近项目中用到了文字图标的按钮,需要居中显示,如果用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);
  }
 }
}

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

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

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网