Vertikales (gedrehtes) Etikett in Android

110

Ich benötige zwei Möglichkeiten, um vertikale Beschriftungen in Android anzuzeigen:

  1. Horizontales Etikett um 90 Grad gegen den Uhrzeigersinn gedreht (Buchstaben an der Seite)
  2. Horizontales Etikett mit Buchstaben untereinander (wie ein Ladenschild)

Muss ich für beide Fälle benutzerdefinierte Widgets entwickeln (ein Fall), kann ich TextView so rendern lassen, und was wäre ein guter Weg, um so etwas zu tun, wenn ich vollständig benutzerdefiniert werden muss?

Bostone
quelle
Dies ist in XML ab API 11 (Android 3.0) möglich. stackoverflow.com/questions/3774770/…
Chobok

Antworten:

239

Hier ist meine elegante und einfache vertikale Textimplementierung, die TextView erweitert. Dies bedeutet, dass alle Standardstile von TextView verwendet werden können, da es sich um erweitertes TextView handelt.

public class VerticalTextView extends TextView{
   final boolean topDown;

   public VerticalTextView(Context context, AttributeSet attrs){
      super(context, attrs);
      final int gravity = getGravity();
      if(Gravity.isVertical(gravity) && (gravity&Gravity.VERTICAL_GRAVITY_MASK) == Gravity.BOTTOM) {
         setGravity((gravity&Gravity.HORIZONTAL_GRAVITY_MASK) | Gravity.TOP);
         topDown = false;
      }else
         topDown = true;
   }

   @Override
   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
      super.onMeasure(heightMeasureSpec, widthMeasureSpec);
      setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
   }

   @Override
   protected boolean setFrame(int l, int t, int r, int b){
      return super.setFrame(l, t, l+(b-t), t+(r-l));
   }

   @Override
   public void draw(Canvas canvas){
      if(topDown){
         canvas.translate(getHeight(), 0);
         canvas.rotate(90);
      }else {
         canvas.translate(0, getWidth());
         canvas.rotate(-90);
      }
      canvas.clipRect(0, 0, getWidth(), getHeight(), android.graphics.Region.Op.REPLACE);
      super.draw(canvas);
   }
}

Standardmäßig wird gedrehter Text von oben nach unten angezeigt. Wenn Sie android :vity = "bottom" einstellen, wird es von unten nach oben gezeichnet.

Technisch gesehen täuscht es die zugrunde liegende TextView vor, zu denken, dass es sich um eine normale Drehung handelt (Vertauschen von Breite / Höhe an wenigen Stellen), während das Zeichnen gedreht wird. Es funktioniert auch gut, wenn es in einem XML-Layout verwendet wird.

BEARBEITEN: Das Posten einer anderen Version oben hat Probleme mit Animationen. Diese neue Version funktioniert besser, verliert jedoch einige TextView-Funktionen, wie z. B. Laufschrift und ähnliche Spezialitäten.

public class VerticalTextView extends TextView{
   final boolean topDown;

   public VerticalTextView(Context context, AttributeSet attrs){
      super(context, attrs);
      final int gravity = getGravity();
      if(Gravity.isVertical(gravity) && (gravity&Gravity.VERTICAL_GRAVITY_MASK) == Gravity.BOTTOM) {
         setGravity((gravity&Gravity.HORIZONTAL_GRAVITY_MASK) | Gravity.TOP);
         topDown = false;
      }else
         topDown = true;
   }

   @Override
   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
      super.onMeasure(heightMeasureSpec, widthMeasureSpec);
      setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
   }

   @Override
   protected void onDraw(Canvas canvas){
      TextPaint textPaint = getPaint(); 
      textPaint.setColor(getCurrentTextColor());
      textPaint.drawableState = getDrawableState();

      canvas.save();

      if(topDown){
         canvas.translate(getWidth(), 0);
         canvas.rotate(90);
      }else {
         canvas.translate(0, getHeight());
         canvas.rotate(-90);
      }


      canvas.translate(getCompoundPaddingLeft(), getExtendedPaddingTop());

      getLayout().draw(canvas);
      canvas.restore();
  }
}

