कैनवास पर Android केंद्र पाठ


191

मैं नीचे दिए गए कोड का उपयोग करके एक पाठ प्रदर्शित करने का प्रयास कर रहा हूं। समस्या यह है कि पाठ क्षैतिज रूप से केंद्रित नहीं है। जब मैं इसके लिए निर्देशांक सेट करता हूं drawText, तो यह इस स्थिति में पाठ के निचले भाग को सेट करता है। मैं चाहूंगा कि पाठ को खींचा जाए ताकि पाठ भी क्षैतिज रूप से केंद्रित हो।

यह मेरी समस्या को आगे प्रदर्शित करने के लिए एक तस्वीर है:

स्क्रीनशॉट

@Override
protected void onDraw(Canvas canvas) {
    // TODO Auto-generated method stub
    super.onDraw(canvas);
    //canvas.drawRGB(2, 2, 200);
    Paint textPaint = new Paint();
    textPaint.setARGB(200, 254, 0, 0);
    textPaint.setTextAlign(Align.CENTER);
    textPaint.setTypeface(font);
    textPaint.setTextSize(300);
    canvas.drawText("Hello", canvas.getWidth()/2, canvas.getHeight()/2  , textPaint);
}

20
मैं आपके onDraw इवेंट के अंदर आपके पेंट ऑब्जेक्ट को घोषित नहीं करूंगा। इसे फिर से तैयार किए जाने पर इसे फिर से बनाया जाता है। इसे एक निजी वर्ग चर बनाने पर विचार करें।
क्रिस्टोफर रथजेब

8
दोस्त! कृपया उल्लेख करें कि आपकी छवि लिंक NSFW है! मेरा मतलब समझदारी भरा नहीं है, लेकिन मुझे कार्यालय में मेरी स्क्रीन पर दिखने वाली टॉपलेस महिलाओं के विज्ञापनों की आवश्यकता नहीं है।
माइकल शेपर

5
@MichaelScheper क्षमा करें, मैंने लिंक अपडेट कर दिया है!
सेबेस्टियन

23
@Sebastian अरे आपको अभी भी वो लिंक मिला है?
एस.लुकस

@ एस.लुकस हाहाहा
BOTJr।

जवाबों:


376

निम्नलिखित प्रयास करें:

 int xPos = (canvas.getWidth() / 2);
 int yPos = (int) ((canvas.getHeight() / 2) - ((textPaint.descent() + textPaint.ascent()) / 2)) ; 
 //((textPaint.descent() + textPaint.ascent()) / 2) is the distance from the baseline to the center.

 canvas.drawText("Hello", xPos, yPos, textPaint);

10
बहुत बढ़िया जवाब। मेरे लिए मैंने निम्न का उपयोग किया क्योंकि मुझे पाठ को केंद्र स्थिति में शुरू करने के बजाय क्षैतिज रूप से पूरी तरह से केंद्र में रखने की आवश्यकता थी: int xPos = (चौड़ाई - textPaint.TextSize * Math.Abs ​​(_text.Length / 2) / 2); यकीन नहीं होता कि इसे पूरा करने का कोई बेहतर तरीका है।
पज

और शायद सबसे अच्छा कास्टिंग _text.Length एक फ्लोट के रूप में यह स्पष्ट रूप से अजीब पाठ लंबाई के लिए काम नहीं करेगा।
पज।।।

61
यदि आप textPaint.setTextAlign (Align.CENTER) सेट करते हैं, तो यह आवश्यक नहीं है;
कोस्टी मुरारू

@ paj7777 यह केवल किसी भी तरह निश्चित-चौड़ाई वाले फोंट के लिए काम करेगा। इसके अलावा, आपको एक फ्लोट पर कास्ट करने की आवश्यकता नहीं है ; यदि आप एक फ्लोट से विभाजित करते हैं, तो परिणाम एक फ्लोट होगा। उदा । float halfLength = text.length() / 2f;इसे टाइप प्रमोशन कहा जाता है ।
माइकल स्काइपर

