自定义View绘制谷歌 图标

自定义View

  • 自定义控件 绘制谷歌 图标
    • 第一步
    • 第二步
    • 直接上代码,看看绘制出来的第一个部分
    • 再通过旋转,绘制其它两个部分
    • 绘制颜色和中间的小圆
    • 为各个色值添加点击事件

自定义控件 绘制谷歌 图标

在这里插入图片描述
当我们第一次看到这种图标是,第一反映就是这怎么绘制啊?赶紧要UI小姐姐切个图算了,但是除了切图,其实我们还可以通过代码的方式完全绘制出来,下面我们就来分析一下,具体怎么绘制?

在这里插入图片描述

如上图所示,这个图标其实就是分为三个部分,红色,黄色,绿色,并且三个部分都是一样的,现在我们想想,我们只需要绘制完成一个部分,然后再把这个部分旋转一定的角度,改变它的颜色,是不是就能绘制出其它两个部分了?答案肯定是可以的,至于中间的两个圆,那就十分的简单了。

那么我们如何绘制其中的一个部分了,就拿 红色 部分来说, canvas 中的API也不能直接绘制出来啊,既然不能直接绘制出来,那我们就把它拆分,一点一点的绘制不就行了。
图中AB是一个圆弧 BC是一条直线,CD又是一个圆弧,DA又是一条直线,那么我们把它们都绘制出来,用 Path.lineTo(),方法连接起来不就行了吗?

在这里插入图片描述

看图可知,x1和x2这两条线是平行的,至于为什么平行了?你拿着谷歌的原图画一条直线比较一下就知道了,D点B点C点是在一条直线上的,x2又是过圆心的直线 由于3个部分组成了一个圆,那么每个部分的弧度都是120度,即DC扫过的弧度为120度,那么由图可知 DOC 的度数为120那么 DOB 和 COB 的度数都是60度,那么由此可以确定,OCB度数为30度,AOE度数为30度
图中 OB是我们自己定义小圆的半径,OB长度知道,OC是自己定义的大圆半径,OC长度知道,那么根据图中线段与角度的关系
A,B,C,D这几点的坐标用三角函数可以求出来

第一步

求出C点坐标
c点横坐标 BC=center_x+OB/tant30 
c点的纵坐标 就等于OB 为 center_y-100求出A点坐标
a点的横坐标 OE=center_x-cos30*100
a点的纵坐标  AE=center_y+sin30*100到此我们所需要的坐标就都求出来了

第二步

先画AB这段圆弧,要画圆弧,就要知道AB这段的弧度 AOE+EOD+DOB=120度,是可以明确求出的,所以AB的弧度为120度,
由于画圆弧 需要四个参数 RectF 圆弧的范围(大小),startAngle开始点的弧度,sweepAngle扫过的弧度,Paint 画笔

  public void drawArc(@RecentlyNonNull RectF oval, float startAngle, float sweepAngle, @RecentlyNonNull Paint paint)Paint 画笔 我们自己创建sweepAngle扫过的弧度 我们已经计算出来了 120度startAngle开始的弧度 就是从A这个点开始,AOZ就是开始绘制时的弧度了 计算可知是 150度RectF  现在就剩下范围了

在这里插入图片描述
RectF 的范围分为两个,图中小的矩形和大的矩形 ,小矩形画AB圆弧这段,大矩形画CD圆弧这段

	我们开始定义小圆的半径  100 即OB=100大圆半径 200吧 即 OG=200;定义圆心坐标 o center_x,center_yRectF   rect_inner 小圆矩形框RectF   rect_outer 大圆矩形框在onMeasure方法中获取控件的 宽 ,高@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){super.onMeasure(widthMeasureSpec, heightMeasureSpec);width = MeasureSpec.getSize(widthMeasureSpec);height = MeasureSpec.getSize(heightMeasureSpec);}圆心坐标 center_x=width/2  center_y=height /2//小圆矩形框 设置RectF rect_inner=new RectF(center_x-100,center_y-100,center_x+100,center_y+100)//大圆矩形框设置RectF rect_outer =new RectF(center_x-200,center_y-200,center_x+200,center_y+200)

直接上代码,看看绘制出来的第一个部分

在这里插入图片描述

