【问题标题】:Is it possible to write vertically in a textview in android?是否可以在android的textview中垂直书写?
【发布时间】:2010-05-22 16:03:46
【问题描述】:

假设您有一个普通的 TextView,其中写有“Stackoverflow”,是否可以将 TextView 旋转 -90°,使 S 位于屏幕底部,W 位于屏幕顶部? 当然,我可以将我的文本写成图像,旋转它并以这种方式使用它,但我现在对文本感兴趣。 谢谢。

【问题讨论】:

标签: android textview vertical-text


【解决方案1】:

你可以像往常一样设置你的文本视图

例如:

 <TextView android:id="@+id/txtview"
    android:layout_height="fill_parent"
    android:layout_width="wrap_content" />

并在您的活动中编写一个函数

  • 反转文本中的字符
  • 在每个字符后插入\n

然后将文本设置到TextView。

如果您不想插入\n,则必须设置android:layout_width 的大小并调整字体大小,不要让2 个字符在同一行且没有截断

编辑 如果我理解正确的话,你可以通过动画得到你想要的。

例如

res/anim/myanim.xml下:

<rotate  xmlns:android="http://schemas.android.com/apk/res/android"
           android:fromDegrees="0" 
           android:toDegrees="-90"
           android:pivotX="50%"
           android:duration="0" />

您必须使用此文件来定义您希望放置文本视图的位置。

在你的活动中:

  TextView t = (TextView)findViewById(R.id.txtview);
  String txt = "Stackoverflow";         
  t.setText(txt);

  RotateAnimation ranim = (RotateAnimation)AnimationUtils.loadAnimation(this, R.anim.myanim);
  ranim.setFillAfter(true); //For the textview to remain at the same place after the rotation
  t.setAnimation(ranim);

【讨论】:

  • 是的,我虽然是这么想的,但这并不是我解释和实际要求的,我不希望每个角色一个在另一个之上,但所有角色都具有 -90° 旋转。 ..这可能吗?
  • 哈哈好吧 - 我想我现在明白你的意思了 - 我不知道该怎么做,但我会考虑的
  • @ccheneson 宽度明智,它占用了更多空间。我试过myanim.xml
  • 很好的样本,真的对我有帮助。
  • 但是,Onclick 监听器无法正常工作。有什么解决办法吗?
【解决方案2】:

为我工作:

public class VerticalTextView extends TextView {

    private int _width, _height;
    private final Rect _bounds = new Rect();

    public VerticalTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

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

    public VerticalTextView(Context context) {
        super(context);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // vise versa
        _height = getMeasuredWidth();
        _width = getMeasuredHeight();
        setMeasuredDimension(_width, _height);
    }

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

        canvas.translate(_width, _height);
        canvas.rotate(-90);

        TextPaint paint = getPaint();
        paint.setColor(getTextColors().getDefaultColor());

        String text = text();

        paint.getTextBounds(text, 0, text.length(), _bounds);
        canvas.drawText(text, getCompoundPaddingLeft(), (_bounds.height() - _width) / 2, paint);

        canvas.restore();
    }

    private String text() {
        return super.getText().toString();
    }
}

xml:

<VerticalTextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="left|center_vertical"
            android:background="@color/feedback_background"
            android:padding="4dip"
            android:text="@string/feedback"
            android:textColor="@color/feedback_text_color"
            android:textSize="@dimen/text_xlarge" />

【讨论】:

  • 我知道这没什么大不了的,但是如果有一天像我这样的一些 n00b 尝试实现它并得到一些错误,请尝试使用:&lt;com.apppackege.VerticalTextView&gt; 而不仅仅是 &lt;VerticalTextView&gt;。不管怎样,你的回答对我帮助很大!谢谢!
  • 完美运行。谢谢!
  • 如何旋转到 90 度而不是 -90 度?
  • 当我将其更改为 90 或 270 时,它变为空白
【解决方案3】:
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:text="xyz"
            android:rotation="-90"
            android:gravity="fill_vertical"/>

【讨论】:

  • 这可行,但之后很难使用 UI 编辑器
【解决方案4】:

试试这个。这对我来说可以。它可以垂直显示一行文本,但只能显示一行。颜色、大小、填充、边距和背景都可以正常工作。

public class VerticalTextView extends TextView {

