Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom android square textview text is not centered

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?

like image 876
Danjoa Avatar asked Dec 04 '22 23:12

Danjoa


1 Answers

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.

like image 116
Rahul Shukla Avatar answered Jan 29 '23 10:01

Rahul Shukla