public class ViewCircle extends View
{private Paint mPaint;private Context context;//控件宽高private int width, height;//圆心坐标private int centerX, centerY;//小圆半径private int smallRadius = 100;//大圆半径private int largeRadius = 200;//小圆的范围private RectF rectInner;//大圆的范围 private RectF rectOuter;public ViewCircle(Context context){super(context);init(context);}public ViewCircle(Context context, AttributeSet attrs){super(context, attrs);init(context);}public ViewCircle(Context context, AttributeSet attrs, int defStyleAttr){super(context, attrs, defStyleAttr);init(context);}private void init(Context context){this.context = context;mPaint = new Paint();mPaint.setAntiAlias(true);mPaint.setColor(context.getResources().getColor(R.color.colorBlack));mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeWidth(1);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){super.onMeasure(widthMeasureSpec, heightMeasureSpec);width = MeasureSpec.getSize(widthMeasureSpec);height = MeasureSpec.getSize(heightMeasureSpec);centerX = width / 2;centerY = height / 2;rectInner = new RectF(centerX - smallRadius, centerY - smallRadius, centerX + smallRadius, centerY + smallRadius);rectOuter =new RectF(centerX-largeRadius,centerY-largeRadius,centerX+largeRadius,centerY+largeRadius);}@Overrideprotected void onDraw(Canvas canvas){super.onDraw(canvas);Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);Canvas canvas1 = new Canvas(bitmap);Path path = new Path();//画小圆的圆弧path.addArc(rectInner, 150, 120);//链接到c点//c点横坐标 BC=centerX+OB/tant30//c点的纵坐标 就等于OB 为 100//Math 里面的 sin cos tan 是弧度制,不能直接写30度,需要把角度转为弧度 Math.PI*30.0/180.0float cx= centerX+(float) (smallRadius / Math.tan(Math.PI*30.0/180.0));float cy=centerY-smallRadius;//画直线path.lineTo(cx,cy);//画大圆圆弧 根据图可知 大圆的圆弧 开始角度为 -30度 逆时针 扫过-120度path.addArc(rectOuter, -30, -120);//画链接到A点的直线 求出A点的坐标float ax=centerX-(float) (smallRadius * Math.cos(Math.PI*30.0/180.0));float ay=centerY+(float) (smallRadius * Math.sin(Math.PI*30.0/180.0));path.lineTo(ax,ay);canvas1.drawPath(path, mPaint);canvas.drawBitmap(bitmap, 0, 0, mPaint);}
}

再通过旋转,绘制其它两个部分

   //以圆心旋转120度Matrix matrix=new Matrix();matrix.setRotate(120,centerX,centerX);path.transform(matrix);canvas1.drawPath(path, mPaint);//再次旋转path.transform(matrix);canvas1.drawPath(path, mPaint);

在这里插入图片描述

绘制颜色和中间的小圆

//设置画笔颜色为红色

    mPaint.setColor(color[0]);canvas1.drawPath(path, mPaint);//以圆心旋转120度Matrix matrix=new Matrix();matrix.setRotate(120,centerX,centerX);path.transform(matrix);mPaint.setColor(color[1]);canvas1.drawPath(path, mPaint);//再次旋转path.transform(matrix);mPaint.setColor(color[2]);canvas1.drawPath(path, mPaint);//绘制中间的小圆mPaint.setColor(color[4]);canvas1.drawCircle(centerX,centerY,smallRadius,mPaint);//绘制蓝色小圆mPaint.setColor(color[3]);canvas1.drawCircle(centerX,centerY,smallRadius-10,mPaint);canvas.drawBitmap(bitmap, 0, 0, mPaint);

在这里插入图片描述

为各个色值添加点击事件

@Override
public boolean onTouchEvent(MotionEvent event)
{int action=event.getAction();//if (action!=MotionEvent.ACTION_DOWN   && action!=MotionEvent.ACTION_UP){return super.onTouchEvent(event);}float x = event.getX();float y = event.getY();int pixe=bitmap.getPixel((int)x,(int)y);//取到的颜色值是透明的if(Color.TRANSPARENT==pixe){return false;}else{for (int i=0;i<color.length;i++){if(pixe==color[i]){//设置tag值 用于判断点击事件this.setTag(i);}}}return super.onTouchEvent(event);
}viewCircle=findViewById(R.id.scrollIndicatorDown);viewCircle.setOnClickListener(new View.OnClickListener(){@Overridepublic void onClick(View view){Object object=view.getTag();if(object==null){return;}int index= (int) object;if(index==0){Toast.makeText(MainActivity.this,"红色",Toast.LENGTH_SHORT).show();}if(index==1){Toast.makeText(MainActivity.this,"黄色",Toast.LENGTH_SHORT).show();}if(index==2){Toast.makeText(MainActivity.this,"绿色",Toast.LENGTH_SHORT).show();}if(index==3){Toast.makeText(MainActivity.this,"蓝色",Toast.LENGTH_SHORT).show();}}});

在这里插入图片描述