View和ViewGroup的测量与绘制




View的测量与绘制:


测量的3种模式
MeasureSpec:封装了测量模式和长宽大小



一般重写View的模板:
public class MyView extends View {
    public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

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

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     *  控制View的大小
     */
    @Override
    protected void  onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    /**
     * 在View上绘制图形图像
     */
    @Override
    protected void  onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // getMeasuredWidth();   getMeasuredHeight()  ,获取高宽
    }

    /**
     *  屏幕大小改变和时调用
     *  这里主要是获取变化后的长宽
     */
    @Override
    protected void  onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        int height = getHeight()  ;
        int width = getWidth() ;
    }


    /**
     * 在这里控制View的布局参数,一般View不需要复写该方法
        一般是在ViewGroup复写onLayout(),用来控制子View的布局位置
     */
    @Override
    protected void  onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        //getLayoutParams()  获取View 的布局参数,获取包括外边距,内边距,布局方向,布局的高度
        ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams)getLayoutParams() ;
        mlp.leftMargin = 10 ;
        setLayoutParams(mlp);
    }
}





public class CustomView extends View {
    public CustomView(Context context) {
        super(context);
    }

    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * View的测量,主要是测量该View在大小
     * View的布局模式和大小都封装在widthMeasureSpec和heightMeasureSpec中
     * 需使用MeasureSpec类将其解析出来,然后随便自定义
     */
    @Override
    protected void  onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int viewWidth = measureWidth(widthMeasureSpec) ;
        int viewHeight = measureHeight(heightMeasureSpec);
        //setMeasuredDimension()是设置View的尺寸
        setMeasuredDimension(viewWidth,viewHeight);
    }

    /**
     * 测量View的宽度
     * @param widthMeasureSpec
     * @return
     */
    private int measureWidth(int widthMeasureSpec){
        int result = 0 ;
        int specMode = MeasureSpec.getMode(widthMeasureSpec) ;
        int specSize =  MeasureSpec.getSize(widthMeasureSpec) ;

        if(specMode == MeasureSpec.EXACTLY){
            result = specSize ;
        }else{          //对其他模式的情况进行处理,如果不处理,其他模式(如wrap_content)下也会match_parent
            result = 200 ;
            if(specMode == MeasureSpec.AT_MOST){
                //取较小的一个
                result = Math.min(result,specSize) ;
            }
        }
        return result ;
    }

    /**
     * 测量View的高度
     */
    private int measureHeight(int heightMeasureSpec){
        int result = 0 ;
        int specMode = MeasureSpec.getMode(heightMeasureSpec) ;
        int specSize =  MeasureSpec.getSize(heightMeasureSpec) ;

        if(specMode == MeasureSpec.EXACTLY){
            result = specSize ;
        }else{                   //对其他模式的情况进行处理,如果不处理,其他模式(如wrap_content)下也会match_parent
            result = 200 ;
            if(specMode == MeasureSpec.AT_MOST){
                //取较小的一个
                result = Math.min(result,specSize) ;
            }
        }
        return result ;
    }

    /**
     * View的绘制
     */
    @Override
    protected void  onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //将整个画布绘制成白色
        canvas.drawColor(Color.RED);

        //设置画笔
        Paint pt = new Paint() ;
        pt.setStyle(Paint.Style.STROKE);
        pt.setColor(Color.BLUE);
        pt.setStrokeWidth(2);

        //画圆形
        canvas.drawCircle(50, 50, 30, pt);
        //画正方形矩形
        canvas.drawRect(10,90,90,170,pt);
        //画矩形
        canvas.drawRect(10, 200, 110, 250, pt);
        //画圆角矩形
        RectF rf1 = new RectF(20,300,120,350) ;
        canvas.drawRoundRect(rf1, 10, 10, pt);
        //画椭圆
        RectF rf2 = new RectF(10,400,120,450) ;
        canvas.drawOval(rf2, pt);

        //画弧形
        RectF rf3 = new RectF(10,500,410,800) ;
        canvas.drawArc(rf3,180,120,false,pt);
    }
}


自定义View,继承了TextView
效果图;
public class CustomTextView extends TextView {

