2017-01-21 29 views
7

我需要建立自己的自定义TextView,所以我一直在学习StaticLayout在画布上绘制文本。这比直接使用Canvas.drawText()更好,或者documentation说。但是,文档没有给出任何示例。对于StaticLayout.Builder只是一个模糊的参考,它是更新的方式。Android中如何使用StaticLayout?

我发现了一个例子here但似乎有点过时了。

我终于工作,虽然如何做到这一点,所以我在下面添加我的解释。

回答

40

StaticLayoutsimilar to DynamicLayout and BoringLayout)用于在画布上布局和绘制文本。它通常用于以下任务:

  • 测量布局后多线文本的大小。
  • 在位图图像上绘制文本。
  • 制作处理其自己的文本布局的自定义视图(而不是使用嵌入的TextView制作复合视图)。 TextView本身使用StaticLayoutinternally

测量文本大小

单线

如果你只有单个文本行,你可以用PaintTextPaint衡量它。

String text = "This is some text." 

TextPaint myTextPaint = new TextPaint(); 
mTextPaint.setAntiAlias(true); 
mTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density); 
mTextPaint.setColor(0xFF000000); 

float width = mTextPaint.measureText(text); 
float height = -mTextPaint.ascent() + mTextPaint.descent(); 

多行

然而,如果换行,你需要的高度,那么最好是使用StaticLayout。您提供宽度,然后您可以从StaticLayout获得高度。

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

新API

如果你想使用StaticLayout.Builder(可从API 23)的更新,你可以得到你的布局是这样的:

StaticLayout.Builder builder = StaticLayout.Builder.obtain(text, 0, text.length(), myTextPaint, width); 
StaticLayout myStaticLayout = builder.build(); 

您可以在除钉使用点符号的设置:

StaticLayout.Builder builder = StaticLayout.Builder.obtain(text, 0, text.length(), myTextPaint, width) 
     .setAlignment(Layout.Alignment.ALIGN_NORMAL) 
     .setLineSpacing(spacingMultiplier, spacingAddition) 
     .setIncludePad(includePadding) 
     .setMaxLines(5); 
StaticLayout myStaticLayout = builder.build(); 

在图像上书写文字

我可能会在将来扩大这个范围,但现在请参阅this post了解使用StaticLayout并返回位图的方法示例。

制作一个自定义的文本处理查看

下面是一个使用StaticLayout自定义视图的一个例子。它的行为像一个简单的TextView。当文字太长而不适合屏幕时,它会自动换行并增加其高度。

enter image description here

代码

MyView.java

public class MyView extends View { 

    String mText = "This is some text."; 
    TextPaint mTextPaint; 
    StaticLayout mStaticLayout; 

    // use this constructor if creating MyView programmatically 
    public MyView(Context context) { 
     super(context); 
     initLabelView(); 
    } 

    // this constructor is used when created from xml 
    public MyView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     initLabelView(); 
    } 

    private void initLabelView() { 
     mTextPaint = new TextPaint(); 
     mTextPaint.setAntiAlias(true); 
     mTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density); 
     mTextPaint.setColor(0xFF000000); 

     // default to a single line of text 
     int width = (int) mTextPaint.measureText(mText); 
     mStaticLayout = new StaticLayout(mText, mTextPaint, (int) width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0, false); 

     // New API alternate 
     // 
     // StaticLayout.Builder builder = StaticLayout.Builder.obtain(mText, 0, mText.length(), mTextPaint, width) 
     //  .setAlignment(Layout.Alignment.ALIGN_NORMAL) 
     //  .setLineSpacing(1, 0) // multiplier, add 
     //  .setIncludePad(false); 
     // mStaticLayout = builder.build(); 
    } 

    @Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
     // Tell the parent layout how big this view would like to be 
     // but still respect any requirements (measure specs) that are passed down. 

     // determine the width 
     int width; 
     int widthMode = MeasureSpec.getMode(widthMeasureSpec); 
     int widthRequirement = MeasureSpec.getSize(widthMeasureSpec); 
     if (widthMode == MeasureSpec.EXACTLY) { 
      width = widthRequirement; 
     } else { 
      width = mStaticLayout.getWidth() + getPaddingLeft() + getPaddingRight(); 
      if (widthMode == MeasureSpec.AT_MOST) { 
       if (width > widthRequirement) { 
        width = widthRequirement; 
        // too long for a single line so relayout as multiline 
        mStaticLayout = new StaticLayout(mText, mTextPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0, false); 
       } 
      } 
     } 

     // determine the height 
     int height; 
     int heightMode = MeasureSpec.getMode(heightMeasureSpec); 
     int heightRequirement = MeasureSpec.getSize(heightMeasureSpec); 
     if (heightMode == MeasureSpec.EXACTLY) { 
      height = heightRequirement; 
     } else { 
      height = mStaticLayout.getHeight() + getPaddingTop() + getPaddingBottom(); 
      if (heightMode == MeasureSpec.AT_MOST) { 
       height = Math.min(height, heightRequirement); 
      } 
     } 

     // Required call: set width and height 
     setMeasuredDimension(width, height); 
    } 

    @Override 
    protected void onDraw(Canvas canvas) { 
     super.onDraw(canvas); 
     // do as little as possible inside onDraw to improve performance 

     // draw the text on the canvas after adjusting for padding 
     canvas.save(); 
     canvas.translate(getPaddingLeft(), getPaddingTop()); 
     mStaticLayout.draw(canvas); 
     canvas.restore(); 
    } 
} 

activity_main.xml中

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:id="@+id/activity_main" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:padding="@dimen/activity_vertical_margin" 
    tools:context="com.example.layoutpractice.MainActivity"> 

    <com.example.layoutpractice.MyView 
     android:layout_centerHorizontal="true" 
     android:background="@color/colorAccent" 
     android:padding="10dp" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content"/> 
</RelativeLayout> 

注意

  • Thisthisthis是在学习如何做一个自定义的文本处理视图非常有用。

  • 请参阅Creating a View Class如果您想添加可以从代码或xml设置的自定义属性。