Android 自定义View 基础篇 画虚线 三角 Paint Style Paint Join 对勾 完成按钮 此篇下部分为Android开发自定义控件

Paint.Style.STROKE 只绘制图形轮廓(描边)
Paint.Style.FILL 只绘制图形内容
Paint.Style.FILL_AND_STROKE 既绘制轮廓也绘制内容

Android 自定义View 基础篇 画虚线 三角 Paint Style Paint Join 对勾 完成按钮 此篇下部分为Android开发自定义控件_第1张图片

Paint.Join.BEVEL 斜边
Paint.Join.MITER 锐角
Paint.Join.ROUND 圆角

Android 自定义View 基础篇 画虚线 三角 Paint Style Paint Join 对勾 完成按钮 此篇下部分为Android开发自定义控件_第2张图片

 

 

Android 自定义View 基础篇 画虚线 三角 Paint Style Paint Join 对勾 完成按钮 此篇下部分为Android开发自定义控件_第3张图片

 

圆的

public class CircleView extends View {


    private Path mPath;
    private Paint mPaint;
    private PathMeasure mPathMeasure;
    private float mAnimatorValue;
    private Path mDst;
    private float mLength;

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

    public CircleView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPathMeasure = new PathMeasure();
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(6);
        mPaint.setTextSize(60);

//        mPaint.setStrokeCap(Paint.Cap.BUTT);
        //圆形的时候 有明显的圆形 开头/结尾
        mPaint.setStrokeCap(Paint.Cap.ROUND);
//        mPaint.setStrokeCap(Paint.Cap.SQUARE);

//        mPaint.setStrokeJoin(Paint.Join.BEVEL);
//        mPaint.setStrokeJoin(Paint.Join.MITER);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPath = new Path();


        //200  200  这个点 就是这个圆形 中心坐标  这个坐标是相对于 View在XML 里的左上角的点为0 0
//        mPath.addCircle(200, 200, 100, Path.Direction.CW);              // 顺时针转
        mPath.addCircle(600, 600, 300, Path.Direction.CW); //逆时针转

        // forceClosed  Path最终是否需要闭合,如果为True的话,
        //                          则不管关联的Path是否是闭合的,都会被闭合。
        mPathMeasure.setPath(mPath, false);
        mLength = mPathMeasure.getLength();
        mDst = new Path();

        final ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                mAnimatorValue = (float) valueAnimator.getAnimatedValue();
                invalidate();
            }
        });
        valueAnimator.setDuration(2000);
        valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        valueAnimator.start();
    }

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

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mDst.reset();
        // 硬件加速的BUG  加上这个会在左上角留下一个黑点
//        mDst.lineTo(0, 0);

        float stop = mLength * mAnimatorValue;
        float start = (float) (stop - ((0.5 - Math.abs(mAnimatorValue - 0.5)) * mLength));
        mPathMeasure.getSegment(start, stop, mDst, true);
//        mPathMeasure.getSegment(0, stop, mDst, true);
        canvas.drawPath(mDst, mPaint);

        //Path.Direction.CCW  时 文字在内环
        canvas.drawTextOnPath("超级无敌长的一段文字.", mDst, 0, -20, mPaint);
    }
}

 

三角形的

public class PathPainterEffect extends View implements View.OnClickListener {

    private Paint mPaint;
    private Path mPath;
    private PathMeasure mPathMeasure;
    private PathEffect mEffect;
    private float fraction = 0;
    private ValueAnimator mAnimator;

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

