QQ运动步数&自定义ProgressBar
效果如下
gif图展示效果不好,实际体验无卡顿

1.自定义属性
早Values目录下New-values resource file,命名为attrs.xml(命名随意,但规范命名为attrs.xml)
自定义属性如下,注意format不要与Android自带的命名重复。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="QQStepView">
<attr name="outerColor" format="color" />
<attr name="innerColor" format="color" />
<attr name="borderWidth" format="dimension" />
<attr name="stepTextSize" format="dimension" />
<attr name="stepTextColor" format="color" />
</declare-styleable>
<declare-styleable name="MyProgressBar">
<attr name="leftColor" format="color" />
<attr name="rightColor" format="color" />
<attr name="progressTextColor" format="color" />
<attr name="progressTextSize" format="dimension" />
<attr name="progressBounds" format="dimension" />
</declare-styleable>
</resources>
2.编写自定义View
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import com.cyq.customview2.R;
import com.cyq.customview2.utils.MeasureUtils;
@SuppressWarnings("all")
public class QQStepView extends View {
private int mOuterColor = Color.parseColor("#2196F3");
private int mInnerColor = Color.parseColor("#F44336");
private int mStepTextColor = Color.parseColor("#EC407A");
private int mBorderWidth = 20;//px
private int mStepTextSize = 18;//px
private int mSeptMax = 10000;
private int mSeptCurrent = 0;
private Paint mOutPaint;
private Paint mInnerPaint;
private Paint mTextPaint;
public QQStepView(Context context) {
this(context, null);
}
public QQStepView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public QQStepView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.QQStepView);
mOuterColor = array.getColor(R.styleable.QQStepView_outerColor, mOuterColor);
mInnerColor = array.getColor(R.styleable.QQStepView_innerColor, mInnerColor);
mStepTextColor = array.getColor(R.styleable.QQStepView_stepTextColor, mStepTextColor);
mBorderWidth = (int) array.getDimension(R.styleable.QQStepView_borderWidth, MeasureUtils.dp2px(mBorderWidth, this));
mStepTextSize = array.getDimensionPixelSize(R.styleable.QQStepView_stepTextSize, MeasureUtils.sp2px(mStepTextSize, this));
array.recycle();
mOutPaint = new Paint();
mOutPaint.setAntiAlias(true);
mOutPaint.setStrokeWidth(mBorderWidth);
mOutPaint.setColor(mOuterColor);
mOutPaint.setStyle(Paint.Style.STROKE);
mOutPaint.setStrokeCap(Paint.Cap.ROUND);//圆角
mInnerPaint = new Paint();
mInnerPaint.setAntiAlias(true);
mInnerPaint.setStrokeWidth(mBorderWidth);
mInnerPaint.setColor(mInnerColor);
mInnerPaint.setStyle(Paint.Style.STROKE);//实心
mInnerPaint.setStrokeCap(Paint.Cap.ROUND);//圆角
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
mTextPaint.setStyle(Paint.Style.STROKE);
mTextPaint.setColor(mStepTextColor);
mTextPaint.setTextSize(mStepTextSize);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {
//用户设置的是wrap_content,此时设置一个默认宽高100
width = height = MeasureUtils.dp2px(200, this);
}
setMeasuredDimension(width > height ? height : width, width > height ? height : width);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int center = getWidth() / 2;
int radius = getWidth() / 2 - mBorderWidth;
RectF rectF = new RectF(mBorderWidth, mBorderWidth, center + radius, center + radius);
canvas.drawArc(rectF, 135, 270, false, mOutPaint);
if (mSeptMax == 0) return;
float sweepAngle = (float) mSeptCurrent / mSeptMax;
canvas.drawArc(rectF, 135, 270 * sweepAngle, false, mInnerPaint);
String stepText = mSeptCurrent + "";
Rect textBounds = new Rect();
mTextPaint.getTextBounds(stepText, 0, stepText.length(), textBounds);
int dx = getWidth() / 2 - textBounds.width() / 2;
int baseLine = MeasureUtils.measureBaseLine(mTextPaint, stepText, this);
canvas.drawText(stepText, dx, baseLine, mTextPaint);
}
public void setmSeptMax(int mSeptMax) {
this.mSeptMax = mSeptMax;
}
public synchronized void setmSeptCurrent(int mSeptCurrent) {
this.mSeptCurrent = mSeptCurrent;
//重绘
invalidate();
}
}
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import com.cyq.customview2.R;
import com.cyq.customview2.utils.MeasureUtils;
@SuppressWarnings("all")
public class MyProgressBar extends View {
private int mLiftColor = Color.parseColor("#F44336");
private int mRightColor = Color.parseColor("#E0E0E0");
private int mProgressTextColor = Color.parseColor("#616161");
private int mProgressTextSize = 12;//px 后续再考虑需不需要转换成sp
private int mProgressBounds = 1;//px
private int mCurrentProgress, mMaxProgress = 100;//默认最大刻度为100
private Paint mLeftPaint, mRightPaint, mTextPaint;
public MyProgressBar(Context context) {
this(context, null);
}
public MyProgressBar(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MyProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyProgressBar);
mLiftColor = array.getColor(R.styleable.MyProgressBar_leftColor, mLiftColor);
mRightColor = array.getColor(R.styleable.MyProgressBar_rightColor, mRightColor);
mProgressTextColor = array.getColor(R.styleable.MyProgressBar_progressTextColor, mProgressTextColor);
mProgressTextSize = array.getDimensionPixelSize(R.styleable.MyProgressBar_progressTextSize, mProgressTextSize);
array.recycle();
mLeftPaint = new Paint();
mLeftPaint.setAntiAlias(true);
mLeftPaint.setColor(mLiftColor);
mRightPaint = new Paint();
mRightPaint.setAntiAlias(true);
mRightPaint.setColor(mRightColor);
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
mTextPaint.setStyle(Paint.Style.STROKE);
mTextPaint.setColor(mProgressTextColor);
mTextPaint.setTextSize(mProgressTextSize);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widht = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(widht, height);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mRightPaint.setStrokeWidth(getHeight());
RectF rightRect = new RectF(0, 0, getWidth(), getHeight());
canvas.drawRoundRect(rightRect, getHeight() / 2, getHeight() / 2, mRightPaint);
mLeftPaint.setStrokeWidth(getHeight());
float progress = (float) mCurrentProgress / (mMaxProgress * 10);
int radius = getHeight() / 2;
RectF rectF = new RectF(0, 0, progress * getWidth(), getHeight());
canvas.drawRoundRect(rectF, radius, radius, mLeftPaint);
//画文字随着进度条右移
String text = (float) mCurrentProgress / 10 + "%";
int dx = getHeight() / 2;
Rect textBounds = new Rect();
mTextPaint.getTextBounds(text, 0, text.length(), textBounds);
int baseLine = MeasureUtils.measureBaseLine(mTextPaint, text, this);
canvas.drawText(text, progress * getWidth() + 10, baseLine, mTextPaint);
}
public void setProgress(int mCurrentProgress) {
this.mCurrentProgress = mCurrentProgress;
//重绘
invalidate();
}
public void setMaxProgress(int mMaxProgress) {
this.mMaxProgress = mMaxProgress;
}
public int getProgress() {
return mCurrentProgress;
}
}
3.为自定义View添加动画
首先在xml中使用我们的自定义布局和自定义属性
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".page3.QQSportActivity">
<com.cyq.customview2.page3.QQStepView
android:id="@+id/custom_QQ_step"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="50dp"
app:borderWidth="6dp"
app:innerColor="@color/innerColor"
app:outerColor="@color/outerColor"
app:stepTextSize="30sp"
android:layout_marginBottom="100dp"/>
<com.cyq.customview2.page3.MyProgressBar
android:id="@+id/custom_progressbar"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_margin="50dp"
app:leftColor="@color/innerColor"
app:progressTextColor="@color/stepTextColor"
app:progressTextSize="16sp"
app:rightColor="@color/greyColor" />
</LinearLayout>
通过属性动画动态增加进度
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.animation.DecelerateInterpolator;
import com.cyq.customview2.R;
import butterknife.BindView;
import butterknife.ButterKnife;
public class QQSportActivity extends AppCompatActivity {
@BindView(R.id.custom_QQ_step)
QQStepView customQQStep;
@BindView(R.id.custom_progressbar)
MyProgressBar customProgressbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_qqsport);
ButterKnife.bind(this);
customQQStep.setmSeptMax(10000);
//属性动画
ValueAnimator valueAnimator = ObjectAnimator.ofFloat(0, 8765);
valueAnimator.setDuration(2000);
valueAnimator.setInterpolator(new DecelerateInterpolator());//插值器
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float currentStep = (Float) animation.getAnimatedValue();
customQQStep.setmSeptCurrent((int) currentStep);
}
});
valueAnimator.start();
//属性动画
ValueAnimator valueAnimator2 = ObjectAnimator.ofFloat(0, 780);
valueAnimator2.setDuration(2000);
valueAnimator2.setInterpolator(new DecelerateInterpolator());//插值器
valueAnimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float currentStep = (Float) animation.getAnimatedValue();
customProgressbar.setProgress((int) currentStep);
}
});
valueAnimator2.start();
}
}
获取文字基线和sp,dp转xp的工具类如下;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.TypedValue;
import android.view.View;
public class MeasureUtils {
/**
* drawText获取基线
*
* @param textPaint
* @param text
* @param view
* @return
*/
public static int measureBaseLine(Paint textPaint, String text, View view) {
Rect textBounds = new Rect();
textPaint.getTextBounds(text, 0, text.length(), textBounds);
Paint.FontMetricsInt fontMetricsInt = textPaint.getFontMetricsInt();
int dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;
int baseLine = view.getHeight() / 2 + dy;
return baseLine;
}
public static int sp2px(int sp, View view) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, view.getResources().getDisplayMetrics());
}
public static int dp2px(int dp, View view) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, view.getResources().getDisplayMetrics());
}
}
后续待改进
1.sp,dp,xp的转换
2.进度文字接近100%时不向右边移动,并且文字和进度重叠部分动态变色
QQ运动步数&自定义ProgressBar的更多相关文章
- 手把手教你修改iOS版QQ的运动步数
手把手教你修改iOS版QQ的运动步数 现在很多软件都加上了运动模块,比如QQ和微信,而且还有排行榜,可以和好友比较谁的运动步数多,任何东西只要添加了比较功能,就变得不一样了.今天教大家用代码去修改QQ ...
- Android 自定义View实现QQ运动积分抽奖转盘
因为偶尔关注QQ运动, 看到QQ运动的积分抽奖界面比较有意思,所以就尝试用自定义View实现了下,原本想通过开发者选项查看下界面的一些信息,后来发现积分抽奖界面是在WebView中展示的,应该是在H5 ...
- Android_AsyncTaskDemo之QQ记步数(画圆形图片知识)
今天学习了AsyncTask Android 的异步机制.我简单的实现我的一个小小案例--qq记步数.然后穿插一个画圆形图片的知识点. 由于所学知识有限,目前我计数,还有排名等等我就简单的利用随机数实 ...
- 微信小程序 初步认识一(微信运动步数)
1.注册微信小程序 2.安装小程序开发工具 3.实例(显示微信运动步数) 4.后端处理(c#) 一 注册微信小程序 注册地址:https://mp.weixin.qq.com/cgi-bin/regi ...
- QQ运动,新楛的马桶还在香,营销人不应摒弃。
QQ运动,都说新楛的马桶还香三天,为毛你这般明日黄花,为营销人所弃. QQ运动,一个差不多被遗忘的冷却地带,却圈粉无数,以性感.狂野.妖艳.线条.汗水等秀元素贯穿始终,狼友显露于此,爱美的女性也未曾缺 ...
- Android ProgressBar分析及自定义ProgressBar
ProgressBar是在执行耗时操作时的一种人性化设计.分为两种形式:转圈的,能显示进度的. 而能取决于是什么样式的PregressBar,当然就是PregressBar的样式啦~ Widget.P ...
- 用 Python 修改微信(支付宝)运动步数,轻松 TOP1
用 Python 修改微信(支付宝)运动步数,轻松 TOP1 项目意义 如果你想在支付宝蚂蚁森林收集很多能量种树,为环境绿化出一份力量,又或者是想每天称霸微信运动排行榜装逼,却不想出门走路,那么该py ...
- Android自定义View实现仿QQ实现运动步数效果
效果图: 1.attrs.xml中 <declare-styleable name="QQStepView"> <attr name="outerCol ...
- 2.自定义view-QQ运动步数
1.效果 2.实现 2.1自定义属性 在res/values 文件夹中新建xx.xml,内容如下 <?xml version="1.0" encoding="utf ...
随机推荐
- 网络Socket编程UDP协议例子
服务端代码 public class UDPChatServer { //通讯端口 private Integer port=8000; //数据报文的通讯通道对象 private DatagramC ...
- Shell 常用的命令
ls功能:列出目录内容常用选项:-a 显示所有文件,包括隐藏的-l 长格式列出信息-i 显示文件 inode 号-t 按修改时间排序-r 按修改时间倒序排序-h 打印易读大小单位 2 echo功能:打 ...
- Shell 相互调用
Shell 文件包含 和其他语言一样,Shell 也可以包含外部脚本.这样可以很方便的封装一些公用的代码作为一个独立的文件. Shell 文件包含的语法格式如下: . filename # 注意点号( ...
- Docker快速入门(一)
Docker是Go语言开发实现的容器.2013年发布至今,备受推崇.相关文档.学习资料十分详尽.近期公司docker项目要推进,得重新学习一下.博客以笔记. 1 容器诞生背景及优势 (1)软件开发和运 ...
- 第五章 Web应用程序状态管理
状态管理概述 Cookie Session URL重写 状态管理概述: HTTP协议使用的是无状态的连接 对容器而言,每一个请求都来自于一个新的客户 这里我们有四种方法来解决这个状态: a:表 ...
- Autowired使用说明
使用了那么久Spring,一下子问我Autowired注解使用条件,答不上来吧,看了Spring源码,一点点收货: 废话少说,要是Autowired生效,需要注册BeanPostProcessor,你 ...
- 拥抱HTML5
HTNL5是2014年10月W3C推出的新标准,引入新的特性并对移动端更加友好. canvas <canvas>标签用于标记画布元素, 使用js脚本可以在画布上绘制自定义图形. 绘制矩形; ...
- Jquery特殊属性
val():获取或设置元素的值,主要用于input. 参数:string 字符串 设置元素的值: 不写参数:获取元素的值: 其实这个属性 我们也可以用attr操作,但是没有这个方便 添加类 ...
- SQL SERVER TRIGGER 触发器
1.触发器简介 触发器是一种特殊的存储过程,它的执行不是由程序调用,也不是手动执行,而是由事件来触发.触发器是当对某一个表进行操作.例如:update.insert.delete这些操作的时候,系统会 ...
- 自动生成编号(B开头后跟6位,数据库查询不重复)
private string GetAccountNo() { try { string shortName="B"; "; //查询数据库 7位且包含“B” & ...