    private Paint mPaint1 = null ;
    private Paint mPaint2 = null ;

    public CustomTextView(Context context) {
        super(context);
        initView();
    }

    public CustomTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView();
    }

    /**
     * 这里不需要复写onMeasure()方法,不需要再重新测量大小了,因为TextView已经搞好了
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //绘制外层矩形
        canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mPaint1);
        canvas.drawRect(5,5, getMeasuredWidth() - 5, getMeasuredHeight() - 5, mPaint2);
        //设置偏移距离之前保存画布
        canvas.save();
        //设置画布的原点偏移距离,x轴偏移10个像素
        canvas.translate(5,0);
        //父类onDraw()负责绘制文本
        super.onDraw(canvas);
        //恢复画布
        canvas.restore();
    }

    /**
     * 初始化View
     */
    private void initView(){
        //初始化画笔
        mPaint1 = new Paint() ;
        mPaint1.setStyle(Paint.Style.FILL);
        mPaint1.setColor(Color.RED);
        mPaint2 = new Paint();
        mPaint2.setStyle(Paint.Style.FILL);
        mPaint2.setColor(Color.BLUE);
    }
}




自定义View,实现圆形进度图
效果图:
public class CustomCircleProcess extends View {

    private int mMeasureWidth = 0 ;
    private int mMeasureHeight = 0 ;

    //圆形圆心
    private float mCircleXY = 0 ;
    //圆形半径
    private float mCircleRadius = 0 ;
    //圆形所用到的画笔
    private Paint mCirclePaint ;

    //弧形所需要的矩形
    private RectF mArcRectF ;
    //弧形起始角度,默认值:270
    private float mArcStartAngle = 270 ;
    //弧形的跨越度数 ,默认值:25
    private float mArcSweepAngle = 25 ;
    //弧形所需要的画笔
    private Paint mArcPaint ;

    //绘制文本所需要的Paint
    private Paint mTextPaint ;
    //文本内容
    private String mTextContent = "万紫辉" ;
    //文本大小
    private float mTextSize = 20f ;

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

    public CustomCircleProcess(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomCircleProcess(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * 复写onMeasure()方法,测量其大小
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //这个View只有MeasureSpec.EXACTLY模式(绝对值或match_parent),没有对其他模式(如:wrap_content)进行处理,
        //所以在其他模式下,长宽也都是match_parent
        //其实这里不需要wrap_content的情况
        mMeasureWidth = MeasureSpec.getSize(widthMeasureSpec) ;
        mMeasureHeight = MeasureSpec.getSize(heightMeasureSpec) ;
        setMeasuredDimension(mMeasureWidth, mMeasureHeight);
        initView();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //画圆
        canvas.drawCircle(mCircleXY, mCircleXY, mCircleRadius, mCirclePaint);
        //画弧
        canvas.drawArc(mArcRectF, mArcStartAngle, mArcSweepAngle, false, mArcPaint);
        //画文本
        canvas.drawText(mTextContent, mCircleXY, mCircleXY, mTextPaint);
    }

    private void initView(){
        float length = 0f ;
        if(mMeasureHeight > mMeasureWidth){
            length = mMeasureWidth ;
        }else{
            length = mMeasureHeight ;
        }

        mCircleXY = length / 2 ;
        mCircleRadius =length / 4 ;

        mCirclePaint = new Paint() ;
        mCirclePaint.setStyle(Paint.Style.FILL);
        mCirclePaint.setColor(Color.RED);
        mCirclePaint.setAntiAlias(true);

        mArcRectF = new RectF(
                (float)(length*0.1),
                (float)(length*0.1),
                (float)(length*0.9),
                (float)(length*0.9)) ;
        mArcSweepAngle = 240f ;
        mArcPaint = new Paint() ;
        mArcPaint.setAntiAlias(true);
        mArcPaint.setStyle(Paint.Style.STROKE);
        mArcPaint.setStrokeWidth((float)(length*0.1));
        mArcPaint.setColor(Color.BLUE);

        mTextPaint = new Paint() ;
        mTextPaint.setStyle(Paint.Style.STROKE);
        mTextPaint.setStrokeWidth(2f);
        mTextPaint.setColor(Color.GREEN);
        //设置要绘制文本的大小
        mTextPaint.setTextSize(mTextSize);
        //设置要绘制文本的对其方式
        mTextPaint.setTextAlign(Paint.Align.CENTER); //CENTER :文本原点为中心点,LEFT or RIGHT :文本原点为起点
    }

    /**
     * 设置弧形范围
     * @param value
     */
    public void setSweepAngle(float value){
        if(value >= 0){
            mArcSweepAngle = value ;
        }else{
            mArcSweepAngle = 25 ;
        }
        //重绘视图
        this.invalidate();
    }

    public void setTextContent(String value){
        mTextContent = value ;
        this.invalidate();
    }

}



条形梯度图:
效果图:
public class CustomGradientView extends View {

