【笔记】第三章Android控件架构与自定义控件详解(1)

详见《Android群英传》

3.1Android控件架构

每一个activity都包含一个window对象,window设置DecorView作为顶层视图,所有View的监听事件由WindowManagerService接收,并通过Activity对象来回调,其中顶层视图由TitleView和ContentView组成,ContentView是一个framelayout


3.2View的测量

在布局中使用自定义View,View的大小通过自定义View类中的onMeasure方法来指定,但是该方法默认调用的是EXACTLY模式(进入super.onMeasure)可知)

对于自定义View的长宽为wrap_content,达不到意想的结果,(当然可以直接到布局中进行设置,就没有下面的了)

如下

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

我们要做到有所区分,就必须重写该方法,针对布局中指定的layout_width,layout_high来给出合适的大小

当布局中指定的是match_parent时,表名是EXACTLY模式,其要求和父类的值相同

当布局中指定的是wrap_content时,表名的是AT_MOST模式,要求最大不能超过默认的值(下面的函数中默认的值用result指定)

至于UNSPECIFIED模式,要求默认值是多大,就是多大,至于布局中如何指定,未知

这样我们可以通过获取其模式来判断布局中的方式,并做修改

如下

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
    }

    private int measureHeight(int heightMeasureSpec) {
        int result=200;
        int specMode=MeasureSpec.getMode(heightMeasureSpec);//获取测量模式
        int specSize=MeasureSpec.getSize(heightMeasureSpec);//获取测量大小

        /*
        关于这三种模式,
         */
        if(specMode==MeasureSpec.EXACTLY){
            result=specSize;//如果等于精确模式,则使用父类指定的大小
        }else if(specMode==MeasureSpec.AT_MOST){
            result=Math.min(result,specSize);//如果为最大模式,则大小不能超过默认的大小
        }else{
            //其他使用默认的大小
        }
        return result;
    }

    private int measureWidth(int widthMeasureSpec) {
        int result=200;
        int specMode=MeasureSpec.getMode(widthMeasureSpec);//获取测量模式
        int specSize=MeasureSpec.getSize(widthMeasureSpec);//获取测量大小

        if(specMode==MeasureSpec.EXACTLY){
            result=specSize;//如果等于精确模式,则使用父类指定的大小
        }else if(specMode==MeasureSpec.AT_MOST){
            result=Math.min(result,specSize);//如果为最大模式,则大小不能超过默认的大小
        }else{
            //其他使用默认的大小
        }
        return result;
    }

3.6自定义View

自定义View要重写onDraw()方法,下面重写TextView的onDraw()方法

@Override
    protected void onDraw(Canvas canvas) {
        //回调父类方法前实现自己的逻辑
        Paint mPaint1=new Paint();
        mPaint1.setColor(getResources().getColor(android.R.color.holo_blue_light));
        mPaint1.setStyle(Paint.Style.STROKE);//设置空心画笔
        mPaint1.setStrokeWidth(10);//设置空心画笔的宽度
        Paint mPaint2=new Paint();
        mPaint2.setColor(Color.YELLOW);
        mPaint2.setStyle(Paint.Style.STROKE);
        mPaint2.setStrokeWidth(10);

        //这个画矩形要说一下,画笔的宽度为10,从5开始画,即10分为左边的5和右边的5
        canvas.drawRect(5, 5, getMeasuredWidth()-5, getMeasuredHeight()-5, mPaint1);
        canvas.drawRect(15, 15, getMeasuredWidth() - 15, getMeasuredHeight() - 15, mPaint2);

        //关于save和restore,save保存了此时的位置,然后将此时的位置平移到20,20,目的是不让原生实现和自定义的逻辑实现重叠,然后restore在返回到save的状态
        canvas.save();
        canvas.translate(20,20);
        //原生的textview实现
        super.onDraw(canvas);
        canvas.restore();
    }

下面继续自定义View,实现文字的闪烁效果

使用到Shader

可以参考以下两篇文章

http://www.tuicool.com/articles/RF7v2qY

http://www.jianshu.com/p/a9d09cb7577f


附上代码的解说

//onSizeChanged()方法是在onDraw()前执行的,也就是用view加载后会自动的执行一次onSizeChanged()方法
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        Log.i("TextView","onSizeChanged");
        super.onSizeChanged(w, h, oldw, oldh);
        if (mViewWidth == 0) {
            mViewWidth = getMeasuredWidth();//获取View的宽度
            if (mViewWidth > 0) {
                mPaint = getPaint();//获取画笔
                /*
                字体渐变,其中参数含义分别是:起始x,起始y,终点x,终点y,渐变的颜色组,对应颜色组渐变的位置值,平铺方式
                 */
                mLinearGradient = new LinearGradient(
                        0,
                        0,
                        mViewWidth,
                        0,
                        new int[]{
                                Color.BLUE, 0xffffffff,
                                Color.BLUE},
                        null,
                        Shader.TileMode.CLAMP);

                mPaint.setShader(mLinearGradient);//通过setShader来设置这个渐变,因为LinearGradient本来就是继承Shader
                mGradientMatrix = new Matrix();//矩阵
            }
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Log.i("TextView","onDraw");
        super.onDraw(canvas);
        if (mGradientMatrix != null) {
            mTranslate += mViewWidth / 5;
            if (mTranslate > 2 * mViewWidth) {
                mTranslate = -mViewWidth;
            }
            mGradientMatrix.setTranslate(mTranslate, 0);//参数为x,y;设置矩阵以(x,y)形式转换
            mLinearGradient.setLocalMatrix(mGradientMatrix);//设置矩阵
            postInvalidateDelayed(100);//重绘,即过100毫秒后,系统会重新调用onDraw()方法,不会再执行onSizeChanged()方法
        }
    }


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值