ক্যানভাসে আঁকতে পাঠ্যের উচ্চতা পরিমাপ করা (অ্যান্ড্রয়েড)


132

পাঠ্যের উচ্চতা পরিমাপ করার জন্য কোনও সোজা ফরোয়ার্ড উপায়? আমি এখন যেভাবে এটি করছি তা হল measureText()প্রস্থটি পেতে পেইন্টগুলি ব্যবহার করা , তারপরে ট্রায়াল এবং ত্রুটি করে একটি আনুমানিক উচ্চতা পাওয়ার জন্য কোনও মান খুঁজে পাওয়া। আমিও ঘুরে বেড়াচ্ছি FontMetrics, তবে এগুলি মনে হয় প্রায় অনুমান পদ্ধতি methods

আমি বিভিন্ন রেজোলিউশনের জন্য জিনিসগুলিকে স্কেল করার চেষ্টা করছি। আমি এটি করতে পারি, তবে আপেক্ষিক আকারগুলি নির্ধারণ করতে প্রচুর গণনা সহ আমি অবিশ্বাস্যভাবে ভার্বোজ কোড দিয়ে শেষ করি। আমি এটা ঘৃণা করি! এখানে অবশ্যই একটি ভাল রাস্তা আছে।

উত্তর:


136

পেইন্ট.জেটেক্সটবাউন্ডস () (অবজেক্ট পদ্ধতি) সম্পর্কে কী


1
যখন আমি কোনও পাঠ্যের উচ্চতাটি মূল্যায়ন করি তখন এটি খুব বিজোড় ফলাফল দেয়। একটি সংক্ষিপ্ত পাঠ্যের 12 টি উচ্চতায় ফলাফল হয়, যেখানে একটি দীর্ঘ দীর্ঘ পাঠ্যের ফলাফল 16 এর উচ্চতায় হয় (16 এর ফন্টের আকার দেওয়া হয়)। আমার কাছে কোনও ধারণা রাখে না (অ্যান্ড্রয়েড 2.3.3)
এজেন্টকনফফ

35
উচ্চতার প্রকরণটি যেখানে পাঠ্যটিতে আপনার বংশধর রয়েছে, অর্থাৎ রেখার নীচের
ছের

208

আপনার প্রয়োজনীয়তার উপর নির্ভর করে উচ্চতা পরিমাপ করার বিভিন্ন উপায় রয়েছে।

getTextBounds

আপনি যদি কিছু সংক্ষিপ্ত পরিমাণ স্থির পাঠ্য ঠিকঠাক করে কেন্দ্র করার মতো কিছু করে থাকেন তবে আপনি সম্ভবত এটি চান getTextBounds। আপনি এ জাতীয় সীমাবদ্ধ আয়তক্ষেত্র পেতে পারেন

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

যেমন আপনি নীচের চিত্রগুলি দেখতে পাচ্ছেন, বিভিন্ন স্ট্রিং বিভিন্ন উচ্চতা দেবে (লাল দেখায়))

এখানে চিত্র বর্ণনা লিখুন

এই ভিন্ন ভিন্ন উচ্চতা কিছু পরিস্থিতিতে অসুবিধা হতে পারে যখন আপনার কেবল পাঠ্য যাই হোক না কেন স্থির উচ্চতার প্রয়োজন 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
@ মিশেল জনসন, আমি অ্যাপটি এখানে গিটহাব প্রকল্প হিসাবে যুক্ত করেছি ।
সুরগাচ

1
"GetTextSize" আপনাকে কী দেয়, তবে?
অ্যান্ড্রয়েড বিকাশকারী

1
পেইন্টগুলি getTextSize()আপনাকে পিক্সেল ইউনিটে ফন্টের আকার দেয় (ইউনিটগুলির বিপরীতে sp)। @
অ্যান্ড্রয়েড