    private Paint mPaint ;
    private int mViewWidth ;
    private int mViewHeight ;

    private int mRectWidth ;
    private int mRectHeight ;
    private int mRectCount = 10 ;
    private int offset = 3 ;

    public CustomGradientView(Context context) {
        super(context);
        initView() ;
    }

    public CustomGradientView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public CustomGradientView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView();
    }

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

    /**
     * 绘制图像
     * @param canvas
     */
    @Override
    protected void  onDraw(Canvas canvas) {
        canvas.drawColor(Color.RED);
        for(int i = 0 ; i < mRectCount ; i++){
            // 0.0 <= random < 1.0
            double random = Math.random() ;
            float topDistance = (float)(mRectHeight * random) ;
            float leftDistance = (float)(mViewWidth * 0.1 + mRectWidth * i + offset*i) ;
            float rightDistance = (float)(mViewWidth * 0.1 + mRectWidth * (i+1) + offset*i) ;
            float bottomDistance = mRectHeight ;
             canvas.drawRect(leftDistance,topDistance,rightDistance,bottomDistance,mPaint);
        }
        //过500毫秒在重新绘制
         postInvalidateDelayed(500);
    }

    /**
     * 横竖屏变化时,获取其长宽
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
         mViewWidth = getWidth() ;
        mViewHeight = getHeight() ;

        mRectHeight = mViewHeight ;
        mRectWidth =(int)(( mViewWidth / mRectCount ) * 0.7) ;
    }

    private void initView(){
        //初始化画笔
        mPaint = new Paint() ;
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(Color.YELLOW);
    }
}



ViewGroup的测量和绘制:
一把要复写:
        onMeasure() ;  onDraw()  ;   onLayout()
public class CustomScrollView extends ViewGroup {
    //屏幕高度
    private int mScreenHeight=  0 ;
    private Scroller mScroller;
    private int mLastY;
    private int mStart;
    private int mEnd;

    public CustomScrollView(Context context) {
        super(context);
        initView(context);
    }

    public CustomScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    public CustomScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView(context);
    }

    private void initView(Context context){
        //获取屏幕高度(像素高度)
        WindowManager wm =  (WindowManager)(context.getSystemService(Context.WINDOW_SERVICE)) ;
        DisplayMetrics dm = new DisplayMetrics() ;
        wm.getDefaultDisplay().getMetrics(dm);
        mScreenHeight = dm.heightPixels ;
    }

    /**
     * onMeasure()  用于设计ViewGoup的大小
     * widthMeasureSpec和heightMeasureSpec封装了ViewGroup的模式和大小,
     * 以这个参数,调用measureChild()来测量子View的大小
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void  onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int count = getChildCount() ;
        for (int i = 0; i < count; i++) {
            View childView = getChildAt(i) ;
             measureChild(childView,widthMeasureSpec,heightMeasureSpec);
        }
    }

    /**
     * onLayout()  用于控制ViewGroup的(子View)布局情况
     * 主要就是控制View的布局方向,各种外边距的
     */
    @Override
    protected void  onLayout(boolean changed, int l, int t, int r, int b) {
        int count =  getChildCount() ;
        //getLayoutParams()  获取View 的布局参数,获取包括外边距,内边距,布局方向,布局的高度
         MarginLayoutParams mlp = (MarginLayoutParams)getLayoutParams() ;
        mlp.height = mScreenHeight *  count;
        //setLayoutParams() 设置布局参数
         setLayoutParams(mlp);
        for(int i = 0 ; i < count ; i++){
            View childView =  getChildAt(i) ;
            //控制子的布局情况
             childView.layout(l,i * mScreenHeight,r,(i+1)*mScreenHeight);
        }
    }

