自定义View实现炫酷进度条

2024-05-28 17:48

本文主要是介绍自定义View实现炫酷进度条,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本篇博客主要介绍利用自定义View来实现自己想要的进度加载效果,其中涉及到的内容不会说的很多,但是我会稍微解释一下,其实只要有了思路都好处理。而且个人感觉自己写一个自定义View要比看别人写的自定义View要简单一点,因为你很明白里面属性的意义,看别人的自定义View还需要不断的判断每个属性的作用,然后是各种计算什么的,感觉不是很好!!(这个炫酷的进度条不是我的想法,是我在网上看到的,不过很不好意思,我当时只是从他的git仓库中把代码clone下来,没有保存原文链接,如果作者看到了,可以告诉我一下,我会将原文链接重新添加上去)。不过这篇的自定义View的实现,是我自己写的,没有完全拷贝作者的代码!!!详细情况可以看一下我的代码!!

好了,废话不多说了,先看一下效果图:
这里写图片描述这里写图片描述这里写图片描述

具体的代码的执行效果就是如上图所示,效果不是很好,还有非常大的优化空间,有兴趣的朋友可以自己更改我的代码,或者直接推倒重写,谢谢!!!

主布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/activity_main"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="com.example.administrator.customview.MainActivity"><com.example.administrator.customview.CustomView
        android:id="@+id/pb"android:layout_width="wrap_content"android:layout_height="wrap_content"></com.example.administrator.customview.CustomView><Button
        android:layout_marginTop="20dp"android:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="startProgressAnimation"android:layout_below="@id/pb"android:text="@string/start_animation"/>
</RelativeLayout>

在这里主要是将我自定义的View引入到布局中,就不做过多的介绍了!!!

Activity文件:

package com.example.administrator.customview;import android.os.CountDownTimer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;public class MainActivity extends AppCompatActivity {private CustomView cv;private int progressValue = 0;private boolean mProgressIsRunning = false;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);cv = (CustomView) findViewById(R.id.pb);}public void startProgressAnimation(View view){if (mProgressIsRunning){timer.cancel();timer.onFinish();}else{mProgressIsRunning = true;if (progressValue>=100){progressValue = 0;}timer.start();}}private CountDownTimer timer = new CountDownTimer(Integer.MAX_VALUE,100) {@Overridepublic void onTick(long millisUntilFinished) {cv.setProgressValue(progressValue);progressValue ++;}@Overridepublic void onFinish() {mProgressIsRunning = false;}};
}

使用一个定时器来模拟加载时value变化,根据时间不断的调整Value值,给人进度不断变化的感觉。这里的cv就是我们自定义的View。

CustomView文件(这个很关键,主要就是这个文件):

