Обоснуйте текст в приложении для Android с помощью WebView, но представляя интерфейс, подобный TextView?


Я ищу простой способ забыть, что я использую WebView, чтобы иметь оправданный текст в моем TextView. Может быть, кто-то сделал для этого собственный вид? Я хорошо знаю, что могу сделать что-то вроде этого:

 WebView view = new WebView(this);    
         view.loadData("my html with text justification","text/html","utf-8");
Но это становится уродливым, когда вы хотите установить размер, цвет или другие общие свойства TextView. Должен быть более удобный способ сделать это.
6 7

6 ответов:

Признаюсь, это действовало мне на нервы. Мне нравится, когда TextViews выглядит как TextViews в коде, и даже если я использую WebView в качестве средства достижения выравнивания текста:оправданное форматирование, я не хочу смотреть на это таким образом.

Я создал пользовательское представление (уродливое, возможно, плохое), которое реализует методы, которые я обычно использую из TextView, и изменяет содержимое веб-представления, чтобы отразить эти изменения. Является ли это полезным для кого-то еще или потенциальной опасностью, я действительно не знаю. знаете, для меня это работает, я использовал его в нескольких проектах и не сталкивался ни с какими проблемами. Единственное незначительное неудобство заключается в том, что я предполагаю, что это большая плата за память, но ничего страшного, если это только один или два (поправьте меня, если я ошибаюсь).

Результат следующий:

Введите описание изображения здесь

И код для установки его программно так прост, как это:

 JustifiedTextView J = new JustifiedTextView();
                   J.setText("insert your text here");

Конечно, было бы глупо оставлять это так, поэтому я также добавил методы для изменения размер шрифта и цвет шрифта, которые в основном все, что я использую TextViews для. То есть я могу сделать что-то вроде этого:

 JustifiedTextView J = new JustifiedTextView();
                   J.setText("insert your text here");
                   J.setTextColor(Color.RED);
                   J.setTextSize(30);

И получаем следующий результат (изображения обрезаются):

Введите описание изображения здесь

Но, это не для того, чтобы показать нам, как это выглядит, это для того, чтобы поделиться, как вы это сделали!

Я знаю, я знаю. Вот полный код. Он также устраняет проблемы при установке прозрачного фона и загрузке строк UTF-8 в представление. Смотрите комментарии в reloadData () для подробности.

public class JustifiedTextView extends WebView{
    private String core      = "<html><body style='text-align:justify;color:rgba(%s);font-size:%dpx;margin: 0px 0px 0px 0px;'>%s</body></html>";
    private String textColor = "0,0,0,255";
    private String text      = "";
    private int textSize     = 12;
    private int backgroundColor=Color.TRANSPARENT;

    public JustifiedTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.setWebChromeClient(new WebChromeClient(){});
    }

    public void setText(String s){
        this.text = s;
        reloadData();
    }

    @SuppressLint("NewApi")
    private void reloadData(){

        // loadData(...) has a bug showing utf-8 correctly. That's why we need to set it first.
        this.getSettings().setDefaultTextEncodingName("utf-8");

        this.loadData(String.format(core,textColor,textSize,text), "text/html","utf-8");

        // set WebView's background color *after* data was loaded.
        super.setBackgroundColor(backgroundColor);

        // Hardware rendering breaks background color to work as expected.
        // Need to use software renderer in that case.
        if(android.os.Build.VERSION.SDK_INT >= 11)
            this.setLayerType(WebView.LAYER_TYPE_SOFTWARE, null);
    }

    public void setTextColor(int hex){
        String h = Integer.toHexString(hex);
        int a = Integer.parseInt(h.substring(0, 2),16);
        int r = Integer.parseInt(h.substring(2, 4),16);
        int g = Integer.parseInt(h.substring(4, 6),16);
        int b = Integer.parseInt(h.substring(6, 8),16);
        textColor = String.format("%d,%d,%d,%d", r, g, b, a); 
        reloadData();
    }

    public void setBackgroundColor(int hex){
        backgroundColor = hex;
        reloadData();
    }

    public void setTextSize(int textSize){
        this.textSize = textSize;
        reloadData();
    }
}

Без webview решение таково: https://github.com/merterhk/JustifiedTextView

import java.util.ArrayList;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.text.TextPaint;
import android.view.View;

public class JustifiedTextView extends View {
        String text;
        ArrayList<Line> linesCollection = new ArrayList<Line>();
        TextPaint textPaint;
        Typeface font;
        int textColor;
        float textSize = 42f, lineHeight = 57f, wordSpacing = 15f, lineSpacing = 15f;
        float onBirim, w, h;
        float leftPadding, rightPadding;

        public JustifiedTextView(Context context, String text) {
                super(context);
                this.text = text;
                init();
        }

        private void init() {
                textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
                textColor = Color.BLACK;
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);

