网上已经有了大量的自定义View的实例,讲了很多教大家如何去写一个自定义View的。虽说本篇博文也是讲的自定义View ,但是并不会教程式的讲述如何去自定义View,
只是提供一个deom,讲述一下,并提供一下想法,仅此而已。
好了,直接上个图吧~
这个就是效果了,就是一段描述性的文字,多行显示,并且,后面有一个“more”的点击区域。
下面介绍代码吧,先是获取资源文件
TypedArray ta=context.obtainStyledAttributes(attrs,R.styleable.MoreView);
try{
mText=ta.getString(R.styleable.MoreView_text);
if(mText==null)
throw new NullPointerException("不能为空!");
mTextColor=ta.getColor(R.styleable.MoreView_color,getResources().getColor(R.color.colorPrimary));
mTextSize=ta.getDimensionPixelSize(R.styleable.MoreView_textsize,20);
}catch (Exception e){
e.printStackTrace();
}finally {
ta.recycle();
}
这段代码,就是可以让用户在xml里面自定义的一些内容,先拿到这些内容,给好初始值。
然后就是初始化画笔部分了。
private void init(Context context){
mTextPaint=new TextPaint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(mTextSize);
mTextPaintmore=new TextPaint(Paint.ANTI_ALIAS_FLAG);
mTextPaintmore.setAntiAlias(true);
mTextPaintmore.setTextSize(mTextSize);
mTextPaintmore.setColor(mTextColor);
ScreenWidth=ScreenUtils.getScreenWidth(context);
}
下面就是要onMeasure了
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSize=MeasureSpec.getSize(widthMeasureSpec);
int heightSize=MeasureSpec.getSize(heightMeasureSpec);
int widthMode=MeasureSpec.getMode(widthMeasureSpec);
int heightMode=MeasureSpec.getMode(heightMeasureSpec);
int height=0;
if(heightMode==MeasureSpec.EXACTLY){
height=heightSize;
}else if(heightMode==MeasureSpec.AT_MOST){
height=800;
}
setMeasuredDimension(widthSize,height);
}
这部分都不难,不需要过多解释,大家应该都能看懂
然后就是绘制部分了。onDraw()
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(!TextUtils.isEmpty(normalString)){
canvas.save();
layout=new StaticLayout(normalString,mTextPaint,ScreenWidth-50, Layout.Alignment.ALIGN_NORMAL
,1.0F,0.0F,true);
layout.draw(canvas);
canvas.restore();
layout2=new StaticLayout(normalString+mText,mTextPaintmore,ScreenWidth-50, Layout.Alignment.ALIGN_NORMAL
,1.0F,0.0F,true);
if(layout2.getLineCount()>layout.getLineCount()){
canvas.drawText(mText,0,layout2.getHeight()-mTextPaintmore.getFontMetrics().bottom,mTextPaintmore);
}else{
canvas.drawText(mText,layout.getLineWidth(layout.getLineCount()-1),layout.getHeight()-mTextPaintmore.getFontMetrics().bottom,mTextPaintmore);
}
}
}
这部分呢,主要是借住StaticLayout这个类,来实现多行显示。可以拿到,一段文字之后可否再加 “more” 这样的字数,或者说另起一行来绘制 "more" ,其实,总的来说,想要绘制好 "more" 主要就是找到 x ,y坐标。
canvas.drawText(mText,0,layout2.getHeight()-mTextPaintmore.getFontMetrics().bottom,mTextPaintmore);
canvas.drawText(mText,layout.getLineWidth(layout.getLineCount()-1),layout.getHeight()-mTextPaintmore.getFontMetrics().bottom,mTextPaintmore);
这个就是绘制代码。x坐标好办,如果是独立的一行就是 0,如果是跟文字同一行,就是
layout.getLineWidth(layout.getLineCount()-1),获取到最后一行的宽度就可以了。
然后 y 坐标的话,如果是独立一行的话,就是layout2的高度 减去 字体的高度,就是了,如果跟文字是同一行的话,就是layout的高度减去文字的高度就可以了。
下面就是onTouchEvent()部分了
@Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction()==MotionEvent.ACTION_DOWN){
float x=event.getX();
float y=event.getY();
if(layout2.getLineCount()>layout.getLineCount()){ //另起一行
if((x>=0 && x<=mTextPaintmore.measureText(mText))&&
(y>=layout2.getHeight()-(mTextPaintmore.getFontMetrics().descent-mTextPaintmore.getFontMetrics().ascent)
&&y <=layout2.getHeight())){
onMoreClicklistener.onClick();
return true;
}
}else{ //同一行
if((x>=layout.getLineWidth(layout.getLineCount()-1) && x<=(layout.getLineWidth(layout.getLineCount()-1) + mTextPaintmore.measureText(mText)))
&&(y>=(layout.getHeight()-(mTextPaintmore.getFontMetrics().descent-mTextPaintmore.getFontMetrics().ascent))
&&y <=layout.getHeight())){
onMoreClicklistener.onClick();
return true;
}
}
}
return super.onTouchEvent(event);
}
这里主要是找到,“more”的点击范围,提供onTouchEvent事件 ,return true 表示消耗此事件。
public interface OnMoreClicklistener{
void onClick();
}
private OnMoreClicklistener onMoreClicklistener;
public void setOnMoreClicklistener(OnMoreClicklistener onMoreClicklistener){
this.onMoreClicklistener=onMoreClicklistener;
}
这里提供接口,供外部调用。
好了,分析就到这了。最后,送上demo链接 点击打开链接