    public PathPainterEffect(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPath = new Path();
        mPath.reset();
        mPath.moveTo(100, 100);
        mPath.lineTo(100, 500);
        mPath.lineTo(400, 300);
        mPath.close();  //坐标闭合  这里如果是forceClosed 为true 不起效果 俺也不知道

        mPaint = new Paint();
        mPaint.setColor(Color.BLACK);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(5);

        mPathMeasure = new PathMeasure(mPath, false);
        final float length = mPathMeasure.getLength();

        mAnimator = ValueAnimator.ofFloat(1, 0);
        mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
        mAnimator.setDuration(2000);

        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                fraction = (float) valueAnimator.getAnimatedValue();
                mEffect = new DashPathEffect(new float[]{length, length}, fraction * length);
                mPaint.setPathEffect(mEffect);
                invalidate();
            }
        });
        setOnClickListener(this);
    }

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

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawPath(mPath, mPaint);
    }

    @Override
    public void onClick(View view) {
        mAnimator.start();
    }
}

对勾View

Android 自定义View 基础篇 画虚线 三角 Paint Style Paint Join 对勾 完成按钮 此篇下部分为Android开发自定义控件_第4张图片

public class MyView_Duihao extends View {

    private Paint mPaint;
    private Path mPath;
    private int[] loc;

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

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


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

        loc = new int[2];
        getLocationInWindow(loc);

        mPaint = new Paint();
        mPaint.setStrokeWidth(5);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.WHITE);


    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int width = getWidth();
        int height = getHeight();

        mPath = new Path();

        mPath.moveTo(width * 0.2f, height * 0.5f);
        mPath.quadTo(width / 2f, height, width * 0.8f, height * 0.1f);

        canvas.drawPath(mPath, mPaint);
    }
}

让对号动起来

public class MyView_Duihao extends View implements View.OnClickListener {

    private Paint mPaint;
    private Path mPath;
    private int[] loc;
    private ValueAnimator mAnimator;

    //可以主动传进来
    private int width;
    private int height;

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

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


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

        loc = new int[2];
        getLocationInWindow(loc);

        mPaint = new Paint();
        mPaint.setStrokeWidth(5);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.WHITE);


        mPath = new Path();

        width = dip2px(context, 100);
        height = dip2px(context, 100);

        mPath.moveTo(width * 0.2f, height * 0.5f);
        mPath.quadTo(width / 2f, height, width * 0.8f, height * 0.1f);

        PathMeasure mPathMeasure = new PathMeasure(mPath, false);
        final float length = mPathMeasure.getLength();


        mAnimator = ValueAnimator.ofFloat(1, 0);
        mAnimator.setInterpolator(new LinearInterpolator());
        mAnimator.setDuration(2000);
        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float fraction = (float) animation.getAnimatedValue();
                DashPathEffect mEffect = new DashPathEffect(new float[]{length, length}, fraction * length);
                mPaint.setPathEffect(mEffect);
                invalidate();
            }
        });

        setOnClickListener(this);
    }


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

        canvas.drawPath(mPath, mPaint);
    }

    @Override
    public void onClick(View v) {
        mAnimator.start();
    }

    /**
     * 根据手机的分辨率从 dip 的单位 转成为 px(像素)
     */
    public static int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    /**
     * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
     */
    public static int px2dip(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

}

这里有一个问题,因为不能在onDraw里边进行 宽高的获取,所以我们可以直接拿xml 里边的宽高

 

Android 自定义View 基础篇 画虚线 三角 Paint Style Paint Join 对勾 完成按钮 此篇下部分为Android开发自定义控件_第5张图片

文字逐渐缩短 ,无法接着扩展了....当然可以自定义样式来写一个,,,下一个

// 圆的直径
        final int height = v.getHeight();
        int width = v.getWidth();


        final RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) v.getLayoutParams();

        ValueAnimator valueAnimator = ValueAnimator.ofInt(width, height);
        ValueAnimator valueAnimator2 = ValueAnimator.ofInt(0, (width - height) / 2);
        valueAnimator.setDuration(duration);
        valueAnimator2.setDuration(duration);

        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int animatedValue = (int) animation.getAnimatedValue();
                layoutParams.width = animatedValue;
                v.setLayoutParams(layoutParams);

            }
        });
        valueAnimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int animatedValue = (int) animation.getAnimatedValue();
                v.setTranslationX(animatedValue);
            }
        });


        AnimatorSet animatorSet = new AnimatorSet();

        animatorSet.play(valueAnimator)
                .with(valueAnimator2);

        animatorSet.start();

 如果实在相对布局中,给View设置固定的位置 那么久只需要第一个Animator 就可以实现了

