Android의 세로 (회전) 레이블


110

Android에서 세로 레이블을 표시하는 두 가지 방법이 필요합니다.

  1. 수평 라벨이 시계 반대 방향으로 90도 회전 됨 (측면에 글자)
  2. 한 글자 아래에 다른 글자가있는 가로 라벨 (점포 표시 ​​등)

두 경우 모두에 대한 사용자 정의 위젯을 개발해야합니까 (하나의 경우), 그런 방식으로 렌더링하도록 TextView를 만들 수 있으며, 완전히 사용자 정의해야하는 경우 이와 같은 작업을 수행하는 좋은 방법은 무엇입니까?


API 11 (Android 3.0)부터 XML로이 작업을 수행 할 수 있습니다. stackoverflow.com/questions/3774770/...
chobok

답변:


239

다음은 TextView를 확장하는 우아하고 간단한 세로 텍스트 구현입니다. 이는 TextView가 확장 된 TextView이기 때문에 모든 표준 스타일의 TextView를 사용할 수 있음을 의미합니다.

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

기본적으로 회전 된 텍스트는 위에서 아래로입니다. android : gravity = "bottom"을 설정하면 아래에서 위로 그려집니다.

기술적으로는 기본 TextView를 속여서 회전을 그리는 동안 정상적인 회전 (폭 / 높이 몇 군데 교체)이라고 생각합니다. xml 레이아웃에서 사용할 때도 잘 작동합니다.

편집 : 위의 다른 버전을 게시하면 애니메이션에 문제가 있습니다. 이 새 버전은 더 잘 작동하지만 marquee 및 유사한 전문 분야와 같은 일부 TextView 기능이 손실됩니다.

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

Kotlin 버전 수정 :

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

2
솔루션이 TextView. 실제로 링크에는 밑줄이 표시되어 있지만 클릭시 응답하지 않습니다.
Gurnetko 2011

5
여러 줄 및 스크롤바에 문제가 있습니다.
Cynichniy BANDERA

1
내 기본적인 질문에 대해 죄송합니다. TextView (XML 파일)가 있고 회전하려면 어떻게 VerticalTextView 클래스를 호출해야합니까?
blackst0ne 2015

2
@ blackst0ne 대신 <텍스트 뷰> 태그, 사용자 지정보기 태그를 사용 : <com.YOUR_PACKAGE_NAME.VerticalTextView>
Daiwik Daarun

1
잘 작동합니다. 제 경우 에는 TextView 대신 android.support.v7.widget.AppCompatTextView 를 확장 하여 스타일 속성이 작동하도록해야했습니다
Louis

32

ChartDroid 프로젝트를 위해 이것을 구현했습니다 . 만들기 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);
    }
}

그리고 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>

굉장히 유용하다. 다음은 프로젝트 code.google.com/p/chartdroid/source/browse//trunk/core/…
rds

유용하지 않습니다. 텍스트가 완전히 표시되지 않습니다. 끝과 시작에서 잘립니다.
Siddarth G

위의 안드로이드 버전 28에서도 작업
Ajeet Choudhary

귀하의 버전이 내 프로젝트에 가장 적합한 옵션이지만 setTextColor가 작동하지 않습니다. 또한 스타일 (background 및 fontFamily)을 적용하고 싶습니다. 가능합니까?
Pablo R.

9

이를 달성하는 한 가지 방법은 다음과 같습니다.

  1. 사용자 정의 보기를 작성 하고 onDraw (Canvas)를 재정의합니다.캔버스에 텍스트를 그린 다음 캔버스를 회전 할 수 있습니다.
  2. 이번에는 Path 를 사용하고 drawTextOnPath (...)를 사용하여 텍스트를 그리는 것을 제외하면 1과 동일합니다.

그래서 그 경로를 가기 전에 (TextView에 대한 onDraw 메서드를 보았습니다-방대합니다) TextView와 Button 확장의 모든 차이점이 내부 스타일 ID (com.android.internal.R.attr.buttonStyle)라는 것을 알았습니다. 사용자 정의 스타일을 정의하고 Button과 유사한 TextView를 확장하려면? 텍스트를 세로 레이아웃으로 스타일링 할 수 없기 때문에 대답은 '아니오'라고 생각합니다
Bostone

이 접근 방식이 실제로 작동합니까? 나는 성공하지 못했고이
nategood 2009

1
2. drawTextOnPath ()는 1과 같이 회전 된 것처럼 텍스트를 그립니다. 문자를 하나씩 아래에 쓰려면 \n각 문자 뒤에 사용 하거나 고정 너비 글꼴이있는 경우 TextView 너비를 한 문자에 맞게 제한합니다.
blub

8

승인 된 답변에서 VerticalTextView 클래스를 모두 시도했으며 합리적으로 잘 작동했습니다.