    /**
     * onDraw()  用于在ViewGroup上绘的图像,
     * 如果不是设置ViewGroup的背景,一般不需要复写ViewGroup的onDraw()方法
     * @param canvas
     */
    @Override
    protected void  onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }

    /**
     * 用于监听响应事件
     * @param event
     * @return
     */
    @Override
    public boolean  onTouchEvent(MotionEvent event) {
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastY = y;
                mStart = getScrollY();
                break;
            case MotionEvent.ACTION_MOVE:
                if (!mScroller.isFinished()) {
                    mScroller.abortAnimation();
                }
                int dy = mLastY - y;
                if (getScrollY() < 0) {
                    dy = 0;
                }
                if (getScrollY() > getHeight() - mScreenHeight) {
                    dy = 0;
                }
                scrollBy(0, dy);
                mLastY = y;
                break;
            case MotionEvent.ACTION_UP:
                mEnd = getScrollY();
                int dScrollY = mEnd - mStart;
                if (dScrollY > 0) {
                    if (dScrollY < mScreenHeight / 3) {
                        mScroller.startScroll(
                                0, getScrollY(),
                                0, -dScrollY);
                    } else {
                        mScroller.startScroll(
                                0, getScrollY(),
                                0, mScreenHeight - dScrollY);
                    }
                } else {
                    if (-dScrollY < mScreenHeight / 3) {
                        mScroller.startScroll(
                                0, getScrollY(),
                                0, -dScrollY);
                    } else {
                        mScroller.startScroll(
                                0, getScrollY(),
                                0, -mScreenHeight - dScrollY);
                    }
                }
                break;
        }
        postInvalidate();
        return true;
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        if (mScroller.computeScrollOffset()) {
            scrollTo(0, mScroller.getCurrY());
            postInvalidate();
        }
    }
}




 

View的测量与绘制:


测量的3种模式
MeasureSpec:封装了测量模式和长宽大小

1

一般重写View的模板:
public class MyView extends View {
    public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

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

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     *  控制View的大小
     */
    @Override
    protected void  onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    /**
     * 在View上绘制图形图像
     */
    @Override
    protected void  onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // getMeasuredWidth();   getMeasuredHeight()  ,获取高宽
    }

    /**
     *  屏幕大小改变和时调用
     *  这里主要是获取变化后的长宽
     */
    @Override
    protected void  onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        int height = getHeight()  ;
        int width = getWidth() ;
    }


    /**
     * 在这里控制View的布局参数,一般View不需要复写该方法
        一般是在ViewGroup复写onLayout(),用来控制子View的布局位置
     */
    @Override
    protected void  onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        //getLayoutParams()  获取View 的布局参数,获取包括外边距,内边距,布局方向,布局的高度
        ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams)getLayoutParams() ;
        mlp.leftMargin = 10 ;
        setLayoutParams(mlp);
    }
}