如果是线性布局,那么他会自动贴边.同样的固定一个位置比如 父布局中

android:gravity="center_horizontal"  

使用一个动画Animator 就可以了


Android 自定义View 基础篇 画虚线 三角 Paint Style Paint Join 对勾 完成按钮 此篇下部分为Android开发自定义控件_第6张图片

public class AnimationButton extends View {

    /**
     * view的宽度
     */
    private int width;
    /**
     * view的高度
     */
    private int height;
    /**
     * 圆角半径
     */
    private int circleAngle;
    /**
     * 默认两圆圆心之间的距离=需要移动的距离
     */
    private int default_two_circle_distance;
    /**
     * 两圆圆心之间的距离
     */
    private int two_circle_distance;
    /**
     * 背景颜色
     */
    private int bg_color = 0xffbc7d53;
    /**
     * 按钮文字字符串
     */
    private String buttonStringBefore = "点我登录";
    private String buttonStringAfter = "完事了";
    /**
     * 是否开始绘制 完成文字
     */
    private boolean isOver = false;
    /**
     * 动画执行时间
     */
    private int duration = 1000;
    /**
     * view向上移动距离
     */
    private int move_distance = 300;

    /**
     * 圆角矩形画笔
     */
    private Paint paint;
    /**
     * 文字画笔
     */
    private Paint textPaint;
    /**
     * 文字绘制所在矩形
     */
    private Rect textRect = new Rect();

    /**
     * 动画集
     */
    private AnimatorSet animatorSet = new AnimatorSet();

    /**
     * 矩形到圆角矩形过度的动画
     */
    private ValueAnimator animator_rect_to_angle;
    /**
     * 矩形到正方形过度的动画
     */
    private ValueAnimator animator_rect_to_square;


    /**
     * 根据view的大小设置成矩形
     */
    private RectF rectf = new RectF();

    /**
     * 路径--用来获取对勾的路径
     */
    private Path path = new Path();
    /**
     * 对路径处理实现绘制动画效果
     */
    private PathEffect effect;
    /**
     * 点击事件及动画事件2完成回调
     */
    private AnimationButtonListener animationButtonListener;

    public void setAnimationButtonListener(AnimationButtonListener listener) {
        animationButtonListener = listener;
    }

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

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

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

        initPaint();

