Jakiś prosty sposób na zmierzenie wysokości tekstu? Sposób, w jaki teraz to robię, polega na użyciu programu Paint, measureText()
aby uzyskać szerokość, a następnie metodą prób i błędów znajdując wartość, aby uzyskać przybliżoną wysokość. Ja też się bawiłem FontMetrics
, ale wszystkie te wydają się być przybliżonymi metodami, które są do niczego.
Próbuję skalować rzeczy dla różnych rozdzielczości. Mogę to zrobić, ale otrzymuję niesamowicie rozwlekły kod z wieloma obliczeniami w celu określenia względnych rozmiarów. Nienawidzę tego! Musi być lepszy sposób.
android
graphics
view
android-canvas
Danedo
źródło
źródło
Istnieją różne sposoby pomiaru wysokości w zależności od potrzeb.
getTextBounds
Jeśli robisz coś takiego jak precyzyjne wyśrodkowanie niewielkiej ilości stałego tekstu, prawdopodobnie chcesz
getTextBounds
. Możesz uzyskać prostokąt ograniczający w ten sposóbRect bounds = new Rect(); mTextPaint.getTextBounds(mText, 0, mText.length(), bounds); int height = bounds.height();
Jak widać na poniższych obrazkach, różne struny będą miały różne wysokości (pokazane na czerwono).
Te różne wysokości mogą być wadą w niektórych sytuacjach, gdy potrzebna jest po prostu stała wysokość bez względu na tekst. Zobacz następną sekcję.
Paint.FontMetrics
Możesz obliczyć wysokość czcionki na podstawie metryk czcionki. Wysokość jest zawsze taka sama, ponieważ jest pobierana z czcionki, a nie z konkretnego ciągu tekstowego.
Paint.FontMetrics fm = mTextPaint.getFontMetrics(); float height = fm.descent - fm.ascent;
Linia bazowa to linia, na której znajduje się tekst. Zejście jest na ogół najdalej, na jaką postać znajdzie się poniżej linii, a wzniesienie jest na ogół najdalej, na jaką postać znajdzie się nad linią. Aby uzyskać wysokość, musisz odjąć wzrost, ponieważ jest to wartość ujemna. (Linia bazowa jest
y=0
iy
zmniejsza się w górę ekranu).Spójrz na poniższy obraz. Wysokości obu strun to
234.375
.Jeśli chcesz mieć wysokość wiersza, a nie tylko wysokość tekstu, możesz wykonać następujące czynności:
float height = fm.bottom - fm.top + fm.leading; // 265.4297
To są
bottom
itop
linii. Początek (odstępy między wierszami) są zwykle równe zero, ale mimo to należy je dodać.Powyższe obrazy pochodzą z tego projektu . Możesz się nim bawić, aby zobaczyć, jak działają wskaźniki czcionki.
StaticLayout
Aby zmierzyć wysokość tekstu wielowierszowego, należy użyć rozszerzenia
StaticLayout
. Mówiłem o tym szczegółowo w tej odpowiedzi , ale podstawowy sposób uzyskania tej wysokości jest taki: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();
źródło
getTextSize()
podaje rozmiar czcionki w pikselach (w przeciwieństwie dosp
jednostek). @androiddeveloperOdpowiedź @brampa jest poprawna - częściowo, ponieważ nie wspomina, że obliczone granice będą minimalnym prostokątem zawierającym cały tekst z niejawnymi współrzędnymi początkowymi równymi 0, 0.
Oznacza to, że wysokość na przykład „Py” będzie inna niż wysokość „py” lub „hi”, „oi” lub „aw”, ponieważ pod względem pikseli wymagają one różnych wysokości.
W żadnym wypadku nie jest to odpowiednik FontMetrics w klasycznej Javie.
Chociaż szerokość tekstu nie jest wielkim problemem, wysokość tak.
W szczególności, jeśli chcesz wyśrodkować narysowany tekst w pionie, spróbuj uzyskać granice tekstu „a” (bez cudzysłowów), zamiast używać tekstu, który zamierzasz narysować. Pracuje dla mnie...
Oto o co mi chodzi:
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
Wyśrodkowanie tekstu w pionie oznacza wyśrodkowanie tekstu w pionie - wyrównanie prostokąta ograniczającego - co jest różne dla różnych tekstów (wielkie litery, długie litery itp.). Ale w rzeczywistości chcemy również wyrównać linie bazowe renderowanych tekstów, tak aby nie wyglądały na podniesione lub wyżłobione. Tak więc, jeśli znamy środek najmniejszej litery (na przykład „a”), możemy ponownie wykorzystać jego wyrównanie w pozostałych tekstach. Spowoduje to wyśrodkowanie wszystkich tekstów, a także wyrównanie ich do linii bazowej.
źródło
x >> 1
od wieków. Głosowanie tylko za tym :)x / 2
i zoptymalizuje go dox >> 1
x / 2
jest dużo bardziej przyjazny podczas czytania kodu, biorąc pod uwagę komentarz Chrisa.buffer
w tym przykładzie? Czy jest tocanvas
przekazane dodraw(Canvas)
metody?Wysokość to rozmiar tekstu ustawiony w zmiennej Paint.
Innym sposobem sprawdzenia wysokości jest
mPaint.getTextSize();
źródło
Możesz użyć
android.text.StaticLayout
klasy, aby określić wymagane granice, a następnie wywołaćgetHeight()
. Możesz narysować tekst (zawarty w układzie), wywołując jegodraw(Canvas)
metodę.źródło
Możesz po prostu pobrać rozmiar tekstu dla obiektu Paint za pomocą metody getTextSize (). Na przykład:
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();
źródło
24.0f
bierze?Musisz użyć
Rect.width()
iRect.Height()
który wrócił zgetTextBounds()
zamiast. To działa dla mnie.źródło
Jeśli ktoś nadal ma problem, to jest mój kod.
Mam niestandardowy widok, który jest kwadratowy (szerokość = wysokość) i chcę przypisać do niego znak.
onDraw()
pokazuje, jak uzyskać wysokość znaku, chociaż go nie używam. Postać zostanie wyświetlona na środku widoku.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(); } }
źródło