老套路先上图:

整个view非常简单,我自定义view里面都有详细的注释说明

先看自定义view部分代码:

package cn.xiayiye5.customizestudy.view;import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;import cn.xiayiye5.customizestudy.R;/*** @author : xiayiye5* @date : 2021/3/18 15:50* 类描述 :自定义view - 画圆基础练习*/
public class BasicView extends View {private int measuredWidth;private int measuredHeight;private Paint paint;private float paintWidth;private int paintColor;private int paintStroke;private Paint textPaint;private final float textWidth;private final int textColor;private final float textSize;@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)public BasicView(Context context) {this(context, null);}@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)public BasicView(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)public BasicView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {this(context, attrs, defStyleAttr, 0);}@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)public BasicView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BasicView);paintWidth = typedArray.getDimension(R.styleable.BasicView_paint_width, 10);paintColor = typedArray.getColor(R.styleable.BasicView_paint_color, Color.GREEN);paintStroke = typedArray.getInt(R.styleable.BasicView_paint_stroke, 1);//获取文字颜色,宽度,大小等textWidth = typedArray.getDimension(R.styleable.BasicView_text_width, 10);textColor = typedArray.getColor(R.styleable.BasicView_text_color, Color.GREEN);textSize = typedArray.getDimension(R.styleable.BasicView_text_size, 20);typedArray.recycle();initView();}private void initView() {//文字用到的画笔textPaint = new Paint();//圆用到的画笔paint = new Paint();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//设置中间文字颜色大小宽度等textPaint.setTextSize(textSize);textPaint.setStrokeWidth(textWidth);textPaint.setColor(textColor);//设置画笔圆的大小颜色宽度等paint.setColor(paintColor);paint.setTextSize(14f);paint.setStrokeWidth(paintWidth);if (paintStroke == StrokeModel.STROKE_ZERO) {paint.setStyle(Paint.Style.FILL);} else if (paintStroke == StrokeModel.STROKE_ONE) {paint.setStyle(Paint.Style.STROKE);} else if (paintStroke == StrokeModel.STROKE_TWO) {paint.setStyle(Paint.Style.FILL_AND_STROKE);} else {throw new NumberFormatException("The value is only 0(BasicView.StrokeModel.STROKE_ZERO) or 1(BasicView.StrokeModel.STROKE_ONE) or 2(BasicView.StrokeModel.STROKE_TWO)");}float length = textPaint.measureText("扬宏豕慧");float fontHeight = getFontHeight(textPaint);//写文字在坐标中心居中canvas.drawText("扬宏豕慧", (measuredWidth - length) / 2f, (measuredHeight + fontHeight / 2f) / 2f, textPaint);canvas.drawCircle(measuredWidth / 2f, measuredHeight / 2f, (measuredWidth - paintWidth) / 2f, paint);//画圆的横线canvas.drawLine(0, measuredHeight / 2f, measuredWidth, measuredHeight / 2f, paint);//画圆的竖线canvas.drawLine(measuredWidth / 2f, 0, measuredHeight / 2f, measuredHeight, paint);}/*** @return 返回指定的文字高度*/public float getFontHeight(Paint paint) {Paint.FontMetrics fm = paint.getFontMetrics();//文字基准线的下部距离-文字基准线的上部距离 = 文字高度return fm.descent - fm.ascent;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int height = 0;int width = 0;width = setViewMode(widthMeasureSpec, width);height = setViewMode(heightMeasureSpec, height);//获取测量模式后设置下即可setMeasuredDimension(width, height);measuredWidth = getMeasuredWidth();measuredHeight = getMeasuredHeight();Log.e("打印宽高", measuredWidth + "-" + measuredHeight);}/*** 获取测量模式的方法** @param measureSpec 测量模式* @param viewSize    view的大小* @return 返回 view经过测量后的大小*/private int setViewMode(int measureSpec, int viewSize) {int viewMode = MeasureSpec.getMode(measureSpec);int size = MeasureSpec.getSize(measureSpec);if (viewMode == MeasureSpec.AT_MOST) {// wrap_content模式 测量规格模式:子级可以任意大到指定的大小。viewSize = getMeasuredWidth() / 3;} else if (viewMode == MeasureSpec.EXACTLY) {// 已经设置了具体大小,类似10dp 和match_parent 测量规格模式:父级已确定子级的确切大小。不管孩子想要多大,都要给他这些限制。viewSize = size;} else if (viewMode == MeasureSpec.UNSPECIFIED) {//设置多大就多大可以无限大 度量规范模式:父级未对子级施加任何约束。它可以是它想要的任何尺寸。viewSize = size;}return viewSize;}@SuppressLint("ClickableViewAccessibility")@Overridepublic boolean onTouchEvent(MotionEvent event) {if (event.getAction() == MotionEvent.ACTION_DOWN) {//获取view在当前屏幕的坐标float rawX = event.getRawX();float rawY = event.getRawY();//获取view在自身的坐标float x = event.getX();float y = event.getY();Log.e("打印屏幕坐标", rawX + "," + rawY);Log.e("打印view坐标y", x + "," + y);if (x > 0 && y > 0) {//证明点击了此viewToast.makeText(getContext(), "点击了此布局(" + x + "," + y + ")", Toast.LENGTH_LONG).show();clickViewListener.clicked(this);}}return true;}public static class StrokeModel {private StrokeModel() {}public static final int STROKE_ZERO = 0;public static final int STROKE_ONE = 1;public static final int STROKE_TWO = 2;}public interface ClickViewListener {/*** 点击了哪个view** @param view 具体的view*/void clicked(View view);}ClickViewListener clickViewListener;public void setClickViewListener(ClickViewListener clickViewListener) {this.clickViewListener = clickViewListener;}/*** 设置画笔圆的宽度** @param paintWidth 宽度*/public void setPaintWidth(float paintWidth) {this.paintWidth = paintWidth;requestLayout();}/*** 设置画笔圆的颜色** @param paintColor 颜色*/public void setPaintColor(int paintColor) {this.paintColor = paintColor;invalidate();}/*** 设置画笔圆的模式** @param paintStroke 模式*/public void setPaintStroke(int paintStroke) {this.paintStroke = paintStroke;requestLayout();}
}