그러나 내가 무엇을 시도하든 상관없이 포함 레이아웃 (RecyclerView에 대해 팽창 된 항목의 일부인 RelativeLayout)의 중앙에 해당 VerticalTextViews를 배치 할 수 없었습니다.

FWIW, 둘러 본 후 GitHub에서 yoog568의 VerticalTextView 클래스를 찾았습니다.

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

원하는대로 배치 할 수있었습니다. 또한 프로젝트에 다음 속성 정의를 포함해야합니다.

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


1
이 구현이 정말 쉽다는 것을 알았습니다!
Hashim Akhtar 2018

4
check = (TextView)findViewById(R.id.check);
check.setRotation(-90);

이것은 나를 위해 일했습니다. 수직으로 내려가는 글자에 관해서는-모르겠습니다.


7
하지만 수평으로 공간을 차지하고 수직으로 회전시킵니다
Prabs

3

주의해야 할 사소한 사항이 있습니다.

회전 또는 경로 방법을 선택할 때 문자 집합에 따라 다릅니다. 예를 들어, 대상 문자 세트가 영어와 같고 예상 효과가 다음과 같으면

a
b
c
d

이 효과는 각 캐릭터를 하나씩 그려서 회전하거나 경로가 필요하지 않습니다.

여기에 이미지 설명 입력

이 효과를 얻으려면 회전 또는 경로가 필요할 수 있습니다.

까다로운 부분은 몽골어와 같은 문자 집합을 렌더링하려고 할 때입니다. 서체의 글리프는 90도 회전해야하므로 drawTextOnPath ()를 사용하는 것이 좋습니다.


어떻게 RightSide에 레프트 사이드에서 대한 다른 wayaround을 수행 할 수 있습니다
케쉬

3
textview.setTextDirection (View.TEXT_DIRECTION_RTL) 또는 textview.setTextDirection (View.TEXT_DIRECTION_ANY_RTL)은 API 레벨 17 이상에서 작동 할 수 있습니다. 테스트 할 수 있습니다.
Zephyr

똑똑하고 간단합니다
Abdulrahman Abdelkader

1

Pointer Null 의 대답에 따라 다음과 같이 onDraw메서드 를 수정하여 텍스트를 가로로 가운데에 배치 할 수있었습니다 .

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

여러 줄로 된 텍스트를 가운데에 맞추려면 TextView MeasuringWidth의 일부를 추가해야 할 수 있습니다.


1

TextView 또는 다른 View xml 회전 값에 추가 할 수 있습니다. 이것은 가장 쉬운 방법이며 올바르게 작동합니다.

<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>

결과


0

수직 LinearLayout 내부에 수직 텍스트를 렌더링하는 초기 접근 방식은 다음과 같습니다 (Java 사용 setRoatation등에서 Kotlin입니다 ).

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

접근 # 1

보시다시피 문제는 TextView가 세로로 이동하지만 여전히 가로 방향 인 것처럼 너비를 처리한다는 것입니다! = /

따라서 접근법 # 2는이를 설명하기 위해 폭과 높이를 수동으로 추가로 전환하는 것으로 구성되었습니다.

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

접근법 # 2

그러나 이로 인해 레이블이 다음 줄로 감싸 지거나 setSingleLine 이 상대적으로 짧은 너비 이후에 . 다시 말하지만 이것은 x와 y를 혼동하는 것으로 귀결됩니다.

따라서 내 접근 방식 # 3은 TextView를 RelativeLayout에 래핑하는 것입니다. 아이디어는 TextView를 왼쪽과 오른쪽으로 멀리 확장하여 원하는 너비를 허용하는 것입니다 (여기서는 양방향으로 200 픽셀). 그러나 그런 다음 RelativeLayout에 음수 여백을 제공하여 좁은 열로 그려 지도록합니다. 이 스크린 샷의 전체 코드는 다음과 같습니다.

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)

접근법 # 3

일반적인 팁으로, 뷰가 다른 뷰를 "보류"하는이 전략은 Android에서 항목을 배치하는 데 정말 유용했습니다. 예를 들어 ActionBar 아래의 정보 창은 동일한 전술을 사용합니다!

상점 간판처럼 나타나는 텍스트의 경우 각 문자 뒤에 개행 문자를 삽입하기 만하면 "N\nu\nt\ns"됩니다. 예를 들면 다음과 같습니다.

점포 표시 ​​예


-1

@kostmo의 접근 방식을 좋아했습니다. 매개 변수를로 설정하면 세로로 회전 된 레이블이 잘리는 문제가 있었기 때문에 약간 수정했습니다 WRAP_CONTENT. 따라서 텍스트가 완전히 보이지 않았습니다.

이것이 내가 해결 한 방법입니다.

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

위에서 아래로 텍스트를 원하면 topToDown(true)방법 을 사용하십시오 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.