足球场,自定义view,football Backgroun.画一个标准足球场

    作为一个老伙计,有点不太好意思写是这么基础的绘制....,害~  每个人都有自己的故事... 我相信你也是...

   搜索了一下都没有发现一个帖子介绍怎么画个正规球场,这里就随笔记录一下吧。就当回顾一下...

1.摸清规则。做什么事情都一样,我们首先要知道我们要的结果和实现的过程和步骤。

/**
* (1)场地:长105米、宽68米.
* (2)球门:长7.32米、高2.44米。
* (3)大禁区(罚球区):长40.32米、宽16.5米,在底线距离球门柱16.5米。
* (4)小禁区(球门区):长18.32米、宽5.5米,在底线距离球门柱5.5米。
* (5)中圈区:半径9.15米。
* (6)角球区:半径1米,距离大禁区13.84米。
* (7)罚球弧:以点球点为中心,半径9.15米的半圆。
* (8)点球点:距离球门线11米。
*/

足球场,自定义view,football Backgroun.画一个标准足球场_第1张图片

2.算出要画各点,对应屏幕的x,y

1)计算缩放比例scale和所有需要的点的坐标,四个角的点,中点,大禁区四个点,小禁区四个点,罚球弧圆心,罚球弧对应圆的角度

2)直接按要求画出来 效果如下

足球场,自定义view,football Backgroun.画一个标准足球场_第2张图片

1).
//整个球场的宽、长
//为了准确等比 首先判断手机屏幕长宽比, 这里转换成 height  with
//如果长宽比大于 105/68 则说明屏幕with可能不够,直接转换会有收缩,反之拉伸
//所以哪边不够我们就以哪边为基准,另一边会多出来 就有padding,一般情况下,手机都是height够,with不足,我这里就没处理另一种情况了。原理说清楚了,需要的话自己处理

所以是不能直接拿来用的,需要处理一下以Height为基准时,with会有多余。横屏未做处理,pad不能直接用,需要转换 x->y ,y->x 只有参考意义...


//角球区
float cornerScale = 1.0f / 68;
float cornerRadius = screenWith * cornerScale;

依次类推,求出所有比例,并求出对应在屏幕的宽高,点,依次画出来就好....

 

类的代码在这里,可以参考一下,很多做的不足的,比如,第一步说的,完全可以把所有点的坐标先算出来,而不是在画的时候才用宽高,scale,padding,radius

这些参数做计算求出,这样容易增加错误率,准确求出每个点的坐标,画时直接point.x ,point.y 这样会比较好一点

现在有强迫症,尽量避免各种警告和其他提示,这个绿色的√ 看着就舒服不少...

足球场,自定义view,football Backgroun.画一个标准足球场_第3张图片

public class FootBallBackGround extends View {


    private Paint paint;
    private Path path;
    private Paint paintBackground;
    private Paint paintBackgroundDeep;
    private Path backgroundPath;

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