package com.example.administrator.customview;import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;/*** Created by zhuyuqiang on 2017/3/13.*/public class CustomView extends View {private final int WHITE_COLOR = Color.WHITE;private final int ORANGE_COLOR = 0xffffa800;//确定叶子旋转方向private final int ROTATE_RIGHT = 0;private final int ROTATE_LEFT = 1;private final int ROTATE_DEGREE = 5;//确定叶子垂直方向的振幅大小private final int SMALL_AMPLITUDE = 0;private final int MIDDLE_AMPLITUDE = 1;private final int BIG_AMPLITUDE = 2;private final int SMALL_Y = 1;private final int MIDDLE_Y = 2;private final int BIG_Y = 3;//确定叶子水平方向的移动大小private final int SMALL_TRANSITION = 0;private final int MIDDLE_TRANSITION = 1;private final int BIG_TRANSITION = 2;private final int SMALL_X = 5;private final int MIDDLE_X = 10;private final int BIG_X = 15;private Paint mWhitePaint,mOrangePaint,mBitmapPaint;private int mPadding_left,mPadding_top,mPadding_right,mPadding_bottom;private Point mLeftCircleCenter,mRightCircleCenter,mFengshanPoint;private BitmapContainer mLeafContainer,mFengShanContainer,mBg_Container;private Matrix mFengShanRotate,mLeafMatrix,mTextMatrix;private int startDegree = 0;private int mProgressValue = 0;private int radius;private final float MAX_PROGRESS_VALUE = 100;private RectF mLeftArcRect;private Rect mTextRect;private final int max = 10;private int y_step = 2;private final String mFinish= "100%";private float mTextScale = 0.1f;private int mTextSize = 42;private List<Leaf> mLeaves = new ArrayList<>();private onProgressChangedListener listener;public interface onProgressChangedListener{void onProgressValueChanged(int progressValue);}public CustomView(Context context) {this(context,null);}public CustomView(Context context, @Nullable AttributeSet attrs) {this(context, attrs,0);}public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {this(context, attrs, defStyleAttr,0);}public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);initAttrs();initBitmaps();initPaints();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);setMeasuredDimension(getCustomMeasureWidth(widthMeasureSpec),getCustomMeasureHeight(heightMeasureSpec));}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);initKeyPoints();initMatrix();generateLeaves();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);drawLeafs(canvas);drawProgress(canvas);canvas.drawBitmap(mBg_Container.src,mPadding_left,mPadding_top,mBitmapPaint);drawFengShan(canvas);postInvalidateDelayed(50);}private void drawLeafs(Canvas canvas) {int mProgressWidth = (int) ((mProgressValue/MAX_PROGRESS_VALUE)*(getWidth()-mPadding_left-mPadding_right-radius));for (Leaf mLeaf:mLeaves){canvas.save();mLeafMatrix.reset();mLeafMatrix.preRotate(mLeaf.degree,mLeafContainer.width/2,mLeafContainer.height/2);switch (mLeaf.rotateDirection){case ROTATE_LEFT:mLeaf.degree = mLeaf.degree-ROTATE_DEGREE;break;case ROTATE_RIGHT:mLeaf.degree = mLeaf.degree+ROTATE_DEGREE;break;}mLeafMatrix.postTranslate(mLeaf.position.x-50,mLeaf.position.y-mLeafContainer.height/2);switch (mLeaf.transition){case SMALL_TRANSITION:mLeaf.position.x = mLeaf.position.x - SMALL_X;break;case MIDDLE_TRANSITION:mLeaf.position.x = mLeaf.position.x - MIDDLE_X;break;case BIG_TRANSITION:mLeaf.position.x = mLeaf.position.x - BIG_X;break;}switch (mLeaf.transition){case SMALL_AMPLITUDE:if(mLeaf.position.y<(mRightCircleCenter.y-max)){y_step = -SMALL_Y;}else if (mLeaf.position.y>(mRightCircleCenter.y+max)){y_step = SMALL_Y;}break;case MIDDLE_AMPLITUDE:if(mLeaf.position.y<(mRightCircleCenter.y-max)){y_step = -MIDDLE_Y;}else if (mLeaf.position.y>(mRightCircleCenter.y+max)){y_step = MIDDLE_Y;}break;case BIG_AMPLITUDE:if(mLeaf.position.y<(mRightCircleCenter.y-max)){y_step = -BIG_Y;}else if (mLeaf.position.y>(mRightCircleCenter.y+max)){y_step = BIG_Y;}break;}mLeaf.position.y = mLeaf.position.y - y_step;if(mLeaf.position.x > mProgressWidth+mPadding_left+10){canvas.drawBitmap(mLeafContainer.src,mLeafMatrix,mBitmapPaint);}else{mLeaf.position.set(mRightCircleCenter.x-radius,mRightCircleCenter.y-mLeafContainer.height/2);mLeaf.transition = new Random().nextInt(3);mLeaf.degree = new Random().nextInt(360);mLeaf.rotateDirection = new Random().nextInt(2);mLeaf.amplitude = new Random().nextInt(3);}canvas.restore();}}public void setProgressValue(int value){this.mProgressValue = value;invalidate();}public int getProgressValue(){return mProgressValue;}public void setProgressChangeListener(onProgressChangedListener listener){this.listener = listener;}private void drawProgress(Canvas canvas) {int shouldDrawWidth = (int) ((mProgressValue/MAX_PROGRESS_VALUE)*(getWidth()-mPadding_left-mPadding_right-radius));Log.d("zyq_progress","shouldDrawWidth = "+shouldDrawWidth);if(shouldDrawWidth<(mLeftCircleCenter.x-mPadding_left)){float degree = (float) Math.toDegrees(Math.acos((radius - shouldDrawWidth)/ (float) radius));canvas.save();canvas.drawArc(mLeftArcRect,180-degree,2*degree,false,mOrangePaint);}else{if (shouldDrawWidth>mRightCircleCenter.x){shouldDrawWidth = mRightCircleCenter.x;}canvas.save();canvas.drawArc(mLeftArcRect,90,180,true,mOrangePaint);canvas.drawRect(radius+mPadding_left,mPadding_top,shouldDrawWidth,2*radius+mPadding_top,mOrangePaint);canvas.restore();}if(listener != null){listener.onProgressValueChanged(mProgressValue);}}private void drawFengShan(Canvas canvas){if(mProgressValue<100){startDegree = startDegree+15;canvas.save();mFengShanRotate.reset();mFengShanRotate.preRotate(startDegree,mFengShanContainer.width/2,mFengShanContainer.height/2);mFengShanRotate.postTranslate(mFengshanPoint.x,mFengshanPoint.y);Log.i("zyq","mFengshanPoint.x ="+mFengshanPoint.x+" mFengshanPoint.y="+mFengshanPoint.y);canvas.drawBitmap(mFengShanContainer.src,mFengShanRotate,mBitmapPaint);canvas.restore();}else{canvas.save();mTextMatrix.reset();if(mTextScale<1){mWhitePaint.setTextSize(mTextSize*mTextScale);mWhitePaint.getTextBounds(mFinish,0,mFinish.length(),mTextRect);}else{mWhitePaint.setTextSize(mTextSize);mWhitePaint.getTextBounds(mFinish,0,mFinish.length(),mTextRect);}canvas.drawText(mFinish,0,mFinish.length(),mRightCircleCenter.x-((mTextRect.width())/2),mRightCircleCenter.y+(mTextRect.height()/2),mWhitePaint);mTextScale = mTextScale+0.1f;canvas.restore();}}private void initKeyPoints(){mLeftCircleCenter = new Point();radius = getHeight()/2-mPadding_bottom/2-mPadding_top/2;mLeftCircleCenter.y = radius+mPadding_top;mLeftCircleCenter.x = radius+mPadding_right;Log.d("zyq_point","View,height="+getHeight()+" mLeftCircleCenter.x = "+mLeftCircleCenter.x+"mLeftCircleCenter.y="+mLeftCircleCenter.y);mRightCircleCenter = new Point();mRightCircleCenter.y = radius+mPadding_top;mRightCircleCenter.x = getWidth()-radius-mPadding_right;Log.d("zyq_point","mRightCircleCenter.x = "+mRightCircleCenter.x+"mRightCircleCenter.y="+mRightCircleCenter.y);mFengshanPoint = new Point();mFengshanPoint.x = mRightCircleCenter.x-mFengShanContainer.width/2;mFengshanPoint.y = mRightCircleCenter.y-mFengShanContainer.height/2;Log.d("zyq_point","mFengshanPoint.x = "+mFengshanPoint.x+"mFengshanPoint.y="+mFengshanPoint.y);}private void initPaints(){mWhitePaint = new Paint();mWhitePaint.setAntiAlias(true);mWhitePaint.setDither(true);mWhitePaint.setTextSize(32);mWhitePaint.setTextAlign(Paint.Align.LEFT);mWhitePaint.setStrokeWidth(6f);mWhitePaint.setColor(WHITE_COLOR);mOrangePaint = new Paint();mOrangePaint.setAntiAlias(true);mOrangePaint.setDither(true);mOrangePaint.setColor(ORANGE_COLOR);mOrangePaint.setStyle(Paint.Style.FILL);mBitmapPaint = new Paint();mBitmapPaint.setAntiAlias(true);mBitmapPaint.setDither(true);mBitmapPaint.setFilterBitmap(true);}private void initBitmaps(){Bitmap mLeaf = ((BitmapDrawable)getResources().getDrawable(R.drawable.leaf_drawable,null)).getBitmap();Bitmap mFengShan = ((BitmapDrawable)getResources().getDrawable(R.drawable.fengshan_drawable,null)).getBitmap();Bitmap mbg_kuang = ((BitmapDrawable)getResources().getDrawable(R.drawable.leaf_kuang_drawable,null)).getBitmap();mLeafContainer = new BitmapContainer();mLeafContainer.src = mLeaf;mLeafContainer.width = mLeaf.getWidth();mLeafContainer.height = mLeaf.getHeight();mFengShanContainer = new BitmapContainer();mFengShanContainer.src = mFengShan;mFengShanContainer.width = mFengShan.getWidth();mFengShanContainer.height = mFengShan.getHeight();Log.i("zyq","fen:width="+mFengShanContainer.width+" height="+mFengShanContainer.height);mBg_Container = new BitmapContainer();mBg_Container.src = mbg_kuang;mBg_Container.width = mbg_kuang.getWidth();mBg_Container.height = mbg_kuang.getHeight();Log.i("zyq_Bg_Container","mBg_Container:width="+mBg_Container.width+" height="+mBg_Container.height);}private void initMatrix(){mFengShanRotate = new Matrix();mLeafMatrix = new Matrix();mTextMatrix = new Matrix();calculatePosition();}private void calculatePosition(){mLeftArcRect = new RectF();mLeftArcRect.left = mPadding_left;mLeftArcRect.top = mPadding_top;mLeftArcRect.right = 2*radius+mPadding_left;mLeftArcRect.bottom = 2*radius+mPadding_top;mTextRect = new Rect();mWhitePaint.getTextBounds(mFinish,0,mFinish.length(), mTextRect);}private class BitmapContainer{Bitmap src;int width;int height;}private class Leaf{Point position;int degree;long startTime;int rotateDirection;int amplitude;int transition;public Leaf(){position = new Point();position.set(mRightCircleCenter.x-radius,mRightCircleCenter.y);degree = new Random().nextInt(360);startTime = System.currentTimeMillis();rotateDirection = new Random().nextInt(2);amplitude = new Random().nextInt(3);transition = new Random().nextInt(3);}public Leaf(int transition){position = new Point();position.set(mRightCircleCenter.x-radius,mRightCircleCenter.y);degree = new Random().nextInt(360);startTime = System.currentTimeMillis();rotateDirection = new Random().nextInt(2);amplitude = new Random().nextInt(3);this.transition = transition;}}private void generateLeaves() {if(mLeaves.isEmpty()){for(int i = 0;i<3;i++){Leaf l = new Leaf(i);mLeaves.add(l);}}}private int getCustomMeasureWidth(int widthMeasureSpec){int mode = MeasureSpec.getMode(widthMeasureSpec);int size = MeasureSpec.getSize(widthMeasureSpec);if (mode == MeasureSpec.EXACTLY){Log.i("zyq_view","view.size = "+size);return size;}else{Log.i("zyq_view","view.width = "+(mBg_Container.width+getPaddingLeft()+getPaddingRight()));return mBg_Container.width+getPaddingLeft()+getPaddingRight();}}private int getCustomMeasureHeight(int heightMeasureSpec){int mode = MeasureSpec.getMode(heightMeasureSpec);int size = MeasureSpec.getSize(heightMeasureSpec);if (mode == MeasureSpec.EXACTLY){return size;}else{return mBg_Container.height+getPaddingTop()+getPaddingBottom();}}private void initAttrs() {mPadding_left = getPaddingLeft();mPadding_top = getPaddingTop();mPadding_right = getPaddingRight();mPadding_bottom = getPaddingBottom();Log.i("zyq_pad","left="+mPadding_left+" top="+mPadding_top+" right="+mPadding_right+" bottom="+mPadding_bottom);}
}

