【Android】之【自定义View实践】

这里以一个进度条的加载为例子,先看效果(运行效果是动态变化的)

一、自定义属性

首先在res->values目录下新建attrs资源文件,如下图:

在这里插入图片描述
内容如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
   <declare-styleable name="ProgressBar">
<!--       圆弧的颜色-->
       <attr name="innerBackground" format="color"/>
       <attr name="outerBackground" format="color"/>
<!--       圆弧的大小-->
       <attr name="roundWidth" format="dimension"/>
<!--       字体大小、颜色-->
       <attr name="progressTextSize" format="dimension"/>
       <attr name="progressTextColor" format="color"/>

   </declare-styleable>
</resources> 

二、在Layout文件中引用自定义View

这里要注意引入自定义View属性的命名空间的方式

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <com.example.viewtest.ProgressBar
        android:id="@+id/progress_bar"
        custom:progressTextSize="20sp"
        custom:progressTextColor="#ff7788"
        custom:innerBackground="#ee9933"
        custom:outerBackground="#229933"
        custom:roundWidth="5dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

<!--    测试按钮-->
    <Button
        android:id="@+id/test"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:layout_marginTop="30dp"
        android:layout_gravity="center"
        android:text="测试"
        android:background="@color/black"
        android:textColor="@color/white"/>

</LinearLayout> 

三、 创建一个类继承View

public class ProgressBar extends View {

    private static final String TAG = "ProgressBar";

    //声明自定义属性
    private int mInnerBackground = Color.RED;
    private int mOuterBackground = Color.GREEN;
    private int mRoundWidth = 30;
    private int mProgressTextSize = 70;
    private int mProgressTextColor = Color.GREEN;

    //创建画笔
    private Paint mInnerPaint=new Paint();
    private Paint mOutterPaint = new Paint();
    private Paint mTextPaint = new Paint();

    //进度条的最大进度
    private int mMax=100;
    //当前进度
    private int mCurrentProgress=50;

    //new对象的时候调用该方法
    public ProgressBar(Context context) {
        super(context);
    }

    //在布局中使用   xml文件中使用
    public ProgressBar(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    //  在layout中调用  自定义样式、有固定style的时候使用
    public ProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        //获取自定义属性
        TypedArray array= context.obtainStyledAttributes(attrs,R.styleable.ProgressBar);
        mInnerBackground=array.getColor(R.styleable.ProgressBar_innerBackground,mInnerBackground);
        mOuterBackground=array.getColor(R.styleable.ProgressBar_outerBackground,mOuterBackground);
        mProgressTextColor= array.getColor(R.styleable.ProgressBar_progressTextColor,mProgressTextColor);
        mProgressTextSize= (int) array.getDimension(R.styleable.ProgressBar_progressTextSize,sp2px(mProgressTextSize));
        mRoundWidth= (int) array.getDimension(R.styleable.ProgressBar_roundWidth,dip2px(mRoundWidth));
        array.recycle();

//        mInnerPaint = new Paint();

    }

    private float sp2px(int sp) {
        return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,sp,getResources().getDisplayMetrics());
    }

    private float dip2px(int dip) {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dip,getResources().getDisplayMetrics());
    }

    public ProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }


    /**
     * onMeasure
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //拿到宽高
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);

        //存储view 的宽高 在这里取最小值 保证是一个正方形即可
        setMeasuredDimension(Math.min(width,height),Math.min(width,height));
    }

    /**
     * onDraw
     */

    @Override
    protected void onDraw(Canvas canvas) {

        mInnerPaint.setAntiAlias(true);//抗锯齿
        mInnerPaint.setColor(mInnerBackground);
        mInnerPaint.setStrokeWidth(mRoundWidth);//线条宽度
        mInnerPaint.setStyle(Paint.Style.STROKE);//空心

        mOutterPaint.setAntiAlias(true);//抗锯齿
        mOutterPaint.setColor(mOuterBackground);
        mOutterPaint.setStrokeWidth(mRoundWidth);//线条宽度
        mOutterPaint.setStyle(Paint.Style.STROKE);//空心

        mOutterPaint.setAntiAlias(true);//抗锯齿
        mTextPaint.setColor(mProgressTextColor);
        mTextPaint.setStrokeWidth(mRoundWidth);
        mTextPaint.setTextSize(mProgressTextSize);

//        super.onDraw(canvas);
        //先画内圆
        int center = getWidth()/2;
        Log.d(TAG, "onDraw: "+center);

       canvas.drawCircle(center,center,center-mRoundWidth/2,mInnerPaint);

        //再画外层圆
        RectF rectF=new RectF(0+mRoundWidth/2,0+mRoundWidth/2,getWidth()-mRoundWidth/2,getHeight()-mRoundWidth/2);
        if (mCurrentProgress==0){
            return;
        }
        float percent = (float) mCurrentProgress/mMax;
        canvas.drawArc(rectF,0,percent*360,false,mOutterPaint);

        //画进度文字
        String text=((int)(percent*100))+"%";
        Rect textBounds=new Rect();
        mTextPaint.getTextBounds(text,0,text.length(),textBounds);

        int x= getWidth()/2-textBounds.width()/2;
        Paint.FontMetricsInt fontMetrics=mTextPaint.getFontMetricsInt();
        int dy=(fontMetrics.bottom-fontMetrics.top)/2 - fontMetrics.bottom;
        int baseLineY=getHeight()/2+dy;

        canvas.drawText(text,x,baseLineY,mTextPaint);
    }


    public synchronized void setMax(int max){
        if (max<0){
            Log.d(TAG, "setMax: max<0 不合法"+max);
        }
        this.mMax=max;
    }

    public synchronized void setProgress(int process){
        if (process<0){
            Log.d(TAG, "setMax: max<0 不合法"+process);
        }
        this.mCurrentProgress=process;
        invalidate();//刷新
    }
} 