2
मैंने नीचे दिए गए मेरे उत्तर के साथ इस दृष्टिकोण (= केंद्र के साथ ) Paint.descent()और Paint.ascent()केंद्र पाठ के दृष्टिकोण के साथ तुलना Paint.getTextBounds()की। Paint.descent()और Paint.ascent()वास्तविक पाठ को ध्यान में न रखें। (आप नीचे दिए गए मेरे पोस्ट में स्क्रीनशॉट में इस अशुद्धि को पहचान सकते हैं।) यही कारण है कि मैं इस दृष्टिकोण के खिलाफ सिफारिश करूंगा। के साथ दृष्टिकोण Paint.getTextBounds()अधिक सटीक काम करने लगता है।
andreas1724

216

Paint.getTextBounds के साथ केंद्र () :

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

private Rect r = new Rect();

private void drawCenter(Canvas canvas, Paint paint, String text) {
    canvas.getClipBounds(r);
    int cHeight = r.height();
    int cWidth = r.width();
    paint.setTextAlign(Paint.Align.LEFT);
    paint.getTextBounds(text, 0, text.length(), r);
    float x = cWidth / 2f - r.width() / 2f - r.left;
    float y = cHeight / 2f + r.height() / 2f - r.bottom;
    canvas.drawText(text, x, y, paint);
}
  • Paint.Align.CENTER का मतलब यह नहीं है कि पाठ का संदर्भ बिंदु लंबवत केंद्रित है। संदर्भ बिंदु हमेशा आधार रेखा पर होता है। तो, Paint.Align.LEFT का उपयोग क्यों नहीं किया जाता है ? आपको वैसे भी संदर्भ बिंदु की गणना करनी होगी।

  • Paint.descent () का नुकसान है, कि यह वास्तविक पाठ पर विचार नहीं करता है। Paint.descent () उसी मान को पुनर्प्राप्त करता है, भले ही पाठ में अवरोही के साथ अक्षर हों या नहीं। इसलिए मैं इसके बजाय r.bottom का उपयोग करता हूं

  • मैं कुछ पड़ा है समस्याओं के साथ Canvas.getHeight () करता है, तो एपीआई <16. के कारण है कि मैं का उपयोग करें कि Canvas.getClipBounds (रेक्ट) के बजाय। ( Canvas.getClipBounds ()। GetHeight () का उपयोग न करें क्योंकि यह एक रेक्ट के लिए मेमोरी आवंटित करता है ।)

  • प्रदर्शन के कारणों के लिए, आपको ऑनड्रा () में उपयोग किए जाने से पहले ऑब्जेक्ट आवंटित करना चाहिए । के रूप में drawCenter () के भीतर बुलाया जाएगा OnDraw () वस्तु रेक्ट आर यहाँ एक क्षेत्र के रूप में पूर्व आबंटित किया गया है।


मैंने दो शीर्ष उत्तरों के कोड को अपने स्वयं के कोड (अगस्त 2015) में डालने की कोशिश की और परिणामों की तुलना करने के लिए एक स्क्रीनशॉट बनाया:

पाठ तीन संस्करणों पर केंद्रित है

पाठ को लाल भरे हुए आयत के भीतर केंद्रित किया जाना चाहिए। मेरा कोड सफेद पाठ का उत्पादन करता है, अन्य दो कोड पूरी तरह से ग्रे पाठ का उत्पादन करते हैं (वे वास्तव में समान हैं, अतिव्यापी)। ग्रे पाठ थोड़ा कम है और दाईं ओर दो बहुत है।

इस तरह मैंने परीक्षण किया:

import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

class MyView extends View {

    private static String LABEL = "long";
    private static float TEXT_HEIGHT_RATIO = 0.82f;