public class CustomView extends View {
    public CustomView(Context context) {
        super(context);
    }

    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * View的测量,主要是测量该View在大小
     * View的布局模式和大小都封装在widthMeasureSpec和heightMeasureSpec中
     * 需使用MeasureSpec类将其解析出来,然后随便自定义
     */
    @Override
    protected void  onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int viewWidth = measureWidth(widthMeasureSpec) ;
        int viewHeight = measureHeight(heightMeasureSpec);
        //setMeasuredDimension()是设置View的尺寸
        setMeasuredDimension(viewWidth,viewHeight);
    }

    /**
     * 测量View的宽度
     * @param widthMeasureSpec
     * @return
     */
    private int measureWidth(int widthMeasureSpec){
        int result = 0 ;
        int specMode = MeasureSpec.getMode(widthMeasureSpec) ;
        int specSize =  MeasureSpec.getSize(widthMeasureSpec) ;

        if(specMode == MeasureSpec.EXACTLY){
            result = specSize ;
        }else{          //对其他模式的情况进行处理,如果不处理,其他模式(如wrap_content)下也会match_parent
            result = 200 ;
            if(specMode == MeasureSpec.AT_MOST){
                //取较小的一个
                result = Math.min(result,specSize) ;
            }
        }
        return result ;
    }

    /**
     * 测量View的高度
     */
    private int measureHeight(int heightMeasureSpec){
        int result = 0 ;
        int specMode = MeasureSpec.getMode(heightMeasureSpec) ;
        int specSize =  MeasureSpec.getSize(heightMeasureSpec) ;

        if(specMode == MeasureSpec.EXACTLY){
            result = specSize ;
        }else{                   //对其他模式的情况进行处理,如果不处理,其他模式(如wrap_content)下也会match_parent
            result = 200 ;
            if(specMode == MeasureSpec.AT_MOST){
                //取较小的一个
                result = Math.min(result,specSize) ;
            }
        }
        return result ;
    }

    /**
     * View的绘制
     */
    @Override
    protected void  onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //将整个画布绘制成白色
        canvas.drawColor(Color.RED);

        //设置画笔
        Paint pt = new Paint() ;
        pt.setStyle(Paint.Style.STROKE);
        pt.setColor(Color.BLUE);
        pt.setStrokeWidth(2);

        //画圆形
        canvas.drawCircle(50, 50, 30, pt);
        //画正方形矩形
        canvas.drawRect(10,90,90,170,pt);
        //画矩形
        canvas.drawRect(10, 200, 110, 250, pt);
        //画圆角矩形
        RectF rf1 = new RectF(20,300,120,350) ;
        canvas.drawRoundRect(rf1, 10, 10, pt);
        //画椭圆
        RectF rf2 = new RectF(10,400,120,450) ;
        canvas.drawOval(rf2, pt);

        //画弧形
        RectF rf3 = new RectF(10,500,410,800) ;
        canvas.drawArc(rf3,180,120,false,pt);
    }
}


自定义View,继承了TextView
效果图;
public class CustomTextView extends TextView {

    private Paint mPaint1 = null ;
    private Paint mPaint2 = null ;

    public CustomTextView(Context context) {
        super(context);
        initView();
    }

    public CustomTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView();
    }

    /**
     * 这里不需要复写onMeasure()方法,不需要再重新测量大小了,因为TextView已经搞好了
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //绘制外层矩形
        canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mPaint1);
        canvas.drawRect(5,5, getMeasuredWidth() - 5, getMeasuredHeight() - 5, mPaint2);
        //设置偏移距离之前保存画布
        canvas.save();
        //设置画布的原点偏移距离,x轴偏移10个像素
        canvas.translate(5,0);
        //父类onDraw()负责绘制文本
        super.onDraw(canvas);
        //恢复画布
        canvas.restore();
    }

    /**
     * 初始化View
     */
    private void initView(){
        //初始化画笔
        mPaint1 = new Paint() ;
        mPaint1.setStyle(Paint.Style.FILL);
        mPaint1.setColor(Color.RED);
        mPaint2 = new Paint();
        mPaint2.setStyle(Paint.Style.FILL);
        mPaint2.setColor(Color.BLUE);
    }
}




自定义View,实现圆形进度图
效果图:
public class CustomCircleProcess extends View {

    private int mMeasureWidth = 0 ;
    private int mMeasureHeight = 0 ;

    //圆形圆心
    private float mCircleXY = 0 ;
    //圆形半径
    private float mCircleRadius = 0 ;
    //圆形所用到的画笔
    private Paint mCirclePaint ;

    //弧形所需要的矩形
    private RectF mArcRectF ;
    //弧形起始角度,默认值:270
    private float mArcStartAngle = 270 ;
    //弧形的跨越度数 ,默认值:25
    private float mArcSweepAngle = 25 ;
    //弧形所需要的画笔
    private Paint mArcPaint ;

    //绘制文本所需要的Paint
    private Paint mTextPaint ;
    //文本内容
    private String mTextContent = "万紫辉" ;
    //文本大小
    private float mTextSize = 20f ;

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

