कैनवस (Android) पर खींची जाने वाली पाठ ऊंचाई मापना


132

पाठ की ऊंचाई को मापने का कोई सीधा आगे का तरीका? अब मैं जिस तरह से कर रहा हूं वह पेंट का उपयोग measureText()चौड़ाई प्राप्त करने के लिए है, फिर परीक्षण और त्रुटि से अनुमानित ऊंचाई प्राप्त करने के लिए एक मूल्य मिल रहा है। मैं भी के साथ खिलवाड़ कर रहा हूँ FontMetrics, लेकिन इन सभी तरीकों से लगता है कि चूसना।

मैं विभिन्न प्रस्तावों के लिए चीजों को स्केल करने की कोशिश कर रहा हूं। मैं इसे कर सकता हूं, लेकिन मैं सापेक्ष आकार निर्धारित करने के लिए बहुत सारी गणनाओं के साथ अविश्वसनीय रूप से क्रिया कोड के साथ समाप्त करता हूं। मुझे इससे घृणा है! कोई बेहतर तरीका ज़रूर होगा।

जवाबों:


136

Paint.getTextBounds () (ऑब्जेक्ट विधि) के बारे में क्या


1
यह बहुत ही अजीब परिणाम देता है, जब मैं किसी पाठ की ऊंचाई का मूल्यांकन करता हूं। एक छोटे पाठ का परिणाम 12 की ऊंचाई पर होता है, जबकि वास्तव में लंबे पाठ का परिणाम 16 की ऊंचाई (16 का फ़ॉन्ट आकार दिया जाता है) होता है। मुझे कोई मतलब नहीं है (Android 2.3.3)
AgentKnopf

35
ऊँचाई में भिन्नता वह जगह है जहाँ आपके पास पाठ में
अवरोही हैं

208

आपकी आवश्यकता के आधार पर ऊंचाई को मापने के विभिन्न तरीके हैं।

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=0और yस्क्रीन के नीचे उतरता है।)

निम्नलिखित छवि को देखें। दोनों स्ट्रिंग्स के लिए ऊंचाइयां हैं 234.375

यहाँ छवि विवरण दर्ज करें

यदि आप केवल पाठ ऊँचाई के बजाय लाइन की ऊँचाई चाहते हैं, तो आप निम्न कार्य कर सकते हैं:

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

ये bottomऔर topरेखा के हैं। अग्रणी (इंटरलाइन स्पेसिंग) आमतौर पर शून्य है, लेकिन आपको इसे वैसे भी जोड़ना चाहिए।

उपरोक्त चित्र इस परियोजना से आए हैं । फ़ॉन्ट मेट्रिक्स कैसे काम करता है, यह देखने के लिए आप इसके साथ खेल सकते हैं।

StaticLayout

बहु-पंक्ति पाठ की ऊंचाई को मापने के लिए आपको एक का उपयोग करना चाहिए StaticLayout। मैंने इस उत्तर में इसके बारे में कुछ विस्तार से बात की , लेकिन इस ऊंचाई को पाने का मूल तरीका इस प्रकार है:

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

अच्छी व्याख्या। स्क्रीनशॉट किस ऐप से हैं?
माइकल जॉनसन

1
@MichealJohnson, मैंने ऐप को यहां GitHub प्रोजेक्ट के रूप में जोड़ा ।
सुरगाच

1
"GetTextSize" आपको क्या देता है, फिर?
Android डेवलपर

1
पेंट getTextSize()आपको पिक्सेल इकाइयों में फ़ॉन्ट आकार देता है (इकाइयों के विपरीत sp)। @androiddeveloper
Suragch

2
पिक्सेल इकाइयों में फॉन्ट साइज का संबंध मापा ऊंचाई और FontMetrics आयामों से क्या है? यह एक ऐसा सवाल है जिसे मैं और अधिक जानना चाहूंगा।
Suragch

85

@ ब्रैंप का उत्तर सही है - आंशिक रूप से, इसमें यह उल्लेख नहीं किया गया है कि गणना की गई सीमाएं न्यूनतम आयत होगी जिसमें पाठ 0, 0 के निहित प्रारंभ निर्देशांक के साथ पूरी तरह से पाठ होता है।

इसका मतलब यह है कि, उदाहरण के लिए, "Py", "py" या "hi" या "oi" या "aw" की ऊंचाई से भिन्न होगा क्योंकि पिक्सेल-वार उन्हें अलग-अलग ऊंचाइयों की आवश्यकता होती है।

