Android菜鸡的提升之路---自定义View简单的实现

首先,先实行一个最简单的自定义View来学习一下有关的属性:

1.在res/values下新建一个xml文件,这里取名hl_attr.xml

在里面定义一些属性:

Android菜鸡的提升之路---自定义View简单的实现Android菜鸡的提升之路---自定义View简单的实现

在写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对象  用于存储测出的widthheight        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那么强大的自动换行对齐,但是我们还是先学下去。