    public FootBallBackGround(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

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

    private void init() {

        paint = new Paint();
        paint.setStrokeWidth(2);
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(getResources().getColor(R.color.design_default_color_background));

        paintBackground = new Paint();
        paintBackground.setStyle(Paint.Style.FILL);
        paintBackground.setColor(getResources().getColor(R.color.green_deep));

        paintBackgroundDeep = new Paint();
        paintBackgroundDeep.setStyle(Paint.Style.FILL);
        paintBackgroundDeep.setColor(getResources().getColor(R.color.green));

        path = new Path();
        backgroundPath = new Path();

    }


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


    /**
     * 画标准球场图 H:长 W:宽
     * 场地:H 105米 W 68米
     * 球门:7.32米、高:2.44
     * (1)场地:长105米、宽68米.
     * (2)球门:长7.32米、高2.44米。
     * (3)大禁区(罚球区):长40.32米、宽16.5米,在底线距离球门柱16.5米。
     * (4)小禁区(球门区):长18.32米、宽5.5米,在底线距离球门柱5.5米。
     * (5)中圈区:半径9.15米。
     * (6)角球区:半径1米,距离大禁区13.84米。
     * (7)罚球弧:以点球点为中心,半径9.15米的半圆。
     * (8)点球点:距离球门线11米。
     *
     * @param canvas c
     */
    private void drawFootBallBackground(Canvas canvas) {

        float screenWith = getWidth();
        float screenHeight = getHeight();
        float scale = 68.00f / 105.00f;
        float padding;
        float radius;


        //画四边
        //为了准确等比 首先判断手机屏幕长宽比, 这里转换成 height  with
        //如果长宽比大于 105/68 则说明屏幕with可能不够,直接转换会有收缩,反之拉伸
        //所以哪边不够我们就以哪边为基准,另一边会多出来 就有padding
        if (screenWith / screenHeight > scale) {
            screenWith = screenHeight * scale;
            padding = (getWidth() - screenWith) / 2;

            path.moveTo(padding, 0);
            path.lineTo(screenWith, 0);
            path.lineTo(screenWith, screenHeight);
            path.lineTo(0, screenHeight);
            path.lineTo(padding, 0);

            //画背景
            canvas.drawPath(path,paintBackground);

        } else {
            screenHeight = screenWith * (1 / scale);
            padding = (getHeight() - screenHeight) / 2;
            backgroundPath.moveTo(0, 0);
            backgroundPath.lineTo(screenWith, 0);
            backgroundPath.lineTo(screenWith, getHeight());
            backgroundPath.lineTo(0,  getHeight());
            backgroundPath.lineTo(0, 0);
            canvas.drawPath(backgroundPath,paintBackground);

            path.moveTo(0, padding);
            path.lineTo(screenWith, padding);
            path.lineTo(screenWith, screenHeight +padding);
            path.lineTo(0, screenHeight + padding);
            path.lineTo(0, padding);

            //画背景
            for (int i = 0; i < 7; i++) {
                canvas.drawRect(0,padding + (2*i +1)*(screenHeight /14),screenWith,padding + 2*(1+i)*(screenHeight / 14),paintBackgroundDeep);
            }
        }

        //画角球区
        float cornerScale = 1.0f / 68;
        float cornerRadius = screenWith * cornerScale;
        RectF rectA = new RectF(0-cornerRadius,padding - cornerRadius,cornerRadius,padding + cornerRadius);
        RectF rectB = new RectF(screenWith - cornerRadius,padding - cornerRadius,screenWith + cornerRadius,padding + cornerRadius);
        RectF rectC = new RectF(screenWith - cornerRadius,screenHeight + padding - cornerRadius,screenWith+ cornerRadius,screenHeight + padding  + cornerRadius);
        RectF rectD = new RectF(0-cornerRadius,screenHeight + padding  - cornerRadius, cornerRadius,screenHeight + padding  + cornerRadius);

        canvas.drawArc(rectA,0,90,false,paint);
        canvas.drawArc(rectB,-180,-270,false,paint);
        canvas.drawArc(rectC,180,270,false,paint);
        canvas.drawArc(rectD,0,-90,false,paint);

        //画中间横线
        path.moveTo(0,screenHeight / 2 + padding);
        path.lineTo(screenWith, screenHeight/2 + padding);

        //画中间圆
        radius = screenHeight * (9.15f / 105);
        canvas.drawCircle(screenWith/2,screenHeight/2 + padding,radius,paint);

        //画大禁区 penalty area
        float penaltyAreaWithScale = 40.32f / 68;
        float penaltyAreaHeightScale = 16.5f / 105;
        float penaltyAreaWith = screenWith * penaltyAreaWithScale;
        float penaltyAreaHeight = screenHeight * penaltyAreaHeightScale;
        float penaltyAreaStartX = (screenWith - penaltyAreaWith) / 2;
        //画大禁区 上方
        path.moveTo(penaltyAreaStartX, padding);
        path.lineTo(penaltyAreaStartX, penaltyAreaHeight + padding);
        path.lineTo(screenWith - penaltyAreaStartX, penaltyAreaHeight + padding);
        path.lineTo(screenWith - penaltyAreaStartX, padding);
        //画大禁区 下方
        path.moveTo(penaltyAreaStartX, screenHeight + padding);
        path.lineTo(penaltyAreaStartX, screenHeight + padding - penaltyAreaHeight);
        path.lineTo(screenWith - penaltyAreaStartX, screenHeight + padding - penaltyAreaHeight);
        path.lineTo(screenWith - penaltyAreaStartX, screenHeight + padding);
        //画小禁区 上方
        float goalAreaWithScale = 11 / 68f;
        float goalAreaHeightScale = 5.5f / 105;

        float goalAreaWith = screenWith * goalAreaWithScale;
        float goalAreaHeight = screenHeight * goalAreaHeightScale;

        path.moveTo(penaltyAreaStartX + goalAreaWith, padding);
        path.lineTo(penaltyAreaStartX  + goalAreaWith, goalAreaHeight + padding);
        path.lineTo(screenWith - penaltyAreaStartX - goalAreaWith, goalAreaHeight + padding);
        path.lineTo(screenWith - penaltyAreaStartX - goalAreaWith, padding);

        path.moveTo(penaltyAreaStartX + goalAreaWith, screenHeight + padding);
        path.lineTo(penaltyAreaStartX  + goalAreaWith, screenHeight + padding - goalAreaHeight);
        path.lineTo(screenWith - penaltyAreaStartX - goalAreaWith, screenHeight + padding - goalAreaHeight);
        path.lineTo(screenWith - penaltyAreaStartX - goalAreaWith, screenHeight + padding);

        //左区罚球弧
        RectF penaltyArcL = new RectF();
        penaltyArcL.left = screenWith / 2 - radius;
        penaltyArcL.right = screenWith / 2 + radius;
        penaltyArcL.bottom = goalAreaHeight * 2 + radius + padding;
        penaltyArcL.top = penaltyArcL.bottom - 2 * radius;
        //计算出弧线对应角度...  求出圆与大禁区的两个交点,再根据圆心,半径 计算出圆周角,起始角度和结束角度... 我能说我是凭直觉设置对的吗 0.0
        canvas.drawArc(penaltyArcL,142.5f,-105,false,paint);

        //右区罚球弧
        RectF downCircle = new RectF();
        downCircle.left = screenWith / 2 - radius;
        downCircle.right = screenWith / 2 + radius;
        downCircle.bottom = screenHeight + padding - Math.abs(goalAreaHeight * 2 - radius) ;
        downCircle.top =  screenHeight + padding - (goalAreaHeight * 2 + radius);
        canvas.drawArc(downCircle,-142.5f,105,false,paint);

        canvas.drawPath(path, paint);
        canvas.save();
        canvas.restore();
    }
}

              

拓展:画3D的背景图的话可能涉及投影,角度  就如一个直角三棱柱,底面是平面,斜面是我们需要的面,根据仰角进行缩放。这个得补充一点数学知识,应该就能实现了...

最后分享一个别人画的不错的模仿自定义view,其实他的3D背景也是一个固定图,可能会出现拉伸,收缩的情况。而且区域不能确定,不能判定滑出范围没有

作者:IAM四十二
       链接:http://www.jianshu.com/p/d06c1d10bf7f

github:https://github.com/REBOOTERS/AndroidAnimationExercise

先上个效果图吧。

 

 

 

 

 

你可能感兴趣的:(Android,canvas,android,java,android,studio,kotlin)