I. Business background

TextView setCompoundDrawables() allows you to set images around it, but has a well-known problem: you can’t set the drawable size. This leads to great limitations in the actual use, must use code to control, slightly troublesome.


We need to customize the TextView. This custom control is simple and very humble, but it is quite useful:

  1. The main contradiction is that you can’t set the size of the TextView image in the layout, making it easier to use.

  2. You can do all the things that TextView can do except set the image size

  3. The simple combination of pictures and text is very common. Originally, in order to adapt to the size of the picture, we had to use an xxxLayout+ImageView+TextView to get things done. Now, we can get things done with a control.

  4. In convenient, efficient use, but also effectively reduce the layout layer. Don’t overlook the fly meat, which could be the culprit for your app stalling

2. Expand the TextView principle

  1. SetBound () of Drawable sets the display area, that is, the image size

  2. Set the image to display using the setCompoundDrawables() of the TextView

Extend TextView implementation

3.1 Define a MkDrawableTextView, inherit from AppCompatTextView, override the three constructors

    public MkDrawableTextView(Context context) {
        super(context);
    }

    public MkDrawableTextView(Context context, AttributeSet attrs) {
 super(context, attrs);  init(context, attrs);  }   public MkDrawableTextView(Context context, AttributeSet attrs, int defStyleAttr) {  super(context, attrs, defStyleAttr);  init(context, attrs);  } Copy the code

3.2 Define Drawable width, height and vertex coordinates through custom attributes; Drawable icon reference

    <declare-styleable name="DrawableTextView">
        <attr name="left_drawable" format="reference" />
        <attr name="right_drawable" format="reference" />
        <attr name="top_drawable" format="reference" />
        <attr name="bottom_drawable" format="reference" />
  <attr name="drawable_width" format="dimension" />  <attr name="drawable_height" format="dimension" />   <attr name="left_drawable_width" format="dimension" />  <attr name="left_drawable_height" format="dimension" />   <attr name="right_drawable_width" format="dimension" />  <attr name="right_drawable_height" format="dimension" />   <attr name="top_drawable_width" format="dimension" />  <attr name="top_drawable_height" format="dimension" />   <attr name="bottom_drawable_width" format="dimension" />  <attr name="bottom_drawable_height" format="dimension" />  </declare-styleable> Copy the code

3.3 Obtaining the True Width and height of Drawable

