王学岗自定义控件(二)

接上一篇文章;我们在部署完项目后,虽然有打印输出,但是在屏幕上却没有任何显示这里写图片描述
这是因为我们还没有调用onDraw()方法的缘故!onDraw()方法是把内容绘制到控件,调用这个方法我们需要两个类的帮助,Paint类和Canvas的帮助,paint是画笔,联想下我们在实际生活中,绘画的时候只需要一支画笔,在android也是这样,既然只需要一支画笔我们就可以把画笔定义在构造方法中!不说了看修改后的MyTextView的代码 !

package com.example.zi_ding_yi_kong_jian.myview;

import com.example.zi_ding_yi_kong_jian.R;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;

public class MyTextView extends View {

    private int myTextColor;
    private int defaultValue;
    private int myTestSize;
    private String myText;
    private Paint myPaint;

    public MyTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        TypedArray ta = context.obtainStyledAttributes(attrs,
                R.styleable.myTextView);
        myText = ta.getString(R.styleable.myTextView_myText);
        myTextColor = ta
                .getColor(R.styleable.myTextView_myTextColor, Color.RED);
        defaultValue = (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_SP, 12, getResources()
                        .getDisplayMetrics());
        myTestSize = (int) ta.getDimension(R.styleable.myTextView_myTextSize,
                defaultValue);
        ta.recycle();// 要回收 Be sure to call recycle() when done with them
        Log.i("zhang_xin", "myText=" + myText + "   myTextColor=" + myTextColor
                + "  MyTestSize=" + myTestSize);
        //在构造方法中实例化画笔
        initPaint();
    }

    private void initPaint() {
        myPaint = new Paint();
        myPaint.setColor(Color.BLACK);
        myPaint.setTextSize(50);
        myPaint.setStyle(Style.STROKE);
        myPaint.setAntiAlias(true);
    }

    public MyTextView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyTextView(Context context) {
        this(context, null);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // TODO Auto-generated method stub
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawText(myText, 100, 100, myPaint);

    }
}

但是这样还有一个问题;我们先看下我们的布局中的MyTextView

 <com.example.zi_ding_yi_kong_jian.myview.MyTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        myandroid:myText="@string/myText"
        myandroid:myTextColor="#13579a"
        myandroid:myTextSize="10sp"
        android:background="#08642d" />

它的宽和高都是包裹内容,但效果却是与match_parent一样,匹配父容器,
这里写图片描述
我们当然可以为他设置固定的值但是这样却很不方便,这我们就用到了onMeasure()方法;该方法就是测量view在屏幕中的长和宽!如果我们不重写他默认调用的就是父类的方法!onMeasure()方法在onDraw()方法之前调用,先测量在绘制!
父容器会调用onMeasure()方法,传进两个参数,这两个参数是父容器的宽高模式!我们首先也要判断容器的宽高模式是MeasureSpec.EXACTLY(固定值或者是match_parent)还是MeasureSpec.AT_MOST(wrap_content);我们来看下代码

package com.example.zi_ding_yi_kong_jian.myview;

import com.example.zi_ding_yi_kong_jian.R;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.View.MeasureSpec;

public class MyTextView extends View {
    private int myTextColor;
    private int defaultValue;
    private int myTestSize;
    private String myText;
    private Paint myPaint;
    private Rect bounds;

    public MyTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        TypedArray ta = context.obtainStyledAttributes(attrs,
                R.styleable.myTextView);
        myText = ta.getString(R.styleable.myTextView_myText);
        myTextColor = ta
                .getColor(R.styleable.myTextView_myTextColor, Color.RED);
        defaultValue = (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_SP, 12, getResources()
                        .getDisplayMetrics());
        myTestSize = (int) ta.getDimension(R.styleable.myTextView_myTextSize,
                defaultValue);
        ta.recycle();// 要回收 Be sure to call recycle() when done with them
        Log.i("zhang_xin", "myText=" + myText + "   myTextColor=" + myTextColor
                + "  MyTestSize=" + myTestSize);
        // 在构造方法中实例化画笔
        initPaint();
    }

    private void initPaint() {
        myPaint = new Paint();
        myPaint.setColor(Color.BLACK);
        myPaint.setTextSize(20);
        myPaint.setStyle(Style.STROKE);
        myPaint.setAntiAlias(true);
        bounds = new Rect();
        // 它返回Rect由文字所占据。但根据这个答案它,然后返回不同的TextView的宽度/高度。
        myPaint.getTextBounds(myText, 0, myText.length(), bounds);
    }

    public MyTextView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyTextView(Context context) {
        this(context, null);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //默认是父容器的宽高模式
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        Log.i("zhangxin",widthSize+"");
        int tempwidth = widthSize;
        if (widthMode == MeasureSpec.AT_MOST) {
            // 控件的宽度=所右内边距+文字的宽度。文字的宽度和高度可以在画笔中计算出
            tempwidth = getPaddingLeft() + getPaddingRight() + bounds.width();
        }
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int tempheight = heightSize;
        if (heightMode == MeasureSpec.AT_MOST) {
            tempheight = getPaddingTop() + getPaddingBottom() + bounds.height();
        }
        // 不需要调用父类的方法,但要把测量好的高度和宽度告诉父容器
        // super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(tempwidth, tempheight);
        Log.i("zhang_xin", "tempwidth:" + tempwidth + "  " + "tempheight:"
                + tempheight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // getwidth(),getHeight()得到绘制后view的宽度和高度
        Log.i("zhang_xin", "getWidth():" + getWidth() + "  " + "getHeight:"
                + getHeight());
        Log.i("zhang_xin", "bounds.width():" + bounds.width() + "  "
                + "bounds.height():" + bounds.height());
        Log.i("zhang_xin", "getMeasuredWidth():" + getMeasuredWidth() + "  " + "getMeasuredHeight():"
                + getMeasuredHeight());
        canvas.drawText(myText, (getWidth() - bounds.width()) / 2,
                (getHeight() + bounds.height()) / 2, myPaint);

    }
}

看下效果
这里写图片描述
另外本文还有个缺点,就是关于drawText的参数的问题,我给大家推荐三个链接,相信大家读完就明白了!哎我读完了,但还是有点迷糊
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2013/0409/1143.html
http://blog.csdn.net/lovexieyuan520/article/details/43153275
http://mikewang.blog.51cto.com/3826268/871765/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值