    public VerticalTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

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

    public VerticalTextView(Context context) {
        super(context);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        final ColorStateList csl = getTextColors();
        final int color = csl.getDefaultColor();
        final int paddingBottom = getPaddingBottom();
        final int paddingTop = getPaddingTop();
        final int viewWidth = getWidth();
        final int viewHeight = getHeight();
        final TextPaint paint = getPaint();
        paint.setColor(color);
        final float bottom = viewWidth * 9.0f / 11.0f;
        Path p = new Path();
        p.moveTo(bottom, viewHeight - paddingBottom - paddingTop);
        p.lineTo(bottom, paddingTop);
        canvas.drawTextOnPath(getText().toString(), p, 0, 0, paint);
    }
}

【讨论】:

  • 我在 xml 中使用该类,但它不起作用。你能告诉我如何使用它吗?谢谢!
  • 你得到解决方案herbertD了吗?
  • 对我不起作用,文本显示不正确
  • 如果想要整齐的定位,请加paint.setTextAlign(Paint.Align.CENTER);进行绘画初始化
【解决方案5】:

如果您使用的是 API 11 或更高版本,您可以尝试:

TextView t = (TextView) findViewById(R.id.txtview);
String txt = "Stackoverflow";         
t.setText(txt);
t.setRotation(90); // 90 degree rotation

【讨论】:

  • 这将有 textview 边界的问题。 onMeasure() 应该为它重新定义。
【解决方案6】:

我将向你们展示我的自定义垂直按钮示例,其中包含旋转的 TextView:

<!--Undo button-->
<LinearLayout
    android:id="@+id/undo_points_pr_a"
    android:layout_width="@dimen/zero_dp"
    android:gravity="center"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:layout_weight="1"
    android:background="@color/timerUndoButton">

    <ImageView
        android:layout_width="@dimen/large"
        android:layout_height="@dimen/large"
        android:src="@drawable/undo_icon"
        android:rotation="-90"
        android:layout_marginBottom="@dimen/medium"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/undo"
        android:textSize="@dimen/small_medium_text"
        android:rotation="-90"/>

</LinearLayout>

这就是它在 Android Studio 中的样子:

当然,您必须修改此代码以使其适合您。 (在 android:layout_width、android:layout_height 等属性中)

【讨论】:

    【解决方案7】:

    我在另一个 StackOverflow question 中提供了解决方案。您可以通过从 View 扩展并覆盖其 onMeasure()onDraw() 方法来获得垂直 TextView。但是,它不会支持所有 TextView 功能,而是支持它的主要功能,如填充、大小、颜色和字体。

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

    【讨论】:

      【解决方案8】:

      我认为垂直编写“Stackoverflow”的问题的最简单答案是使用普通的 TextView,并且由于文本在变窄时会换行到下一行,因此请使用 TextView 的宽度,以便有一个字母在每一行上,如果您需要更多的边缘空间作为缓冲区,请增加 TextView 的“填充”和/或“边距”。

      【讨论】:

        【解决方案9】:

        我最初在垂直 LinearLayout 中呈现垂直文本的方法如下(这是 Kotlin,在 Java 中使用 setRoatation 等):

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

        如您所见,问题在于 TextView 是垂直的,但仍将其宽度视为水平方向! =/

        因此方法 #2 包括额外手动切换宽度和高度以解决此问题:

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

        然而,这导致标签在相对较短的宽度之后环绕到下一行(或者如果您 setSingleLine 被裁剪)。同样,这归结为将 x 与 y 混淆。

        因此,我的方法 #3 是将 TextView 包装在 RelativeLayout 中。这个想法是通过将 TextView 向左和向右(这里,在两个方向上 200 像素)延伸很远来允许 TextView 任何它想要的宽度。但后来我给 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)
        

        作为一般提示,这种让视图“持有”另一个视图的策略对我在 Android 中定位事物非常有用!例如,ActionBar 下方的信息窗口使用相同的策略!

        对于从底部开始的文本,只需将其旋转 -90F 而不是 90F 度。

        【讨论】:

          【解决方案10】:
          public class VerticalTextView extends AppCompatTextView {
              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();
              }
          
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-09-26
            • 1970-01-01
            • 2021-07-14
            • 1970-01-01
            相关资源
            最近更新 更多