So, as most of you know, there is no text justifying inside a TextView in Android. So, I built a custom TextView to get around the problem. However, for some reason, sometim
Try this way to justify text, it works for me
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
LIBRARY: https://github.com/bluejamesbond/TextJustify-Android
SUPPORTS: Android 2.0 to 5.X
SCREENSHOT
So, after looking a bit more at this: https://github.com/ufo22940268/android-justifiedtextview and TextView in general, I discovered that my main problem was my approach.
Using the approach of scaling the width of the " " characters was sound in theory, but after doing so, the width of the line changes again, as it seems that the width of the line is NOT the sum of its parts.
I have changed my approach and took inspiration from the link above, and so in my new approach I draw each character by itself, instead of drawing the whole line. If the text needs to be justified (based on a custom "justify" boolean attribute) then it will draw the line and justify it, else it will just draw the line.
Edit: I have changed the code now so that it also supports RTL texts. I will upload the code somewhere in the next few days.
Here's the result:
Here's the 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;
}
}
}
and the 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" />
Thanks to Aditya Vyas-Lakhan for the links
Just user like bellow
<TextView
android:id="@+id/tvMessageDetails"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:justificationMode="inter_word"/>