    public CustomCircleProcess(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomCircleProcess(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * 复写onMeasure()方法,测量其大小
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //这个View只有MeasureSpec.EXACTLY模式(绝对值或match_parent),没有对其他模式(如:wrap_content)进行处理,
        //所以在其他模式下,长宽也都是match_parent
        //其实这里不需要wrap_content的情况
        mMeasureWidth = MeasureSpec.getSize(widthMeasureSpec) ;
        mMeasureHeight = MeasureSpec.getSize(heightMeasureSpec) ;
        setMeasuredDimension(mMeasureWidth, mMeasureHeight);
        initView();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //画圆
        canvas.drawCircle(mCircleXY, mCircleXY, mCircleRadius, mCirclePaint);
        //画弧
        canvas.drawArc(mArcRectF, mArcStartAngle, mArcSweepAngle, false, mArcPaint);
        //画文本
        canvas.drawText(mTextContent, mCircleXY, mCircleXY, mTextPaint);
    }

    private void initView(){
        float length = 0f ;
        if(mMeasureHeight > mMeasureWidth){
            length = mMeasureWidth ;
        }else{
            length = mMeasureHeight ;
        }

        mCircleXY = length / 2 ;
        mCircleRadius =length / 4 ;

        mCirclePaint = new Paint() ;
        mCirclePaint.setStyle(Paint.Style.FILL);
        mCirclePaint.setColor(Color.RED);
        mCirclePaint.setAntiAlias(true);

        mArcRectF = new RectF(
                (float)(length*0.1),
                (float)(length*0.1),
                (float)(length*0.9),
                (float)(length*0.9)) ;
        mArcSweepAngle = 240f ;
        mArcPaint = new Paint() ;
        mArcPaint.setAntiAlias(true);
        mArcPaint.setStyle(Paint.Style.STROKE);
        mArcPaint.setStrokeWidth((float)(length*0.1));
        mArcPaint.setColor(Color.BLUE);

        mTextPaint = new Paint() ;
        mTextPaint.setStyle(Paint.Style.STROKE);
        mTextPaint.setStrokeWidth(2f);
        mTextPaint.setColor(Color.GREEN);
        //设置要绘制文本的大小
        mTextPaint.setTextSize(mTextSize);
        //设置要绘制文本的对其方式
        mTextPaint.setTextAlign(Paint.Align.CENTER); //CENTER :文本原点为中心点,LEFT or RIGHT :文本原点为起点
    }

    /**
     * 设置弧形范围
     * @param value
     */
    public void setSweepAngle(float value){
        if(value >= 0){
            mArcSweepAngle = value ;
        }else{
            mArcSweepAngle = 25 ;
        }
        //重绘视图
        this.invalidate();
    }

    public void setTextContent(String value){
        mTextContent = value ;
        this.invalidate();
    }

}



条形梯度图:
效果图:
public class CustomGradientView extends View {

    private Paint mPaint ;
    private int mViewWidth ;
    private int mViewHeight ;

    private int mRectWidth ;
    private int mRectHeight ;
    private int mRectCount = 10 ;
    private int offset = 3 ;

    public CustomGradientView(Context context) {
        super(context);
        initView() ;
    }

    public CustomGradientView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public CustomGradientView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView();
    }

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

    /**
     * 绘制图像
     * @param canvas
     */
    @Override
    protected void  onDraw(Canvas canvas) {
        canvas.drawColor(Color.RED);
        for(int i = 0 ; i < mRectCount ; i++){
            // 0.0 <= random < 1.0
            double random = Math.random() ;
            float topDistance = (float)(mRectHeight * random) ;
            float leftDistance = (float)(mViewWidth * 0.1 + mRectWidth * i + offset*i) ;
            float rightDistance = (float)(mViewWidth * 0.1 + mRectWidth * (i+1) + offset*i) ;
            float bottomDistance = mRectHeight ;
             canvas.drawRect(leftDistance,topDistance,rightDistance,bottomDistance,mPaint);
        }
        //过500毫秒在重新绘制
         postInvalidateDelayed(500);
    }

