web-dev-qa-db-ja.com

android)のTextView内のテキストの位置揃え

したがって、ほとんどの人が知っているように、AndroidのTextView内に正当化するテキストはありません。そこで、問題を回避するためにカスタムTextViewを作成しました。ただし、一部のデバイスでは、何らかの理由で句読点が何らかの理由で改行されることがあります。 LG G3とエミュレーター(最新バージョンを実行しているNexus 4)とコンマ "、"でテストしました。たとえば、LG G3では正当化されませんが、エミュレーターでは壊れません。

少なくとも2のパディングの開始と終了(または左右)を追加すると、問題は解決します。これは私には非常に恣意的に見えます。

基本的に、私の論理は、テキストを正当化するために、TextView自体の幅を知り、テキストを最大でその長さの行に構成する必要があるというものでした。次に、行内のスペースの数と残りの空のスペースを見つけて、残りのピクセル(またはビュー内のスペース)に従ってスケーリングされる ""(スペース)文字を引き伸ばします。

ほぼ完全に機能し、ほとんどの場合、RTLテキストもサポートしています。

これは、問題のあるマークがある場合とない場合のテキスト(単純なlorem impsum)の写真です(最初の写真は7.1.1を実行しているエミュレーターネクサス4にあり、2番目の写真はv5.0を実行しているLG G3にあります)- Text on emulator running nexus 4 runningText on LG G3 running Android 5.0

コードは次のとおりです。

public class DTextView extends AppCompatTextView {

    private boolean justify;

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

    public DTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(attrs);
    }

    public DTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }

    private void setJustify(boolean justify) {
        this.justify = justify;
        if (justify) {
            justify();
        }
    }

    private void init(@Nullable AttributeSet attrs) {
        TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.DTextView, 0, 0);
        justify = ta.getBoolean(R.styleable.DTextView_justify, false);

        ta.recycle();
    }

    private SpannableStringBuilder justifyText() {

        String[] words = getText().toString().split(" ");
        setText("");

        int maxLineWidth = getWidth() - getPaddingLeft() - getPaddingRight();

        SpannableStringBuilder justifiedTextSpannable = new SpannableStringBuilder();

        //This will build the new text with the lines rearranged so that they will have a width
        //bigger than the View's own width
        ArrayList<String> lines = new ArrayList<>(0);
        String line = "";
        for (String Word : words) {
            if (getWordWidth(line + Word) < maxLineWidth) {
                line += Word + " ";
            } else {
                line = line.substring(0, line.length() - 1);
                lines.add(line);
                line = Word + " ";
            }
        }
        //Add the last line
        lines.add(line);

        for (int i = 0; i < lines.size() - 1; i++) {
            justifiedTextSpannable.append(justifyLine(lines.get(i), maxLineWidth));
            justifiedTextSpannable.append("\n");
        }

        justifiedTextSpannable.append(lines.get(lines.size() - 1));


        return justifiedTextSpannable;
    }

    private SpannableString justifyLine(String line, float maxWidth) {

        SpannableString sLine = new SpannableString(line);
        float spaces = line.split(" ").length - 1;

        float spaceCharSize = getWordWidth(" ");
        float emptySpace = maxWidth - getWordWidth(line);
        float newSpaceSize = (emptySpace / spaces) + spaceCharSize;
        float scaleX = newSpaceSize / spaceCharSize;

        for (int i = 0; i < line.length(); i++) {
            if (line.charAt(i) == ' ') {
                sLine.setSpan(new ScaleXSpan(scaleX), i, i + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }

        return sLine;
    }

    private void justify() {
        justify = false;
        setText(justifyText());
        invalidate();
    }

    private float getWordWidth(String Word) {
        return getPaint().measureText(Word);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (!justify)
            super.onDraw(canvas);
        else
            justify();
    }
}

これに光を当てることができる人に感謝します。

5
ShayR

したがって、これをもう少し調べた後: https://github.com/ufo22940268/Android-justifiedtextview およびTextView全般、私の主な問題は私のアプローチであることがわかりました。

「」文字の幅をスケーリングするアプローチを使用することは理論的には適切でしたが、そうすると、線の幅はその部分の合計ではないように見えるため、線の幅は再び変化します。

私はアプローチを変更し、上のリンクからインスピレーションを得たので、新しいアプローチでは、線全体を描くのではなく、各キャラクターを単独で描きます。テキストを(カスタムの「ジャスティファイ」ブール属性に基づいて)位置揃えする必要がある場合は、線を描画して位置合わせします。それ以外の場合は、線を描画します。

編集:RTLテキストもサポートするようにコードを変更しました。数日中にコードをどこかにアップロードします。

結果は次のとおりです。 justify textview

コードは次のとおりです。

public class DTextView extends AppCompatTextView {


    private boolean justify;
    private float textAreaWidth;
    private float spaceCharSize;
    private float lineY;

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

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

    public DTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }

    /**
     * @param attrs the attributes from the xml
     *              This function loads all the parameters from the xml
     */
    private void init(AttributeSet attrs) {

        TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.DTextView, 0, 0);

        justify = ta.getBoolean(R.styleable.DTextView_justify, false);

        ta.recycle();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        drawText(canvas);
    }

    private void drawText(Canvas canvas) {
        TextPaint Paint = getPaint();
        Paint.setColor(getCurrentTextColor());
        Paint.drawableState = getDrawableState();
        textAreaWidth = getMeasuredWidth() - (getPaddingLeft() + getPaddingRight());

        spaceCharSize = Paint.measureText(" ");

        String text = getText().toString();
        lineY = getTextSize();

        Layout textLayout = getLayout();

        if (textLayout == null)
            return;

        Paint.FontMetrics fm = Paint.getFontMetrics();
        int textHeight = (int) Math.ceil(fm.descent - fm.ascent);
        textHeight = (int) (textHeight * getLineSpacingMultiplier() + textLayout.getSpacingAdd());

        for (int i = 0; i < textLayout.getLineCount(); i++) {

            int lineStart = textLayout.getLineStart(i);
            int lineEnd = textLayout.getLineEnd(i);

            float lineWidth = StaticLayout.getDesiredWidth(text, lineStart, lineEnd, Paint);
            String line = text.substring(lineStart, lineEnd);

            if (line.charAt(line.length() - 1) == ' ') {
                line = line.substring(0, line.length() - 1);
            }

            if (justify && i < textLayout.getLineCount() - 1) {
                drawLineJustified(canvas, line, lineWidth);
            } else {
                canvas.drawText(line, 0, lineY, Paint);
            }

            lineY += textHeight;
        }

    }

    private void drawLineJustified(Canvas canvas, String line, float lineWidth) {
        TextPaint Paint = getPaint();

        float emptySpace = textAreaWidth - lineWidth;
        int spaces = line.split(" ").length - 1;
        float newSpaceSize = (emptySpace / spaces) + spaceCharSize;

        float charX = 0;

        for (int i = 0; i < line.length(); i++) {
            String character = String.valueOf(line.charAt(i));
            float charWidth = StaticLayout.getDesiredWidth(character, Paint);
            if (!character.equals(" ")) {
                canvas.drawText(character, charX, lineY, Paint);
            }

            if (character.equals(" ") && i != line.length() - 1)
                charX += newSpaceSize;
            else
                charX += charWidth;
        }

    }
}