EDIT Kotlin Version:

import android.content.Context
import android.graphics.Canvas
import android.text.BoringLayout
import android.text.Layout
import android.text.TextUtils.TruncateAt
import android.util.AttributeSet
import android.view.Gravity
import androidx.appcompat.widget.AppCompatTextView
import androidx.core.graphics.withSave

class VerticalTextView(context: Context, attrs: AttributeSet) : AppCompatTextView(context, attrs) {
    private val topDown = gravity.let { g ->
        !(Gravity.isVertical(g) && g.and(Gravity.VERTICAL_GRAVITY_MASK) == Gravity.BOTTOM)
    }
    private val metrics = BoringLayout.Metrics()
    private var padLeft = 0
    private var padTop = 0

    private var layout1: Layout? = null

    override fun setText(text: CharSequence, type: BufferType) {
        super.setText(text, type)
        layout1 = null
    }

    private fun makeLayout(): Layout {
        if (layout1 == null) {
            metrics.width = height
            paint.color = currentTextColor
            paint.drawableState = drawableState
            layout1 = BoringLayout.make(text, paint, metrics.width, Layout.Alignment.ALIGN_NORMAL, 2f, 0f, metrics, false, TruncateAt.END, height - compoundPaddingLeft - compoundPaddingRight)
            padLeft = compoundPaddingLeft
            padTop = extendedPaddingTop
        }
        return layout1!!
    }

    override fun onDraw(c: Canvas) {
        //      c.drawColor(0xffffff80); // TEST
        if (layout == null)
            return
        c.withSave {
            if (topDown) {
                val fm = paint.fontMetrics
                translate(textSize - (fm.bottom + fm.descent), 0f)
                rotate(90f)
            } else {
                translate(textSize, height.toFloat())
                rotate(-90f)
            }
            translate(padLeft.toFloat(), padTop.toFloat())
            makeLayout().draw(this)
        }
    }
}
Zeiger Null
quelle
2
Ihre Lösung deaktiviert Links in TextView. Tatsächlich sind Links unterstrichen, reagieren jedoch nicht auf einen Klick.
Gurnetko
5
Dies hat Probleme mit mehrzeiligen und Bildlaufleisten.
Cynichniy Bandera
1
Entschuldigung für meine grundlegende Frage: Wenn ich eine Textansicht (in einer XML-Datei) habe und diese drehen möchte, wie muss ich die VerticalTextView-Klasse aufrufen?
Blackst0ne
2
@ blackst0ne anstelle von <TextView> -Tags verwenden Sie ein benutzerdefiniertes Ansichtstag: <com.YOUR_PACKAGE_NAME.VerticalTextView>
Daiwik Daarun
1
funktioniert super , in meinem Fall musste ich android.support.v7.widget.AppCompatTextView anstelle von TextView erweitern , damit mein Stilattribut funktioniert
Louis
32

Ich habe dies für mein ChartDroid- Projekt implementiert . Erstellen VerticalLabelView.java:

public class VerticalLabelView extends View {
    private TextPaint mTextPaint;
    private String mText;
    private int mAscent;
    private Rect text_bounds = new Rect();

    final static int DEFAULT_TEXT_SIZE = 15;

    public VerticalLabelView(Context context) {
        super(context);
        initLabelView();
    }

