Comment obtenez-vous le texte d'un TextView
à justifier (avec un texte affleurant à gauche et à droite)?
J'ai trouvé une solution possible ici , mais cela ne fonctionne pas (même si vous changez vertical-center en center_vertical, etc.).
Je ne crois pas que Android prenne en charge la justification complète.
UPDATE 2018-01-01 : Android 8.0+ prend en charge modes de justification avec TextView
.
La réponse @CommonsWare est correcte. Android ne prend pas en charge la "justification complète" (ou simplement la "justification", comme il est parfois désigné de manière ambiguë).
Cependant, Android prend en charge l '"alignement du texte à gauche/à droite". Voir l'article de Wikipédia sur Justification pour la distinction. Beaucoup de gens considèrent que le concept de "justification" englobe la justification complète ainsi que l'alignement gauche/droite du texte, ce qu'ils recherchent quand ils veulent faire l'alignement du texte gauche/droite. Cette réponse explique comment réaliser l'alignement du texte gauche/droite.
Il est possible d’obtenir l’alignement du texte à l’échelle gauche/droite (par opposition à la justification complète, selon la question posée). Pour illustrer mon propos, j'utiliserai comme exemple un formulaire de base à 2 colonnes (étiquettes dans la colonne de gauche et champs de texte dans la colonne de droite). Dans cet exemple, le texte dans les étiquettes de la colonne de gauche sera aligné à droite de manière à ce qu'il apparaisse au même niveau que leurs champs de texte dans la colonne de droite.
Dans la présentation XML, vous pouvez aligner les éléments TextView eux-mêmes (la colonne de gauche) sur la droite en ajoutant l'attribut suivant dans toutes les vues TextViews:
<TextView
...
Android:layout_gravity="center_vertical|end">
...
</TextView>
Toutefois, si le texte est enroulé sur plusieurs lignes, il restera aligné à gauche dans le TextView. L'ajout de l'attribut suivant rend le texte réel aligné à droite dans le TextView:
<TextView
...
Android:gravity="end">
...
</TextView>
Ainsi, l'attribut gravity indique comment aligner le texte à l'intérieur du TextView layout_gravity spécifie comment aligner/mettre en forme l'élément TextView lui-même.
Pour justifier le texte dans Android j'ai utilisé WebView
setContentView(R.layout.main);
WebView view = new WebView(this);
view.setVerticalScrollBarEnabled(false);
((LinearLayout)findViewById(R.id.inset_web_view)).addView(view);
view.loadData(getString(R.string.hello), "text/html; charset=utf-8", "utf-8");
et html.
<string name="hello">
<![CDATA[
<html>
<head></head>
<body style="text-align:justify;color:gray;background-color:black;">
Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Nunc pellentesque, urna
nec hendrerit pellentesque, risus massa
</body>
</html>
]]>
</string>
Je ne peux pas encore télécharger des images pour le prouver, mais "ça marche pour moi".
Nous avons créé une classe simple pour cela. Il existe actuellement deux méthodes pour réaliser ce que vous recherchez. Les deux nécessitent NO WEBVIEW et SUPPORTS SPANNABLES .
BIBLIOTHÈQUE: https://github.com/bluejamesbond/TextJustify-Android
PREND EN CHARGE: Android 2.0 à 5.X
SETUP
// Please visit Github for latest setup instructions.
CAPTURE D'ÉCRAN
TextView
dans Android O
offre une justification complète (nouvel alignement typographique).
Tu as juste besoin de faire ça,
textView.setJustificationMode(JUSTIFICATION_MODE_INTER_Word);
la valeur par défaut est JUSTIFICATION_MODE_NONE
.
Vous pouvez utiliser le projet JustifiedTextView for Android dans github. Il s'agit d'une vue personnalisée qui simule un texte justifié pour vous. Il supporte Android 2.0+ et les langues de droite à gauche.
J'écris un widget basé sur textview natif pour le faire.
J'ai trouvé un moyen de résoudre ce problème, mais cela n'a peut-être pas beaucoup de grâce, mais l'effet n'est pas mauvais.
Son principe est de remplacer les espaces de chaque ligne par ImageSpan à largeur fixe (la couleur est transparente).
public static void justify(final TextView textView) {
final AtomicBoolean isJustify = new AtomicBoolean(false);
final String textString = textView.getText().toString();
final TextPaint textPaint = textView.getPaint();
final SpannableStringBuilder builder = new SpannableStringBuilder();
textView.post(new Runnable() {
@Override
public void run() {
if (!isJustify.get()) {
final int lineCount = textView.getLineCount();
final int textViewWidth = textView.getWidth();
for (int i = 0; i < lineCount; i++) {
int lineStart = textView.getLayout().getLineStart(i);
int lineEnd = textView.getLayout().getLineEnd(i);
String lineString = textString.substring(lineStart, lineEnd);
if (i == lineCount - 1) {
builder.append(new SpannableString(lineString));
break;
}
String trimSpaceText = lineString.trim();
String removeSpaceText = lineString.replaceAll(" ", "");
float removeSpaceWidth = textPaint.measureText(removeSpaceText);
float spaceCount = trimSpaceText.length() - removeSpaceText.length();
float eachSpaceWidth = (textViewWidth - removeSpaceWidth) / spaceCount;
SpannableString spannableString = new SpannableString(lineString);
for (int j = 0; j < trimSpaceText.length(); j++) {
char c = trimSpaceText.charAt(j);
if (c == ' ') {
Drawable drawable = new ColorDrawable(0x00ffffff);
drawable.setBounds(0, 0, (int) eachSpaceWidth, 0);
ImageSpan span = new ImageSpan(drawable);
spannableString.setSpan(span, j, j + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
builder.append(spannableString);
}
textView.setText(builder);
isJustify.set(true);
}
}
});
}
J'ai mis le code sur GitHub: https://github.com/twiceyuan/TextJustification
Vue d'ensemble:
XML Layout: déclarer WebView au lieu de TextView
<WebView
Android:id="@+id/textContent"
Android:layout_width="fill_parent"
Android:layout_height="wrap_content" />
Code Java: définir les données texte sur WebView
WebView view = (WebView) findViewById(R.id.textContent);
String text;
text = "<html><body><p align=\"justify\">";
text+= "This is the text will be justified when displayed!!!";
text+= "</p></body></html>";
view.loadData(text, "text/html", "utf-8");
Cela peut résoudre votre problème. Son entièrement travaillé pour moi.
Voici comment je l'ai fait, je pense de la manière la plus élégante possible. Avec cette solution, les seules choses à faire dans vos mises en page sont les suivantes:
xmlns
supplémentaireTextView
s du texte source de Android en votre nouvel espace de nomsTextView
s par x.y.z.JustifiedTextView
Voici le code. Fonctionne parfaitement bien sur mes téléphones (Galaxy Nexus Android 4.0.2, Galaxy Teos Android 2.1). N'hésitez pas, bien sûr, à remplacer le nom de votre paquet par le vôtre.
/ assets/excluded_textview.css:
body {
font-size: 1.0em;
color: rgb(180,180,180);
text-align: justify;
}
@media screen and (-webkit-device-pixel-ratio: 1.5) {
/* CSS for high-density screens */
body {
font-size: 1.05em;
}
}
@media screen and (-webkit-device-pixel-ratio: 2.0) {
/* CSS for extra high-density screens */
body {
font-size: 1.1em;
}
}
/ res/values / attrs.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="JustifiedTextView">
<attr name="text" format="reference" />
</declare-styleable>
</resources>
/ res/layout/test.xml:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:myapp="http://schemas.Android.com/apk/res/net.bicou.myapp"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<LinearLayout
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:orientation="vertical" >
<net.bicou.myapp.widget.JustifiedTextView
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
myapp:text="@string/surv1_1" />
</LinearLayout>
</ScrollView>
/ src/net/bicou/monapp/widget/JustifiedTextView.Java:
package net.bicou.myapp.widget;
import net.bicou.myapp.R;
import Android.content.Context;
import Android.content.res.TypedArray;
import Android.graphics.Color;
import Android.util.AttributeSet;
import Android.util.TypedValue;
import Android.view.View;
import Android.webkit.WebView;
public class JustifiedTextView extends WebView {
public JustifiedTextView(final Context context) {
this(context, null, 0);
}
public JustifiedTextView(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}
public JustifiedTextView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
if (attrs != null) {
final TypedValue tv = new TypedValue();
final TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.JustifiedTextView, defStyle, 0);
if (ta != null) {
ta.getValue(R.styleable.JustifiedTextView_text, tv);
if (tv.resourceId > 0) {
final String text = context.getString(tv.resourceId).replace("\n", "<br />");
loadDataWithBaseURL("file:///Android_asset/",
"<html><head>" +
"<link rel=\"stylesheet\" type=\"text/css\" href=\"justified_textview.css\" />" +
"</head><body>" + text + "</body></html>",
"text/html", "UTF8", null);
setTransparentBackground();
}
}
}
}
public void setTransparentBackground() {
try {
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
} catch (final NoSuchMethodError e) {
}
setBackgroundColor(Color.TRANSPARENT);
setBackgroundDrawable(null);
setBackgroundResource(0);
}
}
Nous devons définir le rendu sur logiciel afin d'obtenir un arrière-plan transparent sur Android 3+. D'où l'essayage des anciennes versions d'Android.
J'espère que cela t'aides!
PS: s'il vous plait, pas qu'il soit utile d'ajouter ceci à toute votre activité sur Android 3+ afin d'obtenir le comportement attendu:Android:hardwareAccelerated="false"
Bien que le texte justifié ne soit toujours pas complet, vous pouvez maintenant équilibrer les longueurs de ligne à l'aide de Android:breakStrategy="balanced"
à partir de l'API 23
http://developer.Android.com/reference/Android/widget/TextView.html#attr_Android:breakStrategy
J'écris ma propre classe pour résoudre ce problème, la voici. Il suffit d'appeler la fonction de justification statique qui prend deux arguments.
//Activité principale
package com.fawad.textjustification;
import Android.app.Activity;
import Android.database.Cursor;
import Android.graphics.Point;
import Android.graphics.Typeface;
import Android.os.Bundle;
import Android.util.DisplayMetrics;
import Android.view.Display;
import Android.view.Gravity;
import Android.view.Menu;
import Android.widget.TextView;
public class MainActivity extends Activity {
static Point size;
static float density;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Display display = getWindowManager().getDefaultDisplay();
size=new Point();
DisplayMetrics dm=new DisplayMetrics();
display.getMetrics(dm);
density=dm.density;
display.getSize(size);
TextView tv=(TextView)findViewById(R.id.textView1);
Typeface typeface=Typeface.createFromAsset(this.getAssets(), "Roboto-Medium.ttf");
tv.setTypeface(typeface);
tv.setLineSpacing(0f, 1.2f);
tv.setTextSize(10*MainActivity.density);
//some random long text
String myText=getResources().getString(R.string.my_text);
tv.setText(myText);
TextJustification.justify(tv,size.x);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
// TextJustificationClass
package com.fawad.textjustification;
import Java.util.ArrayList;
import Android.graphics.Paint;
import Android.text.TextUtils;
import Android.widget.TextView;
public class TextJustification {
public static void justify(TextView textView,float contentWidth) {
String text=textView.getText().toString();
Paint paint=textView.getPaint();
ArrayList<String> lineList=lineBreak(text,Paint,contentWidth);
textView.setText(TextUtils.join(" ", lineList).replaceFirst("\\s", ""));
}
private static ArrayList<String> lineBreak(String text,Paint paint,float contentWidth){
String [] wordArray=text.split("\\s");
ArrayList<String> lineList = new ArrayList<String>();
String myText="";
for(String Word:wordArray){
if(Paint.measureText(myText+" "+Word)<=contentWidth)
myText=myText+" "+Word;
else{
int totalSpacesToInsert=(int)((contentWidth-Paint.measureText(myText))/Paint.measureText(" "));
lineList.add(justifyLine(myText,totalSpacesToInsert));
myText=Word;
}
}
lineList.add(myText);
return lineList;
}
private static String justifyLine(String text,int totalSpacesToInsert){
String[] wordArray=text.split("\\s");
String toAppend=" ";
while((totalSpacesToInsert)>=(wordArray.length-1)){
toAppend=toAppend+" ";
totalSpacesToInsert=totalSpacesToInsert-(wordArray.length-1);
}
int i=0;
String justifiedText="";
for(String Word:wordArray){
if(i<totalSpacesToInsert)
justifiedText=justifiedText+Word+" "+toAppend;
else
justifiedText=justifiedText+Word+toAppend;
i++;
}
return justifiedText;
}
}
// XML
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
tools:context=".MainActivity"
>
<ScrollView
Android:id="@+id/scrollView1"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
>
<LinearLayout
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:orientation="vertical"
>
<TextView
Android:id="@+id/textView1"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:text="@string/hello_world" />
</LinearLayout>
</ScrollView>
</RelativeLayout>
FILL_HORIZONTAL
est équivalent à CENTER_HORIZONTAL
. Vous pouvez voir cet extrait de code dans le code source de textview:
case Gravity.CENTER_HORIZONTAL:
case Gravity.FILL_HORIZONTAL:
return (mLayout.getLineWidth(0) - ((mRight - mLeft) -
getCompoundPaddingLeft() - getCompoundPaddingRight())) /
getHorizontalFadingEdgeLength();
Il existe un CustomView pour ce problème, cette vue de texte personnalisée prend en charge la vue de texte justifiée.
Butin à ceci: 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;
}
}
}
Ajoutez la classe ci-dessus à votre dossier src et utilisez cet exemple de code pour ajouter à votre mise en page:
JustifiedTextView jtv= new JustifiedTextView(getApplicationContext(), "Lorem ipsum dolor sit amet... ");
LinearLayout place = (LinearLayout) findViewById(R.id.book_profile_content);
place.addView(jtv);
Très simple, nous pouvons le faire dans le fichier XML
<TextView
Android:justificationMode="inter_Word"
/>
voir ici dans le github
Importez simplement les deux fichiers "TextJustifyUtils.Java" et "TextViewEx.Java" dans votre projet.
public class TextJustifyUtils {
// Please use run(...) instead
public static void justify(TextView textView) {
Paint paint = new Paint();
String[] blocks;
float spaceOffset = 0;
float textWrapWidth = 0;
int spacesToSpread;
float wrappedEdgeSpace;
String block;
String[] lineAsWords;
String wrappedLine;
String smb = "";
Object[] wrappedObj;
// Pull widget properties
Paint.setColor(textView.getCurrentTextColor());
Paint.setTypeface(textView.getTypeface());
Paint.setTextSize(textView.getTextSize());
textWrapWidth = textView.getWidth();
spaceOffset = Paint.measureText(" ");
blocks = textView.getText().toString().split("((?<=\n)|(?=\n))");
if (textWrapWidth < 20) {
return;
}
for (int i = 0; i < blocks.length; i++) {
block = blocks[i];
if (block.length() == 0) {
continue;
} else if (block.equals("\n")) {
smb += block;
continue;
}
block = block.trim();
if (block.length() == 0)
continue;
wrappedObj = TextJustifyUtils.createWrappedLine(block, Paint,
spaceOffset, textWrapWidth);
wrappedLine = ((String) wrappedObj[0]);
wrappedEdgeSpace = (Float) wrappedObj[1];
lineAsWords = wrappedLine.split(" ");
spacesToSpread = (int) (wrappedEdgeSpace != Float.MIN_VALUE ? wrappedEdgeSpace
/ spaceOffset
: 0);
for (String Word : lineAsWords) {
smb += Word + " ";
if (--spacesToSpread > 0) {
smb += " ";
}
}
smb = smb.trim();
if (blocks[i].length() > 0) {
blocks[i] = blocks[i].substring(wrappedLine.length());
if (blocks[i].length() > 0) {
smb += "\n";
}
i--;
}
}
textView.setGravity(Gravity.LEFT);
textView.setText(smb);
}
protected static Object[] createWrappedLine(String block, Paint paint,
float spaceOffset, float maxWidth) {
float cacheWidth = maxWidth;
float origMaxWidth = maxWidth;
String line = "";
for (String Word : block.split("\\s")) {
cacheWidth = Paint.measureText(Word);
maxWidth -= cacheWidth;
if (maxWidth <= 0) {
return new Object[] { line, maxWidth + cacheWidth + spaceOffset };
}
line += Word + " ";
maxWidth -= spaceOffset;
}
if (Paint.measureText(block) <= origMaxWidth) {
return new Object[] { block, Float.MIN_VALUE };
}
return new Object[] { line, maxWidth };
}
final static String SYSTEM_NEWLINE = "\n";
final static float COMPLEXITY = 5.12f; // Reducing this will increase
// efficiency but will decrease
// effectiveness
final static Paint p = new Paint();
public static void run(final TextView tv, float origWidth) {
String s = tv.getText().toString();
p.setTypeface(tv.getTypeface());
String[] splits = s.split(SYSTEM_NEWLINE);
float width = origWidth - 5;
for (int x = 0; x < splits.length; x++)
if (p.measureText(splits[x]) > width) {
splits[x] = wrap(splits[x], width, p);
String[] microSplits = splits[x].split(SYSTEM_NEWLINE);
for (int y = 0; y < microSplits.length - 1; y++)
microSplits[y] = justify(removeLast(microSplits[y], " "),
width, p);
StringBuilder smb_internal = new StringBuilder();
for (int z = 0; z < microSplits.length; z++)
smb_internal.append(microSplits[z]
+ ((z + 1 < microSplits.length) ? SYSTEM_NEWLINE
: ""));
splits[x] = smb_internal.toString();
}
final StringBuilder smb = new StringBuilder();
for (String cleaned : splits)
smb.append(cleaned + SYSTEM_NEWLINE);
tv.setGravity(Gravity.LEFT);
tv.setText(smb);
}
private static String wrap(String s, float width, Paint p) {
String[] str = s.split("\\s"); // regex
StringBuilder smb = new StringBuilder(); // save memory
smb.append(SYSTEM_NEWLINE);
for (int x = 0; x < str.length; x++) {
float length = p.measureText(str[x]);
String[] pieces = smb.toString().split(SYSTEM_NEWLINE);
try {
if (p.measureText(pieces[pieces.length - 1]) + length > width)
smb.append(SYSTEM_NEWLINE);
} catch (Exception e) {
}
smb.append(str[x] + " ");
}
return smb.toString().replaceFirst(SYSTEM_NEWLINE, "");
}
private static String removeLast(String s, String g) {
if (s.contains(g)) {
int index = s.lastIndexOf(g);
int indexEnd = index + g.length();
if (index == 0)
return s.substring(1);
else if (index == s.length() - 1)
return s.substring(0, index);
else
return s.substring(0, index) + s.substring(indexEnd);
}
return s;
}
private static String justifyOperation(String s, float width, Paint p) {
float holder = (float) (COMPLEXITY * Math.random());
while (s.contains(Float.toString(holder)))
holder = (float) (COMPLEXITY * Math.random());
String holder_string = Float.toString(holder);
float lessThan = width;
int timeOut = 100;
int current = 0;
while (p.measureText(s) < lessThan && current < timeOut) {
s = s.replaceFirst(" ([^" + holder_string + "])", " "
+ holder_string + "$1");
lessThan = p.measureText(holder_string) + lessThan
- p.measureText(" ");
current++;
}
String cleaned = s.replaceAll(holder_string, " ");
return cleaned;
}
private static String justify(String s, float width, Paint p) {
while (p.measureText(s) < width) {
s = justifyOperation(s, width, p);
}
return s;
}
}
et
public class TextViewEx extends TextView {
private Paint paint = new Paint();
private String[] blocks;
private float spaceOffset = 0;
private float horizontalOffset = 0;
private float verticalOffset = 0;
private float horizontalFontOffset = 0;
private float dirtyRegionWidth = 0;
private boolean wrapEnabled = false;
int left, top, right, bottom = 0;
private Align _align = Align.LEFT;
private float strecthOffset;
private float wrappedEdgeSpace;
private String block;
private String wrappedLine;
private String[] lineAsWords;
private Object[] wrappedObj;
private Bitmap cache = null;
private boolean cacheEnabled = false;
public TextViewEx(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// set a minimum of left and right padding so that the texts are not too
// close to the side screen
// this.setPadding(10, 0, 10, 0);
}
public TextViewEx(Context context, AttributeSet attrs) {
super(context, attrs);
// this.setPadding(10, 0, 10, 0);
}
public TextViewEx(Context context) {
super(context);
// this.setPadding(10, 0, 10, 0);
}
@Override
public void setPadding(int left, int top, int right, int bottom) {
// TODO Auto-generated method stub
super.setPadding(left + 10, top, right + 10, bottom);
}
@Override
public void setDrawingCacheEnabled(boolean cacheEnabled) {
this.cacheEnabled = cacheEnabled;
}
public void setText(String st, boolean wrap) {
wrapEnabled = wrap;
super.setText(st);
}
public void setTextAlign(Align align) {
_align = align;
}
@SuppressLint("NewApi")
@Override
protected void onDraw(Canvas canvas) {
// If wrap is disabled then,
// request original onDraw
if (!wrapEnabled) {
super.onDraw(canvas);
return;
}
// Active canas needs to be set
// based on cacheEnabled
Canvas activeCanvas = null;
// Set the active canvas based on
// whether cache is enabled
if (cacheEnabled) {
if (cache != null) {
// Draw to the OS provided canvas
// if the cache is not empty
canvas.drawBitmap(cache, 0, 0, Paint);
return;
} else {
// Create a bitmap and set the activeCanvas
// to the one derived from the bitmap
cache = Bitmap.createBitmap(getWidth(), getHeight(),
Config.ARGB_4444);
activeCanvas = new Canvas(cache);
}
} else {
// Active canvas is the OS
// provided canvas
activeCanvas = canvas;
}
// Pull widget properties
Paint.setColor(getCurrentTextColor());
Paint.setTypeface(getTypeface());
Paint.setTextSize(getTextSize());
Paint.setTextAlign(_align);
Paint.setFlags(Paint.ANTI_ALIAS_FLAG);
// minus out the paddings pixel
dirtyRegionWidth = getWidth() - getPaddingLeft() - getPaddingRight();
int maxLines = Integer.MAX_VALUE;
int currentapiVersion = Android.os.Build.VERSION.SDK_INT;
if (currentapiVersion >= Android.os.Build.VERSION_CODES.JELLY_BEAN) {
maxLines = getMaxLines();
}
int lines = 1;
blocks = getText().toString().split("((?<=\n)|(?=\n))");
verticalOffset = horizontalFontOffset = getLineHeight() - 0.5f; // Temp
// fix
spaceOffset = Paint.measureText(" ");
for (int i = 0; i < blocks.length && lines <= maxLines; i++) {
block = blocks[i];
horizontalOffset = 0;
if (block.length() == 0) {
continue;
} else if (block.equals("\n")) {
verticalOffset += horizontalFontOffset;
continue;
}
block = block.trim();
if (block.length() == 0) {
continue;
}
wrappedObj = TextJustifyUtils.createWrappedLine(block, Paint,
spaceOffset, dirtyRegionWidth);
wrappedLine = ((String) wrappedObj[0]);
wrappedEdgeSpace = (Float) wrappedObj[1];
lineAsWords = wrappedLine.split(" ");
strecthOffset = wrappedEdgeSpace != Float.MIN_VALUE ? wrappedEdgeSpace
/ (lineAsWords.length - 1)
: 0;
for (int j = 0; j < lineAsWords.length; j++) {
String Word = lineAsWords[j];
if (lines == maxLines && j == lineAsWords.length - 1) {
activeCanvas.drawText("...", horizontalOffset,
verticalOffset, Paint);
} else if (j == 0) {
// if it is the first Word of the line, text will be drawn
// starting from right Edge of textview
if (_align == Align.RIGHT) {
activeCanvas.drawText(Word, getWidth()
- (getPaddingRight()), verticalOffset, Paint);
// add in the paddings to the horizontalOffset
horizontalOffset += getWidth() - (getPaddingRight());
} else {
activeCanvas.drawText(Word, getPaddingLeft(),
verticalOffset, Paint);
horizontalOffset += getPaddingLeft();
}
} else {
activeCanvas.drawText(Word, horizontalOffset,
verticalOffset, Paint);
}
if (_align == Align.RIGHT)
horizontalOffset -= Paint.measureText(Word) + spaceOffset
+ strecthOffset;
else
horizontalOffset += Paint.measureText(Word) + spaceOffset
+ strecthOffset;
}
lines++;
if (blocks[i].length() > 0) {
blocks[i] = blocks[i].substring(wrappedLine.length());
verticalOffset += blocks[i].length() > 0 ? horizontalFontOffset
: 0;
i--;
}
}
if (cacheEnabled) {
// Draw the cache onto the OS provided
// canvas.
canvas.drawBitmap(cache, 0, 0, Paint);
}
}
}
Maintenant, si vous utilisez textView normal comme:
<TextView
Android:id="@+id/original"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:text="@string/lorum_ipsum" />
Simplement utiliser
<yourpackagename.TextViewEx
Android:id="@+id/changed"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:text="@string/lorum_ipsum" />
Définir une variable et définir justifier d'être vrai,
TextViewEx changed = (TextViewEx) findViewById(R.id.changed);
changed.setText(getResources().getString(R.string.lorum_ipsum),true);
Essayez cette solution dans le lien ci-dessous, créez simplement cette classe dans le dossier du projet et utilisez-la. Ça fonctionne bien pour moi :)
Sur Android, pour justifier le texte à gauche et ne pas tronquer la couleur de fond, essayez-le, cela a fonctionné pour moi et produire des résultats cohérents sur Android, ff, c.-à-d. & chrome mais vous devez mesurer l'espace qui est disponible. laissé entre les deux pour le texte lors du calcul du remplissage.
<td style="font-family:Calibri,Arial;
font-size:15px;
font-weight:800;
background-color:#f5d5fd;
color:black;
border-style:solid;
border-width:1px;
border-color:#bd07eb;
padding-left:10px;
padding-right:1000px;
padding-top:3px;
padding-bottom:3px;
>
Le hack est le padding-right:1000px;
qui pousse le texte à l'extrême gauche.
Toute tentative de gauche ou de justification de code en css ou html entraîne un arrière-plan de seulement une demi-largeur.
Android ne supporte pas encore la justification complète. Nous pouvons utiliser Webview et justifier HTML au lieu d'utiliser textview. Cela fonctionne si bien. Si vous n'êtes pas clairs, n'hésitez pas à me demander :)
Je pense qu'il y a deux options:
Utilisez quelque chose comme Pango spécialisé dans ce domaine via le NDK et restituez le texte sur une surface OpenGL ou autre.
Utilisez Paint.measureText () et amis pour obtenir la longueur des mots et les disposer manuellement sur un canevas dans une vue personnalisée.
Pour le formatage HTML, vous n'avez pas besoin d'appeler le Webkit, vous pouvez utiliser Html.fromHtml(text)
pour effectuer le travail.
Source: http://developer.Android.com/guide/topics/resources/string-resource.html