Как StaticLayout используется в Android?

Мне нужно создать свой собственный заказ TextView так что я узнал о StaticLayout рисовать текст на холсте. Это предпочтительнее использования Canvas.drawText() напрямую, или так говорится в документации. Тем не менее, документация не дает примеров того, как это сделать. Существует только смутная ссылка на StaticLayout.Builder быть более новым способом сделать это.

Я нашел пример здесь, но он кажется немного устаревшим.

Я наконец-то работал, хотя, как это сделать, поэтому я добавляю свое объяснение ниже.

2 ответа

Решение

StaticLayout ( аналогично DynamicLayout а такжеBoringLayout) используется для макета и рисования текста на холсте. Обычно используется для следующих задач:

  • Измерение размера многострочного текста после его размещения.
  • Рисование текста на растровом изображении.
  • Создание собственного представления, которое обрабатывает свой собственный текстовый макет (в отличие от создания составного представления со встроенным TextView).TextViewсам используетStaticLayout внутренне.

Измерение размера текста

Одна линия

Если у вас есть только одна строка текста, вы можете измерить ее Paintили жеTextPaint,

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

Написание текста на изображении

Я могу расширить это в будущем, но пока смотрите этот пост для примера метода, который использует StaticLayout и возвращает растровое изображение.

Создание пользовательского просмотра текста

Вот пример пользовательского представления с использованием StaticLayout, Ведет себя как простой TextView, Когда текст слишком длинный, чтобы поместиться на экране, он автоматически переносится на новую строку и увеличивает ее высоту.

Код

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>

Заметки

  • Это, это, и это было полезно для изучения того, как создать собственное представление для обработки текста.

  • См. Создание класса представления, если вы хотите добавить пользовательские атрибуты, которые можно установить из кода или xml.

Вот мое объяснение рисования многострочного текста на холсте.

Объявить объект Paint. Используйте TextPaint, который является расширением Paint.

TextPaint textPaint;

Инициализируйте объект Paint. Установите свой цвет, размер и т. Д.

textPaint = new TextPaint();
textPaint.setAntiAlias(true);
textPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
textPaint.setColor(Color.YELLOW);

Добавить функцию getTextHeight

private float getTextHeight(String text, Paint paint) {
    Rect rect = new Rect();
    paint.getTextBounds(text, 0, text.length(), rect);
    return rect.height();
}

в вашей функции onDraw поместите следующие строки, как это

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

    String text = "This is a lengthy text. We have to render this properly. If layout mess users review will mess. Is that so ? ";

    Rect bounds = canvas.getClipBounds();

    StaticLayout sl = new StaticLayout(text, textPaint, bounds.width(),
            Layout.Alignment.ALIGN_CENTER, 1, 1, true);

    canvas.save();

    //calculate X and Y coordinates - In this case we want to draw the text in the
    //center of canvas so we calculate
    //text height and number of lines to move Y coordinate to center.
    float textHeight = getTextHeight(text, textPaint);
    int numberOfTextLines = sl.getLineCount();
    float textYCoordinate = bounds.exactCenterY() -
            ((numberOfTextLines * textHeight) / 2);

    //text will be drawn from left
    float textXCoordinate = bounds.left;

    canvas.translate(textXCoordinate, textYCoordinate);

    //draws static layout on canvas
    sl.draw(canvas);
    canvas.restore();
}

Вежливость идет на почту КОК

Другие вопросы по тегам