If the local size Settings are normal, we get the width and height of the local Settings. If the local size is not set, we see whether the global size is set correctly. If it is correct, we get the width and height of the global size

    public static class SizeWrap {
        int width;
        int height;

        / * ** Check whether the width and height of Drawable meet the requirements * @paramThe globalWidth XML defined Drawable gets the true width * @paramThe globalHeight XML defines the Drawable to get the true height * @paramLocalWidth Drawable specifies the localWidth of the icon * @paramLocalHeight Drawable specifies the localHeight of the icon * @returnWhether it meets the requirements* /  public boolean checkWidthAndHeight(int globalWidth, int globalHeight, int localWidth, int localHeight) {  width = 0;  height = 0;   // Local size Settings are normal  if (localWidth > 0 && localHeight > 0) {  width = localWidth;  height = localHeight;  return true;  }   // If the local size is not set, check whether the global size is set correctly  if (localWidth == -1 && localHeight == -1) {  if (globalWidth > 0 && globalHeight > 0) {  width = globalWidth;  height = globalHeight;  return true;  }  }   return false;  }  } } Copy the code

3.4 Set the top corner icon Drawable to our TextView

    private void init(Context context, AttributeSet attrs) {
        // 1. Get all the style files from style.xml
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.DrawableTextView);
        int width = ta.getDimensionPixelOffset(R.styleable.DrawableTextView_drawable_width, -1);
        int height = ta.getDimensionPixelOffset(R.styleable.DrawableTextView_drawable_height, -1);
  SizeWrap sizeWrap = new SizeWrap();  Drawable leftDrawable = ta.getDrawable(R.styleable.DrawableTextView_left_drawable);  if(leftDrawable ! =null) {  int lwidth = ta.getDimensionPixelOffset(R.styleable.DrawableTextView_left_drawable_width, -1);  int lheight = ta.getDimensionPixelOffset(R.styleable.DrawableTextView_left_drawable_height, -1);  if (sizeWrap.checkWidthAndHeight(width, height, lwidth, lheight)) {  leftDrawable.setBounds(0.0, sizeWrap.width, sizeWrap.height);  } else {  throw new IllegalArgumentException("error left drawable size setting");  }  }   Drawable rightDrawable = ta.getDrawable(R.styleable.DrawableTextView_right_drawable);  if(rightDrawable ! =null) {  int rwidth = ta.getDimensionPixelOffset(R.styleable.DrawableTextView_right_drawable_width, -1);  int rheight = ta.getDimensionPixelOffset(R.styleable.DrawableTextView_right_drawable_height, -1);  if (sizeWrap.checkWidthAndHeight(width, height, rwidth, rheight)) {  rightDrawable.setBounds(0.0, sizeWrap.width, sizeWrap.height);  } else {  throw new IllegalArgumentException("error right drawable size setting");  }  }   Drawable topDrawable = ta.getDrawable(R.styleable.DrawableTextView_top_drawable);  if(topDrawable ! =null) {  int twidth = ta.getDimensionPixelOffset(R.styleable.DrawableTextView_top_drawable_width, -1);  int theight = ta.getDimensionPixelOffset(R.styleable.DrawableTextView_top_drawable_height, -1);  if (sizeWrap.checkWidthAndHeight(width, height, twidth, theight)) {  topDrawable.setBounds(0.0, sizeWrap.width, sizeWrap.height);  } else {  throw new IllegalArgumentException("error top drawable size setting");  }  }   Drawable bottomDrawable = ta.getDrawable(R.styleable.DrawableTextView_bottom_drawable);  if(bottomDrawable ! =null) {  int bwidth = ta.getDimensionPixelOffset(R.styleable.DrawableTextView_bottom_drawable_width, -1);  int bheight = ta.getDimensionPixelOffset(R.styleable.DrawableTextView_bottom_drawable_height, -1);  if (sizeWrap.checkWidthAndHeight(width, height, bwidth, bheight)) {  bottomDrawable.setBounds(0.0, sizeWrap.width, sizeWrap.height);  } else {  throw new IllegalArgumentException("error bottom drawable size setting");  }  }   this.setCompoundDrawables(leftDrawable, topDrawable, rightDrawable, bottomDrawable);  ta.recycle();  ta = null;  } Copy the code

4. Usage Guide

        <com.github.microkibaco.view.MkDrawableTextView
           android:id="@+id/mk_text"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
 android:layout_marginStart="8dp"  android:layout_toEndOf="@+id/top_text"  android:background="@drawable/mk_circle_rect_10_white_bg"  android:drawablePadding="4dp"  android:gravity="center"  android:paddingStart="10dp"  android:paddingTop="3dp"  android:paddingEnd="10dp"  android:paddingBottom="3dp"  android:textColor="@color/white"  android:textSize="@dimen/text_size_11"  android:visibility="gone"  app:right_drawable="@drawable/mk_arrow"  app:right_drawable_height="10dp"  app:right_drawable_width="10dp"  tools:text="@string/mk_rank_no" /> Copy the code

5. Notes for expanding TextView

SetBound () on onMeasure() : setCompoundDrawables(). SetCompoundDrawables () will end up calling Invalide () and requestLayout(), which can cause onMeasure() and onDraw() to loop back and forth indefinitely

The Bug that can’t be changed, the pretense that can’t be written. The public account Yang Zhengyou now focuses on mobile basic development, covering audio and video, APM, information security and other knowledge fields; Only do the whole network the most Geek public number, welcome your attention!