    private FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(0, 0);
    private Rect r = new Rect();
    private Paint paint = new Paint();
    private Paint rectPaint = new Paint();

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

    private void drawTextBounds(Canvas canvas, Rect rect, int x, int y) {
        rectPaint.setColor(Color.rgb(0, 0, 0));
        rectPaint.setStyle(Paint.Style.STROKE);
        rectPaint.setStrokeWidth(3f);
        rect.offset(x, y);
        canvas.drawRect(rect, rectPaint);
    }

    // andreas1724 (white color):
    private void draw1(Canvas canvas, Paint paint, String text) {
        paint.setTextAlign(Paint.Align.LEFT);
        paint.setColor(Color.rgb(255, 255, 255));
        canvas.getClipBounds(r);
        int cHeight = r.height();
        int cWidth = r.width();
        paint.getTextBounds(text, 0, text.length(), r);
        float x = cWidth / 2f - r.width() / 2f - r.left;
        float y = cHeight / 2f + r.height() / 2f - r.bottom;
        canvas.drawText(text, x, y, paint);
        drawTextBounds(canvas, r, (int) x, (int) y);
    }

    // Arun George (light green color):
    private void draw2(Canvas canvas, Paint textPaint, String text) {
        textPaint.setTextAlign(Paint.Align.CENTER);
        textPaint.setColor(Color.argb(100, 0, 255, 0));
        int xPos = (canvas.getWidth() / 2);
        int yPos = (int) ((canvas.getHeight() / 2) - ((textPaint.descent() + textPaint.ascent()) / 2));
        canvas.drawText(text, xPos, yPos, textPaint);
    }

    // VinceStyling (light blue color):
    private void draw3(Canvas yourCanvas, Paint mPaint, String pageTitle) {
        mPaint.setTextAlign(Paint.Align.LEFT);
        mPaint.setColor(Color.argb(100, 0, 0, 255));
        r = yourCanvas.getClipBounds();
        RectF bounds = new RectF(r);
        bounds.right = mPaint.measureText(pageTitle, 0, pageTitle.length());
        bounds.bottom = mPaint.descent() - mPaint.ascent();
        bounds.left += (r.width() - bounds.right) / 2.0f;
        bounds.top += (r.height() - bounds.bottom) / 2.0f;
        yourCanvas.drawText(pageTitle, bounds.left, bounds.top - mPaint.ascent(), mPaint);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        int margin = 10;
        int width = w - 2 * margin;
        int height = h - 2 * margin;
        params.width = width;
        params.height = height;
        params.leftMargin = margin;
        params.topMargin = margin;
        setLayoutParams(params);
        paint.setTextSize(height * TEXT_HEIGHT_RATIO);
        paint.setAntiAlias(true);
        paint.setTypeface(Typeface.create(Typeface.SERIF, Typeface.BOLD_ITALIC));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.rgb(255, 0, 0));
        draw1(canvas, paint, LABEL);
        draw2(canvas, paint, LABEL);
        draw3(canvas, paint, LABEL);
    }
}

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        FrameLayout container = new FrameLayout(this);
        container.setLayoutParams(new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT));
        container.addView(new MyView(this));
        setContentView(container);
    }
}

1
बहुत-बहुत धन्यवाद .. आपके तर्क ने वास्तव में मेरी बहुत मदद की।
सुजय यूएन

आपका बहुत-बहुत धन्यवाद .. आपके तर्क ने वास्तव में मेरी बहुत मदद की!
लियूवेनबिन_NO।

यह एकमात्र उत्तर है जो वास्तव में पाठ को केंद्र में रखता है।
जॉरी

63

