
If you want to justify your text in Android first need to below dependency in gradle
1 |
compile 'com.uncopt:android.justified:1.0' |
after that need to add below two java files in your src
TextJustifyUtils.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
package androindin.learnandroid; /** * Created by Raj on 6/16/2016. */ import android.graphics.Paint; import android.view.Gravity; import android.widget.TextView; 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; } } |
TextViewEx.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
package androindin.learnandroid; /** * Created by Raj on 6/16/2016. */ import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.Paint.Align; import android.graphics.Canvas; import android.graphics.Paint; import android.widget.TextView; import android.util.AttributeSet; 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); } } } |
After that need add textview in xml like below
1 2 3 4 5 6 7 8 9 10 |
<androindin.learnandroid.TextViewEx android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/serv" android:textColor="@color/title" android:textSize="14sp" android:paddingTop="5dp" android:breakStrategy="balanced" android:visibility="gone" /> |
And in Java file add like below
1 2 3 4 |
TextViewEx acttext; acttext=(TextViewEx)findViewById(R.id.activ); acttext.setText(getResources().getString(R.string.activity),true); |