    public VerticalLabelView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initLabelView();

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.VerticalLabelView);

        CharSequence s = a.getString(R.styleable.VerticalLabelView_text);
        if (s != null) setText(s.toString());

        setTextColor(a.getColor(R.styleable.VerticalLabelView_textColor, 0xFF000000));

        int textSize = a.getDimensionPixelOffset(R.styleable.VerticalLabelView_textSize, 0);
        if (textSize > 0) setTextSize(textSize);

        a.recycle();
    }

    private final void initLabelView() {
        mTextPaint = new TextPaint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setTextSize(DEFAULT_TEXT_SIZE);
        mTextPaint.setColor(0xFF000000);
        mTextPaint.setTextAlign(Align.CENTER);
        setPadding(3, 3, 3, 3);
    }

    public void setText(String text) {
        mText = text;
        requestLayout();
        invalidate();
    }

    public void setTextSize(int size) {
        mTextPaint.setTextSize(size);
        requestLayout();
        invalidate();
    }

    public void setTextColor(int color) {
        mTextPaint.setColor(color);
        invalidate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        mTextPaint.getTextBounds(mText, 0, mText.length(), text_bounds);
        setMeasuredDimension(
                measureWidth(widthMeasureSpec),
                measureHeight(heightMeasureSpec));
    }

    private int measureWidth(int measureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            // We were told how big to be
            result = specSize;
        } else {
            // Measure the text
            result = text_bounds.height() + getPaddingLeft() + getPaddingRight();

            if (specMode == MeasureSpec.AT_MOST) {
                // Respect AT_MOST value if that was what is called for by measureSpec
                result = Math.min(result, specSize);
            }
        }
        return result;
    }

    private int measureHeight(int measureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        mAscent = (int) mTextPaint.ascent();
        if (specMode == MeasureSpec.EXACTLY) {
            // We were told how big to be
            result = specSize;
        } else {
            // Measure the text
            result = text_bounds.width() + getPaddingTop() + getPaddingBottom();

            if (specMode == MeasureSpec.AT_MOST) {
                // Respect AT_MOST value if that was what is called for by measureSpec
                result = Math.min(result, specSize);
            }
        }
        return result;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        float text_horizontally_centered_origin_x = getPaddingLeft() + text_bounds.width()/2f;
        float text_horizontally_centered_origin_y = getPaddingTop() - mAscent;

        canvas.translate(text_horizontally_centered_origin_y, text_horizontally_centered_origin_x);
        canvas.rotate(-90);
        canvas.drawText(mText, 0, 0, mTextPaint);
    }
}

Und in attrs.xml:

<resources>
     <declare-styleable name="VerticalLabelView">
        <attr name="text" format="string" />
        <attr name="textColor" format="color" />
        <attr name="textSize" format="dimension" />
    </declare-styleable>
</resources>
kostmo
quelle
Sehr hilfreich. Hier ist ein Link auf die Stamm - Version Ihres Projekts code.google.com/p/chartdroid/source/browse//trunk/core/...
rds
Nicht nützlich, Text wird nicht vollständig angezeigt. Er wird vom Ende und Anfang abgeschnitten.
Siddarth G
Arbeitete auch in der obigen Android-Version 28
Ajeet Choudhary
Ihre Version ist die beste Option für mein Projekt, aber setTextColor funktioniert nicht. Außerdem möchte ich einen Stil anwenden (Hintergrund und Schriftfamilie). Ist es möglich, dies zu tun?
Pablo R.
9

Ein Weg, dies zu erreichen, wäre:

  1. Schreiben Sie Ihre eigene benutzerdefinierte Ansicht und überschreiben Sie onDraw (Canvas). Sie können den Text auf die Leinwand zeichnen und dann die Leinwand drehen.
  2. Wie 1. Verwenden Sie diesmal einen Pfad und zeichnen Sie Text mit drawTextOnPath (...)
Prashast
quelle
Bevor ich diesen Weg gehe (ich habe mir die onDraw-Methode für TextView angesehen - sie ist riesig), habe ich festgestellt, dass der gesamte Unterschied zwischen TextView und der Erweiterung von Button eine interne Stil-ID ist (com.android.internal.R.attr.buttonStyle). Wäre dies möglich? um einfach einen benutzerdefinierten Stil zu definieren und TextView ähnlich wie Button zu erweitern? Ich vermute, dass die Antwort nein wäre, da es wahrscheinlich nicht möglich ist, Text vertikal zu gestalten
Bostone
Funktioniert dieser Ansatz tatsächlich? Ich hatte keinen Erfolg und dieser Typ auch nicht ... osdir.com/ml/Android-Developers/2009-11/msg02810.html
nategood
1
2. drawTextOnPath () zeichnet den Text so, wie er gedreht wurde, genau wie 1. Um Buchstaben untereinander zu schreiben, verwenden Sie entweder \n untereinander nach jedem Zeichen oder wenn Sie eine Schriftart mit fester Breite haben, beschränken Sie die TextView-Breite auf nur ein Zeichen.
Blub
8