再看layout布局代码

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><cn.xiayiye5.customizestudy.view.BasicViewandroid:id="@+id/bv_view"android:layout_width="wrap_content"android:layout_height="wrap_content"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"app:paint_color="@color/purple_500"app:paint_stroke="stroke"app:paint_width="1dp"app:text_color="@color/purple_200"app:text_size="16sp"app:text_width="10dp" /><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="changeColor"android:text="改变颜色"app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

再看activity页面代码

package cn.xiayiye5.customizestudy.ui.activity;import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.Toast;import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;import java.util.Random;import cn.xiayiye5.customizestudy.R;
import cn.xiayiye5.customizestudy.view.BasicView;
import cn.xiayiye5.customizestudy.view.BasicView.StrokeModel;/*** @author : xiayiye5* @date : 2021/3/19 11:36* 类描述 :*/
public class BasicActivity extends AppCompatActivity {int num = 0;BasicView bvView;private ObjectAnimator rotation;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_basic);bvView = findViewById(R.id.bv_view);bvView.setClickViewListener(view -> Toast.makeText(BasicActivity.this, "点击了此布局", Toast.LENGTH_LONG).show());}public void changeColor(View view) {if (num % StrokeModel.STROKE_TWO == 0) {//开始执行动画startAnim();Toast.makeText(this, "彩虹红灯开启", Toast.LENGTH_SHORT).show();handler.sendEmptyMessageDelayed(0, 500);} else {Toast.makeText(this, "彩虹红灯关闭", Toast.LENGTH_SHORT).show();handler.removeCallbacksAndMessages(null);//关闭动画rotation.end();}num++;}/*** 开始动画的方法*/private void startAnim() {ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(bvView, "alpha", 0.0f, 1.0f);ObjectAnimator scaleX = ObjectAnimator.ofFloat(bvView, "scaleX", 0.0f, 1.0f);ObjectAnimator scaleY = ObjectAnimator.ofFloat(bvView, "scaleY", 0.0f, 1.0f);rotation = ObjectAnimator.ofFloat(bvView, "rotation", 0.0f, 1080f);rotation.setRepeatCount(100);//旋转不停顿rotation.setInterpolator(new LinearInterpolator());//重复次数rotation.setDuration(1000);rotation.start();
//        AnimatorSet set = new AnimatorSet();
//        set.playTogether(alphaAnim, scaleX, scaleY);
//        set.setDuration(3000);
//        set.start();}private final Handler handler = new Handler(Looper.getMainLooper()) {@Overridepublic void handleMessage(@NonNull Message msg) {super.handleMessage(msg);Log.e("打印", "发送消息");bvView.setPaintColor(Color.rgb(new Random().nextInt(255), new Random().nextInt(255), new Random().nextInt(255)));bvView.setPaintStroke(StrokeModel.STROKE_ONE);bvView.setPaintWidth(new Random().nextInt(30));//继续发送形成循环模式sendEmptyMessageDelayed(0, 500);}};@Overrideprotected void onPause() {super.onPause();handler.removeCallbacksAndMessages(null);}@Overrideprotected void onResume() {super.onResume();if (num > 0) {//继续发送形成循环模式handler.sendEmptyMessageDelayed(0, 500);}}@Overrideprotected void onDestroy() {super.onDestroy();handler.removeCallbacksAndMessages(null);}
}

在看下attrs.xml属性文件

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="BasicView"><!--画笔颜色--><attr name="paint_color" format="color" /><!--画笔宽度--><attr name="paint_width" format="dimension" /><!--画笔形状--><attr name="paint_stroke" format="enum"><enum name="fill" value="0" /><enum name="stroke" value="1" /><enum name="fill_and_stroke" value="2" /></attr><!--文字颜色--><attr name="text_color" format="color" /><!--文字大小--><attr name="text_size" format="dimension" /><!--文字宽度--><attr name="text_width" format="dimension" /></declare-styleable>
</resources>

整个理偶成非常简单说下具体步骤:

先通过attires文件自定义属性=>然后绘制view将自定义属性通过layout文件与attrs的自定义属性对应设置相应的属性值即可。其它就是API相关的东西了。

感谢博主提供动画结束方法:博主直达

关于view的测量模式可以查看Google官方文档的说明:Google官方文档说明

Android开发之自定义view进行旋转动画相关推荐