        this.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (animationButtonListener != null) {
                    animationButtonListener.onClickListener();
                }
            }
        });

        animatorSet.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                if (animationButtonListener != null) {
                    animationButtonListener.animationFinish();
                }
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
    }

    /**
     * 初始化所有动画
     */
    private void initAnimation() {
        set_rect_to_angle_animation();
        set_rect_to_circle_animation();

        animatorSet
                .play(animator_rect_to_square)
                .after(animator_rect_to_angle);

    }


    /**
     * 设置矩形过度到圆角矩形的动画
     */
    private void set_rect_to_angle_animation() {
        animator_rect_to_angle = ValueAnimator.ofInt(0, height / 2);
        animator_rect_to_angle.setDuration(duration);
        animator_rect_to_angle.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                circleAngle = (int) animation.getAnimatedValue();
                invalidate();
            }
        });
    }


    /**
     * 设置圆角矩形过度到圆的动画
     */
    private void set_rect_to_circle_animation() {
        animator_rect_to_square = ValueAnimator.ofInt(0, default_two_circle_distance);
        animator_rect_to_square.setDuration(duration);
        animator_rect_to_square.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                two_circle_distance = (int) animation.getAnimatedValue();

                if (default_two_circle_distance != 0) {
//                    int alpha = 255 - (two_circle_distance * 255) / default_two_circle_distance;
//                    textPaint.setAlpha(alpha);
                }
                if (two_circle_distance == default_two_circle_distance) {
                    isOver = true;
                }

                invalidate();
            }
        });
    }


    private void initPaint() {

        paint = new Paint();
        paint.setStrokeWidth(4);
        paint.setStyle(Paint.Style.FILL);
        paint.setAntiAlias(true);
        paint.setColor(bg_color);

        textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        textPaint.setTextSize(60);
        textPaint.setColor(Color.WHITE);
        textPaint.setTextAlign(Paint.Align.CENTER);
        textPaint.setAntiAlias(true);

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        width = w;
        height = h;

        default_two_circle_distance = (w - h) / 2;

        initAnimation();

    }

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

        draw_oval_to_circle(canvas);

        if (isOver) {
            isOver = false;
            drawText(canvas, buttonStringAfter);
        }else{
            drawText(canvas, buttonStringBefore);
        }


    }


    /**
     * 绘制长方形变成圆形
     *
     * @param canvas 画布
     */
    private void draw_oval_to_circle(Canvas canvas) {

        rectf.left = two_circle_distance;
        rectf.top = 0;
        rectf.right = width - two_circle_distance;
        rectf.bottom = height;

        //画圆角矩形
        canvas.drawRoundRect(rectf, circleAngle, circleAngle, paint);
    }


    /**
     * 绘制文字
     *
     * @param canvas 画布
     */
    private void drawText(Canvas canvas, String string) {

        textRect.left = 0;
        textRect.top = 0;
        textRect.right = width;
        textRect.bottom = height;
        Paint.FontMetricsInt fontMetrics = textPaint.getFontMetricsInt();
        int baseline = (textRect.bottom + textRect.top - fontMetrics.bottom - fontMetrics.top) / 2;
        //文字绘制到整个布局的中心位置

        canvas.drawText(string, textRect.centerX(), baseline, textPaint);
    }


    /**
     * 启动动画
     */
    public void start() {
        animatorSet.start();
    }

    /**
     * 动画还原
     */
    public void reset() {
        circleAngle = 0;
        two_circle_distance = 0;
        default_two_circle_distance = (width - height) / 2;
        textPaint.setAlpha(255);
        setTranslationY(getTranslationY() + move_distance);
        invalidate();
    }

    /**
     * 借口回调
     */
    public interface AnimationButtonListener {
        /**
         * 按钮点击事件
         */
        void onClickListener();

        /**
         * 动画完成回调
         */
        void animationFinish();
    }
}

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mWidth = MeasureSpec.getSize(widthMeasureSpec);
        mHeight = MeasureSpec.getSize(heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (widthMode == MeasureSpec.EXACTLY) {
            mWidth = Math.min(mWidth, mHeight);
        } else {
            mWidth = dp2px(getContext(), 50);
        }
        if (heightMode == MeasureSpec.EXACTLY) {
            mHeight = Math.min(mWidth, mHeight);
        } else {
            mHeight = dp2px(getContext(), 50);
        }
        mWidth = mHeight = Math.min(mWidth, mHeight);
        setMeasuredDimension(mWidth, mHeight);
    }

画虚线:


1.Shape



    
 

layerType 是关闭硬件加速

2.自定义View

关闭硬件加速

public class MyView extends View {


    private Paint mPaint;

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

    public MyView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);


        mPaint = new Paint();

        mPaint.setAntiAlias(true);//设置抗锯齿
        mPaint.setColor(Color.BLACK);//设置画笔颜色
        mPaint.setDither(true);// 防止抖动
        mPaint.setStyle(Paint.Style.STROKE); // 边框
        mPaint.setStrokeWidth(10);//宽度

        mPaint.setPathEffect(new DashPathEffect(new float[]{5, 5}, 0));

    }


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

        setLayerType(LAYER_TYPE_SOFTWARE, null);

        int centerY = getHeight() / 2;
        canvas.drawLine(0, centerY, getWidth(), centerY, mPaint);


    }

}

