2012-08-12 10 views
7

Szukam prosty sposób, aby zapomnieć, że używam WebView, aby mieć usprawniony tekst w moim TextView. Czy ktoś zrobił niestandardowy widok do tego? Jestem świadomy, że mogę zrobić coś takiego:Wyjaśnij tekst w aplikacji na Androida przy użyciu WebView, ale z interfejsem podobnym do TextView?

WebView view = new WebView(this);  
     view.loadData("my html with text justification","text/html","utf-8"); 

Ale robi się brzydkie, gdy chcesz ustawić rozmiar, kolor lub inne typowe właściwości TextView. Musi być wygodniejszy sposób na zrobienie tego.

Odpowiedz

19

Podejmowałam się nerwów, przyznaję. Lubię kod TextViews, który wygląda jak TextViews w kodzie, a nawet jeśli używam WebView jako środka do uzyskania wyrównania tekstu wyrównanego: nie chcę na to patrzeć w ten sposób.

Utworzono niestandardowy widok (brzydki, prawdopodobnie zły), który implementuje metody, które zwykle używam z TextView i modyfikuje zawartość WebView, aby odzwierciedlić te zmiany. Wszystko, co jest przydatne dla kogoś innego lub potencjalne zagrożenie Naprawdę nie wiem, dla mnie działa, użyłem go w kilku projektach i nie napotkaliśmy żadnych problemów. Jedyną drobną niedogodnością jest to, że zakładam, że jest to większa pamięć, ale nie ma się czym martwić, jeśli to tylko jeden lub dwa (popraw mnie, jeśli się mylę).

Wynik jest następujący:

enter image description here

a kod na ustawienie go programowo jest tak proste, jak to:

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

Oczywiście byłoby głupie, aby pozostawić go jak tak więc dodałem również metody zmiany rozmiaru czcionki i koloru czcionki, które są w zasadzie wszystkim, do czego używam TextView. Czyli mogę zrobić coś takiego:

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

i uzyskać następujący wynik (obrazy są przycinane):

enter image description here

Ale nie jest to, aby pokazać nam, jak to wygląda, to do podziel się tym, jak to zrobiłeś!

Wiem, wiem. Oto pełny kod. Dotyczy także problemów podczas ustawiania przezroczystego tła i ładowania łańcuchów znaków UTF-8 do widoku. Zobacz komentarze w reloadData(), aby poznać szczegóły.

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(); 
    } 
} 
+1

Jeśli użyjemy tekst WebView wziąć trochę czasu, aby wyświetlić. W moim przypadku obraz tła jest wyświetlany jako pierwszy i po 2 sekundach wyświetlania tekstu. Jak pokonać ten problem? –

+2

i czy można ustawić czcionkę w widoku tekstowym? dzięki – Igor

+0

To jest dobre rozwiązanie dla widoków, które nie będą wymagały użycia pamięci, na przykład nie jest to dobry pomysł przy użyciu widoku sieciowego (to) wewnątrz listview będzie zużywać dużo pamięci i Twoja aplikacja będzie reagować trochę wolniej niż przy użyciu widoku tekstowego. – superUser

2

Jest to ta sama klasa JustifiedTextView podane przez Juan (i edytowane przeze mnie), ale przedłużony do pracy z niestandardowych atrybutów XML można użyć w układzie plików XML. Nawet edytor układu Eclipse pokaże twoje niestandardowe atrybuty w tabeli atrybutów, co jest fajne. Dodaję to do dodatkowej odpowiedzi, na wypadek gdybyś chciał zachować rzeczy w czystości i nie potrzebował atrybutów 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); 
    } 
} 

Albo dodać to jako justified_text_view_attr.xml do swojej RES/Wartości/folderu, lub połączyć go z istniejącymi 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>       

Możesz edytować, jeśli znajdziesz jakieś błędy.

+0

Bardzo ładne @sulai –

+0

Czy mógłbyś dać pomysł, jak zaimplementować metodę setTypeface() dla niestandardowego widoku ..? dzięki – Droidman

+0

Ponieważ typ czcionki jest zdefiniowany przez html w 'JustifiedTextView', musisz przetłumaczyć' Kroje pisma 'na odpowiednio html-tags lub atrybuty css. W przypadku 'Typeface.BOLD' (i podobnego), jest to łatwe do zrobienia. Aby zmienić styl czcionki, możesz użyć danej rodziny czcionek i spróbować użyć [css atrybut 'font-family'] (http://de.selfhtml.org/css/eigenschaften/schrift.htm#font_family), ale należy pamiętać, że wynik może być inny niż zwykły 'TextView.setTypeface()'. W przypadku kroju pisma utworzonego z pliku, myślę, że nie można go załadować do 'JustifiedTextView'. – sulai

6

Bez rozwiązania Webview jest: 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; 
       } 
     } 
} 
+3

Podczas gdy ten link może odpowiedzieć na pytanie, lepiej umieścić tutaj istotne części odpowiedzi i podać link do odsyłacza. Odpowiedzi dotyczące linków mogą stać się nieprawidłowe, jeśli strona z linkami się zmieni. – Szymon

+0

Dodano kod źródłowy. – Merter

+0

Czy to działa dla języków RTL? –

0

Wierzę w tę najprostszą formę. I działało idealnie

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

przykład Włóż 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> 
+2

To nie działa. – Mbt925

2

W ciągu zaledwie trzech krokach można uzasadnić zobaczyć web tekst.

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", ""); 
Powiązane problemy