Versuchte beide VerticalTextView-Klassen in der genehmigten Antwort und sie funktionierten ziemlich gut.

Unabhängig davon, was ich versucht habe, konnte ich diese VerticalTextViews nicht in der Mitte des enthaltenen Layouts positionieren (ein RelativeLayout, das Teil eines Elements ist, das für eine RecyclerView aufgeblasen wurde).

FWIW, nachdem ich mich umgesehen hatte, fand ich die VerticalTextView-Klasse von yoog568 auf GitHub:

https://github.com/yoog568/VerticalTextView/blob/master/src/com/yoog/widget/VerticalTextView.java

was ich wie gewünscht positionieren konnte. Sie müssen außerdem die folgende Attributdefinition in Ihr Projekt aufnehmen:

https://github.com/yoog568/VerticalTextView/blob/master/res/values/attr.xml

albert c braun
quelle
1
Ich fand diese Implementierung sehr einfach!
Hashim Akhtar
4
check = (TextView)findViewById(R.id.check);
check.setRotation(-90);

Das hat bei mir funktioniert, ganz gut. Was die vertikal abfallenden Buchstaben betrifft - ich weiß es nicht.

ERJAN
quelle
7
Aber es nimmt sogar den Raum horizontal ein und dreht ihn vertikal
Prabs
3

Es gibt einige kleinere Dinge, auf die man achten muss.

Dies hängt vom Zeichensatz ab, wenn Sie den Dreh- oder den Pfad wählen. Wenn der Zielzeichensatz beispielsweise englisch ist und der erwartete Effekt wie folgt aussieht:

a
b
c
d

Sie können diesen Effekt erzielen, indem Sie jedes Zeichen einzeln zeichnen, ohne dass eine Drehung oder ein Pfad erforderlich ist.

Geben Sie hier die Bildbeschreibung ein

Möglicherweise müssen Sie drehen oder einen Pfad erstellen, um diesen Effekt zu erzielen.

Der schwierige Teil ist, wenn Sie versuchen, Zeichensätze wie Mongolisch zu rendern. Die Glyphe in der Schrift muss um 90 Grad gedreht werden, daher ist drawTextOnPath () ein guter Kandidat.

Zephyr
quelle
Wie kann es anders gemacht werden für von leftSide nach RightSide
Rakesh
3
textview.setTextDirection (View.TEXT_DIRECTION_RTL) oder textview.setTextDirection (View.TEXT_DIRECTION_ANY_RTL) funktionieren möglicherweise über der API-Ebene 17. Sie können es testen.
Zephyr
klug und einfach
Abdulrahman Abdelkader
1

Nach der Antwort von Pointer Null konnte ich den Text horizontal zentrieren, indem ich die onDrawMethode folgendermaßen änderte :

@Override
protected void onDraw(Canvas canvas){
    TextPaint textPaint = getPaint();
    textPaint.setColor(getCurrentTextColor());
    textPaint.drawableState = getDrawableState();
    canvas.save();
    if(topDown){
        canvas.translate(getWidth()/2, 0);
        canvas.rotate(90);
    }else{
        TextView temp = new TextView(getContext());
        temp.setText(this.getText().toString());
        temp.setTypeface(this.getTypeface());
        temp.measure(0, 0);
        canvas.rotate(-90);
        int max = -1 * ((getWidth() - temp.getMeasuredHeight())/2);
        canvas.translate(canvas.getClipBounds().left, canvas.getClipBounds().top - max);
    }
    canvas.translate(getCompoundPaddingLeft(), getExtendedPaddingTop());
    getLayout().draw(canvas);
    canvas.restore();
}

Möglicherweise müssen Sie einen Teil der gemessenen Textansicht hinzufügen, um einen mehrzeiligen Text zu zentrieren.

dequec64
quelle
1

