下面来写IntroView的onMeasureHeight:
private int measureHeight(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
Paint paint = new Paint();
paint.setTextSize(getTextSize());
paint.setAntiAlias(true);
paint.setStyle(Style.FILL);
displayHeight = -paint.ascent() + paint.descent() + 2;//-paint.ascent() 为字体高于baseLine的部分 paint.descent() 为低于baseline的部分
measureList(paint, titleList, 0);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min((int)displayHeight, specSize);
}
else{
result = (int)displayHeight;
}
}
return result;
}
private float measureList(Paint paint, ArrayList infoList, float StartX){
if(infoList == null || infoList.size() == 0){
displayHeight = StartX;
return StartX;
}
float x = StartX;
int len = infoList.size();
//FontMetrics fontMetrics = paint.getFontMetrics();
float fontHeight = -paint.ascent() + paint.descent();//fontMetrics.bottom - fontMetrics.top;
for(int i = 0; i < len; i++){
LinkInfo info = infoList.get(i);
//这里开始计算每个链接的点击区域
info.getRectFList().clear();
if(info.isFace()){//表情符排版
Bitmap faceBmp = null;
if(mFaceType == MSG_FACE_TYPE) {
faceBmp = MessageFaceModel.getInstance().getFaceIcon(info.getContent());
}
if(faceBmp != null){
int xLen = faceBmp.getWidth() + 4;//表情图标左右各空两个像素
if(x + xLen >= displayWidth){
displayHeight += fontHeight;
x = 0;
}
x += xLen;
}
continue;
}
String strContent = info.getContent();
strContent = strContent.replaceAll("\n", " ");
float xLen = paint.measureText(strContent);
//这里处理换行的情况
if(x + xLen >= displayWidth){
float startX = x;
int lenStr = strContent.length();
for(int j = 0; j < lenStr; j++){
float width = paint.measureText(strContent, j, j + 1);
if(x + width >= displayWidth){
RectF rectF = new RectF();
rectF.set(startX, displayHeight - fontHeight, x, displayHeight);
info.addRectF(rectF);
displayHeight += fontHeight;
x = width;//下一行的X方向起始偏移量,width是一个字符的偏移量,所以这里rectF只在换行的时候执行一次
startX = 0;
}else{
x += width;
}
}
RectF rectF = new RectF();
//如果换行则startX为0,x为第下一行的宽度
rectF.set(startX, displayHeight - fontHeight, x - startX, displayHeight);
info.addRectF(rectF);
}
else{
RectF rectF = new RectF();
rectF.set(x, displayHeight - fontHeight, x + xLen, displayHeight);
info.addRectF(rectF);
x += xLen;
}
}
return x;
}
onDraw:
@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
try{
if(titleList == null || titleList.size() == 0){
return;
}
curLen = 0;
Paint paint = new Paint();
paint.setTextSize(getTextSize());
paint.setAntiAlias(true);
paint.setStyle(Style.FILL);
float y = -paint.ascent();//(fontMetrics.bottom - fontMetrics.ascent);
y = drawList(canvas, paint, titleList, y);
}catch(Exception ex){
}
}
private float drawList(Canvas canvas, Paint paint, ArrayList infoList, float StartY){
if(infoList == null || infoList.size() == 0){
return StartY;
}
float y = StartY;
float fontHeight = -paint.ascent() + paint.descent();//fontMetrics.bottom - fontMetrics.ascent;
int len = infoList.size();
int color = getCurrentTextColor();
for(int i = 0; i < len; i++){
LinkInfo info = infoList.get(i);
if(info.isFace()){//表情符排版
Bitmap faceBmp = null;
if(mFaceType == MSG_FACE_TYPE) {
faceBmp = MessageFaceModel.getInstance().getFaceIcon(info.getContent());
}
if(faceBmp != null){
int xLen = faceBmp.getWidth() + 4;//表情图标左右各空两个像素
if(curLen + xLen >= displayWidth){
y += fontHeight;
curLen = 0;
}
canvas.drawBitmap(faceBmp, curLen + 2, y - fontHeight + 4, paint);
curLen += xLen;
}
continue;
}
String strContent = info.getContent();
if(mFaceType == MSG_FACE_TYPE && strContent.startsWith("\n")){
y += fontHeight;
curLen = 0;
}
strContent = strContent.replaceAll("\n", " ");
if((info.isEmail() || info.isPhoneNumber() || info.isWebUrl()) && info.isSelected()){
paintSelectRectF(canvas, paint, info);
}
float xLen = paint.measureText(strContent);
int starLen = 0;
if(info.isCommonString()){
paint.setColor(color);
}else{
paint.setColor(getResources().getColor(R.drawable.blue1));
}
if(curLen + xLen + starLen >= displayWidth){
int lenStr = strContent.length();
for(int j = 0; j < lenStr; j++){
float width = paint.measureText(strContent, j, j + 1);
if(curLen + width >= displayWidth){
y += fontHeight;
curLen = 0;
}
canvas.drawText(strContent, j, j + 1, curLen, y, paint);
curLen += width;
}
}else{
canvas.drawText(strContent, curLen, y, paint);
curLen += xLen;
}
}
return y;
}
onTouch事件,可以点击Text里面的链接(email,phone)
@Override
public boolean onTouchEvent(MotionEvent event){
super.onTouchEvent(event);
if(!this.isEnabled() || Listener == null){
return false;
}
if(event.getAction() == MotionEvent.ACTION_UP){
float x = event.getX();
float y = event.getY();
boolean flag = cancelCurInfo(x, y);
if(flag){
return false;//up时的坐标已经不在down时记录的Link对象中,则直接返回
}
if(clickLink(titleList, x, y, MotionEvent.ACTION_UP)){
//Log.i("curInfo", "ACTION_UP");
return true;
}
}
else if(event.getAction() == MotionEvent.ACTION_DOWN){
float x = event.getX();
float y = event.getY();
boolean flag = clickLink(titleList, x, y, MotionEvent.ACTION_DOWN);
if(flag){
//Log.i("curInfo", "ACTION_DOWN");
return true;
}
}
else{
float x = event.getX();
float y = event.getY();
cancelCurInfo(x, y);
}
return false;
}
private void paintSelectRectF(Canvas canvas, Paint paint, LinkInfo info){
ArrayList rectList = info.getRectFList();
int len = rectList.size();
for(int i = 0; i < len; i++){
RectF rectF = rectList.get(i);
paint.setColor(this.getContext().getResources().getColor(R.drawable.gray3));
canvas.drawRect(rectF.left, rectF.top - 2, rectF.right, rectF.bottom - 2, paint);
}
}
/** x,y所代表的点已经不在当前Link对象中,则清除掉当前Link对象的选中效果 */
private boolean cancelCurInfo(float x, float y){
if(curInfo == null){
return true;
}
if(!curInfo.contains(x, y)){
curInfo.setSelected(false);
this.invalidate();
curInfo = null;
return true;
}
return false;
}
private boolean clickLink(ArrayList infoList, float x, float y, int action){
if(infoList == null){
return false;
}
int len = infoList.size();
for(int i = 0; i < len; i++){
LinkInfo info = infoList.get(i);
if(info.isCommonString()){
continue;
}
if(info.contains(x, y)){
if(action == MotionEvent.ACTION_DOWN){
info.setSelected(true);
this.invalidate();
this.curInfo = info;
}
else if(action == MotionEvent.ACTION_UP){
this.curInfo = null;
info.setSelected(false);
this.invalidate();
Listener.onClick(info);
}
return true;
}
}
return false;
}
Listener:
private OnClickLinkListener Listener;
public void setOnClickLinkListener(OnClickLinkListener listener){
this.Listener = listener;
}
public interface OnClickLinkListener{
/**点击了动态中的某个链接对象*/
public abstract void onClick(LinkInfo linkInfo);
}
原文:http://blog.csdn.net/baidu_nod/article/details/38470275