Custom android square textview text is not centered

时间:2016-08-31 18:24:48

标签: android textview android-custom-view

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?

1 个答案:

答案 0 :(得分:12)

希望你现在已经得到了答案。如果没有,您可以使用:

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

你需要再次使用EXACT规范和计算出的大小调用super.onMeasure(),因为setMeasureDimension()似乎忽略了重力。