Pertanyaan Bagaimana StaticLayout digunakan di Android?


Saya perlu membangun kebiasaan saya sendiri TextView jadi saya telah belajar tentang StaticLayout menggambar teks di kanvas. Ini lebih baik digunakan Canvas.drawText() langsung, atau begitu dokumentasi kata. Namun, dokumentasi tidak memberikan contoh bagaimana melakukannya. Hanya ada referensi yang tidak jelas StaticLayout.Builder menjadi cara baru untuk melakukannya.

Saya menemukan sebuah contoh sini tetapi tampaknya sedikit tertanggal.

Saya akhirnya bekerja meskipun bagaimana melakukannya sehingga saya menambahkan penjelasan saya di bawah ini.


10
2018-01-21 13:26


asal


Jawaban:


StaticLayout (mirip dengan DynamicLayout dan BoringLayout) digunakan untuk menata dan menggambar teks pada kanvas. Ini biasanya digunakan untuk tugas-tugas berikut:

  • Mengukur seberapa besar teks multilina akan menjadi setelah ditata.
  • Menggambar teks pada gambar bitmap.
  • Membuat tampilan khusus yang menangani tata letak teksnya sendiri (sebagai lawan dari membuat tampilan gabungan dengan yang disematkan TextView). TextView itu sendiri menggunakan StaticLayout  secara internal.

Mengukur ukuran teks

Garis tunggal

Jika Anda hanya memiliki satu baris teks, Anda bisa mengukurnya Paint atau 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();

Multiline

Namun, jika ada pembungkus garis dan Anda perlu ketinggiannya, maka lebih baik menggunakan a StaticLayout. Anda memberikan lebar dan kemudian Anda bisa mendapatkan tinggi dari 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 Baru

Jika Anda ingin menggunakan yang lebih baru StaticLayout.Builder (tersedia dari API 23), Anda bisa mendapatkan tata letak seperti ini:

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

Anda dapat menerapkan pengaturan tambahan menggunakan notasi titik:

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

Menulis teks pada suatu gambar

Saya dapat memperluas ini lebih banyak di masa depan, tetapi untuk sekarang lihat posting ini untuk contoh metode yang menggunakan StaticLayout dan mengembalikan bitmap.

Membuat tampilan penanganan teks kustom

Berikut ini contoh tampilan kustom menggunakan a StaticLayout. Itu berperilaku seperti sederhana TextView. Ketika teks terlalu panjang untuk muat di layar, itu secara otomatis membungkus garis dan meningkatkan tingginya.

enter image description here

Kode 

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>

Catatan

  • Ini, ini, dan ini berguna dalam mempelajari cara membuat tampilan penanganan teks kustom.

  • Lihat Membuat Kelas Tampilan jika Anda ingin menambahkan atribut khusus yang dapat diatur dari kode atau xml.


49
2018-01-21 13:26