およびXML:

<il.co.drapp.views.text.DTextView
                Android:layout_width="match_parent"
                Android:inputType="textMultiLine|textNoSuggestions"
                app:justify="true"
                Android:id="@+id/justifyText"
                Android:text="@string/article_dummy_text"
                Android:layout_height="wrap_content" />

リンクをくれたAdityaVyas-Lakhanに感謝します

3
ShayR

[〜#〜]ライブラリ[〜#〜]https://github.com/bluejamesbond/TextJustify-Android

[〜#〜]サポート[〜#〜]:Android 2.0〜5.X

[〜#〜]スクリーンショット[〜#〜]enter image description here

0
Amit Thakkar

テキストを正当化するためにこの方法を試してください、それは私のために働きます

public class MainActivity extends Activity {

    private JustifiedTextView mJTv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mJTv=(JustifiedTextView) findViewById(R.id.activity_main_jtv_text);
        mJTv.setText(getResources().getString(R.string.test));
        mJTv.setTextSize(TypedValue.COMPLEX_UNIT_SP,20);
        mJTv.setLineSpacing(15);
        mJTv.setBackgroundColor(Color.RED);
        mJTv.setAlignment(Align.LEFT);
        mJTv.setTypeFace(Typeface.createFromAsset(getAssets(), "fonts/naskh_bold.ttf"));

    }
}

XML

<ScrollView xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:tools="http://schemas.Android.com/tools"
    Android:id="@+id/activity_main_jsv"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent" >

    <ir.noghteh.JustifiedTextView
        Android:id="@+id/activity_main_jtv_text"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:layout_gravity="right"
        Android:padding="25dp"
        xmlns:noghteh="http://noghteh.ir"
        noghteh:text="@string/hello_world"
        noghteh:textColor="@color/text"
        noghteh:textSize="18sp"
       >
    </ir.noghteh.JustifiedTextView>

</ScrollView>

https://github.com/navabi/JustifiedTextView

https://github.com/ufo22940268/Android-justifiedtextview

https://github.com/PareshMayani/Android-JustifyText

0