自定义view-制作一个加载中的圆形
16lz
2021-01-24
最近因为项目的需求做的一个加载中圆,刚好记录一下
/** * 自定义加载中的圆,主要代码 */public class LoadingSearchView extends View { private Paint mCirclePaint; private Paint mInnerPaint; private float mCircleRadius; private final static float RADIUS = 180f; private final static float INITIAL_ANGLE = 90f; /** * 旋转角度 */ private float mRotationAngle = 0; /** * 实心半圆最初的位置 */ private float mCircleStartAngle; /** * 实心半圆应该绘制多大的 */ private float mCircleSweepAngle; /** * 文字的画笔 */ private Paint mTextPaint; /** * 外圈圆的宽 */ private float mLoadingRoundWidth; /** * 外圈圆与内圆的间距 */ private float mSpacingOfCircles; /** * 内圆的颜色 */ private int mInnerCircleColor; /** * 设置几个默认的值 */ private float mInitialDefaultSize, mLoadingRoundDefaultWidth, mSpacingOfDefaultCircles; public LoadingSearchView(Context context) { this(context, null); } public LoadingSearchView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public LoadingSearchView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initDefaultValue(); initAttributeSet(attrs); setCirclePaint(); initTextPaint(); } /** * 初始化一些默认值 */ private void initDefaultValue() { mCircleStartAngle = INITIAL_ANGLE; mLoadingRoundDefaultWidth = dp2px(getContext(), 8); mInitialDefaultSize = sp2px(getContext(), 50); mSpacingOfDefaultCircles = dp2px(getContext(), 5); } /** * 初始化画笔的颜色 */ private void initTextPaint() { mTextPaint = new Paint(); mTextPaint.setAntiAlias(true); mTextPaint.setTextSize(sp2px(getContext(), 16)); mTextPaint.setColor(Color.WHITE); } /** * 初始化圆的画笔 */ private void setCirclePaint() { mCirclePaint = initCircle(); mCirclePaint.setStyle(Paint.Style.STROKE); mCirclePaint.setStrokeWidth(mLoadingRoundWidth); mInnerPaint = initCircle(); mInnerPaint.setStyle(Paint.Style.FILL); mInnerPaint.setColor(mInnerCircleColor); } private Paint initCircle() { Paint paint = new Paint(); paint.setAntiAlias(true); paint.setStrokeCap(Paint.Cap.ROUND); paint.setStrokeJoin(Paint.Join.ROUND); return paint; } private void initAttributeSet(AttributeSet attrs) { TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.LoadingSearchView); mLoadingRoundWidth = array.getDimension(R.styleable.LoadingSearchView_loading_round_width, mLoadingRoundDefaultWidth); mSpacingOfCircles = array.getDimension(R.styleable.LoadingSearchView_spacing_of_circles, mSpacingOfDefaultCircles); float defaultCircle = mLoadingRoundDefaultWidth + mSpacingOfDefaultCircles + mInitialDefaultSize; mCircleRadius = array.getDimension(R.styleable.LoadingSearchView_loading_circle_radius, defaultCircle); mInnerCircleColor = array.getColor(R.styleable.LoadingSearchView_inner_circle_color, Color.parseColor("#00d8c9")); array.recycle(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int measuredWidth = getMeasuredWidth(); float digitalDifference = (measuredWidth - mCircleRadius * 2) / 2; if (digitalDifference < 0) { setMeasuredDimension((int) (mCircleRadius * 2), (int) (mCircleRadius * 2)); } drawOuterCircle(digitalDifference, canvas); drawInnerCircle(digitalDifference, canvas); drawSuccessAnimator(digitalDifference, canvas); } private void drawSuccessAnimator(float digitalDifference, Canvas canvas) { if (mCircleSweepAngle >= 360) { String success = "成功"; Rect bounds = new Rect(); mTextPaint.getTextBounds(success, 0, success.length(), bounds); float startX = mCircleRadius - bounds.right / 2; Paint.FontMetricsInt fontMetricsInt = mTextPaint.getFontMetricsInt(); int dy = (fontMetricsInt.top - fontMetricsInt.bottom) / 2 - fontMetricsInt.top; float baseLine = mCircleRadius + dy; canvas.drawText(success, startX + digitalDifference, baseLine + digitalDifference, mTextPaint); } } private void drawInnerCircle(float digitalDifference, Canvas canvas) { RectF circleRectF = new RectF(mLoadingRoundWidth + mSpacingOfCircles + digitalDifference, mLoadingRoundWidth + mSpacingOfCircles + digitalDifference, (mCircleRadius * 2 - (mLoadingRoundWidth + mSpacingOfCircles)) + digitalDifference, (mCircleRadius * 2 - (mLoadingRoundWidth + mSpacingOfCircles)) + digitalDifference); canvas.drawArc(circleRectF, mCircleStartAngle, mCircleSweepAngle, false, mInnerPaint); } /** * 画外圆 * * @param digitalDifference * @param canvas */ private void drawOuterCircle(float digitalDifference, Canvas canvas) { RectF rectF = new RectF(mLoadingRoundWidth / 2 + digitalDifference, mLoadingRoundWidth / 2 + digitalDifference, (mCircleRadius * 2 - mLoadingRoundWidth / 2) + digitalDifference, (mCircleRadius * 2 - mLoadingRoundWidth / 2) + digitalDifference); mCirclePaint.setColor(Color.parseColor("#00d8c9")); canvas.drawArc(rectF, mRotationAngle, RADIUS, false, mCirclePaint); mCirclePaint.setColor(Color.parseColor("#64e27f")); float rotationAngle = mRotationAngle + RADIUS; canvas.drawArc(rectF, rotationAngle, RADIUS, false, mCirclePaint); } public void setRotationAngle(float rotationAngle) { mRotationAngle = mRotationAngle + 3; float angle = RADIUS * rotationAngle; mCircleStartAngle = INITIAL_ANGLE - angle; mCircleSweepAngle = angle * 2; invalidate(); } /** * dp转px */ public float dp2px(Context context, float dpVal) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, context.getApplicationContext().getResources().getDisplayMetrics()); } /** * sp转px */ public int sp2px(Context context, float spVal) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal, context.getApplicationContext().getResources().getDisplayMetrics()); }}
自定义的属性如下,在values文件中创建文件attrs.xml:
activity页面的布局也是只有一个加载的view,如下:
MainActivity里面的代码如下:
public class MainActivity extends AppCompatActivity { private LoadingSearchView mTestView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTestView = findViewById(R.id.test_view); mTestView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 创建一个属性动画,来启动圆的动画 ObjectAnimator animator = ObjectAnimator.ofFloat(mTestView, "rotationAngle", 1f); animator.setInterpolator(new DecelerateInterpolator()); animator.setDuration(4000); animator.start(); } }); }}
更多相关文章
- Android底部导航栏实现(一)之BottomNavigationBar
- Android(安卓)Shader应用开发之雷达扫描效果
- Bitmap and DrawPoint
- Android实现圆角矩形和圆形ImageView的方式
- AES加解密在Android(安卓)4.2上的Encryption error
- 使用百度地图SDK 这是之前版本 现在的sdk v2-1-2使用方法完全改
- Android培训班(38)
- Android系统启动流程之Init说明
- flutter集成推送功能-小米推送集成