实现自定义View有那些方式
① 继承View,例如折线图等。
② 继承ViewGroup,例如流式布局等。
③ 继承现有的View,例如TextView、ListView等。

四、在Activity中调用

public class MainActivity extends AppCompatActivity {

    private ProgressBar mProgressBar;

    private Button mTest;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initData();
    }

    private void initData() {
        mTest=findViewById(R.id.test);

        mProgressBar=(ProgressBar) findViewById(R.id.progress_bar);
        mProgressBar.setMax(1000);

        mTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                test();
            }
        });
    }

    private void test() {
        //值不断变化
        ValueAnimator animator= ObjectAnimator.ofFloat(0,1000);
        animator.setDuration(3000);
        animator.start();
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float progress = (float) animation.getAnimatedValue();
                mProgressBar.setProgress((int) progress);
            }
        });
    }
} 

五、参考

  • Android自定义View
  • 【Android学习】—自定义view的流程以及实践
  • Android自定义View入门(一)
  • Android 自定义View 之 Mac地址输入框

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/7829.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot基础学习之(九)添加员工的信息

本次项目所有能够使用的静态资源可以免费进行下载 静态资源 在本篇代码DAO层将通过Java文件去实现&#xff0c;在这里就不连接数据&#xff0c;然后通过jdbc将数据库内容的内容显示出来 案例&#xff1a;员工管理系统 上一篇博文的主要的内容是展示员工的信息&#xff0c;本篇…

Oracle JDK 和 OpenJDK 有什么区别?

可能在看这个问题之前很多人和我一样并没有接触和使用过 OpenJDK 。那么 Oracle JDK 和 OpenJDK 之间是否存在重大差异&#xff1f;下面我通过收集到的一些资料&#xff0c;为你解答这个被很多人忽视的问题。 首先&#xff0c;2006 年 SUN 公司将 Java 开源&#xff0c;也就有…

JAVA——网络编程基本概念

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了 博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点!人生格言&#xff1a;当你的才华撑不起你的野心的时候,你就应该静下心来学习! 欢迎志同道合的朋友一起加油喔&#x1f9be;&am…

腾讯云轻量服务器和云服务器区别对比(超详细)

腾讯云轻量服务器和云服务器有什么区别&#xff1f;为什么轻量应用服务器费用更低&#xff1f;是因为轻量服务器CPU内存性能比云服务器CVM性能差吗&#xff1f;轻量应用服务器适合中小企业或个人开发者搭建企业官网、博客论坛、微信小程序或开发测试环境&#xff0c;云服务器CV…

orcad library builder 建库及报错问题

目录 一.安装orcad library builder 二.orcad library builder 使用 1.建立一个orcad 原理图库测试下 尝试理解tcl那段的意思 xml文件导入建orcad库 折腾了2个多小时&#xff0c;居然没有直接方案搞定&#xff0c;简单记录下&#xff0c;后面遇到该问题的兄弟可参考借鉴&am…

Java集合框架之collection

1. 什么是集合 1.1 概念 对象的容器&#xff0c;实现类对对象常用的操作。 1.2 和数组的区别 数组长度固定&#xff0c;集合长度不固定。数组可以存储基本类型和引用类型&#xff0c;集合只能存储引用类型。 1.3 位置 java.util.*; 2. Collection体系 2.1 Collection父接…

网络编程 1

前言 小亭子正在努力的学习编程&#xff0c;接下来将开启javaEE的学习~~ 分享的文章都是学习的笔记和感悟&#xff0c;如有不妥之处希望大佬们批评指正~~ 同时如果本文对你有帮助的话&#xff0c;烦请点赞关注支持一波, 感激不尽~~ 目录 网络编程 什么是网络编程&#xff1f;…

ASP网上视频点播系统的设计与实现