पाठ को वंशानुक्रम में संरेखित करना मुश्किल है क्योंकि पाठ वंश और चढ़ाई हुई, बहुत से लोगों ने TextWidth और TextHeight को पुनः प्राप्त करने के लिए Paint.getTextBounds () का उपयोग किया , लेकिन यह पाठ केंद्र को बहुत अधिक नहीं बनाता है। यहां हम TextWidth की गणना करने के लिए Paint.measureText () का उपयोग कर सकते हैं , TextHeight हम बस वंश और चढ़ाई के साथ घटाना करते हैं, तो हमें सबसे अधिक दृष्टिकोण मिला TextSize, निम्नलिखित काम एक दूसरे के लिए काफी आसान है।

// the Paint instance(should be assign as a field of class).
Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setTextSize(getResources().getDimension(R.dimen.btn_textsize));

// the display area.
Rect areaRect = new Rect(0, 0, 240, 60);

// draw the background style (pure color or image)
mPaint.setColor(Color.BLACK);
yourCanvas.drawRect(areaRect, mPaint);

String pageTitle = "文字小说";

RectF bounds = new RectF(areaRect);
// measure text width
bounds.right = mPaint.measureText(pageTitle, 0, pageTitle.length());
// measure text height
bounds.bottom = mPaint.descent() - mPaint.ascent();

bounds.left += (areaRect.width() - bounds.right) / 2.0f;
bounds.top += (areaRect.height() - bounds.bottom) / 2.0f;

mPaint.setColor(Color.WHITE);
yourCanvas.drawText(pageTitle, bounds.left, bounds.top - mPaint.ascent(), mPaint);

कोड द्वारा स्क्रीन शॉट

वैसे, हम अत्यधिक Rect के बजाय RectF का उपयोग करने की सलाह देते हैं क्योंकि पदों को अधिक सटीक मानों की आवश्यकता होती है, मेरे अनुभव में, RectF ने xhdpi डिवाइस पर सिर्फ एक पिक्सेल का शीर्ष और निचला विचलन किया, Rect दो और होगा।


जैसा लिखा गया है, वैर "पेंट" भ्रामक है। इसे कैसे सौंपा गया है? यह कैसे सीमा और पाठ की सीमा को जानता है।
राउंडस्पारो हिल्टैक्स

1
हां, मैंने इसके लिए अपने उत्तर को अनुकूलित कर लिया है, कृपया देख लें।
विंसट्लिंग

मेरे कीमती समय को बचाने के लिए धन्यवाद)
एंड्री

16

आपका कोड दृश्य के केंद्र में पाठ की आधार रेखा का केंद्र खींच रहा है। किसी बिंदु, x, y पर पाठ को केंद्र में रखने के लिए, आपको पाठ के केंद्र की गणना करने की आवश्यकता है, और उस बिंदु पर रखें।

यह विधि बिंदु x, y पर केंद्रित पाठ को आकर्षित करेगी। यदि आप इसे अपने दृश्य का केंद्र मानते हैं, तो यह केंद्रित पाठ को आकर्षित करेगा।

private void drawTextCentered(String text, int x, int y, Paint paint, Canvas canvas) {
    int xPos = x - (int)(paint.measureText(text)/2);
    int yPos = (int) (y - ((textPaint.descent() + textPaint.ascent()) / 2)) ;

    canvas.drawText(text, xPos, yPos, textPaint);
}

@MarcioGranzotto इसका android.graphics.Paintउपयोग पाठ आकर्षित करने के लिए किया जा रहा है
विलियम रीड

4

मुझे लगता है कि पाठ को केंद्रित करने के लिए सबसे अच्छा समाधान निम्नानुसार है:

