慢慢成长路——android学习,自定义View(1)

知识来源:http://blog.csdn.net/xmxkf/article/details/51454685#reply

由于项目需要,花费了很大的时间开始学习View的自定义方式,但是发现很多文章都不适合我这种新手,于是跟着上面连接博主的文章开始从基础学习,以此来做学习笔记:po上我的代码:

 

class MagicTextView extends View {
    //需要绘制的文本
    private String text;
    //文本颜色
    private int textColor;
    //文本大小
    private float textSize;
    //文本范围
    private Rect rect;
    //画笔
    private Paint paint;

    public MagicTextView(Context context) {
        super(context);
    }

    public MagicTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MagicTextView, 0, 0);
        text = a.getString(R.styleable.MagicTextView_text);
        textColor = a.getColor(R.styleable.MagicTextView_textColor,Color.BLACK);
        textSize = a.getDimension(R.styleable.MagicTextView_textSize, 2);
        a.recycle();
        rect=new Rect();
        paint=new Paint();
        paint.setColor(Color.BLUE);
        paint.setTextSize(textSize);
        paint.getTextBounds(text,0,text.length(),rect);


    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode=MeasureSpec.getMode(widthMeasureSpec);//取得宽的模式
        int hightMode=MeasureSpec.getMode(heightMeasureSpec);//取得高的模式
        int widthsize=MeasureSpec.getSize(widthMeasureSpec);//取得宽的尺寸
        int hightsize=MeasureSpec.getSize(heightMeasureSpec);//取得高的尺寸
        int width;
        int hight;
        //判定是不是match
        if (widthMode==MeasureSpec.EXACTLY){
            //如果是的话使宽度等于屏幕的宽度
            width=widthsize;
        }else {
            //如果不是的话,使宽度等于文本的宽度加上左右padding的宽度
            float textWidth=rect.width();
            width= (int) (getPaddingLeft()+textWidth+getPaddingRight());
        }
        //高度同理
        if (hightMode==MeasureSpec.EXACTLY){
            hight=hightsize;
        }else{
            float textHight=rect.height();
            hight= (int) (getPaddingTop()+textHight+getPaddingBottom());
        }
        //储存宽和高的值,这个方法忽略掉的话wrap和match都会变成match
        setMeasuredDimension(width,hight);
    }

    public MagicTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

    }


    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //getwidth与getheiht是当前控件所在父布局的宽度与高度,X为控件横坐标起始点,Y为纵坐标起始点
        canvas.drawText(text,0,getHeight()/2,paint);
    }

    public void setText(String text) {
        this.text = text;
    }
}

 

收获1:

大致内容和博主的差不多,不过这里面也有不同之处,关于构造函数的知识,在很多时候我们集成某个类的时候,当它原本中存在多个带参数的构造函数时,我们会发现在随便一个构造函数里面初始化变量会导致程序崩溃,打开日志一看报空,于是我去网上科普了一下,原来构造函数分为很多种,而每一种都在不同的时候被调用:

以上为例,第一个构造函数是其中只包含了context这个参数,所以这个参数实在这个类被初始化的时侯调用的。

而有两个参数的构造函数,其实是在这个类中的变量初始化的时候被调用的,第三个则是重写这个类的时候被调用,下同,所以不同的构造函数是不可以随便用来初始化变量的。

收获2:

关于TypedArray的理解:这个类是用来获取安卓中的资源文件的,他可以通过检索res资源中结构的特定值的索引的到对应的资源,支持大部分的变量类型

TypedArray中的obtainStyledAttributes方法,此方法被调用会返回一个TypedArray类型的持有属性排序的属性值,用完这个之后必须使用TypedArray.recycle()方法将其释放。

-----(2018.1.27)说一下关于刚才了解到的TypedArray和AttriButeSet的区别,如果我们使用AttriButeSet去获得我们要的属性也是可以的,这个类将xml文件中的属性以键值对的形式解析出来,然后它获得的值是我们xml文件中原原本本的数据,比如我们在xml中设置的宽度为100dip,这个方法返回的值就是100dip,所以我们如果使用这个方法来获取值的话,还需要将结果进行处理,而TypedArray返回的则是经过处理后的值,所以我们大可以使用TypedArray来获取属性值(下面还是po上使用AttriButeSet的获取方式)attrName为属性的名字,attrVal为属性的具体值:

public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr); int count = attrs.getAttributeCount();

for (int i = 0; i < count; i++) {

String attrName = attrs.getAttributeName(i);

String attrVal = attrs.getAttributeValue(i);

}}

 

obtainStyledAttributes方法有三个方式:

第一种:

 

public TypedArray obtainStyledAttributes(AttributeSet set,
        @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
    return mThemeImpl.obtainStyledAttributes(this, set, attrs, defStyleAttr, defStyleRes);
}

 

第二种:

 

public TypedArray obtainStyledAttributes(@StyleRes int resId, @StyleableRes int[] attrs)
        throws NotFoundException {
    return mThemeImpl.obtainStyledAttributes(this, null, attrs, 0, resId);
}

 

 

 

第三种:

 

public TypedArray obtainStyledAttributes(@StyleableRes int[] attrs) {
    return mThemeImpl.obtainStyledAttributes(this, null, attrs, 0, 0);
}

 

这个方法用来加载Values中的属性文件,比如下面:

 

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="text" format="string" />
    <attr name="textColor" format="color" />
    <attr name="textSize" format="dimension" />
    <declare-styleable name="MagicTextView">
        <attr name="text" />
        <attr name="textColor" />
        <attr name="textSize" />
    </declare-styleable>
</resources>

用法和含义在文章上连接有,这里就不赘述。由几种方法可以看到其实所有的返回类型都是四个参数,所以在我们重写属性的时候,只需将defStyleattr改为0就可以再第二个构造函数中调用此方法。以上

收获3:

设置自动换行的时候,刚开始尝试了使用stringbulider在获取到文本之后,判断其是否到达最大长度,如果到达了则自动插入换行符换行,但是发现做下来之后出现了问题,那就是你超出最大长度的字符每次多增加一个字符,view的高度就会增高一个字符的高度,查看了连接中文档的方法,多出来的字符截取成多段的时候使用list存入,然后使用paint的getTextBounds()(此方法官方解释为:返回文本的所有连合边界,相当于在文本周围的方框大小)方法

如有说错的地方欢迎指出,以上内容纯属个人理解和学习记录之用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值