您的位置:首页 > 移动开发 > Android开发

一些Android TextView不能满足的需求

2015-09-28 20:37 316 查看
废话不多说,还是上代码吧,根据网上的一些demo然后自己改了改,不会出现字错位和隐藏半个字符的bug了

package com.prayer.android.views;

import java.util.ArrayList;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.text.Layout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;

public class MTextView extends TextView {
private String TAG = "BaikeTextView";
public Context mContext = null;
public Paint mPaint = null;
public int mTextHeight = 1080;
public int mBaikeTextHeight = 0;
public int mTextWidth = 1920;
public String mText = "";
public float mLineSpace = 0;
public int mOffset = -2;
public float mTextSize = 0;
public int mTextColor = 0xffbbbbbb;
public int mFontHeight = 0;
public int mPaddingLeft = 0;
public int mPaddingRight = 0;

public MTextView(Context context, AttributeSet set) {
super(context, set);
this.mContext = context;
mPaint = new Paint();
mPaint.setAntiAlias(true);
}

@Override
protected void onDraw(Canvas canvas) {
TextPaint paint = getPaint();
mTextWidth = this.getWidth();
setmTextHeight(this.getHeight());
mText = this.getText().toString().trim();
mText = getTextString(mContext, mText);
if (mText == null || mText.equals("") == true) {
return;
}
Log.i(TAG, "mTextStr: " + mText + "");
//        这有问题
mTextSize = this.getTextSize();
Layout layout = getLayout();

// layout.getLayout()在4.4.3出现NullPointerException
if (layout == null) {
return;
}
Paint.FontMetrics fm = paint.getFontMetrics();

int textHeight = (int) (Math.ceil(fm.descent - fm.ascent));
textHeight = (int) (textHeight * layout.getSpacingMultiplier() + layout.getSpacingAdd()/2 );
mFontHeight = textHeight;
mPaddingLeft = this.getPaddingLeft();
mPaddingRight = this.getPaddingRight();
mTextColor = this.getCurrentTextColor();
Log.i(TAG, "mTextSize: " + mTextSize + "");
Log.i(TAG, "mFontHeight: " + mFontHeight + "");
Log.i(TAG, "mPaddingLeft: " + mPaddingLeft + "");
Log.i(TAG, "mPaddingRight: " + mPaddingRight + "");
mPaint.setTextSize(mTextSize);
mPaint.setColor(mTextColor);
ArrayList<LinePar> tempLineArray = getLineParList(mText);
drawText(tempLineArray, mText, canvas);
}

/*
* Obtain the information of each row
*/
public ArrayList<LinePar> getLineParList(String mTextStr) {
if (mTextStr == null || mTextStr.isEmpty() == true) {
return null;
}
int tempStart = 0;
int tempLineWidth = 0;
int tempLineCount = 0;
ArrayList<LinePar> tempLineArray = new ArrayList<LinePar>();
//
// 对字符串进行一次循环
for (int i = 0; i < mTextStr.length(); i++) {
char ch = mTextStr.charAt(i);
String str = String.valueOf(ch);
float strWidth = 0;
if (str != null && str.isEmpty() == false) {
strWidth = MyConstant.getWidthofString(str, mPaint);
}

/*
* 如果是换行符,将这一行的信息存入列表中
*/
if (ch == '\n' && tempStart != i) {
tempLineCount++;
addLinePar(tempStart, i, tempLineCount, 0, tempLineArray);
if (i == (mTextStr.length() - 1)) {
break;
} else {
tempStart = i + 1;
tempLineWidth = 0;
}
continue;
} else {
tempLineWidth += Math.ceil(strWidth);
if (tempLineWidth >= mTextWidth - mPaddingRight) {
tempLineCount++;
/*
* 对正常绘制时的“下一行第一个字符”进行判断,如果是“成对出现标点”的左侧半个,
* 对上一行的字符间距进行拉伸,或者不处理
*/
if (MyConstant.isLeftPunctuation(ch) == true) {
Log.i(TAG, "i: " + i + "");
Log.i(TAG,
"the char is the left half of the punctuation");
Log.i(TAG, "str: " + str + " ");
/*
* if the char is the left half of the punctuation. Go
* into the next line of the current character
*/
i--;
float tempWordSpaceOffset = (float) (tempLineWidth
- Math.ceil(strWidth) - mTextWidth)
/ (float) (i - tempStart);
addLinePar(tempStart, i, tempLineCount,
tempWordSpaceOffset, tempLineArray);
} else if (MyConstant.isRightPunctuation(ch) == true) {
/*
* 对正常绘制时的“下一行第一个字符”进行判断,如果是“成对出现标点”的右侧半个
*/
Log.i(TAG,
"the char is the right half of the punctuation");
Log.i(TAG, "str: " + str + " ");
if (i == (mTextStr.length() - 1)) {
addLinePar(tempStart, i, tempLineCount, 0,
tempLineArray);
break;
} else {
char nextChar = mTextStr.charAt(i + 1);
if ((MyConstant.isHalfPunctuation(nextChar) == true || MyConstant
.isPunctuation(nextChar) == true)
&& MyConstant
.isLeftPunctuation(nextChar) == false) {
/*
* 对正常绘制时的“下一行第一个字符”进行判断,如果是“成对出现标点”的右侧半个
* 并且,“再下一个字符”是“英文标点”、“中文标点”、“右侧标点”
* 处理:讲这两个标点都放在上一行进行绘制
*/
String nextStr = String.valueOf(nextChar);
float nextStrWidth = 0;
if (nextStr != null
&& nextStr.isEmpty() == false) {
nextStrWidth = MyConstant
.getWidthofString(nextStr, mPaint);
}
i++;
float tempWordSpaceOffset = (float) (tempLineWidth
+ Math.ceil(nextStrWidth) - mTextWidth)
/ (float) (i - tempStart);
addLinePar(tempStart, i, tempLineCount,
tempWordSpaceOffset, tempLineArray);
} else {

/*
* 对正常绘制时的“下一行第一个字符”进行判断,如果是“成对出现标点”的右侧半个
* 并且,“再下一个字符”是“左侧标点”、非标点的字符
* 处理:只将右侧标点放在上一行进行绘制
*/
float tempWordSpaceOffset = (float) (tempLineWidth - mTextWidth)
/ (float) (i - tempStart);
addLinePar(tempStart, i, tempLineCount,
tempWordSpaceOffset, tempLineArray);
}
}
} else {

/*
* 如果下一行的第一个字符是“单个出现的标点”和“非标点字符”
*/
/*
* if the char is not the left And Right half of the
* punctuation.
*/
if (MyConstant.isHalfPunctuation(ch) == true
|| MyConstant.isPunctuation(ch) == true) {
/*
* 如果下一行的第一个字符是“单个出现的标点”
* 放在上一行进行绘制
*/
/*
* If the current character is a punctuation mark,
* on the end of the Bank
*/

float tempWordSpaceOffset = (float) (tempLineWidth - mTextWidth)
/ (float) (i - tempStart);
addLinePar(tempStart, i, tempLineCount,
tempWordSpaceOffset, tempLineArray);
} else {
/*
* 如果下一行的第一个字符是“非标点”
*/
/*
* If the current character is not a punctuation
*/
if (i >= 1) {
char preChar = mTextStr.charAt(i - 1);
if (MyConstant.isLeftPunctuation(preChar) == true) {
/*
* 如果下一行的第一个字符是“非标点”
* 上一个字符(即结尾的字符),是左侧标点
* 处理:两个字符全都放在下一行进行绘制
*/
String preStr = String.valueOf(preChar);
float preStrWidth = 0;
if (preStr != null
&& preStr.isEmpty() == false) {
preStrWidth = MyConstant
.getWidthofString(preStr,
mPaint);
}
Log.i(TAG,
"the char is the left half of the punctuation");
Log.i(TAG, "preChar: " + preChar + " ");
i = i - 2;
float tempWordSpaceOffset = (float) (tempLineWidth
- Math.ceil(strWidth)
- Math.ceil(preStrWidth) - mTextWidth)
/ (float) (i - tempStart);
addLinePar(tempStart, i, tempLineCount,
tempWordSpaceOffset, tempLineArray);
} else {
/*
* 如果下一行的第一个字符是“非标点”
* 上一个字符(即结尾的字符),是“非左侧标点”
* 处理:下一行的第一个字符放在下一行(即,不处理)
*/
i--;
float tempWordSpaceOffset = (float) (tempLineWidth
- Math.ceil(strWidth) - mTextWidth)
/ (float) (i - tempStart);
addLinePar(tempStart, i, tempLineCount,
tempWordSpaceOffset, tempLineArray);
}
}
}
}
if (i == (mTextStr.length() - 1)) {
break;
} else {
tempStart = i + 1;
tempLineWidth = 0;
}
continue;
} else {
if (i == (mTextStr.length() - 1)) {
tempLineCount++;
addLinePar(tempStart, i, tempLineCount, 0,
tempLineArray);
break;
}
continue;
}
}
}
return tempLineArray;
}

public void addLinePar(int start, int end, int lineCount,
float wordSpaceOffset, ArrayList<LinePar> lineList) {
if (lineList != null) {
LinePar linePar = new LinePar();
linePar.setLineCount(lineCount);
linePar.setStart(start);
linePar.setEnd(end);
linePar.setWordSpaceOffset(wordSpaceOffset);
lineList.add(linePar);
}
}

public void drawText(ArrayList<LinePar> tempLineArray, String mTextStr,
Canvas canvas) {
if (tempLineArray == null || canvas == null || mTextStr == null
|| mTextStr.equals("") == true) {
return;
}

for (int lineNum = 0; lineNum < tempLineArray.size(); lineNum++) {
LinePar linePar = tempLineArray.get(lineNum);
int start = linePar.getStart();
int end = linePar.getEnd();
float width = linePar.getWordSpaceOffset();
int lineCount = linePar.getLineCount();
if (lineNum > 0 && lineNum == tempLineArray.size() - 1) {
mBaikeTextHeight = (int) (lineCount * (mLineSpace + mTextSize));
}
if (start > end || end > mTextStr.length() - 1) {
continue;
}
float lineWidth = 0;
for (int strNum = start; strNum <= end; strNum++) {
char ch = mTextStr.charAt(strNum);
String str = String.valueOf(ch);
if (str == null || str.equals("") == true) {
continue;
}
if (ch == '\n') {
str = "";
}
if (strNum > end) {
break;
}

if (strNum >= start && strNum <= end && lineCount >= 1) {
canvas.drawText(str, mPaddingLeft + lineWidth, lineCount
* mFontHeight - mOffset + (lineCount - 1)
* mLineSpace, mPaint);
lineWidth += MyConstant.getWidthofString(str, mPaint);
lineWidth = lineWidth - width;
}
}
}
}

public int getBaikeTextHeight() {
return mBaikeTextHeight;
}

public String getTextString(Context mContext, String mText) {
if (mContext != null && mText != null && mText.equals("") == false) {
return MyConstant.replaceTABToSpace(mText);
}
return "";
}

public void setmTextHeight(int mTextHeight) {
this.mTextHeight = mTextHeight;
}

public int getmTextHeight() {
return mTextHeight;
}

public class LinePar {
private int mStart;
private int mEnd;
private int mLineCount;
private float mWordSpaceOffset;

public void setStart(int mStart) {
this.mStart = mStart;
}

public void setEnd(int mEnd) {
this.mEnd = mEnd;
}

public void setLineCount(int count) {
this.mLineCount = count;
}

public void setWordSpaceOffset(float mWordSpaceOffset) {
this.mWordSpaceOffset = mWordSpaceOffset;
}

public int getStart() {
return mStart;
}

public int getEnd() {
return mEnd;
}

public int getLineCount() {
return mLineCount;
}

public float getWordSpaceOffset() {
return mWordSpaceOffset;
}

}
}