textPaint.setTextAlign(Paint.Align.CENTER);
//textPaint is the Paint object being used to draw the text (it must be initialized beforehand)
float textY=center.y;
float textX=center.x; 
// in this case, center.x and center.y represent the coordinates of the center of the rectangle in which the text is being placed
canvas.drawText(text,textX,textY,textPaint);    `

यह बिल्कुल वैसे ही दिखता है, जैसे प्रश्नकर्ता ने पाठ को केंद्र में रखने की कोशिश की थी। पाठ लंबवत केंद्रित नहीं होगा क्योंकि Paint.Align.Center का अर्थ यह नहीं है, कि पाठ का संदर्भ बिंदु लंबवत केंद्रित है।
andreas1724

3

मेरे लिए उपयोग करने के लिए काम करता है: textPaint.textAlign = Paint.Align.CENTER with textPaint.getTextBounds

private fun drawNumber(i: Int, canvas: Canvas, translate: Float) {
            val text = "$i"
            textPaint.textAlign = Paint.Align.CENTER
            textPaint.getTextBounds(text, 0, text.length, textBound)

            canvas.drawText(
                    "$i",
                    translate + circleRadius,
                    (height / 2 + textBound.height() / 2).toFloat(),
                    textPaint
            )
        }

परिणाम है:

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


1

मैं इसे सरल बनाने के लिए एक विधि बनाता हूं:

    public static void drawCenterText(String text, RectF rectF, Canvas canvas, Paint paint) {
    Paint.Align align = paint.getTextAlign();
    float x;
    float y;
    //x
    if (align == Paint.Align.LEFT) {
        x = rectF.centerX() - paint.measureText(text) / 2;
    } else if (align == Paint.Align.CENTER) {
        x = rectF.centerX();
    } else {
        x = rectF.centerX() + paint.measureText(text) / 2;
    }
    //y
    metrics = paint.getFontMetrics();
    float acent = Math.abs(metrics.ascent);
    float descent = Math.abs(metrics.descent);
    y = rectF.centerY() + (acent - descent) / 2f;
    canvas.drawText(text, x, y, paint);

    Log.e("ghui", "top:" + metrics.top + ",ascent:" + metrics.ascent
            + ",dscent:" + metrics.descent + ",leading:" + metrics.leading + ",bottom" + metrics.bottom);
}

rectF वह क्षेत्र है जिसे आप पाठ आकर्षित करना चाहते हैं, बस। विवरण


1

यदि हम स्टेटिक लेआउट का उपयोग कर रहे हैं

mStaticLayout = new StaticLayout(mText, mTextPaint, mTextWidth,
                Layout.Alignment.ALIGN_CENTER, 1.0f, 0, true);

लेआउट .lignment.ALIGN_CENTER यह चाल करेगा। स्टेटिक लेआउट को कई अन्य फायदे भी मिले हैं।

संदर्भ: Android प्रलेखन


1

यह मेरे लिए काम किया:

 paint.setTextAlign(Paint.Align.CENTER);
        int xPos = (newWidth / 2);
        int yPos = (newHeight / 2);
        canvas.drawText("Hello", xPos, yPos, paint);

अगर किसी को कोई समस्या मिलती है तो कृपया केट को जानें


यह केंद्र बिंदु से पाठ लिखना शुरू कर देगा, लेकिन पूरा पाठ केंद्र में नहीं होगा
एम शाबान अली

0

मेरे मामले में, मुझे टेक्स्ट को एक कैनवास के बीच में नहीं डालना था, लेकिन एक पहिया में जो घूमता है। हालाँकि मुझे सफल होने के लिए इस कोड का उपयोग करना था:

fun getTextRect(textSize: Float, textPaint: TextPaint, string: String) : PointF {
    val rect = RectF(left, top, right, bottom)
    val rectHeight = Rect()
    val cx = rect.centerX()
    val cy = rect.centerY()

    textPaint.getTextBounds(string, 0, string.length, rectHeight)
    val y = cy + rectHeight.height()/2
    val x = cx - textPaint.measureText(string)/2

    return PointF(x, y)
}

तब मैं इस विधि को व्यू क्लास से कहता हूं:

private fun drawText(canvas: Canvas, paint: TextPaint, text: String, string: String) {
    val pointF = getTextRect(paint.textSize, textPaint, string)
    canvas.drawText(text, pointF!!.x, pointF.y, paint)
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.