    /**
     * 横竖屏变化时,获取其长宽
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
         mViewWidth = getWidth() ;
        mViewHeight = getHeight() ;

        mRectHeight = mViewHeight ;
        mRectWidth =(int)(( mViewWidth / mRectCount ) * 0.7) ;
    }

    private void initView(){
        //初始化画笔
        mPaint = new Paint() ;
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(Color.YELLOW);
    }
}



ViewGroup的测量和绘制:
一把要复写:
        onMeasure() ;  onDraw()  ;   onLayout()
public class CustomScrollView extends ViewGroup {
    //屏幕高度
    private int mScreenHeight=  0 ;
    private Scroller mScroller;
    private int mLastY;
    private int mStart;
    private int mEnd;

    public CustomScrollView(Context context) {
        super(context);
        initView(context);
    }

    public CustomScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    public CustomScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView(context);
    }

    private void initView(Context context){
        //获取屏幕高度(像素高度)
        WindowManager wm =  (WindowManager)(context.getSystemService(Context.WINDOW_SERVICE)) ;
        DisplayMetrics dm = new DisplayMetrics() ;
        wm.getDefaultDisplay().getMetrics(dm);
        mScreenHeight = dm.heightPixels ;
    }

    /**
     * onMeasure()  用于设计ViewGoup的大小
     * widthMeasureSpec和heightMeasureSpec封装了ViewGroup的模式和大小,
     * 以这个参数,调用measureChild()来测量子View的大小
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void  onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int count = getChildCount() ;
        for (int i = 0; i < count; i++) {
            View childView = getChildAt(i) ;
             measureChild(childView,widthMeasureSpec,heightMeasureSpec);
        }
    }

    /**
     * onLayout()  用于控制ViewGroup的(子View)布局情况
     * 主要就是控制View的布局方向,各种外边距的
     */
    @Override
    protected void  onLayout(boolean changed, int l, int t, int r, int b) {
        int count =  getChildCount() ;
        //getLayoutParams()  获取View 的布局参数,获取包括外边距,内边距,布局方向,布局的高度
         MarginLayoutParams mlp = (MarginLayoutParams)getLayoutParams() ;
        mlp.height = mScreenHeight *  count;
        //setLayoutParams() 设置布局参数
         setLayoutParams(mlp);
        for(int i = 0 ; i < count ; i++){
            View childView =  getChildAt(i) ;
            //控制子的布局情况
             childView.layout(l,i * mScreenHeight,r,(i+1)*mScreenHeight);
        }
    }

    /**
     * onDraw()  用于在ViewGroup上绘的图像,
     * 如果不是设置ViewGroup的背景,一般不需要复写ViewGroup的onDraw()方法
     * @param canvas
     */
    @Override
    protected void  onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }

    /**
     * 用于监听响应事件
     * @param event
     * @return
     */
    @Override
    public boolean  onTouchEvent(MotionEvent event) {
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastY = y;
                mStart = getScrollY();
                break;
            case MotionEvent.ACTION_MOVE:
                if (!mScroller.isFinished()) {
                    mScroller.abortAnimation();
                }
                int dy = mLastY - y;
                if (getScrollY() < 0) {
                    dy = 0;
                }
                if (getScrollY() > getHeight() - mScreenHeight) {
                    dy = 0;
                }
                scrollBy(0, dy);
                mLastY = y;
                break;
            case MotionEvent.ACTION_UP:
                mEnd = getScrollY();
                int dScrollY = mEnd - mStart;
                if (dScrollY > 0) {
                    if (dScrollY < mScreenHeight / 3) {
                        mScroller.startScroll(
                                0, getScrollY(),
                                0, -dScrollY);
                    } else {
                        mScroller.startScroll(
                                0, getScrollY(),
                                0, mScreenHeight - dScrollY);
                    }
                } else {
                    if (-dScrollY < mScreenHeight / 3) {
                        mScroller.startScroll(
                                0, getScrollY(),
                                0, -dScrollY);
                    } else {
                        mScroller.startScroll(
                                0, getScrollY(),
                                0, -mScreenHeight - dScrollY);
                    }
                }
                break;
        }
        postInvalidate();
        return true;
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        if (mScroller.computeScrollOffset()) {
            scrollTo(0, mScroller.getCurrY());
            postInvalidate();
        }
    }
}




 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值