ป้ายกำกับแนวตั้ง (หมุน) ใน Android


110

ฉันต้องการ 2 วิธีในการแสดงป้ายแนวตั้งใน Android:

  1. ฉลากแนวนอนหัน 90 องศาทวนเข็มนาฬิกา (ตัวอักษรด้านข้าง)
  2. ป้ายชื่อแนวนอนที่มีตัวอักษรอยู่ด้านล่าง (เหมือนป้ายร้านค้า)

ฉันจำเป็นต้องพัฒนาวิดเจ็ตแบบกำหนดเองสำหรับทั้งสองกรณี (กรณีเดียว) ฉันสามารถสร้าง TextView เพื่อแสดงผลแบบนั้นได้หรือไม่และจะมีวิธีใดที่ดีในการทำสิ่งนั้นหากฉันต้องการกำหนดเองทั้งหมด


เป็นไปได้ที่จะทำใน XML ตั้งแต่ API 11 (Android 3.0) stackoverflow.com/questions/3774770/…
chobok

คำตอบ:


239

นี่คือการใช้งานข้อความแนวตั้งที่หรูหราและเรียบง่ายของฉันซึ่งขยาย 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: แรงโน้มถ่วง = "bottom" ระบบจะดึงจากล่างขึ้นบน

ในทางเทคนิคแล้ว TextView ที่อยู่เบื้องหลังจะคิดว่าเป็นการหมุนตามปกติ (การสลับความกว้าง / ความสูงในไม่กี่แห่ง) ในขณะที่การวาดนั้นหมุน ใช้งานได้ดีเมื่อใช้ในรูปแบบ xml

แก้ไข: การ โพสต์เวอร์ชันอื่นด้านบนมีปัญหากับภาพเคลื่อนไหว เวอร์ชันใหม่นี้ทำงานได้ดีขึ้น แต่สูญเสียคุณสมบัติ 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

5
ปัญหานี้มีปัญหาเกี่ยวกับมัลติไลน์และแถบเลื่อน
Cynichniy Bandera

1
ขออภัยสำหรับคำถามพื้นฐานของฉันหากฉันได้รับ TextView (ในไฟล์ XML) และฉันต้องการหมุนฉันจะเรียกคลาส VerticalTextView ได้อย่างไร
blackst0ne

2
@ blackst0ne แทนแท็ก <TextView> ให้ใช้แท็กมุมมองที่กำหนดเอง: <com.YOUR_PACKAGE_NAME.VerticalTextView>
Daiwik Daarun

1
ใช้งานได้ดีในกรณีของฉันฉันต้องขยายandroid.support.v7.widget.AppCompatTextViewแทนTextViewเพื่อให้แอตทริบิวต์สไตล์ของฉันใช้งานได้
หลุยส์

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>

มีประโยชน์มาก. นี่คือลิงค์ไปยังเวอร์ชัน trunk ของรหัสโครงการของคุณhttps://google.com/p/chartdroid/source/browse//trunk/core/…
rds

ไม่มีประโยชน์ข้อความแสดงไม่ครบ .. ถูกตัดออกจากจุดสิ้นสุดและเริ่มต้น
Siddarth G

ทำงานใน Android เวอร์ชัน 28 ข้างต้นด้วย
Ajeet Choudhary

เวอร์ชันของคุณเป็นตัวเลือกที่ดีที่สุดสำหรับโปรเจ็กต์ของฉัน แต่ setTextColor ไม่ทำงานฉันต้องการใช้สไตล์ (background และ fontFamily) เป็นไปได้หรือไม่ที่จะทำ
Pablo R.

9

วิธีหนึ่งที่จะบรรลุสิ่งเหล่านี้คือ:

  1. เขียนมุมมองแบบกำหนดเองของคุณเองและเขียนทับ onDraw (Canvas) คุณสามารถวาดข้อความบนผืนผ้าใบแล้วหมุนผืนผ้าใบ
  2. เหมือนกับ 1. ยกเว้นครั้งนี้ใช้Pathและวาดข้อความโดยใช้drawTextOnPath (... )