2
পরিমাপ করা উচ্চতা এবং ফন্টমেট্রিক্সের মাত্রার সাথে পিক্সেল ইউনিটে ফন্টের আকারের সম্পর্ক কী ? এটি এমন একটি প্রশ্ন যা আমি আরও অন্বেষণ করতে চাই।
সুরগ্যাচ

85

@ ব্র্যাম্পের উত্তরটি সঠিক - আংশিকভাবে, এতে উল্লেখ করা হয়নি যে গণনা করা সীমাগুলি সর্বনিম্ন আয়তক্ষেত্র হবে যা সম্পূর্ণরূপে 0, 0 এর সূচনা স্থানাঙ্ক সহ পাঠ্যকে অন্তর্ভুক্ত করে।

এর অর্থ, উদাহরণস্বরূপ, "পাই" এর উচ্চতা "পাই" বা "হাই" বা "ওআই" বা "অ্যাও" এর উচ্চতা থেকে আলাদা হবে কারণ পিক্সেল অনুযায়ী তাদের বিভিন্ন উচ্চতা প্রয়োজন।

এটি কোনওভাবেই ক্লাসিক জাভাতে ফন্টমেট্রিক্সের সমতুল্য নয়।

যদিও কোনও পাঠ্যের প্রস্থ ব্যথা বেশি নয়, উচ্চতা is

বিশেষত, যদি আপনাকে আঁকা পাঠ্যটি উল্লম্বভাবে কেন্দ্র-প্রান্তিককরণের প্রয়োজন হয় তবে আপনি আঁকতে চান এমন পাঠ্যটি ব্যবহার না করে "a" (উদ্ধৃতি ব্যতীত) পাঠ্যের সীমানা পাওয়ার চেষ্টা করুন। আমার জন্য কাজ কর...

আমি যা বলতে চাইছি তা এখানে:

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

উল্লম্বভাবে পাঠ্য সারিবদ্ধ করার অর্থ উল্লম্বভাবে কেন্দ্র বিন্যাসের আয়তক্ষেত্রটি বিন্যস্ত করা - যা বিভিন্ন পাঠ্যের (ক্যাপস, দীর্ঘ অক্ষর ইত্যাদি) জন্য আলাদা is তবে আমরা আসলে যা করতে চাই তা হল রেন্ডারগ্রন্থগুলির বেসলাইনগুলিও সারিবদ্ধ করা, যেমন সেগুলি উন্নত বা খাঁজকাটে দেখা যায় নি। সুতরাং, যতক্ষণ না আমরা ক্ষুদ্রতম বর্ণের কেন্দ্র জানি ("উদাহরণস্বরূপ" একটি ") আমরা তারপরে বাকী লেখাগুলির জন্য এর প্রান্তিককরণটি পুনরায় ব্যবহার করতে পারি। এটি সমস্ত পাঠ্যকে কেন্দ্ররেখার পাশাপাশি বেসলাইন-সারিবদ্ধ করবে।


25
x >> 1যুগে যুগে দেখা হয়নি । কেবলমাত্র এটির জন্যই উজ্জীবিত হচ্ছে :)
কেওক্রেন

62
একটি ভাল আধুনিক সংকলক এটি দেখতে x / 2এবং এটি অনুকূল করে তুলবেx >> 1
ইন্ট্রিপিডিস

37
x / 2ক্রিসের মন্তব্য বিবেচনা করে কোড পড়ার সময় @ কেওক্রেন অনেক বেশি বন্ধুত্বপূর্ণ।
d3dave

কি bufferএই উদাহরণে? এটা কি পদ্ধতিতে canvasপাস draw(Canvas)?
স্বায়ত্তশাসিত

@ অটোনমাস অ্যাপস হ্যাঁ, এটি ক্যানভাস
চিসকো

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: আপনি ক্লাসে ক্ষেত্রগুলি ঘোষণা করতে (কনস্ট্রাক্টরের সূচনা) এবং অন-ড্র () ব্যবহার করে পুনরায় ব্যবহার করতে পারলে এটি এক টন পারফরম্যান্স বেনিফিট পেতে পারে।
জুলটিশ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.