4

I am trying to create a textview that will always be squared so I have implemented this custom class.

public class SquareTextView extends TextView {

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

    public SquareTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public SquareTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int max = Math.max(getMeasuredWidth(), getMeasuredHeight());
        setMeasuredDimension(max, max);
    }

}

Here is an example layout that illustrates the problem:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="8dp"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:paddingTop="8dp">


    <com.mypackage.SquareTextView
        android:layout_width="wrap_content"
        android:layout_height="50dp"
        android:layout_gravity="right|top"
        android:background="#000"
        android:gravity="center"
        android:padding="4dp"
        android:text="1"
        android:textColor="#FFF"/>

</LinearLayout>

Here is an image of this

enter image description here

This works great in getting the view squared, however, it seems like the gravity gets messed up. With this, the text seems to always be in the top left corner. How can I have a TextView that will always be squared but still keep the gravity or at least be able to center the text?

EDIT: After some testing I have noticed that if you set the width or height to a specific dp size the gravity seems to be working again. So it probably has to do with the WRAP_CONTENT attribute. Will that be handled in another way in the onmeasure method that could cause my own method to not work as expected?

Danjoa
  • 143
  • 4
  • 14
  • have you tried adding to xml: `android:gravity="center"` or you could modify the gravity via java code too in order to do this by default for the custom view – Lucas Crawford Aug 31 '16 at 18:32
  • @LucasCrawford Yes, I have updated my question with the layout XML and as you can see I have set the gravity. – Danjoa Aug 31 '16 at 19:59

1 Answers1

16

Hope you have already got the answer by now. If not, you can use this:

public class TextAlphaSquareTextView extends AppCompatTextView {
    private int mTextAlpha = 0;
    private boolean isSquare = false;

    public TextAlphaSquareTextView(Context context) {
        super(context);
        init(null);
    }

    public TextAlphaSquareTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs);
    }

    public TextAlphaSquareTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(attrs);
    }

    private void init(AttributeSet attrs) {
        if (attrs == null) {

        } else {
            TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.TextAlphaSquareTextView);
            mTextAlpha = a.getInteger(R.styleable.TextAlphaSquareTextView_textAlpha, 100);
            isSquare = a.getBoolean(R.styleable.TextAlphaSquareTextView_squareMode, false);
            a.recycle();

            if(mTextAlpha < 0 || mTextAlpha > 100)
                throw new IllegalArgumentException("Alpha range should be b/w 0 to 100 (in percentage)");
            else {
                setAlphaOnTextColor();
            }
        }
        setText(getText());
    }


    void setAlphaOnTextColor() {
        int alpha = ((255 * mTextAlpha) / 100);
        setTextColor(getTextColors().withAlpha(alpha));
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (isSquare) {
            int width = this.getMeasuredWidth();
            int height = this.getMeasuredHeight();
            int size = Math.max(width, height);
            int widthSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
            int heightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
            super.onMeasure(widthSpec, heightSpec);
        }
    }
}

you need to call super.onMeasure() again with EXACT spec and the calculated size, since setMeasureDimension() seems to be ignoring the gravity.

Rahul Shukla
  • 1,292
  • 9
  • 25