ดังนั้นก่อนที่ฉันจะไปเส้นทางนั้น (ฉันดูวิธี onDraw สำหรับ TextView - มันใหญ่มาก) ฉันสังเกตเห็นความแตกต่างทั้งหมดระหว่าง TextView และปุ่มขยายเป็น ID สไตล์ภายใน (com.android.internal.R.attr.buttonStyle) จะเป็นไปได้ไหม เพียงแค่กำหนดสไตล์ที่กำหนดเองและขยาย TextView ที่คล้ายกับปุ่ม? ฉันเดาว่าคำตอบคงไม่ใช่เพราะอาจเป็นไปไม่ได้ที่จะจัดรูปแบบข้อความให้เป็นแนวตั้ง
Bostone

แนวทางนี้ใช้ได้จริงหรือไม่? ฉันไม่ประสบความสำเร็จและผู้ชายคนนี้ก็ไม่มี ... osdir.com/ml/Android-Developers/2009-11/msg02810.html
nategood

1
2. drawTextOnPath () วาดข้อความเหมือนที่หมุนเช่นเดียวกับ 1. ในการเขียนตัวอักษรข้างใต้อีกตัวให้ใช้\nหลังอักขระแต่ละตัวหรือถ้าคุณมีแบบอักษรที่มีความกว้างคงที่ให้จำกัดความกว้างของ TextView ให้พอดีกับอักขระเพียงตัวเดียว
blub

8

ลองทั้งสองคลาส VerticalTextView ในคำตอบที่ได้รับอนุมัติแล้วและทำงานได้ดีพอสมควร

แต่ไม่ว่าฉันจะพยายามอย่างไรฉันไม่สามารถวางตำแหน่ง VerticalTextView เหล่านั้นไว้ตรงกลางของเลย์เอาต์ที่มีอยู่ (RelativeLayout ซึ่งเป็นส่วนหนึ่งของรายการที่สูงเกินจริงสำหรับ RecyclerView)

FWIW หลังจากมองไปรอบ ๆ ฉันพบคลาส VerticalTextView ของ yoog568 บน GitHub:

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

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

สิ่งนี้ใช้ได้ผลสำหรับฉันดี สำหรับตัวอักษรในแนวตั้งลงไป - ฉันไม่รู้


7
แต่มันใช้พื้นที่ในแนวนอนและหมุนในแนวตั้ง
ประจบ

3

มีบางสิ่งเล็กน้อยที่ต้องให้ความสนใจ

ขึ้นอยู่กับชุดอักขระเมื่อเลือกวิธีการหมุนหรือเส้นทาง ตัวอย่างเช่นหากชุดอักขระเป้าหมายเป็นภาษาอังกฤษและผลที่คาดหวังมีลักษณะดังนี้

a
b
c
d

คุณสามารถรับเอฟเฟกต์นี้ได้โดยการวาดอักขระทีละตัวโดยไม่จำเป็นต้องหมุนหรือเปลี่ยนเส้นทาง

ใส่คำอธิบายภาพที่นี่

คุณอาจต้องหมุนหรือเส้นทางเพื่อให้ได้เอฟเฟกต์นี้

ส่วนที่ยุ่งยากคือเมื่อคุณพยายามสร้างชุดอักขระเช่นภาษามองโกเลีย สัญลักษณ์ใน Typeface จะต้องหมุน 90 องศาดังนั้น drawTextOnPath () จึงเป็นตัวเลือกที่ดีที่จะใช้


วิธีการอื่นจะทำได้อย่างไรสำหรับจาก leftSide to RightSide
Rakesh

3
textview.setTextDirection (View.TEXT_DIRECTION_RTL) หรือ textview.setTextDirection (View.TEXT_DIRECTION_ANY_RTL) อาจทำงานได้เหนือระดับ API 17 คุณสามารถทดสอบได้
Zephyr

ฉลาดและเรียบง่าย
Abdulrahman Abdelkader

1

ต่อไปนี้ชี้โมฆะคำตอบของฉันได้รับสามารถไปยังศูนย์ข้อความในแนวนอนโดยการปรับเปลี่ยน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 ที่วัดความกว้างเพื่อให้ข้อความหลายบรรทัดอยู่ตรงกลาง


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 แนวตั้งมีดังนี้ (นี่คือ Kotlin ในการใช้ Java setRoatationเป็นต้น):

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.