作为一个老伙计,有点不太好意思写是这么基础的绘制....,害~ 每个人都有自己的故事... 我相信你也是...
搜索了一下都没有发现一个帖子介绍怎么画个正规球场,这里就随笔记录一下吧。就当回顾一下...
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米。
*/
2.算出要画各点,对应屏幕的x,y
1)计算缩放比例scale和所有需要的点的坐标,四个角的点,中点,大禁区四个点,小禁区四个点,罚球弧圆心,罚球弧对应圆的角度
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 这样会比较好一点
现在有强迫症,尽量避免各种警告和其他提示,这个绿色的√ 看着就舒服不少...
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
先上个效果图吧。