在文件刚开始的时候,定义了各种宽高,比如叶子每次水平移动的距离、垂直移动的距离,旋转的角度、旋转的方向等。基本上来说就是你想控制什么样的动作,就需要你定义什么样的属性,通过属性控制对象的动作。这里的三个图片都是提前准备好的。然后在view中获取这个单个图片对应的bitmap,并获取每个bitmap的宽高,这里的宽高用于以后确定这些bitmap的绘制位置。

在实际的绘制过程中,还需要考虑图层的关系,因为需要有叶子融入的感觉,所以在这里把绘制叶子的步骤放在最前面,这样实现的了叶子融入的感觉。

其次,自定义View中的动画都是通过控制矩阵来实现,比如旋转、移动等。但是字体放大的动画,我试过矩阵,但是不起作用,最后不得已通过改变字体尺寸来实现,希望有知道的朋友可以告诉我一下,不胜感激!!!

其实,其他的动画还好,就是叶子的动画不太好弄,因为需要一种,叶子随机出现的效果,我这里做的不好,希望大神们可以帮忙更改一下!!原作者的叶子动画是与时间关联的,我没有采用,只是限定了叶子出现的位置。具体的情况,还请麻烦各位看代码吧!!!

好了,关于自定义View,暂时就说到这里,以后还将继续介绍有关于自定义View方面的内容,希望大家可以关一下!!!