  1. Android开发,自定义View的学习合集

    转载自:http://blog.csdn.net/u011507982/article/details/51199644 自定义控件学习  https://github.com/GcsSloop/An ...

  2. Android开发之自定义View(一)

    Android常见的自定义控件有三种方式: 继承View 继承原有的控件,在原有控件的基础上进行修改 重新拼装组合 今天先来简单说一说第一种也是最复杂的一种~~ 剩下的下次再说~~ 继承View,重写 ...

  3. android自定义view凯,Android开发之自定义View(一)

    Android常见的自定义控件有三种方式: 继承View 继承原有的控件,在原有控件的基础上进行修改 重新拼装组合 今天先来简单说一说第一种也是最复杂的一种~~ 剩下的下次再说~~ 继承View,重写 ...

  4. Android开发之自定义View

    目录 一.View的简介 1.1 View的构造函数 1.2 View的绘制流程图 二.自定义View 2.1 onMeasure()方法 2.2 OnDraw()方法 一.View的简介 View类 ...

  5. Android开发之自定义view预览不显示的问题

    老套路上图看: 如何解决呢?只需要我们点击右上角的感叹号查看不显示的原因即可 3.查看不显示的原因 4.查看具体报错代码以及报错解决方法 5.自行排查自定义view中有哪些没有初始化的数据进行修改或者 ...

  6. Android开发之自定义view绘制坐标位置出错的问题解决

    老套路先看效果图 解释下:如上图我自定义view的时候再onDraw方法进行绘制文本的时候想要的效果是让文字居中,计算都是正确的,相应的坐标也打印出来手动计算检查了下都是对的,但是就是有问题,问题就是 ...

  7. Android开发之自定义View之音阶图谱

    看下效果图 上代码 package com.xiayiye5.songview;/** Copyright (c) 2022, 13343401268@163.com All Rights Reser ...

  8. Android中的自定义View以及绘图工具

    1.1自定义view的简介 为什么要使用自定义view 在Android开发中有很多业务场景,原生的控件是无法满足应用,并且经常也会遇到一个UI在多处 重复使用情况,那么就需要通过自定义View的方式 ...

  9. android动画view上移,在Android开发中使用View制作一个引导动画

    在Android开发中使用View制作一个引导动画 发布时间:2020-11-20 16:46:16 来源:亿速云 阅读:98 作者:Leah 这篇文章将为大家详细讲解有关在Android开发中使用V ...

最新文章

  1. python菜鸟excel教程-Python操作Excel的Xlwings教程(一)
  2. language is the key
  3. Hat’s Words(HDU-1247)
  4. php获取模型错误,php – 解析错误,期望activecollab模型类中出现“T_PAAMAYIM_NEKUDOTAYIM”错误...
  5. 便利蜂发布《白领早餐报告》:仅5成白领每天吃早餐
  6. extjs的panel怎么自适应高度_Ext Js自适应高度
  7. 【commons-httpclient】Java中HttpClient工具访问Web请求
  8. 【Qt教程】3.2 - Qt5 event事件、定时器timerEvent
  9. 如何摆脱初学者的不自信,成为一名专业编程人士?
  10. 【车牌识别】基于matlab GUI字符匹配车牌识别(18省份)【含Matlab源码 1617期】
  11. python游戏程序中游戏对象是什么_Python游戏编程入门
  12. photoshop 调用扫描仪扫描证件至电脑
  13. 计算机硬件输出设备有哪些,输出设备有哪些,输出设备的作用
  14. 29.Go异常处理-recover
  15. html中鼠标悬停图片变大,JavaScript通过mouseover()实现图片变大效果的示例
  16. mysql5.7修改密码
  17. Sql语句操作数据库(修改表,修改数据库)
  18. css 真正意义上达到height:100%,自适应屏幕高度
  19. 博客字体颜色、大小、字体都可以更改,直接套用就可以
  20. vue3 composition(组合式)API 是什么?我为什么要使用它?

热门文章

  1. 新手如何快速上手Linux,韦东山告诉你。
  2. ST-Link如何秒变J-link,手把手教你实现该功能
  3. python string类型_Python的基本数据类型——String
  4. mysql基础表和修理表_MySQL基础知识——创建数据库和表
  5. python爬贴吧回复内容_Python 基础语法+简单地爬取百度贴吧内容
  6. Educational Codeforces Round 37-F.SUM and REPLACE (线段树,线性筛,收敛函数)
  7. python 爬虫 selenium
  8. rest framework错误笔记——身份验证和权限
  9. java.lang.NoClassDefFoundError: org/apache/juli/logging/LogFactory
  10. SVN本地代码未提交而被覆盖