IT박스

Canvas에 그릴 텍스트 높이 측정 (Android)

itboxs 2020. 7. 24. 07:56
반응형

Canvas에 그릴 텍스트 높이 측정 (Android)


텍스트 높이를 측정하는 간단한 방법은 무엇입니까? 내가 지금하고있는 방법은 페인트를 사용 measureText()하여 너비를 얻은 다음 시행 착오를 통해 대략적인 높이를 얻는 것입니다. 나는 또한 엉망 FontMetrics이되었지만, 이것들은 모두 대략적인 방법처럼 보입니다.

다른 해상도로 조정하려고합니다. 나는 그것을 할 수 있지만, 상대적인 크기를 결정하기 위해 많은 계산으로 엄청나게 장황한 코드로 끝납니다. 난 싫어! 더 좋은 방법이 있어야합니다.


paint.getTextBounds () (객체 메소드) 어떻습니까 ?


필요한 것에 따라 높이를 측정하는 방법은 여러 가지가 있습니다.

getTextBounds

적은 양의 고정 텍스트를 정확하게 가운데에 맞추는 것과 같은 일을하는 경우 원할 것 getTextBounds입니다. 이처럼 경계 사각형을 얻을 수 있습니다

Rect bounds = new Rect();
mTextPaint.getTextBounds(mText, 0, mText.length(), bounds);
int height = bounds.height();

다음 이미지에서 볼 수 있듯이 문자열마다 다른 높이가 표시됩니다 (빨간색으로 표시).

여기에 이미지 설명을 입력하십시오

텍스트의 크기에 관계없이 일정한 높이가 필요한 경우에 따라 높이가 다른 것이 단점이 될 수 있습니다. 다음 섹션을 참조하십시오.

Paint.FontMetrics

글꼴 메트릭에서 글꼴의 높이를 계산할 수 있습니다. 높이는 특정 텍스트 문자열이 아닌 글꼴에서 가져 오기 때문에 항상 동일합니다.

Paint.FontMetrics fm = mTextPaint.getFontMetrics();
float height = fm.descent - fm.ascent;

기준선은 텍스트가있는 선입니다. 하강은 일반적으로 캐릭터가 선 아래로 가장 먼 곳이며 상승은 일반적으로 캐릭터가 선 위로 가장 먼 곳입니다. 높이를 얻으려면 음수 가기 때문에 상승을 빼야합니다. (기준선이다 y=0y스크린까지 descreases).

다음 이미지를보십시오. 두 문자열의 높이는입니다 234.375.

여기에 이미지 설명을 입력하십시오

텍스트 높이가 아닌 선 높이를 원하면 다음을 수행 할 수 있습니다.

float height = fm.bottom - fm.top + fm.leading; // 265.4297

이것 bottomtop라인입니다. 선행 (인라인 간격)은 일반적으로 0이지만 어쨌든 추가해야합니다.

위의 이미지는 이 프로젝트 에서 나온 것입니다 . 이것으로 놀아서 Font Metrics의 작동 방식을 볼 수 있습니다.

정적 레이아웃

For measuring the height of multi-line text you should use a StaticLayout. I talked about it in some detail in this answer, but the basic way to get this height is like this:

String text = "This is some text. This is some text. This is some text. This is some text. This is some text. This is some text.";

TextPaint myTextPaint = new TextPaint();
myTextPaint.setAntiAlias(true);
myTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
myTextPaint.setColor(0xFF000000);

int width = 200;
Layout.Alignment alignment = Layout.Alignment.ALIGN_NORMAL;
float spacingMultiplier = 1;
float spacingAddition = 0;
boolean includePadding = false;

StaticLayout myStaticLayout = new StaticLayout(text, myTextPaint, width, alignment, spacingMultiplier, spacingAddition, includePadding);

float height = myStaticLayout.getHeight(); 

@bramp's answer is correct - partially, in that it does not mention that the calculated boundaries will be the minimum rectangle that contains the text fully with implicit start coordinates of 0, 0.

This means, that the height of, for example "Py" will be different from the height of "py" or "hi" or "oi" or "aw" because pixel-wise they require different heights.