                if (font != null) {
                        font = Typeface.createFromAsset(getContext().getAssets(), "font/Trykker-Regular.ttf");
                        textPaint.setTypeface(font);
                }
                textPaint.setColor(textColor);

                int minw = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();
                w = resolveSizeAndState(minw, widthMeasureSpec, 1);
                h = MeasureSpec.getSize(widthMeasureSpec);

                onBirim = 0.009259259f * w;
                lineHeight = textSize + lineSpacing;
                leftPadding = 3 * onBirim + getPaddingLeft();
                rightPadding = 3 * onBirim + getPaddingRight();

                textPaint.setTextSize(textSize);

                wordSpacing = 15f;
                Line lineBuffer = new Line();
                this.linesCollection.clear();
                String[] lines = text.split("\n");
                for (String line : lines) {
                        String[] words = line.split(" ");
                        lineBuffer = new Line();
                        float lineWidth = leftPadding + rightPadding;
                        float totalWordWidth = 0;
                        for (String word : words) {
                                float ww = textPaint.measureText(word) + wordSpacing;
                                if (lineWidth + ww + (lineBuffer.getWords().size() * wordSpacing) > w) {// is
                                        lineBuffer.addWord(word);
                                        totalWordWidth += textPaint.measureText(word);
                                        lineBuffer.setSpacing((w - totalWordWidth - leftPadding - rightPadding) / (lineBuffer.getWords().size() - 1));
                                        this.linesCollection.add(lineBuffer);
                                        lineBuffer = new Line();
                                        totalWordWidth = 0;
                                        lineWidth = leftPadding + rightPadding;
                                } else {
                                        lineBuffer.setSpacing(wordSpacing);
                                        lineBuffer.addWord(word);
                                        totalWordWidth += textPaint.measureText(word);
                                        lineWidth += ww;
                                }
                        }
                        this.linesCollection.add(lineBuffer);
                }
                setMeasuredDimension((int) w, (int) ((this.linesCollection.size() + 1) * lineHeight + (10 * onBirim)));
        }

        @Override
        protected void onDraw(Canvas canvas) {
                super.onDraw(canvas);
                canvas.drawLine(0f, 10f, getMeasuredWidth(), 10f, textPaint);
                float x, y = lineHeight + onBirim;
                for (Line line : linesCollection) {
                        x = leftPadding;
                        for (String s : line.getWords()) {
                                canvas.drawText(s, x, y, textPaint);
                                x += textPaint.measureText(s) + line.spacing;
                        }
                        y += lineHeight;
                }
        }

        public String getText() {
                return text;
        }

        public void setText(String text) {
                this.text = text;
        }

        public Typeface getFont() {
                return font;
        }

        public void setFont(Typeface font) {
                this.font = font;
        }

        public float getLineHeight() {
                return lineHeight;
        }

        public void setLineHeight(float lineHeight) {
                this.lineHeight = lineHeight;
        }

        public float getLeftPadding() {
                return leftPadding;
        }

        public void setLeftPadding(float leftPadding) {
                this.leftPadding = leftPadding;
        }

        public float getRightPadding() {
                return rightPadding;
        }

        public void setRightPadding(float rightPadding) {
                this.rightPadding = rightPadding;
        }

        public void setWordSpacing(float wordSpacing) {
                this.wordSpacing = wordSpacing;
        }

        public float getWordSpacing() {
                return wordSpacing;
        }

        public float getLineSpacing() {
                return lineSpacing;
        }

        public void setLineSpacing(float lineSpacing) {
                this.lineSpacing = lineSpacing;
        }

        class Line {
                ArrayList<String> words = new ArrayList<String>();
                float spacing = 15f;

                public Line() {
                }

                public Line(ArrayList<String> words, float spacing) {
                        this.words = words;
                        this.spacing = spacing;
                }

                public void setSpacing(float spacing) {
                        this.spacing = spacing;
                }

                public float getSpacing() {
                        return spacing;
                }

                public void addWord(String s) {
                        words.add(s);
                }

                public ArrayList<String> getWords() {
                        return words;
                }
        }
}

Всего за три шага вы можете обосновать текст веб-представления.

1)

// Justify tag
String justifyTag = "<html><body style='text-align:justify;'>%s</body></html>";

2)

// Concatenate your string with the tag to Justify it
String dataString = String.format(Locale.US, justifyTag, "my html with text justification");

3)

// Load the data in the web view
webView.loadDataWithBaseURL("", dataString, "text/html", "UTF-8", "");

Это тот же класс JustifiedTextView, который был дан Хуаном (и отредактирован мной), но расширен для работы с пользовательскими XML-атрибутами, которые можно использовать в xml-файлах макета. Даже редактор макетов Eclipse покажет ваши пользовательские атрибуты в таблице атрибутов, что здорово. Я помещаю это в дополнительный ответ, на случай, если вы хотите сохранить все в чистоте и не нуждаетесь в атрибутах xml.

