自我感覺做什么事情都是事倍功半铃辖,同樣性格還是丟三落四的人跨蟹。記錄每一次解決問題的思路經(jīng)過,以供自我學(xué)
前幾天讓做一個(gè)效果如上圖搔谴,于是引發(fā)了一些列的思路風(fēng)暴:
(思路1)TextView+Html的形式:html在網(wǎng)頁(yè)實(shí)現(xiàn)很常見的干旁,所以不免第一個(gè)反應(yīng)就是用html驶沼。于是讓前端哥們寫了一段html文本,但是當(dāng)我用著個(gè)文本顯示的時(shí)候發(fā)現(xiàn)沒有效果争群,于是開始想是不是因?yàn)楦鐐冇玫腃SS3.0回怜,html5的原因(因?yàn)榭赡苁謾C(jī)的TextView不支持,所以可能是這原因)换薄,然后去網(wǎng)上搜索看TextView都支持什么html標(biāo)簽玉雾,最后發(fā)現(xiàn)TextView支持有限的Html標(biāo)簽,其中知識(shí)一些簡(jiǎn)單的字體轻要,顏色复旬,背景,還不支持CSS(更不用說CSS3.0了)
思路1總結(jié):整個(gè)過程耗費(fèi)了半個(gè)下午冲泥,其中還包括1一個(gè)人情(前端哥們的幫忙) 驹碍。查詢TextView具體支持標(biāo)簽在Html.from("")的方法中查找
知識(shí)點(diǎn)總結(jié):TextView支持的html很是有限的,關(guān)于字體的樣式還是用自個(gè)的標(biāo)簽<font>凡恍。而且最后html會(huì)被轉(zhuǎn)換span的形式
(思路2)ImageScpan+自定義drawable方式:textview+html不行,那么志秃,只能用span。為什么使用ImageSpan原因:1嚼酝,因?yàn)榭梢园选胺?wù)中”這個(gè)塊當(dāng)成圖片浮还。如果用ImageScpan實(shí)現(xiàn)了的話,后期可以隨便換成任何圖片革半。2碑定。不使用ImageSpan的話流码,只能使用backgroundscpan,relativespan和字體顏色span等至少三個(gè)集合又官,有點(diǎn)多了感覺,最重要的是Imagespan是可以到行尾部換行了(解釋:如果行尾的預(yù)留的寬度不夠的話漫试,會(huì)另起一行六敬。所選文字對(duì)于一個(gè)圖片塊),不知道其他的行不行(解釋:字面意思backgroundspan只是改變所選文章的背景色驾荣,所針對(duì)的文字還是一個(gè)對(duì)一個(gè)外构。另外兩個(gè)span一樣的)普泡。使用imagespan+圖片的形式是合理的選擇,既然這個(gè)形式的話那么imagespan+自定義的drawable是最好的思路出現(xiàn)了审编,這里是因?yàn)樽远xdrawable可以繪制任何圖片撼班。于是要自個(gè)實(shí)現(xiàn)一個(gè)drawable和系統(tǒng)的imagespan組裝這個(gè)效果。到這里以為終于可以了垒酬,走幾步才發(fā)現(xiàn)砰嘁,嘿嘿...
系統(tǒng)的Imagescpan不行,不能和文字垂直居中勘究,并且當(dāng)所使用圖片高度大于文字的ascent(矮湘。好像是這個(gè)。 )時(shí)口糕,改行的行高使用會(huì)加上一定高度缅阳。于是上網(wǎng)搜索垂直居中ImageScpan 。
思路2總結(jié):整個(gè)過程進(jìn)展也算合理景描。最后的結(jié)果是:搜索的垂直居中imagescpan+自定義drawable十办。(出錯(cuò)了,為什么不直接寫一個(gè)自定義自個(gè)的Imagescpan呢)工作量相對(duì)多超棺,自定義兩個(gè)東西
知識(shí)點(diǎn)總結(jié):
1橘洞,系統(tǒng)的Imagescpan不行,不能和文字垂直居中说搅,并且當(dāng)所使用圖片高度大于文字的ascent(炸枣。好像是這個(gè)。 )時(shí)弄唧,改行的行高使用會(huì)加上一定高度适肠。于是上網(wǎng)搜索垂直居中ImageScpan 。
2候引,牽扯到了drawable自定義 侯养,了解到當(dāng)drawable.draw(canvas)之前 drawable.getbouds返回的區(qū)域必須是有個(gè)有空間的區(qū)域。不能是高為0澄干,寬為0逛揩,這樣的話只會(huì)看不到
3,中間搜索到了一個(gè)大神寫的垂直居中的ImageSpan
(思路3) 自定義自個(gè)的ImageSpan:直接自定義自個(gè)的span麸俘,拋棄了思路2還用自個(gè)寫自定義drawable辩稽,顯然這個(gè)是不錯(cuò)的。直接朝這個(gè)方向前進(jìn)吧4用摹逞泄!最后完成了效果
思路3總結(jié):canvas.drawline的時(shí)候水平線應(yīng)該是字體的baseline的位置。
針對(duì)這個(gè)問題最終總結(jié):
1, 是因?yàn)樽詡€(gè)不知道textview支持多少html標(biāo)簽喷众,所以有了思路1各谚。途中得到的戰(zhàn)果
TextView支持的html很是有限的,關(guān)于字體的樣式還是用自個(gè)的標(biāo)簽到千。而且最后html會(huì)被轉(zhuǎn)換span的形式
2昌渤, 為什么會(huì)出現(xiàn)思路2的情況,有兩個(gè)需要自定義的類憔四,是因?yàn)楫?dāng)時(shí)大腦亂糾結(jié)這個(gè)問題太長(zhǎng)時(shí)間了愈涩。沒想過直接二合一直接自定義一個(gè) 途中得到的戰(zhàn)果
- 系統(tǒng)的Imagescpan不行,不能和文字垂直居中加矛,并且當(dāng)所使用圖片高度大于文字的ascent(履婉。好像是這個(gè)。 )時(shí)斟览,改行的行高使用會(huì)加上一定高度毁腿。于是上網(wǎng)搜索垂直居中ImageScpan 。
- 牽扯到了drawable自定義 苛茂,了解到當(dāng)drawable.draw(canvas)之前 drawable.getbouds返回的區(qū)域必須是有個(gè)有空間的區(qū)域已烤。不能是高為0,寬為0妓羊,這樣的話只會(huì)看不到
- 中間搜索到了一個(gè)大神寫的垂直居中的ImageSpan
- 在xml中設(shè)置textview的行高不會(huì)體現(xiàn)的設(shè)置字體高度(原以為會(huì)體現(xiàn)到字體 dscent )胯究,只是體現(xiàn)到行與行之間的距離上
獻(xiàn)上最后的兩個(gè)重要的ImageSpan
網(wǎng)上搜索的某個(gè)大神:
public class VerticalImageSpan extends ImageSpan { //根據(jù)圖片調(diào)整字體,來是適應(yīng)圖片的高度
public VerticalImageSpan(Context context,int drawableid) {
super(context,drawableid);
}
/**
* update the text line height
*/
@Override
public int getSize(Paint paint,CharSequence text, intstart, intend, Paint.FontMetricsInt fontMetricsInt) { //設(shè)置圖片塊的寬度
Drawable drawable = getDrawable();
Rect rect = drawable.getBounds(); //注意點(diǎn)躁绸,這個(gè)rect應(yīng)該是有效的空間 高度為0裕循,寬度為0 drawable就繪制不出來,在這個(gè)地方是用
if(fontMetricsInt !=null) { //來調(diào)整字體高度的净刮,因?yàn)橐屛谋拘羞m應(yīng)圖片高度
Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt();
int fontHeight = fmPaint.descent- fmPaint.ascent;
int drHeight = rect.bottom- rect.top;
int centerY = fmPaint.ascent+ fontHeight /2;
fontMetricsInt.ascent= centerY - drHeight /2;
fontMetricsInt.top= fontMetricsInt.ascent;
fontMetricsInt.bottom= centerY + drHeight /2;
fontMetricsInt.descent= fontMetricsInt.bottom;
}
return rect.right;
}
/**
* see detail message in android.text.TextLine
*
*@paramcanvasthe canvas, can be null if not rendering
*@paramtextthe text to be draw
*@paramstartthe text start position
*@paramendthe text end position
*@paramxthe edge of the replacement closest to the leading margin
*@paramtopthe top of the line //文本所在改行的頂部
*@paramythe baseline //文本的基準(zhǔn)線
*@parambottomthe bottom of the line //文本所在改行的底部 及下行的頂部剥哑,xml文件中的設(shè)置的行間距會(huì)直接影響 bottom到baseline的距離
*@parampaintthe work paint
*/
@Override
public void draw(Canvas canvas,CharSequence text, int start, int end,
float x, int top, inty, int bottom,Paint paint) {
CharSequence targetText=text.subSequence(start,end);
Log.v("文字",targetText.toString());
Drawable drawable = getDrawable();
canvas.save();
Rect rect =drawable.getBounds(); //注意點(diǎn),這個(gè)rect應(yīng)該是有效的空間 高度為0淹父,寬度為0 drawable就繪制不出來株婴,
Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt();
int fontHeight = fmPaint.descent- fmPaint.ascent;
int centerY = y + fmPaint.descent- fontHeight /2;
int transY = centerY - (rect.bottom- rect.top) /2;
canvas.translate(x,transY);
drawable.draw(canvas);
canvas.restore();
}
}
這個(gè)是我最終的圖文居中span,如下:
public class CustomSpan extends ImageSpan { //圖片適應(yīng)文本行高度
int resourceId;
int textColor;
float textRadio;
int marginH;//左右間隔
Rect rect;
Drawable drawable;
publicCustomSpan(Context context, int resourceId, int textColor, float textRadio, int marginH) {
super(context,resourceId);
this.resourceId= resourceId;
drawable= context.getResources().getDrawable(resourceId);
this.textRadio= textRadio;
this.textColor= textColor;
this.marginH= marginH;
}
@Override
public int getSize(Paint paint,CharSequence text, intstart, intend,Paint.FontMetricsInt fm) { //設(shè)置圖片塊的寬度
CharSequence targetText=text.subSequence(start,end);
Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt();
int txtW = (int) Math.ceil(paint.measureText(targetText.toString()));
int fontHeight = fmPaint.descent- fmPaint.ascent;
rect=newRect(0,0,txtW,fontHeight);
return rect.right+2*marginH;
}
/**
* see detail message in android.text.TextLine
*
*@paramcanvasthe canvas, can be null if not rendering
*@paramtextthe text to be draw
*@paramstartthe text start position
*@paramendthe text end position
*@paramxthe edge of the replacement closest to the leading margin
*@paramtopthe top of the line //文本所在改行的頂部
*@paramythe baseline //文本的基準(zhǔn)線
*@parambottomthe bottom of the line //文本所在改行的底部 及下行的頂部,xml文件中的設(shè)置的行間距
會(huì)直接影響 bottom到baseline的距離
*@parampaintthe work paint
*/
@Override
public void draw(Canvas canvas,CharSequence text, int start, int end, float x, int top, int y, int bottom,Paint paint) {
CharSequence targetText=text.subSequence(start,end);
intoldTextColor =paint.getColor();
floatoldTextSize =paint.getTextSize();
// canvas.drawLine(0,top,400,top,paint);
// canvas.drawLine(0,y,400,y,paint);
// canvas.drawLine(0,bottom,400,bottom,paint);
Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt();
int oldfontascent = fmPaint.ascent;
paint.setColor(textColor);
paint.setTextSize(oldTextSize*textRadio);
fmPaint = paint.getFontMetricsInt();
int txtW = (int) Math.ceil(paint.measureText(targetText.toString()));
int fontHeight = fmPaint.descent- fmPaint.ascent;
canvas.save();
canvas.translate(marginH+x,y+oldfontascent);//移動(dòng)到該塊的原點(diǎn)
drawable.setBounds(rect);//背景的繪制
drawable.draw(canvas);
Log.e("尺寸",rect.bottom-((rect.bottom-fontHeight))+","+(0-oldfontascent*textRadio));
canvas.translate((rect.right-txtW)/2.0f,rect.bottom/2.f+fontHeight/2-fmPaint.descent); //移動(dòng)的值是相對(duì)的暑认。移動(dòng)到“塊”中字體“服務(wù)中”baseline
canvas.drawText(targetText.toString(),0,0,paint);
paint.setColor(oldTextColor);
paint.setTextSize(oldTextSize);
canvas.restore();
}
}