This by no means is an equivalent to FontMetrics in classic java.

While width of a text is not much of a pain, height is.

In particular, if you need to vertically center-align the drawn text, try getting the boundaries of the text "a" (without quotes), instead of using the text you intend to draw. Works for me...

Here's what I mean:

Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG);

paint.setStyle(Paint.Style.FILL);
paint.setColor(color);
paint.setTextAlign(Paint.Align.CENTER);
paint.setTextSize(textSize);

Rect bounds = new Rect();
paint.getTextBounds("a", 0, 1, bounds);

buffer.drawText(this.myText, canvasWidth >> 1, (canvasHeight + bounds.height()) >> 1, paint);
// remember x >> 1 is equivalent to x / 2, but works much much faster

Vertically center aligning the text means vertically center align the bounding rectangle - which is different for different texts (caps, long letters etc). But what we actually want to do is to also align the baselines of rendered texts, such that they did not appear elevated or grooved. So, as long as we know the center of the smallest letter ("a" for example) we then can reuse its alignment for the rest of the texts. This will center align all the texts as well as baseline-align them.


The height is the text size you have set on the Paint variable.

Another way to find out the height is

mPaint.getTextSize();

You could use the android.text.StaticLayout class to specify the bounds required and then call getHeight(). You can draw the text (contained in the layout) by calling its draw(Canvas) method.


You can simply get the text size for a Paint object using getTextSize() method. For example:

Paint mTextPaint = new Paint (Paint.ANTI_ALIAS_FLAG);
//use densityMultiplier to take into account different pixel densities
final float densityMultiplier = getContext().getResources()
            .getDisplayMetrics().density;  
mTextPaint.setTextSize(24.0f*densityMultiplier);

//...

float size = mTextPaint.getTextSize();

You must use Rect.width() and Rect.Height() which returned from getTextBounds() instead. That works for me.


If anyone still has problem, this is my code.

I have a custom view which is square (width = height) and I want to assign a character to it. onDraw() shows how to get height of character, although I'm not using it. Character will be displayed in the middle of view.

public class SideBarPointer extends View {

    private static final String TAG = "SideBarPointer";

    private Context context;
    private String label = "";
    private int width;
    private int height;

    public SideBarPointer(Context context) {
        super(context);
        this.context = context;
        init();
    }

    public SideBarPointer(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init();
    }

    public SideBarPointer(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.context = context;
        init();
    }

    private void init() {
//        setBackgroundColor(0x64FF0000);
    }

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

        height = this.getMeasuredHeight();
        width = this.getMeasuredWidth();

        setMeasuredDimension(width, width);
    }

    protected void onDraw(Canvas canvas) {
        float mDensity = context.getResources().getDisplayMetrics().density;
        float mScaledDensity = context.getResources().getDisplayMetrics().scaledDensity;

        Paint previewPaint = new Paint();
        previewPaint.setColor(0x0C2727);
        previewPaint.setAlpha(200);
        previewPaint.setAntiAlias(true);

        Paint previewTextPaint = new Paint();
        previewTextPaint.setColor(Color.WHITE);
        previewTextPaint.setAntiAlias(true);
        previewTextPaint.setTextSize(90 * mScaledDensity);
        previewTextPaint.setShadowLayer(5, 1, 2, Color.argb(255, 87, 87, 87));

        float previewTextWidth = previewTextPaint.measureText(label);
//        float previewTextHeight = previewTextPaint.descent() - previewTextPaint.ascent();
        RectF previewRect = new RectF(0, 0, width, width);

        canvas.drawRoundRect(previewRect, 5 * mDensity, 5 * mDensity, previewPaint);
        canvas.drawText(label, (width - previewTextWidth)/2, previewRect.top - previewTextPaint.ascent(), previewTextPaint);

        super.onDraw(canvas);
    }

    public void setLabel(String label) {
        this.label = label;
        Log.e(TAG, "Label: " + label);

        this.invalidate();
    }
}

참고URL : https://stackoverflow.com/questions/3654321/measuring-text-height-to-be-drawn-on-canvas-android

반응형