Android自定义控件之循环旋转弧度不断变化圆弧的控件

xiaoxiao2021-02-28  72

Android自定义控件的绘制流程为Measure(测量)–>Layout(布局)–>Draw(绘制)。测量控件的宽高,需要重写onMeasure方法,其中涉及到一个关键的知识点:MeasureSpec类。一个MeasureSpec封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求。一个MeasureSpec由大小和模式组成。它有三种模式:UNSPECIFIED(未指定),父元素不对子元素施加任何束缚,子元素可以得到任意想要的大小,一般用于AdapterView,比如Listview,Gridview等;EXACTLY(精确),父元素决定自元素的确切大小,子元素将被限定在给定的边界里而忽略它本身大小或者子元素的尺寸是精确的,比如 android:layout_width=”50dp” android:layout_height=”50dp”;AT_MOST(至多),子元素至多达到指定大小的值,也就是只要不超过父容器所给定的大小,子元素多大都可以。   它常用的三个函数:   1.static int getMode(int measureSpec):根据提供的测量值(格式)提取模式(上述三个模式之一)   2.static int getSize(int measureSpec):根据提供的测量值(格式)提取大小值(这个大小也就是我们通常所说的大小)   3.static int makeMeasureSpec(int size,int mode):根据提供的大小值和模式创建一个测量值(格式)。   对于一般的控件,我们只需要判断它是MeasureSpec.EXACTLY还是MeasureSpec.AT_MOST。MeasureSpec.EXACTLY代表子元素的尺寸是确定的了,比如子容器是match_parent,或者子元素的尺寸是固定尺寸;MeasureSpec.AT_MOST代表在父容器的尺寸范围内,子元素要多大就是多大,比如wrap_content.。     本篇文章所要介绍的是如何自定义一个循环旋转圆弧不断变化的控件。  首先要继承于View,重写构造方法,在构造方法中初始化画笔等等。  

public MyArc02(Context context, AttributeSet attrs) { super(context, attrs); //实例化画笔 paint = new Paint(); //控件的宽度 width = getResources().getDimensionPixelSize(R.dimen.header_width); height = width; //圆弧的矩形范围 oval = new RectF(15, 15, width - 15, width - 15); //圆弧的半径 radius = getResources().getDimensionPixelSize(R.dimen.radius); cx = width / 2; cy = cx; }

重写View的onMeasure方法,测量控件的宽高,调用setMeasuredDimension方法,设置控件的宽高,否则控件的宽高默认为父容器的宽高。

@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int mWidth = MeasureSpec.getSize(widthMeasureSpec); int mHeight = MeasureSpec.getSize(heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int HeightMode = MeasureSpec.getMode(widthMeasureSpec); System.out.println("宽度: " + mWidth); System.out.println("高度: " + mHeight); //width是绘制控件所需要的最大宽度尺寸,height为绘制控制所需的最大高度尺寸 int measuredWidth = (int) (widthMode == MeasureSpec.EXACTLY ? mWidth : width); int measuredHeight = (int) (HeightMode == MeasureSpec.EXACTLY ? mHeight : height); setMeasuredDimension(measuredWidth, measuredHeight); }

由于本demo中没有涉及到控件的自定义布局,所以没有重写onLayout方法。重写onDraw方法,绘制背景圆形、弧度不断变化圆弧和旋转canvas,并调用postInvalidateDelayed方法,定时刷新界面

@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); paint.setStrokeWidth(5); drawRoundBackground(canvas); drawRunningArc(canvas); } private void drawRoundBackground(Canvas canvas) { paint.setColor(Color.WHITE); paint.setStyle(Paint.Style.FILL); canvas.drawCircle(cx, cy, radius, paint); paint.setColor(Color.GRAY); paint.setStyle(Paint.Style.STROKE); paint.setAlpha(20); canvas.drawCircle(cx, cy, radius, paint); } /** * 画转动圆弧 * @param canvas */ private void drawRunningArc(Canvas canvas) { paint.setColor(Color.RED); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(10); startAngle += deltaAngle; if (sweepAngle >= 360 - deltaAngle) { flag = true; } if (sweepAngle <= deltaAngle ) { flag = false; } if (flag) { sweepAngle -= deltaAngle; }else { sweepAngle += deltaAngle; } angle += deltaAngle; canvas.rotate(angle, cx, cy); canvas.drawArc(oval, startAngle, sweepAngle, false, paint); //每隔200毫秒,刷新界面 postInvalidateDelayed(200); }

  在布局文件中使用该控件   

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <com.example.arc.MyArc02 android:id="@+id/arc" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:src="@drawable/ic_launcher" /> </FrameLayout>
转载请注明原文地址: https://www.6miu.com/read-73159.html

最新回复(0)