2017-06-05 2 views
1

So, wie die meisten von Ihnen wissen, gibt es keinen Text in einem TextView in Android rechtfertigen. Also habe ich eine benutzerdefinierte Textansicht erstellt, um das Problem zu umgehen. Aus irgendeinem Grund brechen jedoch manchmal bei einigen Geräten Interpunktionszeichen die Zeile aus irgendeinem Grund. Ich habe auf einem LG G3 und Emulator (Nexus 4 mit der neuesten Version) getestet und ein Komma "," zum Beispiel bricht die Begründung auf dem LG G3, aber nicht auf dem Emulator.Rechtfertigung von Text in einem TextView in Android

Wenn ich einen Padding Anfang und Ende (oder links und rechts) von mindestens 2 hinzufügen, ist das Problem gelöst. Das sieht mir sehr willkürlich aus.

Im Grunde war meine Logik, dass, um den Text zu rechtfertigen, ich die Breite des TextView selbst kennen müsste, konstruiere den Text in Zeilen, die maximal diese Länge haben. Dann, indem Sie die Anzahl der Leerzeichen in der Zeile und den verbleibenden leeren Platz finden, strecken Sie die Zeichen "" (Leerzeichen), die entsprechend den verbleibenden Pixeln (oder dem Platz in der Ansicht) skaliert werden sollen.

Es funktioniert fast perfekt, und die meiste Zeit unterstützt es auch RTL-Text.

here're einige Bilder des Textes (eine einfache lorem impsum) mit und ohne die störenden Markierungen (erste ist 4 auf Emulator nexus läuft 7.1.1, zweite ist auf LG G3 läuft v5.0) Text on emulator running nexus 4 running Text on LG G3 running android 5.0

Hier ist der Code:

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

ich würde es sehr schätzen jemand, der etwas Licht auf diesem verschütten kann.

+0

ist es gelöst oder nicht –

+0

ja, ich habe es selbst gelöst und es markiert als basierend auf einen der Links gelöst Sie gab. Schrieb es in der Antwort natürlich. – ShayR

Antwort

0

So, nach ein wenig mehr auf diese suchen: https://github.com/ufo22940268/android-justifiedtextview und Textview im Allgemeinen, entdeckte ich, dass mein Hauptproblem mein Ansatz war .

Der Ansatz der Skalierung der Breite der Zeichen "" war in der Theorie ein guter Ton, aber nach dieser Änderung ändert sich die Breite der Linie wieder, da die Breite der Linie NICHT die Summe ihrer Teile ist .

Ich habe meine Herangehensweise geändert und habe mich von dem obigen Link inspirieren lassen, und so zeichne ich in meinem neuen Ansatz jeden Charakter selbst, anstatt die ganze Linie zu zeichnen. Wenn der Text (basierend auf einem benutzerdefinierten booleschen Attribut "justify") gerechtfertigt werden muss, wird die Zeile gezeichnet und begründet, andernfalls wird nur die Linie gezeichnet.

Edit: Ich habe den Code jetzt geändert, so dass es auch RTL-Texte unterstützt. Ich werde den Code irgendwo in den nächsten Tagen hochladen.

Hier ist das Ergebnis: justify textview

Hier ist der Code:

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

    } 
} 

und die 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" /> 

Dank Aditya Vyas-Lakhan für die Links

0

BIBLIOTHEK: https://github.com/bluejamesbond/TextJustify-Android

STÜTZT: Android 2.0

SCREENSHOT enter image description here

+0

Ich habe das schon bei der Online-Suche gesehen. Zwei Gründe, die es nicht gut für mich ist: 1. Es unterstützt nicht Android> 5 und 2. Ich wollte es selbst als Übung – ShayR

+0

Schätzen Sie Ihre Begeisterung. Jeder ist hier, um nur neue Dinge zu lernen. Sie können es aber auch als Referenz verwenden, um eine eigene benutzerdefinierte Ansicht zu erstellen. –

+0

Ich schaue mir diese Bibliothek genauer an und obwohl sie cool aussieht, verwendet sie die ScrollView als Basis. Ich verwende TextView als Basis, damit ich alle anderen Aspekte von TextView genießen kann. Da TextView auch Unterstützung für das Scrollen bietet, wird kein ScrollView benötigt. – ShayR

0

Versuchen Sie, diese Art und Weise 5.x Text zu rechtfertigen, es funktioniert für mich

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

Ich sehe, dass meine Implementierung ein bisschen ähnlich der hier https://github.com/navabi/JustifiedTextView ist. Ich bekomme tatsächlich die Breite der Textansicht auf die gleiche Weise. Ich habe immer noch keine Ahnung, warum es auf einigen Geräten funktioniert und manche nicht. Ich habe es mit 6.x, 5.x und 7.x versucht und es scheint, als ob es funktioniert, wenn es will – ShayR

0

@ ShayR, kannst du bitte detaillierte Informationen darüber geben, wie man imp lege deine eigene Lösung.

Bitte mich nicht stört, bin ein bisschen neu in die Programmierung

Verwandte Themen