3.不关硬件加速

public class MyView extends View {


    private Paint mPaint;
    private Path mPath;

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

    public MyView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);


        mPaint = new Paint();

        mPaint.setAntiAlias(true);//设置抗锯齿
        mPaint.setColor(Color.BLACK);//设置画笔颜色
        mPaint.setDither(true);// 防止抖动
        mPaint.setStyle(Paint.Style.STROKE); // 边框
        mPaint.setStrokeWidth(10);//宽度

        mPaint.setPathEffect(new DashPathEffect(new float[]{5, 5}, 0));

        mPath = new Path();

    }


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


        mPath.reset();

        int centerY = getHeight() / 2;
        mPath.moveTo(0,centerY);
        mPath.lineTo(getWidth(), centerY);
        canvas.drawPath(mPath, mPaint);

    }

}

4.自定义虚线样式

public class MyView extends View {


    private Paint mPaint;
    private Path mPath;

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

    public MyView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);


        mPaint = new Paint();

        mPaint.setAntiAlias(true);//设置抗锯齿
        mPaint.setColor(Color.BLACK);//设置画笔颜色
        mPaint.setDither(true);// 防止抖动
        mPaint.setStyle(Paint.Style.STROKE); // 边框
        mPaint.setStrokeWidth(10);//宽度

        Path path = new Path();
        path.addCircle(0, 0, 5, Path.Direction.CW);
        mPaint.setPathEffect(new PathDashPathEffect(path, 15, 0, PathDashPathEffect.Style.ROTATE));


        mPath = new Path();

    }

    // 其它方法还是不变
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        // 前四个参数没啥好讲的,就是起点和终点而已。
        // color数组的意思是从透明 -> 黑 -> 黑 -> 透明。
        // float数组与color数组对应:
        // 0 -> 0.3 (透明 -> 黑)
        // 0.3 - 0.7 (黑 -> 黑,即不变色)
        // 0.7 -> 1 (黑 -> 透明)
        mPaint.setShader(new LinearGradient(0, 0, getWidth(), 0,
                new int[] {Color.TRANSPARENT, Color.BLACK, Color.BLACK, Color.TRANSPARENT},
                new float[] {0, 0.3f, 0.7f, 1f}, Shader.TileMode.CLAMP));
    }



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


        mPath.reset();


        int centerY = getHeight() / 2;
        mPath.moveTo(0,centerY);
        mPath.lineTo(getWidth(), centerY);
        canvas.drawPath(mPath, mPaint);

    }

}

在这里,学到了一种View 设置渐变色的方法,可以通过LinearGradient()初始化的四个点来设置渐变的方向


画弧:


Android 自定义View 基础篇 画虚线 三角 Paint Style Paint Join 对勾 完成按钮 此篇下部分为Android开发自定义控件_第7张图片

public class MyView extends View {


    private Paint mPaint;

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

    public MyView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);


        mPaint = new Paint();

        mPaint.setAntiAlias(true);//设置抗锯齿
        mPaint.setColor(Color.BLACK);//设置画笔颜色
        mPaint.setDither(true);// 防止抖动
        mPaint.setStyle(Paint.Style.STROKE); // 边框
        mPaint.setStrokeWidth(10);//宽度

    }

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


        RectF mRectF = new RectF(100, 200, 700, 600); //这个矩形的 左上 右下俩个点 (100,200),(700,600)
        canvas.drawRect(mRectF, mPaint);

        mPaint.setColor(Color.RED);
        canvas.drawArc(mRectF, 180, 270, false, mPaint);
    }

}

这里主要是这个方法

canvas.drawArc(mRectF, 180, 270, false, mPaint);

改变一下参数看看

canvas.drawArc(mRectF, 180, 270, true, mPaint);

Android 自定义View 基础篇 画虚线 三角 Paint Style Paint Join 对勾 完成按钮 此篇下部分为Android开发自定义控件_第8张图片

startAngle:起始的角度 3点钟方向是0°

