Android菜鸡的提升之路---自定义View简单的实现
首先,先实行一个最简单的自定义View来学习一下有关的属性:
1.在res/values下新建一个xml文件,这里取名hl_attr.xml
在里面定义一些属性:
在写View的时候可以获取属性:
package com.example.admin.my_view.my_view; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Paint; import android.util.AttributeSet; import android.view.View; import android.support.v7.widget.AppCompatTextView; import android.widget.TextView; import com.example.admin.my_view.R; /** * Created by admin on 2018/4/26. */ public class my_text_view extends AppCompatTextView{ private TypedArray mTypedArray; //TypedArray:TypedArray是存储资源数组的容器, // 他可以通过obtaiStyledAttributes()方法创建出来。 // 不过创建完后,如果不在使用了,请注意调用recycle()方法把它释放。 //通过TypedArray来获取xml里面的资源文件 private Paint mPaint; public my_text_view(Context context){ super(context);//调用父类的构造函数 } public my_text_view(Context context, AttributeSet attributeSet){ //ArrtibuteSet 获取xml文件的属性的特征,说明,一般用来传递资源,比如传递给TypedArray. super(context,attributeSet);//继续调用父类构造函数 init(context,attributeSet);//绑定对应的资源文件 } public my_text_view(Context context,AttributeSet attributeSet,int defStyle){ super(context,attributeSet,defStyle); init(context,attributeSet); } private void init(Context context,AttributeSet attributeSet){ TypedArray typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.my_view);//可以利用typedArray来获取定义过的属性 float textsize = typedArray.getFloat(R.styleable.my_view_my_text_size,30); int textcolor = typedArray.getColor(R.styleable.my_view_my_text_color,0x000000); int bgcolor = typedArray.getColor(R.styleable.my_view_my_text_background,0xffffff); String text = typedArray.getString(R.styleable.my_view_my_text); super.setTextSize(textsize); super.setTextColor(textcolor); super.setBackgroundColor(bgcolor); //super.setText(text); super.setText(text); typedArray.recycle();//释放 } }这里是全部的代码。(真的很少)
最后调用:
<com.example.admin.my_view.my_view.my_text_view android:layout_width="wrap_content" android:layout_height="wrap_content" app:my_text_size="30" app:my_text_color="#48ed44" app:my_text="Hdssasdad" android:layout_marginLeft="150dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="163dp" />
很简单,因为是继承TextView,上面每一个参数我几乎都有注释,新手应该比较幸福,因为我当时查的比较累(hhh),那么在上面我们学到了如何设置属性,和利用AttributeSet去得到资源的信息,如何传递给TypedArray,让它去解析获取调出我们之前定义的属性。下面我们要难一点点,就是继承于View去实现一个TextView:
package com.example.admin.my_view.my_view; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; import com.example.admin.my_view.R; import java.util.ArrayList; import java.util.List; /** * Created by admin on 2018/4/26. */ public class my_view_text extends View { private String mtext; //文字 private List<String> mtextlist;//文本列表 private int mcolor;//yanse private float mtextsize;//大小 private Rect mbound;//绘制的范围 private Paint mpaint;//画笔 boolean isoneLine = true;//文本只有一行? float lineNum;//文本的行数(只能整数) float splineNum;//文本的行数(计算需要,存在小数) public my_view_text(Context context){ this(context,null);//调用第二种构造函数 } public my_view_text(Context context , AttributeSet attributeSet){ this(context,attributeSet,0);//调用第三种构造函数 } public my_view_text(Context context,AttributeSet attributeSet,int defstyleattr ) { super(context, attributeSet, defstyleattr);//调用父类的构造函数 TypedArray typedArray =context.obtainStyledAttributes(attributeSet, R.styleable.my_view); mtextlist = new ArrayList<String>(); mtext = typedArray.getString(R.styleable.my_view_my_text); mcolor = typedArray.getColor(R.styleable.my_view_my_text_color,0xff0000); mtextsize = typedArray.getFloat(R.styleable.my_view_my_text_size,100); typedArray.recycle();//释放TypedArray mpaint = new Paint();//画笔对象 mpaint.setColor(mcolor); mpaint.setTextSize(mtextsize);//设置画笔的属性 mbound = new Rect(); //getTextBounds参数:(文本,第一个字符,最后一个字符的后一个,RECT对象 用于存储测出的width和height) mpaint.getTextBounds(mtext, 0, mtext.length(), mbound); } //设置 @Override protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec){ super.onMeasure(widthMeasureSpec,heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec);//获取宽的模式 int heightMode = MeasureSpec.getMode(heightMeasureSpec);//获取高的模式 int widthSize = MeasureSpec.getSize(widthMeasureSpec);//获取宽的尺寸 int heightSize = MeasureSpec.getSize(heightMeasureSpec);//获取高的尺寸 //自动换行 float textwidth = mbound.width();//文本的宽度 if(mtextlist.size() == 0){ int padding = getPaddingLeft() + getPaddingRight();//边距 int xian_shi_width = widthSize - padding;//可显示文本的宽度 //只有一行 if(textwidth<xian_shi_width){ lineNum = 1; isoneLine = true; mtextlist.add(mtext); }else{ isoneLine=false; splineNum = textwidth/xian_shi_width; //需要显示行数 if((splineNum+"").contains(".")){//先转化为字符串,然后判断是否存在“.” lineNum = Integer.parseInt((splineNum+"").substring(0,(splineNum+"").indexOf(".")))+1; //转化为字符串截取到点之前的字符 转化为int类型再加1; //lineNum = (int)splineNum + 1; }else { lineNum = splineNum;//整数型需要显示的行数 } int lengthline = (int) (mtext.length() / splineNum);//每一行显示的字符的长度用于截取字符 //把输入的一串字符串截取出一段段放入list中 for(int i = 0; i<lineNum; i++){ String str; if(mtext.length() < lengthline){ str = mtext.substring(0,mtext.length());//当前行显示的内容 // mtext ="";//清空输入的长字符串 }else { str = mtext.substring(0,lengthline);//截取可以显示的当前行的内容 // mtext = mtext.substring(lengthline,mtext.length());//切掉之前已经显示过的内容 } mtextlist.add(str); if(!TextUtils.isEmpty(mtext)) { if(mtext.length()<lengthline){ mtext = mtext.substring(0, mtext.length()); }else{ mtext = mtext.substring(lengthline, mtext.length()); } }else{ break; } } } } int width; int height; //设置宽度 if(widthMode == MeasureSpec.EXACTLY){ //match_parent或者其它具体的值 width = widthSize; } else{ //float textwidth = mbound.width();//文本的宽度 //wrap_parent //getPaddingLeft内边距(距离左边) getPaddingRight(距离右边) //width = ( int )(getPaddingLeft() + textwidth + getPaddingRight()); if(isoneLine)//单行 width = ( int )(getPaddingLeft() + textwidth +getPaddingRight()); else//多行直接给全部尺寸 width = widthSize; } //设置高度 if(heightMode == MeasureSpec.EXACTLY){ height = heightSize; } else { float textheight = mbound.height(); //getPaddingLeft内边距(距离顶边) getPaddingRight(距离底边) if(isoneLine) height = ( int )(getPaddingTop() + textheight + getPaddingBottom()); else height = ( int )(getPaddingTop() + textheight * lineNum + getPaddingBottom()); } setMeasuredDimension(width,height);//保存宽度和高度 } @Override protected void onDraw(Canvas canvas){ //分行绘出文字 for(int i = 0 ; i < mtextlist.size() ; i++) { mpaint.getTextBounds(mtextlist.get(i),0,mtextlist.get(i).length(),mbound); canvas.drawText(mtextlist.get(i),getWidth()/2 - mbound.width()/2,getPaddingTop()+(mbound.height()*i),mpaint); } // canvas.drawText(mtext,getWidth()/2-mbound.width()/2,getHeight()/2+mbound.height()/2,mpaint); } }
这里注释给的很全了,但是在显示的时候高度好像还是有点问题,没有做到和textview那么强大的自动换行对齐,但是我们还是先学下去。