Textview 줄 바 꾸 기 혼란 해결
그리고 이 MTextView. java 를 바탕 으로 수정 하여 Html 색상 기능 을 추 가 했 습 니 다.
xxx
다음은 소스!
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.Html;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import android.text.style.ImageSpan;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.widget.TextView;
/** * @ TextView, {@link #setMText(CharSequence)} * @author huangwei * @2014 5 27 * @ 5:29:27 */
public class MTextView extends TextView {
private static final String TAG = "MTextView";
private Context context;
/** * */
private Paint paint = new Paint();
private int textColor = Color.BLACK;
//
private float lineSpacing;
private int lineSpacingDP = 2;
// private float lineSpacingMult = 0.5f;
/** * */
private int maxWidth;
/** * */
private int oneLineWidth = -1;
/** * */
private float lineWidthMax = -1;
/** * , item ImageSpan */
private ArrayList<Object> obList = new ArrayList<Object>();
/** * {@link TextView#onMeasure(int, int)} {@link TextView#onDraw(Canvas)} */
private boolean useDefault = false;
/** * , item */
ArrayList<LINE> contentList = new ArrayList<LINE>();
/** * */
private static HashMap<String, SoftReference<MeasuredData>> measuredData = new HashMap<String, SoftReference<MeasuredData>>();
private static int hashIndex = 0;
private CharSequence text = "";
/** * */
private int minHeight;
/** * */
private DisplayMetrics displayMetrics;
public MTextView(Context context) {
super(context);
init(context);
}
public MTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public MTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public MTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
private void init(Context context){
this.context = context;
paint.setAntiAlias(true);
lineSpacing = dip2px(context, lineSpacingDP);
minHeight = dip2px(context, 30);
displayMetrics = new DisplayMetrics();
}
@Override
public void setMaxWidth(int maxpixels) {
super.setMaxWidth(maxpixels);
maxWidth = maxpixels;
}
@Override
public void setMinHeight(int minHeight)
{
super.setMinHeight(minHeight);
this.minHeight = minHeight;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
if (useDefault){
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
int width = 0, height = 0;
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
switch (widthMode){
case MeasureSpec.EXACTLY:
width = widthSize;
break;
case MeasureSpec.AT_MOST:
width = widthSize;
break;
case MeasureSpec.UNSPECIFIED:
((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
width = displayMetrics.widthPixels;
break;
default:
break;
}
if (maxWidth > 0) {
width = Math.min(width, maxWidth);
}
paint.setTextSize(this.getTextSize());
paint.setColor(textColor);
int realHeight = measureContentHeight((int) width);
// ,
int leftPadding = getCompoundPaddingLeft();
int rightPadding = getCompoundPaddingRight();
width = Math.min(width, (int) lineWidthMax + leftPadding+ rightPadding);
if (oneLineWidth > -1) {
width = oneLineWidth;
}
switch (heightMode) {
case MeasureSpec.EXACTLY:
height = heightSize;
break;
case MeasureSpec.AT_MOST:
height = realHeight;
break;
case MeasureSpec.UNSPECIFIED:
height = realHeight;
break;
default:
break;
}
height += getCompoundPaddingTop() + getCompoundPaddingBottom();
height = Math.max(height,minHeight);
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
invalidate();
if (useDefault){
super.onDraw(canvas);
return;
}
int width;
Object ob;
int leftPadding = getCompoundPaddingLeft();
int topPadding = getCompoundPaddingTop();
float height = 0 + topPadding + lineSpacing;
//
if(oneLineWidth != -1){
height = getMeasuredHeight() /2 - contentList.get(0).height/2;
}
for (int i = 0; i < contentList.size(); i++){
//
float realDrawedWidth = 0 + leftPadding;
LINE line = contentList.get(i);
for (int j = 0; j < line.line.size(); j++){
ob = line.line.get(j);
width = line.widthList.get(j);
if (ob instanceof ImageSpan){
ImageSpan is = (ImageSpan) ob;
Drawable d = is.getDrawable();
int left = (int) (realDrawedWidth);
int top = (int) height;
int right = (int) (realDrawedWidth + width);
int bottom = (int) (height + line.height);
d.setBounds(left, top, right, bottom);
d.draw(canvas);
realDrawedWidth += width;
}else if (ob instanceof String || ob instanceof StringWithColor){
String textStr = ob.toString();
paint.setColor(textColor);
if(ob instanceof StringWithColor){
paint.setColor(((StringWithColor)ob).color);
}
canvas.drawText(textStr, realDrawedWidth, height + line.height, paint);
realDrawedWidth += width;
}
}
height += line.height + lineSpacing;
}
}
@Override
public void setTextColor(int color){
super.setTextColor(color);
textColor = color;
}
/** * ImageSpan * @param width * @return */
private int measureContentHeight(int width) {
int cachedHeight = getCachedData(text.toString(), width);
if(cachedHeight > 0) {
return cachedHeight;
}
//
float obWidth = 0;
float obHeight = 0;
float textSize = this.getTextSize();
//
float lineHeight = textSize;
//
float height = lineSpacing;
int leftPadding = getCompoundPaddingLeft();
int rightPadding = getCompoundPaddingRight();
float drawedWidth = 0;
width = width - leftPadding - rightPadding;
oneLineWidth = -1;
contentList.clear();
StringBuilder sb;
LINE line = new LINE();
for (int i = 0; i < obList.size(); i++) {
Object ob = obList.get(i);
if (ob instanceof ImageSpan) {
Rect r = ((ImageSpan) ob).getDrawable().getBounds();
obWidth = r.right - r.left;
obHeight = r.bottom - r.top;
if (obHeight > lineHeight) {
lineHeight = obHeight;
}
}else if (ob instanceof String) {
obWidth = paint.measureText((String) ob);
obHeight = textSize;
}else if(ob instanceof StringWithColor){
obWidth = paint.measureText( ((StringWithColor) ob).str );
obHeight = textSize;
}
// , contentList,
if (width - drawedWidth < obWidth) {
contentList.add(line);
if (drawedWidth > lineWidthMax){
lineWidthMax = drawedWidth;
}
drawedWidth = 0;
height += line.height + lineSpacing;
lineHeight = obHeight;
line = new LINE();
}
drawedWidth += obWidth;
if ((ob instanceof String || ob instanceof StringWithColor)
&& line.line.size() > 0
&& (line.line.get(line.line.size() - 1) instanceof String)){
if(ob instanceof StringWithColor){
ob = ob.toString();
}
int size = line.line.size();
sb = new StringBuilder();
sb.append(line.line.get(size - 1));
sb.append(ob);
ob = sb.toString();
obWidth = obWidth + line.widthList.get(size - 1);
line.line.set(size - 1, ob);
line.widthList.set(size - 1, (int) obWidth);
line.height = (int) lineHeight;
}else{
line.line.add(ob);
line.widthList.add((int) obWidth);
line.height = (int) lineHeight;
}
}
if (line != null && line.line.size() > 0) {
contentList.add(line);
height += lineHeight + lineSpacing;
}
if (contentList.size() <= 1) {
oneLineWidth = (int) drawedWidth + leftPadding + rightPadding;
height = lineSpacing + lineHeight + lineSpacing;
}
cacheData(width,(int) height);
return (int) height;
}
/** * , * @param text * @param width * @return height */
@SuppressWarnings("unchecked")
private int getCachedData(String text, int width){
SoftReference<MeasuredData> cache = measuredData.get(text);
if(cache == null) {
return -1;
}
MeasuredData md = cache.get();
if (md != null && md.textSize == this.getTextSize() && width == md.width) {
lineWidthMax = md.lineWidthMax;
contentList = (ArrayList<LINE>) md.contentList.clone();
oneLineWidth = md.oneLineWidth;
StringBuilder sb = new StringBuilder();
for(int i=0;i<contentList.size();i++) {
LINE line = contentList.get(i);
sb.append(line.toString());
}
return md.measuredHeight;
}else {
return -1;
}
}
/** * * @param width * @param height */
@SuppressWarnings("unchecked")
private void cacheData(int width, int height)
{
MeasuredData md = new MeasuredData();
md.contentList = (ArrayList<LINE>) contentList.clone();
md.textSize = this.getTextSize();
md.lineWidthMax = lineWidthMax;
md.oneLineWidth = oneLineWidth;
md.measuredHeight = height;
md.width = width;
md.hashIndex = ++hashIndex;
StringBuilder sb = new StringBuilder();
for(int i=0;i<contentList.size();i++) {
LINE line = contentList.get(i);
sb.append(line.toString());
}
SoftReference<MeasuredData> cache = new SoftReference<MeasuredData>(md);
measuredData.put(text.toString(),cache);
}
/** * {@link #setText(CharSequence)} * @param textStr */
public void setMText(CharSequence textStr) {
text = textStr;
obList.clear();
// contentList.clear();
ArrayList<SpanBean> isList = new ArrayList<>();
useDefault = false;
if (textStr instanceof SpannableString) {
SpannableString ss = (SpannableString) textStr;
ForegroundColorSpan[] spanneds = ss.getSpans(0, ss.length(), ForegroundColorSpan.class);
for (int i = 0; i < spanneds.length; i++) {
int s = ss.getSpanStart(spanneds[i]);
int e = ss.getSpanEnd(spanneds[i]);
ForegroundColorSpanBean spanBean = new ForegroundColorSpanBean();
spanBean.fcspan = spanneds[i];
spanBean.start = s;
spanBean.end = e;
isList.add(spanBean);
}
ImageSpan[] imageSpans = ss.getSpans(0, ss.length(), ImageSpan.class);
for (int i = 0; i < imageSpans.length; i++) {
int s = ss.getSpanStart(imageSpans[i]);
int e = ss.getSpanEnd(imageSpans[i]);
IS iS = new IS();
iS.is = imageSpans[i];
iS.start = s;
iS.end = e;
isList.add(iS);
}
}
// isList , start
if(isList.size() > 1){
for(int i = 0 ; i < isList.size()-1;i++){
///
for(int j = (i+1) ; j < isList.size();j++){
SpanBean temp01 = isList.get(i);
SpanBean temp02 = isList.get(j);
if(temp01.start > temp02.start){
isList.set(i,temp02);
isList.set(j,temp01);
}
}
///
}
}
String str = textStr.toString();
for (int i = 0, j = 0; i < textStr.length();) {
if (j < isList.size()) {
SpanBean spanBean = isList.get(j);
if (i < spanBean.start) {
Integer cp = str.codePointAt(i);
//
if (Character.isSupplementaryCodePoint(cp)) {
i += 2;
}else {
i++;
}
obList.add(new String(Character.toChars(cp)));
}else if (i >= spanBean.start) {
if(spanBean instanceof IS){
obList.add(((IS)spanBean).is);
j++;
i = spanBean.end;
}else if(spanBean instanceof ForegroundColorSpanBean){
Integer cp = str.codePointAt(i);
if (Character.isSupplementaryCodePoint(cp)){
i += 2;
}else{
i++;
}
obList.add(new StringWithColor(new String(Character.toChars(cp)),
((ForegroundColorSpanBean)spanBean).fcspan.getForegroundColor()));
if(i >= spanBean.end){
j++;
}
}else{
Log.e(TAG , "--- geolo , ---");
}
}
}else{
Integer cp = str.codePointAt(i);
if (Character.isSupplementaryCodePoint(cp)){
i += 2;
}else{
i++;
}
obList.add(new String(Character.toChars(cp)));
}
}
requestLayout();
}
public void setUseDefault(boolean useDefault) {
this.useDefault = useDefault;
if (useDefault) {
this.setText(text);
this.setTextColor(textColor);
}
}
public static int px2sp(Context context, float pxValue)
{
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (pxValue / fontScale + 0.5f);
}
/** * dp px( ) */
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/** * @ : Span */
class SpanBean{
public int start;
public int end;
}
/** * @ : ImageSpan */
class IS extends SpanBean{
public ImageSpan is;
}
/** * @ : ForegroundColorSpan * (Html) */
class ForegroundColorSpanBean extends SpanBean{
public ForegroundColorSpan fcspan;
public String str;
}
/** * @ : */
class StringWithColor{
int color = 0;
String str;
StringWithColor(String str , int color){
this.str = str;
this.color = color;
}
@Override
public String toString() {
return str;
}
}
/** * @ : * @author huangwei * @2014 5 27 * @ 5:22:12 */
class LINE {
public ArrayList<Object> line = new ArrayList<Object>();
public ArrayList<Integer> widthList = new ArrayList<Integer>();
public int height;
@Override
public String toString() {
StringBuilder sb = new StringBuilder("height:"+height+" ");
for(int i=0;i<line.size();i++) {
sb.append(line.get(i)+":"+widthList.get(i));
}
return sb.toString();
}
}
/** * @ : * @author huangwei * @2014 5 27 * @ 5:22:25 */
class MeasuredData {
public int measuredHeight;
public float textSize;
public int width;
public float lineWidthMax;
ArrayList<LINE> contentList;
public int oneLineWidth;
public int hashIndex;
}
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.