自定义ProgressBar打造酷炫进度条
Android系统默认的ProgressBar往往都不能满足实际开发需要,一般都会开发者自定义ProgressBar。
在Android开发中,自定义ProgressBar一般有三种思路来完成。
一、在系统进度条基础上优化
首先来看一下style="@android:style/Widget.ProgressBar.Horizontal"的源码。鼠标移动到style属性值上,按住Ctrl键,鼠标左键点击即可打开对应资源文件。
当然也可以直接找到源码文件直接打开进行查看,本地相对路径为sdkplatformsandroid-25dataresvaluesstyles.xml。打开后可以看到源码如下:
<style name="Widget.ProgressBar.Horizontal">
<item name="indeterminateOnly">false</item>
<item name="progressDrawable">@drawable/progress_horizontal</item>
<item name="indeterminateDrawable">@drawable/progress_indeterminate_horizontal</item>
<item name="minHeight">20dip</item>
<item name="maxHeight">20dip</item>
<item name="mirrorForRtl">true</item>
</style>
从上述代码可以看到,水平进度条的核心就是android:progressDrawable,接着继续去寻找progress_horizontal的源码(本地相对路径为sdkplatformsandroid-25dataresdrawableprogress_horizontal.xml),如下:
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<corners android:radius="5dip" />
<gradient
android:startColor="#ff9d9e9d"
android:centerColor="#ff5a5d5a"
android:centerY="0.75"
android:endColor="#ff747674"
android:angle="270"
/>
</shape>
</item>
<item android:id="@android:id/secondaryProgress">
<clip>
<shape>
<corners android:radius="5dip" />
<gradient
android:startColor="#80ffd300"
android:centerColor="#80ffb600"
android:centerY="0.75"
android:endColor="#a0ffcb00"
android:angle="270"
/>
</shape>
</clip>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="5dip" />
<gradient
android:startColor="#ffffd300"
android:centerColor="#ffffb600"
android:centerY="0.75"
android:endColor="#ffffcb00"
android:angle="270"
/>
</shape>
</clip>
</item>
</layer-list>
从上述代码可以发现,progress_horizontal一共包括3个item,分别为background、secondProgress、progress,看名字就能知道其大概作用,其中我们比较关心的应该是后两个。
其实把这个文件copy一份到自己的项目下,就可以随心所欲的修改shape属性的圆角、渐变等,实现我们想要的效果了。
由于此处我们还没有学习Drawable资源,所以这里先给大家介绍一下概念,关于具体如何操作可以等学了Drawable资源后,再回过头来自定义ProgressBar。欢迎关注微信公众分享达人秀ShareExpert获取第一手教程,也可添加小编微信jinwenyu2010,然后拽入Android零基础入门技术讨论微信群一同学习。
二、使用动画来代替进度条
使用动画来替代进度条,其实就是使用一套连续图片,形成一个帧动画,当需要进度图的时候,让动画可见,不需要的时候让动画不可见即可。
继续使用WidgetSample工程的advancedviewsample模块,首先在drawable目录下准备一组连续的图片,然后在res/drawable/目录下定义一个myprogressbar.xml的资源文件,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@drawable/loading_01" android:duration="200" />
<item android:drawable="@drawable/loading_02" android:duration="200" />
<item android:drawable="@drawable/loading_03" android:duration="200" />
<item android:drawable="@drawable/loading_04" android:duration="200" />
<item android:drawable="@drawable/loading_05" android:duration="200" />
<item android:drawable="@drawable/loading_06" android:duration="200" />
<item android:drawable="@drawable/loading_07" android:duration="200" />
<item android:drawable="@drawable/loading_08" android:duration="200" />
<item android:drawable="@drawable/loading_09" android:duration="200" />
<item android:drawable="@drawable/loading_10" android:duration="200" />
<item android:drawable="@drawable/loading_11" android:duration="200" />
<item android:drawable="@drawable/loading_12" android:duration="200" />
</animation-list>
关于上述代码的具体意义会在Android动画进行讲解,此处大家知道如何操作即可。
接着新建一个布局文件myprogressbar_layout.xml,里面仅仅有一个ImageView即可,用于显示进度条,把src设置为上述drawable资源即可,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/mypg_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:src="@drawable/myprogressbar"/>
</RelativeLayout>
新建MyProgressbarActivity.java文件,加载上面新建的布局文件,具体代码如下:
package com.jinyu.cqkxzsxy.android.advancedviewsample;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;
public class MyProgressbarActivity extends AppCompatActivity {
private ImageView mProgressbarImg = null;
private AnimationDrawable mProgressAnimation = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.myprogressbar_layout);
mProgressbarImg = (ImageView) findViewById(R.id.mypg_img);
mProgressAnimation = (AnimationDrawable) mProgressbarImg.getDrawable();
// 启动动画
mProgressbarImg.postDelayed(new Runnable() {
@Override
public void run() {
// 启动动画
mProgressAnimation.start();
}
}, 100);
}
}
这里只是简单启动上述定义的动画,在开发中你可以根据需要显示和隐藏即可。
修改启动的Activity,运行可以看到如下图所示效果。
三、通过自定义View来实现进度条
使用动画来完成进度条实际上比较巧妙,但还是不能满足实际开发需要,那么最强大的自定义ProgressBar就是重写View来实现了,可以定义出任何需要的进度条。
如定义一个CircleProgressBar类,继承View,并重写其方法,示例代码如下:
package com.jinyu.cqkxzsxy.android.advancedviewsample.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
/**
* @创建者 鑫鱻
* @描述 Android零基础入门到精通系列教程,欢迎关注微信公众号ShareExpert
*/
public class CircleProgressBar extends View {
private Paint mBackPaint;
private Paint mFrontPaint;
private Paint mTextPaint;
private float mStrokeWidth = 50;
private float mHalfStrokeWidth = mStrokeWidth / 2;
private float mRadius = 200;
private RectF mRect;
private int mProgress = 0;
private int mTargetProgress = 90;
private int mMax = 100;
private int mWidth;
private int mHeight;
public CircleProgressBar(Context context) {
super(context);
init();
}
public CircleProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CircleProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
// 完成相关参数初始化
private void init() {
mBackPaint = new Paint();
mBackPaint.setColor(Color.WHITE);
mBackPaint.setAntiAlias(true);
mBackPaint.setStyle(Paint.Style.STROKE);
mBackPaint.setStrokeWidth(mStrokeWidth);
mFrontPaint = new Paint();
mFrontPaint.setColor(Color.GREEN);
mFrontPaint.setAntiAlias(true);
mFrontPaint.setStyle(Paint.Style.STROKE);
mFrontPaint.setStrokeWidth(mStrokeWidth);
mTextPaint = new Paint();
mTextPaint.setColor(Color.GREEN);
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(80);
mTextPaint.setTextAlign(Paint.Align.CENTER);
}
// 重写测量大小的onMeasure方法和绘制View的核心方法onDraw()
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = getRealSize(widthMeasureSpec);
mHeight = getRealSize(heightMeasureSpec);
setMeasuredDimension(mWidth, mHeight);
}
@Override
protected void onDraw(Canvas canvas) {
initRect();
float angle = mProgress / (float) mMax * 360;
canvas.drawCircle(mWidth / 2, mHeight / 2, mRadius, mBackPaint);
canvas.drawArc(mRect, -90, angle, false, mFrontPaint);
canvas.drawText(mProgress + "%", mWidth / 2 + mHalfStrokeWidth,
mHeight / 2 + mHalfStrokeWidth, mTextPaint);
if (mProgress < mTargetProgress) {
mProgress += 1;
invalidate();
}
}
public int getRealSize(int measureSpec) {
int result = 1;
int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec);
if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.UNSPECIFIED) {
//自己计算
result = (int) (mRadius * 2 + mStrokeWidth);
} else {
result = size;
}
return result;
}
private void initRect() {
if (mRect == null) {
mRect = new RectF();
int viewSize = (int) (mRadius * 2);
int left = (mWidth - viewSize) / 2;
int top = (mHeight - viewSize) / 2;
int right = left + viewSize;
int bottom = top + viewSize;
mRect.set(left, top, right, bottom);
}
}
}
关于上述代码的具体含义,此处不理解没关系,可以等学了Android绘图后再回过头来进行学习。
然后新建一个布局文件circleprogressbar_layout.xml,使用上述的自定义进度条类,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.jinyu.cqkxzsxy.android.advancedviewsample.view.CircleProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
修改MainActivity.java里面加载的布局文件,运行后其效果如下图所示。
如果已经学会本期里面提及的内容,那就可以放手去打造属于你自己的酷炫进度条了。如果不会也没关系,这里只做了解,等后期学完后再来回顾即可。
- 【Java学习笔记之十二】Java8增强的工具类:Arrays的用法整理总结
- 利用insert,update和delete注入获取数据
- 【机器学习笔记之二】决策树的python实现
- 【Java学习笔记之十三】初探Java面向对象的过程及代码实现
- 洛谷 P1308 统计单词数【字符串+模拟】
- 【Java学习笔记之十四】Java中this用法小节
- Codeforces 839E Mother of Dragons【__builtin_popcount()的使用】
- 【Java学习笔记之十五】Java中的static关键字解析
- Codeforces 839D Winter is here【数学:容斥原理】
- Codeforces 839C Journey【DFS】
- Facebook的漏洞可以让攻击者在分分钟内重置用户账户密码
- 【Java学习笔记之十七】Java中普通代码块,构造代码块,静态代码块区别及代码示例分析
- 【机器学习笔记之六】Bagging 简述
- 洛谷 P1553 数字反转(升级版)【字符串+STL stack】
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- python让函数不返回结果的方法
- PHP微商城开源代码实例
- PHP小程序支付功能完整版【基于thinkPHP】
- CodeIgniter框架实现的整合Smarty引擎DEMO示例
- PHP微信支付功能示例
- PHP中ltrim()函数的用法与实例讲解
- Laravel 中创建 Zip 压缩文件并提供下载的实现方法
- pytorch随机采样操作SubsetRandomSampler()
- Pytorch上下采样函数–interpolate用法
- scrapy框架携带cookie访问淘宝购物车功能的实现代码
- 浅析Python __name__ 是什么
- PHP判断访客是否手机端(移动端浏览器)访问的方法总结【4种方法】
- PHP后期静态绑定实例浅析
- php+mysql开发中的经验与常识小结
- PHP时间戳和日期相互转换操作实例小结