package com.prayer.android.views;
import android.graphics.Paint;
/**
* Created by  on 2015/09/28/0028.
*/
public class MyConstant {
/*
* replace TAB
*/

public static String replaceTABToSpace(String str) {
str = str.replaceAll(" ", "      ");
return str;
}

public static String replaceBreakLineToSpace(String str) {
str = str.replaceAll("\n", " ");
return str;
}

/*
* Letters and numbers
*/

public static boolean isLetterOfEnglish(char c) {
int count = (int) c;
if (count >= 65 && count <= 90) {
// A ~ Z
return true;
} else if (count >= 97 && count <= 122) {
// a ~ z
return true;
} else if (count >= 48 && count <= 57) {
// 0 ~ 9
return true;
}
return false;
}

/*

* English punctuation

*/

public static boolean isHalfPunctuation(char c) {
int count = (int) c;
if (count >= 33 && count <= 47) {
// !~/
return true;
} else if (count >= 58 && count <= 64) {
// :~@
return true;
} else if (count >= 91 && count <= 96) {
// [~
return true;

} else if (count >= 123 && count <= 126) {
// {~~
return true;
}
return false;

}

/*

* Chinese punctuation

*/

public static boolean isPunctuation(char c) {
Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
if (ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
|| ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
|| ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) {
return true;
}
return false;

}

/*

* Get the pixel length of the string value

*/

public static int getWidthofString(String str, Paint paint) {
if (str != null && str.equals("") == false && paint != null) {
int strLength = str.length();
int result = 0;
float[] widths = new float[strLength];
paint.getTextWidths(str, widths);
for (int i = 0; i < strLength; i++) {
result += widths[i];
}
return (int) result;
}
return 0;
}

/*
* the left half of the punctuation . For example:" ( < [ { "
*/

public static boolean isLeftPunctuation(char c) {
int count = (int) c;
if (count == 8220 || count == 12298 || count == 65288 || count == 12304
|| count == 40 || count == 60 || count == 91 || count == 123) {
return true;
}
return false;
}

/*
* the right half of the punctuation . For example:" ) > ] } "
*/

public static boolean isRightPunctuation(char c) {
int count = (int) c;
if (count == 8221 || count == 12299 || count == 65289 || count == 12305
|| count == 41 || count == 62 || count == 93 || count == 125) {
return true;
}
return false;
}

public static String ToDBC(String input) {
char[] c = input.toCharArray();
for (int i = 0; i < c.length; i++) {
if (isPunctuation(c[i])) {
if (c[i] == 12288) {
c[i] = (char) 32;
continue;
}
if (c[i] > 65280 && c[i] < 65375) {
c[i] = (char) (c[i] - 65248);
}
}
}
return new String(c);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: