首页 > 系统 > Android > 正文

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

2019-11-07 23:48:05
字体:
来源:转载
供稿:网友

详见《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()方法        }    }


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表