public class JustifiedTextView extends WebView{
    private String core      = "<html><body style='text-align:justify;color:rgba(%s);font-size:%dpx;margin: 0px 0px 0px 0px;'>%s</body></html>";
    private String text;
    private int textColor;
    private int backgroundColor;
    private int textSize;

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

    public JustifiedTextView(Context context, AttributeSet attrs, int i) {
        super(context, attrs, i);
        init(attrs);
    }

    @SuppressLint("NewApi")
    public JustifiedTextView(Context context, AttributeSet attrs, int i, boolean b) {
        super(context, attrs, i, b);
        init(attrs);
    }

    private void init(AttributeSet attrs) { 
        TypedArray a=getContext().obtainStyledAttributes(
                 attrs,
                 R.styleable.JustifiedTextView);

        text = a.getString(R.styleable.JustifiedTextView_text);
        if(text==null) text="";
        textColor = a.getColor(R.styleable.JustifiedTextView_textColor, Color.BLACK);
        backgroundColor = a.getColor(R.styleable.JustifiedTextView_backgroundColor, Color.TRANSPARENT);
        textSize = a.getInt(R.styleable.JustifiedTextView_textSize, 12);

        a.recycle();

        this.setWebChromeClient(new WebChromeClient(){});
        reloadData();
    }

    public void setText(String s){
        if(s==null)
            this.text="";
        else
            this.text = s;
        reloadData();
    }

    @SuppressLint("NewApi")
    private void reloadData(){

        if(text!=null) {
            String data = String.format(core,toRgba(textColor),textSize,text);
            Log.d("test", data);
            this.loadDataWithBaseURL(null, data, "text/html","utf-8", null);
        }

        // set WebView's background color *after* data was loaded.
        super.setBackgroundColor(backgroundColor);

        // Hardware rendering breaks background color to work as expected.
        // Need to use software renderer in that case.
        if(android.os.Build.VERSION.SDK_INT >= 11)
            this.setLayerType(WebView.LAYER_TYPE_SOFTWARE, null);
    }

    public void setTextColor(int hex){
        textColor = hex; 
        reloadData();
    }

    public void setBackgroundColor(int hex){
        backgroundColor = hex;
        reloadData();
    }

    public void setTextSize(int textSize){
        this.textSize = textSize;
        reloadData();
    }

    private String toRgba(int hex) {
        String h = Integer.toHexString(hex);
        int a = Integer.parseInt(h.substring(0, 2),16);
        int r = Integer.parseInt(h.substring(2, 4),16);
        int g = Integer.parseInt(h.substring(4, 6),16);
        int b = Integer.parseInt(h.substring(6, 8),16);
        return String.format("%d,%d,%d,%d", r, g, b, a); 
    }
}

Либо добавьте это как justified_text_view_attr.xml в папку res/values/ или слейте ее в ваши существующие attrs.xml:

<?xml version="1.0" encoding="utf-8"?>                                                                               
<resources>                                                                                                          
    <declare-styleable name="JustifiedTextView">                                                                     
        <attr name="text" format="string" localization="suggested"/>                                                 
        <attr name="textColor" format="color|reference" />                                                           
        <attr name="backgroundColor" format="color|reference" />                                                     
        <attr name="textSize" format="integer" min="1" />                                                            
    </declare-styleable>
</resources>                         

Не стесняйтесь редактировать, если вы найдете какие-либо ошибки.

Я верю в эту простейшую форму. И я работал отлично

package domo.suichbt.util;

import android.content.Context;
import android.text.Html;
import android.util.AttributeSet;
import android.widget.TextView;

public class JustifiedTextView extends TextView
{
    private final String CORE_TEMPLATE = "<html><body style='text-

align:justify;margin: 0px 0px 0px 0px;'>%s</body></html>";  

public JustifiedTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
    setText(Html.fromHtml(String.format(CORE_TEMPLATE,getText())));
}

public JustifiedTextView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    setText(Html.fromHtml(String.format(CORE_TEMPLATE,getText())));
}

public JustifiedTextView(Context context) {
    super(context);
    setText(Html.fromHtml(String.format(CORE_TEMPLATE,getText())));
}

public JustifiedTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
    setText(Html.fromHtml(String.format(CORE_TEMPLATE,getText())));
}
}

Вставить пример xml

    <domo.suichbt.util.JustifiedTextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/sw_titulo"
    android:singleLine="false">
</domo.suichbt.util.JustifiedTextView>

Взгляните на эту ссылку. Он использует WebView, чтобы быть связкой, чтобы полностью оправдать текст флажка в Android. Он также может быть использован точно так же в TextView, так как каждый флажок фактически является TextView и кнопкой. http://www.collegemobile.com/2014/09/justify-text-android-checkbox/