这是我的微信公众号,如果可以的话,希望您可以帮忙关注一下,这将是对我最大的鼓励了,谢谢!!

公众号

代码地址:
https://github.com/zhuyuqiang2017/CustomView

这篇关于自定义View实现炫酷进度条的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1011264

相关文章

windos server2022里的DFS配置的实现

《windosserver2022里的DFS配置的实现》DFS是WindowsServer操作系统提供的一种功能,用于在多台服务器上集中管理共享文件夹和文件的分布式存储解决方案,本文就来介绍一下wi... 目录什么是DFS?优势:应用场景:DFS配置步骤什么是DFS?DFS指的是分布式文件系统(Distr

NFS实现多服务器文件的共享的方法步骤

《NFS实现多服务器文件的共享的方法步骤》NFS允许网络中的计算机之间共享资源,客户端可以透明地读写远端NFS服务器上的文件,本文就来介绍一下NFS实现多服务器文件的共享的方法步骤,感兴趣的可以了解一... 目录一、简介二、部署1、准备1、服务端和客户端:安装nfs-utils2、服务端:创建共享目录3、服

C#使用yield关键字实现提升迭代性能与效率

《C#使用yield关键字实现提升迭代性能与效率》yield关键字在C#中简化了数据迭代的方式,实现了按需生成数据,自动维护迭代状态,本文主要来聊聊如何使用yield关键字实现提升迭代性能与效率,感兴... 目录前言传统迭代和yield迭代方式对比yield延迟加载按需获取数据yield break显式示迭

Python实现高效地读写大型文件

《Python实现高效地读写大型文件》Python如何读写的是大型文件,有没有什么方法来提高效率呢,这篇文章就来和大家聊聊如何在Python中高效地读写大型文件,需要的可以了解下... 目录一、逐行读取大型文件二、分块读取大型文件三、使用 mmap 模块进行内存映射文件操作(适用于大文件)四、使用 pand

python实现pdf转word和excel的示例代码

《python实现pdf转word和excel的示例代码》本文主要介绍了python实现pdf转word和excel的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一、引言二、python编程1,PDF转Word2,PDF转Excel三、前端页面效果展示总结一

Python xmltodict实现简化XML数据处理

《Pythonxmltodict实现简化XML数据处理》Python社区为提供了xmltodict库,它专为简化XML与Python数据结构的转换而设计,本文主要来为大家介绍一下如何使用xmltod... 目录一、引言二、XMLtodict介绍设计理念适用场景三、功能参数与属性1、parse函数2、unpa

C#实现获得某个枚举的所有名称

《C#实现获得某个枚举的所有名称》这篇文章主要为大家详细介绍了C#如何实现获得某个枚举的所有名称,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考一下... C#中获得某个枚举的所有名称using System;using System.Collections.Generic;usi

Go语言实现将中文转化为拼音功能

《Go语言实现将中文转化为拼音功能》这篇文章主要为大家详细介绍了Go语言中如何实现将中文转化为拼音功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 有这么一个需求:新用户入职 创建一系列账号比较麻烦,打算通过接口传入姓名进行初始化。想把姓名转化成拼音。因为有些账号即需要中文也需要英

C# 读写ini文件操作实现

《C#读写ini文件操作实现》本文主要介绍了C#读写ini文件操作实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录一、INI文件结构二、读取INI文件中的数据在C#应用程序中,常将INI文件作为配置文件,用于存储应用程序的

C#实现获取电脑中的端口号和硬件信息

《C#实现获取电脑中的端口号和硬件信息》这篇文章主要为大家详细介绍了C#实现获取电脑中的端口号和硬件信息的相关方法,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 我们经常在使用一个串口软件的时候,发现软件中的端口号并不是普通的COM1,而是带有硬件信息的。那么如果我们使用C#编写软件时候,如