Android自定义View:带背景颜色的TextView和条形图--(1)

  • 初始:
    最近在看《Android群英传》一书,代码自己敲了一遍,想想之前敲了又忘记的惨痛经历,决定在博客上记录自己敲的代码,有几个写几篇,放在一个系列里边,就这样,以后看就能一下子找到了。

  • 自定义View
    自定义View我们大致可以从是三个方面着手:
    (1)对现有的控件进行扩展
    (2)通过组合实现全新的控件
    (3)重写View来实现全新的
    没怎么汇总,用到什么知识就注解解释了。

  • 对现有的控件进行扩展
    基于TextView,绘制边框和背景颜色
    关于Paint和Canvas,他们就相当于画画时候的画笔和画板,没有他们我们就不能改变任何东西。

/**
 * 基于已有空间上进行修改
 * 写一个TextView  绘制边框  绘制背景颜色
 * @author fanshenxia
 * 一个自定义类继承TextView  重写构造方法
 */
public class MyTextView extends TextView{
    private Paint mPaint,mPaint2;
    //这个不太清楚,重写了就重写了
    public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
    //这个构造用于xml文件中的构造
    public MyTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    //这个构造方法用于在代码中定义控件
    public MyTextView(Context context) {
        super(context);
        init();
    }
    /**
     * 初始化画笔
     */
    private void init() {
        //实例化画笔
        mPaint = new Paint();
        //设置画笔颜色
        mPaint.setColor(Color.CYAN);
        //设置它的填充方法,用的多的是FILL 和 STORKE
        mPaint.setStyle(Paint.Style.FILL);
        mPaint2 = new Paint();
        mPaint2.setColor(Color.LTGRAY);
        mPaint2.setStyle(Style.FILL);
    }
    /**
     * 重写onDraw方法 可以在绘制文字前后进行一些自己的操作
     * super.onDraw(canvas);调用父类方法绘制文字   
     * 如果绘制矩形的代码写在它的后边,文字就会被覆盖
     */
    @Override
    protected void onDraw(Canvas canvas) {
        //在回调父类方法之前,对TextView来说是绘制文本内容之前
        canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);
        //绘制里层矩形 参数:左、上、右、下、画笔
        //除了绘制矩形,用的多的还可以绘制线,圆,扇形,Path等
        canvas.drawRect(10, 10, getMeasuredWidth()-10, getMeasuredHeight()-10, mPaint2);
        super.onDraw(canvas);
        //绘制文本之后
    }
}

XML中MyTextView内容:

<custom.MyTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:padding="10dp"
        android:text="我是自定义的控件哦~"
        android:textSize="20sp"
        android:visibility="visible" >
    custom.MyTextView>

运行效果:
这里写图片描述

总结:可以看到,上述xml中TextView的相关属性保留着,我们没有自定义其他的任何属性,只是添加了边框和背景。 自定义属性在下边呢~

  • 通过组合来实现新的控件
    这个应该用过吧,平时如果UI给我们的原型图有好多地方搜索框都是一样的,我们会自定义一个控件,将它的大体布局写好,到用的地方就不用一次一次的写了。
    这个简单,我没写代码,以后把它补上。

  • 自定义全新的View
    这里实现了三个自定义View,一个条形图,一个钟表绘制,一个百分比图。先说条形图。

/**
 * 自定义条形图
 * 
 * @author fanshenxia
 *
 */
public class MyBarChartView extends View {
    private Context mContext;
    // 柱状的数值
    private int mNum = 15;
    private Paint mPaint;
    public MyBarChartView(Context context) {
        super(context);
        this.mContext = context;
        init();
    }
    public MyBarChartView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
        init();
    }
    public MyBarChartView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
        init();
    }
    private void init() {
        mPaint = new Paint();
        mPaint.setColor(Color.BLACK);
        mPaint.setStrokeWidth(2);
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Style.FILL);
    }
    /**
        重写onMeasure()方法重新测量控件的宽高
        测量方式有三种
        MeasureSpec.EXACTLY:相当xml中控件layout_width="match_parent/固定XXdp"
        MeasureSpec.AT_MOST:想当wrap_content,它不能大于父控件的宽/高
        MeasureSpec.UNSPECIFIED:不指定其大小测量模式,View想多大就多大,一般用于自定义View
    */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
    }

    private int measureWidth(int measureSpec) {
        int result = 300;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        if (specMode == MeasureSpec.EXACTLY) {
            // 指定数值或者match_parent
            result = specSize;
        } else if (specMode == MeasureSpec.AT_MOST) {
            // 为warp_content时
            result = Math.min(result, specSize);
        } else {
            // view想多大就多大
            result = 300;
        }
        return result;
    }

    private int measureHeight(int measureSpec) {
        int result = 400;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        if (specMode == MeasureSpec.EXACTLY) {
            // 指定数值或者match_parent
            result = specSize;
        } else if (specMode == MeasureSpec.AT_MOST) {
            // 为warp_content时
            result = Math.min(result, specSize);
        } else {
            // view想多大就多大
            result = 400;
        }
        return result;
    }

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

        int width = getMeasuredWidth();
        int height = getMeasuredHeight();
        int rectWidth = (width - 60) / mNum - 20;

        // 绘制坐标线
        canvas.drawLine(20, 20, 20, height - 20, mPaint);
        canvas.drawLine(getWidth() - 20, getHeight() - 20, 20, getHeight() - 20, mPaint);

        int min = 50;
        int max = getHeight()-50;
        Random random = new Random();
        int num = random.nextInt(max) % (max - min + 1) + min;
        // 绘制柱体  这里给的值不是很逻辑的,用的时候需要自己计算后给出相应的值。
        for (int i = 0; i < mNum; i++) {
            canvas.drawRect(20 + rectWidth * i + 20 * (i + 1), num, 20 + rectWidth * (i + 1) + 20 * (i + 1),
                    getHeight() - 20, mPaint);
            num = random.nextInt(max) % (max - min + 1) + min;
        }

        //延时重绘,让条形图每1s刷新一次,它走这个方法时 ,只会执行onDraw方法   init那些不执行,Paint的颜色值等都会保留
        postInvalidateDelayed(1*1000);

    }

}

xml布局:

<custom.MyBarChartView
        android:id="@+id/myBarChartView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

效果:

Android自定义View:带背景颜色的TextView和条形图--(1)_第1张图片模拟器效果录屏效果不太好

你可能感兴趣的:(Android群英传demo)