在线视频服务系统的功能模块划分如下图&#xff08;2-2&#xff09;所示&#xff1a; 电影分类浏览 用户可以通过电影的类别进行浏览。显示近期热门电影&#xff0c;近期点机排行。用户能很方便的找到自己感兴趣的电影进行观看。 电影搜索 如果用户有很明确的目的&#xff0c;…

JUC结构

JUC是java.util.concurrent包的简称在Java5.0添加&#xff0c;目的就是为了更好的支持高并发任务。让开发者进行多线程编程时减少竞争条件和死锁的问题&#xff01;进程与线程的区别&#xff1a;进程 : 一个运行中的程序的集合; 一个进程往往可以包含多个线程,至少包含一个线程…

JVM的内存区域划分

目录 1、程序计数器&#xff08;内存中最小的一块&#xff0c;里面保存了当前线程下一条执行的指令的地址&#xff09; 2、栈&#xff08;保存局部变量和方法调用的信息&#xff09; 3、堆 &#xff08;成员变量和new出来的对象都在堆上&#xff09; 4、方法区&#xff08…

闲人闲谈PS之四十——项目售前费用归集

惯例闲话&#xff1a;广东这段时间老是下雨&#xff0c;堪比江浙一带梅雨季节&#xff0c;人的心情也像这天气一样&#xff0c;阴雨绵绵。2023年伊始&#xff0c;确实感觉很多事情在发生剧变&#xff0c;这种变化也稍微影响了闲人那本来稳如老狗的心。面对未知和变化&#xff0…

FreeRTOS学习(一)

裸机与RTOS对比 裸机&#xff1a;又称为前后台系统&#xff0c;前台系统指的是中断服务函数&#xff0c;后台系统指的大循环&#xff0c;即应用程序。 实时性差&#xff1a;&#xff08;应用程序轮流执行&#xff09;delay&#xff1a;空等待&#xff0c;CPU不执行其它代码结…

智能汽车赛道「年度大奖」揭晓,哪些供应商在细分市场独占鳌头

智能汽车产业链年度细分市场领军供应商&#xff0c;是高工智能汽车研究院在每个年度基于前装量产数据库及定点车型库数据进行综合评价颁发的年度重量级行业奖项。 2022年&#xff0c;是中国乘用车市场从电动化转型升级到全面普及智能化的关键节点。从计算平台、域控制器、传感…

python天狗吃月 青少年编程电子学会python编程等级考试一级真题解析2022年9月

目录 python天狗吃月 一、题目要求 编程实现 二、解题思路 1、图形分析

thinkphp5.0无限极分类及格式化输出详解案例一则

首先我们来看数据表 从上图中可以发现&#xff0c;中国下有贵州&#xff0c;北京两个子节点&#xff0c;而北京有天安门一个子节点&#xff0c;纽约的子节点是“纽约的子类”。 从pid为0看出&#xff0c;中国和纽约是顶级节点。 因为贵州的pid是1&#xff0c;而中国的id为1…

概率论基础2

文章目录多个random variable条件下的multi random variable 分布和independencemulti random variable continuous**2D normal distribution**two random variable independencemuilti random variable conditional expectional value(discrete)multi random variable conditi…

docker-compose 搭建 MinIO

目录1、搭建单机MinIO1、搭建单机MinIO &#xff08;1&#xff09;配置 docker-compose.yml minio: image: minio/minio container_name: "chain-minio" ports: - 9000:9000 # 服务端口 - 9090:9090 # 控制台端口 environment: - "MINIO_ACCESS_KEYadmin"…

【Python入门第四十七天】Python丨NumPy 数组迭代

数组迭代 迭代意味着逐一遍历元素&#xff0c;当我们在 numpy 中处理多维数组时&#xff0c;可以使用 python 的基本 for 循环来完成此操作。 如果我们对 1-D 数组进行迭代&#xff0c;它将逐一遍历每个元素。 实例 迭代以下一维数组的元素&#xff1a; import numpy as n…

Mysql忘记密码或者有修改密码的需求

今天突然有个想法&#xff0c;想要把毕设弄到服务器上去&#xff0c;所以要配置一下环境安装一下使用一下MySQL&#xff0c;导入一下SQL脚本来创建数据&#xff1b;结果长时间不用MySQL密码不记得了&#xff0c;最后参考了一些博主发现可以这样子修改。 1、打开mysql的配置文件…

OA系统是什么意思?企业为什么要用OA办公系统软件?

阅读本文您将了解&#xff1a;1、什么是OA&#xff1b;2、OA系统是什么意思&#xff1b;2、OA系统功能和对企业重要性 什么是OA&#xff1f; OA即办公自动化&#xff08;Office Automation&#xff0c;简称OA&#xff09;&#xff0c;是将计算机、通信等现代化技术运用到传统…