Sie können einfach zu Ihrer TextView oder einem anderen View-XML-Rotationswert hinzufügen. Dies ist der einfachste Weg und für mich funktioniert es richtig.

<LinearLayout
    android:rotation="-90"
    android:layout_below="@id/image_view_qr_code"
    android:layout_above="@+id/text_view_savva_club"
    android:layout_marginTop="20dp"
    android:gravity="bottom"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical">

   <TextView
       android:textColor="@color/colorPrimary"
       android:layout_marginStart="40dp"
       android:textSize="20sp"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="Дмитриевский Дмитрий Дмитриевич"
       android:maxLines="2"
       android:id="@+id/vertical_text_view_name"/>
    <TextView
        android:textColor="#B32B2A29"
        android:layout_marginStart="40dp"
        android:layout_marginTop="15dp"
        android:textSize="16sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/vertical_text_view_phone"
        android:text="+38 (000) 000-00-00"/>

</LinearLayout>

Ergebnis

Marina Budkovets
quelle
0

Mein anfänglicher Ansatz zum Rendern von vertikalem Text in einem vertikalen LinearLayout war wie folgt (dies ist Kotlin, in Java setRoatationusw.):

val tv = TextView(context)
tv.gravity = Gravity.CENTER
tv.rotation = 90F
tv.height = calcHeight(...)
linearLabels.addView(tv)

Ansatz Nr. 1

Wie Sie sehen, besteht das Problem darin, dass die Textansicht vertikal verläuft, ihre Breite jedoch so behandelt, als ob sie horizontal ausgerichtet wäre! = /

Daher bestand Ansatz Nr. 2 darin, Breite und Höhe zusätzlich manuell zu wechseln, um dies zu berücksichtigen:

tv.measure(0, 0)
// tv.setSingleLine()
tv.width = tv.measuredHeight
tv.height = calcHeight(...)

Ansatz # 2

Dies führte jedoch dazu, dass die Etiketten in die nächste Zeile umbrochen wurden (oder beschnitten wurden, wenn Sie dies tun) setSingleLine nach der relativ kurzen Breite ). Dies läuft wiederum darauf hinaus, x mit y zu verwechseln.

Mein Ansatz Nr. 3 bestand daher darin, die Textansicht in ein RelativeLayout zu verpacken. Die Idee ist, der Textansicht eine beliebige Breite zu ermöglichen, indem sie weit nach links und rechts erweitert wird (hier 200 Pixel in beide Richtungen). Aber dann gebe ich dem RelativeLayout negative Ränder, um sicherzustellen, dass es als schmale Spalte gezeichnet wird. Hier ist mein vollständiger Code für diesen Screenshot:

val tv = TextView(context)
tv.text = getLabel(...)
tv.gravity = Gravity.CENTER
tv.rotation = 90F

tv.measure(0, 0)
tv.width = tv.measuredHeight + 400  // 400 IQ
tv.height = calcHeight(...)

val tvHolder = RelativeLayout(context)
val lp = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
    LinearLayout.LayoutParams.WRAP_CONTENT)
lp.setMargins(-200, 0, -200, 0)
tvHolder.layoutParams = lp
tvHolder.addView(tv)
linearLabels.addView(tvHolder)

val iv = ImageView(context)
iv.setImageResource(R.drawable.divider)
linearLabels.addView(iv)

Ansatz # 3

Als allgemeiner Tipp war diese Strategie, eine Ansicht eine andere Ansicht "halten" zu lassen, für mich sehr nützlich, um Dinge in Android zu positionieren! Das Infofenster unter der ActionBar verwendet beispielsweise dieselbe Taktik!

Für Text, der wie ein Geschäftsschild erscheint, fügen Sie nach jedem Zeichen einfach Zeilenumbrüche ein, z. B "N\nu\nt\ns".:

Beispiel für ein Ladenschild

xjcl
quelle
-1

Ich mochte @ kostmos Ansatz. Ich habe es ein wenig modifiziert, weil ich ein Problem hatte - das vertikal gedrehte Etikett abzuschneiden, wenn ich seine Parameter als einstelle WRAP_CONTENT. Somit war ein Text nicht vollständig sichtbar.