sweepAngle:是增加的角度,旋转的角度

useCenter:是否与中心相连


Path mPath = new Path();
        mPath.moveTo(10, 10);
        RectF mRectF = new RectF(100, 200, 700, 600); //这个矩形的 左上 右下俩个点 (100,200),(700,600)
        canvas.drawRect(mRectF, mPaint);

        mPaint.setColor(Color.RED);
        canvas.drawArc(mRectF, 0, 90, true, mPaint);

        mPaint.setColor(Color.GREEN);
        mPath.addArc(mRectF, 180, 90);
        canvas.drawPath(mPath, mPaint);

Android 自定义View 基础篇 画虚线 三角 Paint Style Paint Join 对勾 完成按钮 此篇下部分为Android开发自定义控件_第9张图片

改为ArcTo

mPath.arcTo(mRectF, 180, 90);

 Android 自定义View 基础篇 画虚线 三角 Paint Style Paint Join 对勾 完成按钮 此篇下部分为Android开发自定义控件_第10张图片

mPath.arcTo(mRectF, 180, 90,true);
在arcTo 的方法里有一个参数

forceMoveTo:是否将弧的起始点做为绘制起始位置

也就是抛弃path 之前的一些路径,重新开始


Region

public class MyView extends View {


    private Paint mPaint;

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

    public MyView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);


        mPaint = new Paint();

        mPaint.setAntiAlias(true);//设置抗锯齿
        mPaint.setColor(Color.BLACK);//设置画笔颜色
        mPaint.setDither(true);// 防止抖动
        mPaint.setStyle(Paint.Style.STROKE); // 边框
        mPaint.setStrokeWidth(10);//宽度

    }

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

        Rect mRect = new Rect(100, 100, 500, 300);
        Region mRegion = new Region(mRect);
        drawRegion(canvas, mRegion, mPaint);

    }


    private void drawRegion(Canvas canvas, Region mRegion, Paint mPaint) {
        RegionIterator iterator = new RegionIterator(mRegion);
        Rect rectF = new Rect();
        while (iterator.next(rectF)) {
            canvas.drawRect(rectF, mPaint);
        }
    }

}

Android 自定义View 基础篇 画虚线 三角 Paint Style Paint Join 对勾 完成按钮 此篇下部分为Android开发自定义控件_第11张图片

类似普通的矩形,但是既然要通过Region来包装,那么这里一定是有不同寻常的Api

它可以用来画俩个区域重叠的地方

Android 自定义View 基础篇 画虚线 三角 Paint Style Paint Join 对勾 完成按钮 此篇下部分为Android开发自定义控件_第12张图片

public class MyView extends View {


    private Paint mPaint;

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

    public MyView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);


        mPaint = new Paint();

        mPaint.setAntiAlias(true);//设置抗锯齿
        mPaint.setColor(Color.BLACK);//设置画笔颜色
        mPaint.setDither(true);// 防止抖动
        mPaint.setStyle(Paint.Style.FILL); // 边框
        mPaint.setStrokeWidth(10);//宽度

    }

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


        Path mPath = new Path();
        mPath.addOval(new RectF(100, 100, 500, 500), Path.Direction.CW);

        Region mRegion = new Region();

        Rect mRect = new Rect(100, 100, 500, 200);
        mRegion.setPath(mPath, new Region(mRect));

        drawRegion(canvas, mRegion, mPaint);


    }


    private void drawRegion(Canvas canvas, Region mRegion, Paint mPaint) {
        RegionIterator iterator = new RegionIterator(mRegion);
        Rect rectF = new Rect();
        while (iterator.next(rectF)) {
            canvas.drawRect(rectF, mPaint);
        }
    }

}

union函数

区域相交  合并矩形

Region region = new Region(10, 10, 510, 410);
        region.union(new Rect(10,10,310,610));
        drawRegion(canvas, region, mPaint);