यह किसी भी तरह से क्लासिक जावा में FontMetrics के बराबर है।

जबकि एक पाठ की चौड़ाई एक दर्द की ज्यादा नहीं है, ऊंचाई है।

विशेष रूप से, यदि आपको खींचे गए पाठ को लंबवत-संरेखित करने की आवश्यकता है, तो पाठ का उपयोग करने के लिए "उद्धरण" (बिना उद्धरण) की सीमाओं को प्राप्त करने का प्रयास करें, बजाय इसके कि आप आकर्षित करना चाहते हैं। मेरे लिये कार्य करता है...

यहाँ मेरा मतलब है:

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

मुख्य रूप से पाठ को संरेखित करने का अर्थ है लंबवत केंद्र को बाउंडिंग आयत संरेखित करें - जो अलग-अलग ग्रंथों (कैप्स, लंबे अक्षर आदि) के लिए अलग है। लेकिन जो हम वास्तव में करना चाहते हैं, वह प्रदान किए गए ग्रंथों की आधार रेखाओं को भी संरेखित करना है, जैसे कि वे ऊंचे या नीचे दिखाई नहीं दिए। इसलिए, जब तक हम सबसे छोटे अक्षर (उदाहरण के लिए "a") के केंद्र को जानते हैं, तब तक हम बाकी ग्रंथों के लिए इसके संरेखण का पुन: उपयोग कर सकते हैं। यह सभी ग्रंथों के साथ-साथ आधारभूत-संरेखित करेगा।


25
x >> 1उम्र के लिए नहीं देखा गया है। केवल उसके लिए अपवित्र करना :)
keaukraine

62
एक अच्छा आधुनिक संकलक इसे देखेगा x / 2और इसका अनुकूलन करेगाx >> 1
intrepidis

37
x / 2क्रिस की टिप्पणी को देखते हुए कोड पढ़ते समय @keaukraine बहुत अधिक अनुकूल है।
d3dave 20

bufferइस उदाहरण में क्या है ? क्या यह विधि canvasको पारित किया गया draw(Canvas)है?
ऑटोनोमस

@AutonomousApps हाँ, यह कैनवास है
चिस्को जू

16

ऊँचाई वह पाठ आकार है जिसे आपने पेंट चर पर सेट किया है।

ऊंचाई का पता लगाने का एक और तरीका है

mPaint.getTextSize();

3

आप android.text.StaticLayoutआवश्यक सीमा निर्दिष्ट करने और फिर कॉल करने के लिए कक्षा का उपयोग कर सकते हैं getHeight()। आप इसकी draw(Canvas)विधि को कॉल करके टेक्स्ट (लेआउट में निहित) आकर्षित कर सकते हैं ।


2

आप बस GetTextSize () पद्धति का उपयोग करके किसी पेंट ऑब्जेक्ट के लिए पाठ आकार प्राप्त कर सकते हैं। उदाहरण के लिए:

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

कहां से 24.0fआता है?
एरिगामी

24.0f यह सिर्फ टेक्स्ट साइज़ के लिए एक उदाहरण है
moondroid

1

आपको इसका उपयोग करना चाहिए Rect.width()और Rect.Height()जो getTextBounds()इसके बजाय वापस आ गया है । ये मेरे लिए सही है।


2
नहीं यदि आप ग्रंथों के कई खंडों के साथ काम कर रहे हैं। कारण ऊपर मेरे उत्तर में है।
नर गर

0

अगर किसी को अभी भी समस्या है, तो यह मेरा कोड है।

मेरे पास एक कस्टम दृश्य है जो चौकोर (चौड़ाई = ऊंचाई) है और मैं इसे एक चरित्र निर्दिष्ट करना चाहता हूं। onDraw()दिखाता है कि चरित्र की ऊंचाई कैसे प्राप्त की जाए, हालांकि मैं इसका उपयोग नहीं कर रहा हूं। चरित्र को दृश्य के बीच में प्रदर्शित किया जाएगा।

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

3
-1 onDraw () में आबंटन के लिए: यह प्रदर्शन लाभ का एक टन प्राप्त करेगा यदि आप कक्षा में खेतों को घोषित करें (निर्माणकर्ता में आरंभ करें) और onDraw () में फिर से उपयोग करें।
झोलाछाप
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.