So habe ich es gelöst:

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.os.Build;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class VerticalLabelView extends View
{
    private final String LOG_TAG           = "VerticalLabelView";
    private final int    DEFAULT_TEXT_SIZE = 30;
    private int          _ascent           = 0;
    private int          _leftPadding      = 0;
    private int          _topPadding       = 0;
    private int          _rightPadding     = 0;
    private int          _bottomPadding    = 0;
    private int          _textSize         = 0;
    private int          _measuredWidth;
    private int          _measuredHeight;
    private Rect         _textBounds;
    private TextPaint    _textPaint;
    private String       _text             = "";
    private TextView     _tempView;
    private Typeface     _typeface         = null;
    private boolean      _topToDown = false;

    public VerticalLabelView(Context context)
    {
        super(context);
        initLabelView();
    }

    public VerticalLabelView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        initLabelView();
    }

    public VerticalLabelView(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
        initLabelView();
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public VerticalLabelView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
    {
        super(context, attrs, defStyleAttr, defStyleRes);
        initLabelView();
    }

    private final void initLabelView()
    {
        this._textBounds = new Rect();
        this._textPaint = new TextPaint();
        this._textPaint.setAntiAlias(true);
        this._textPaint.setTextAlign(Paint.Align.CENTER);
        this._textPaint.setTextSize(DEFAULT_TEXT_SIZE);
        this._textSize = DEFAULT_TEXT_SIZE;
    }

    public void setText(String text)
    {
        this._text = text;
        requestLayout();
        invalidate();
    }

    public void topToDown(boolean topToDown)
    {
        this._topToDown = topToDown;
    }

    public void setPadding(int padding)
    {
        setPadding(padding, padding, padding, padding);
    }

    public void setPadding(int left, int top, int right, int bottom)
    {
        this._leftPadding = left;
        this._topPadding = top;
        this._rightPadding = right;
        this._bottomPadding = bottom;
        requestLayout();
        invalidate();
    }

    public void setTextSize(int size)
    {
        this._textSize = size;
        this._textPaint.setTextSize(size);
        requestLayout();
        invalidate();
    }

    public void setTextColor(int color)
    {
        this._textPaint.setColor(color);
        invalidate();
    }

    public void setTypeFace(Typeface typeface)
    {
        this._typeface = typeface;
        this._textPaint.setTypeface(typeface);
        requestLayout();
        invalidate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        try
        {
            this._textPaint.getTextBounds(this._text, 0, this._text.length(), this._textBounds);

            this._tempView = new TextView(getContext());
            this._tempView.setPadding(this._leftPadding, this._topPadding, this._rightPadding, this._bottomPadding);
            this._tempView.setText(this._text);
            this._tempView.setTextSize(TypedValue.COMPLEX_UNIT_PX, this._textSize);
            this._tempView.setTypeface(this._typeface);

            this._tempView.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

            this._measuredWidth = this._tempView.getMeasuredHeight();
            this._measuredHeight = this._tempView.getMeasuredWidth();

            this._ascent = this._textBounds.height() / 2 + this._measuredWidth / 2;

            setMeasuredDimension(this._measuredWidth, this._measuredHeight);
        }
        catch (Exception e)
        {
            setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
            Log.e(LOG_TAG, Log.getStackTraceString(e));
        }
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);

        if (!this._text.isEmpty())
        {
            float textHorizontallyCenteredOriginX = this._measuredHeight / 2f;
            float textHorizontallyCenteredOriginY = this._ascent;

            canvas.translate(textHorizontallyCenteredOriginY, textHorizontallyCenteredOriginX);

            float rotateDegree = -90;
            float y = 0;

            if (this._topToDown)
            {
                rotateDegree = 90;
                y = this._measuredWidth / 2;
            }

            canvas.rotate(rotateDegree);
            canvas.drawText(this._text, 0, y, this._textPaint);
        }
    }
}

Wenn Sie einen Text von oben nach unten haben möchten, verwenden Sie die topToDown(true)Methode.

Ayaz Alifov
quelle