Android 自定义View 基础篇 画虚线 三角 Paint Style Paint Join 对勾 完成按钮 此篇下部分为Android开发自定义控件_第13张图片

op方法

Android 自定义View 基础篇 画虚线 三角 Paint Style Paint Join 对勾 完成按钮 此篇下部分为Android开发自定义控件_第14张图片

 

public class MyView extends View {

    private Paint mPaint;

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

    public MyView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);


        mPaint = new Paint();

        mPaint.setAntiAlias(true);//设置抗锯齿
        mPaint.setColor(Color.BLACK);//设置画笔颜色
        mPaint.setDither(true);// 防止抖动
        mPaint.setStyle(Paint.Style.STROKE); // 边框
        mPaint.setStrokeWidth(10);//宽度

    }

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


        Rect rect1 = new Rect(100, 100, 400, 200);
        Rect rect2 = new Rect(200, 0, 300, 300);

        Region region1 = new Region(rect1);
        Region region2 = new Region(rect2);

        Region region = new Region();
//        region.op(region1, region2, Region.Op.DIFFERENCE);
//        region.op(region1, region2, Region.Op.INTERSECT);
//        region.op(region1, region2, Region.Op.REPLACE);
//        region.op(region1, region2, Region.Op.UNION);
//        region.op(region1, region2, Region.Op.XOR);
        region.op(region1, region2, Region.Op.REVERSE_DIFFERENCE);

        canvas.drawRect(rect1, mPaint);
        canvas.drawRect(rect2, mPaint);

        mPaint.setStyle(Paint.Style.FILL);
        drawRegion(canvas, region, mPaint);

    }


    private void drawRegion(Canvas canvas, Region mRegion, Paint mPaint) {
        RegionIterator iterator = new RegionIterator(mRegion);
        Rect rectF = new Rect();
        while (iterator.next(rectF)) {
            canvas.drawRect(rectF, mPaint);
        }
    }

}

canvas.save/restore

当我们对canvas(画布)进行操作后就需要对画布状态进行保存(save),恢复(restore)

举个栗子

        canvas.drawCircle(100, 100, 50, mPaint);
        canvas.translate(200, 200);
        canvas.drawCircle(100, 100, 50, mPaint);

Android 自定义View 基础篇 画虚线 三角 Paint Style Paint Join 对勾 完成按钮 此篇下部分为Android开发自定义控件_第15张图片

默认的中心点是:0,0 所有100,100的圆在左上角,当我们使用translate之后画布换了位置,中心点到了200,200,所以100,100画在了右下角

 

        canvas.drawCircle(100, 100, 50, mPaint);
        canvas.save();
        canvas.translate(200, 200);
        canvas.restore();
        mPaint.setColor(Color.RED);
        canvas.drawCircle(110, 110, 50, mPaint);

Android 自定义View 基础篇 画虚线 三角 Paint Style Paint Join 对勾 完成按钮 此篇下部分为Android开发自定义控件_第16张图片

可以看到这样画布恢复了,中心点又回去了

小栗子:

Android 自定义View 基础篇 画虚线 三角 Paint Style Paint Join 对勾 完成按钮 此篇下部分为Android开发自定义控件_第17张图片

 

 canvas.drawCircle(500, 500, 400, mPaint);

        mPaint.setStyle(Paint.Style.FILL); // 实心


        for (int i = 0; i < 7; i++) {
            canvas.save();
            canvas.rotate(60 * i, 500, 500);
            canvas.drawLine(500, 500, 500, 0, mPaint);
            canvas.restore();
        }


        // 看看最终的中心点在哪
        canvas.drawPoint(10, 10, mPaint);

 

这个有个问题,每次打开App 然后退到后台不杀死再打开就会变成Fill 类型的

这个问题找到了原因了就是每次界面可见时,就会调用自定义View 的OnDraw ,所以

Android 自定义View 基础篇 画虚线 三角 Paint Style Paint Join 对勾 完成按钮 此篇下部分为Android开发自定义控件_第18张图片

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(学习ing)