效果如下

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的更多相关文章

  1. 手把手教你修改iOS版QQ的运动步数

    手把手教你修改iOS版QQ的运动步数 现在很多软件都加上了运动模块,比如QQ和微信,而且还有排行榜,可以和好友比较谁的运动步数多,任何东西只要添加了比较功能,就变得不一样了.今天教大家用代码去修改QQ ...

  2. Android 自定义View实现QQ运动积分抽奖转盘

    因为偶尔关注QQ运动, 看到QQ运动的积分抽奖界面比较有意思,所以就尝试用自定义View实现了下,原本想通过开发者选项查看下界面的一些信息,后来发现积分抽奖界面是在WebView中展示的,应该是在H5 ...

  3. Android_AsyncTaskDemo之QQ记步数(画圆形图片知识)

    今天学习了AsyncTask Android 的异步机制.我简单的实现我的一个小小案例--qq记步数.然后穿插一个画圆形图片的知识点. 由于所学知识有限,目前我计数,还有排名等等我就简单的利用随机数实 ...

  4. 微信小程序 初步认识一(微信运动步数)

    1.注册微信小程序 2.安装小程序开发工具 3.实例(显示微信运动步数) 4.后端处理(c#) 一 注册微信小程序 注册地址:https://mp.weixin.qq.com/cgi-bin/regi ...

  5. QQ运动,新楛的马桶还在香,营销人不应摒弃。

    QQ运动,都说新楛的马桶还香三天,为毛你这般明日黄花,为营销人所弃. QQ运动,一个差不多被遗忘的冷却地带,却圈粉无数,以性感.狂野.妖艳.线条.汗水等秀元素贯穿始终,狼友显露于此,爱美的女性也未曾缺 ...

  6. Android ProgressBar分析及自定义ProgressBar

    ProgressBar是在执行耗时操作时的一种人性化设计.分为两种形式:转圈的,能显示进度的. 而能取决于是什么样式的PregressBar,当然就是PregressBar的样式啦~ Widget.P ...

  7. 用 Python 修改微信(支付宝)运动步数,轻松 TOP1

    用 Python 修改微信(支付宝)运动步数,轻松 TOP1 项目意义 如果你想在支付宝蚂蚁森林收集很多能量种树,为环境绿化出一份力量,又或者是想每天称霸微信运动排行榜装逼,却不想出门走路,那么该py ...

  8. Android自定义View实现仿QQ实现运动步数效果

    效果图: 1.attrs.xml中 <declare-styleable name="QQStepView"> <attr name="outerCol ...

  9. 2.自定义view-QQ运动步数

    1.效果 2.实现 2.1自定义属性 在res/values 文件夹中新建xx.xml,内容如下 <?xml version="1.0" encoding="utf ...

随机推荐

  1. 一眼看穿flatMap和map的区别

    背景 map和flatmap,从字面意思或者官网介绍,可能会给一些人在理解上造成困扰[包括本人],所以今天专门花时间来分析,现整理如下: 首先做一下名词解释---------------------- ...

  2. python _、__、__xx__之间的差别

    默认情况下,Python中的成员函数和成员变量都是公开的(public),在python中没有类public,private等关键词来修饰成员函数和成员变量.其实,Python并没有真正的私有化支持, ...

  3. PHP-引入文件(include)后,页面错位,不居中解决办法

    1.把include文件放在head里,不要放在html或doctype上面,这样可以解决居中的问题,空白行的话可以用<div style="display:none"> ...

  4. haproxy+keepalived原理特点

    所有的系统,都是先经历一个单台机器搞所有业务的时代,一个程序+一个mysql数据库,就可以满足开发及第一个版本上线的要求.随着,数据的增加以及业务的增长,这些应用就面临一个访问量的扩大以及扩展的问题. ...

  5. java EE第一周博客

    一,课程目标 能够完成javaee开发框架的深入学习,能够熟练的构建出基本开发框架,熟练掌握配置文件以及各种插件的应用.实现一个较为复杂的javaee项目 二.企业级应用与互联网应用的区别 企业级应用 ...

  6. 面试:C++String类实现

    #include <iostream> #include <cstring> using namespace std; class CString { private: cha ...

  7. setup&hold

    setup time:建立时间,也就是在时钟上升沿到来前,数据需要稳定的时间.hold time:保持时间,指的是在时钟上升沿到来后,数据还需要保持的时间.实际上设置setup time和hold t ...

  8. 厌倦了“正在输入…”的客服对话,是时候pick视频客服了

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由腾讯云视频发表于云+社区专栏 关注公众号"腾讯云视频",一键获取 技术干货 | 优惠活动 | 视频方案 什么?! ...

  9. 程序员必知的8大排序(四)-------归并排序,基数排序(java实现)

    程序员必知的8大排序(一)-------直接插入排序,希尔排序(java实现) 程序员必知的8大排序(二)-------简单选择排序,堆排序(java实现) 程序员必知的8大排序(三)-------冒 ...

  10. Java 使用pipeline对redis进行批量读写

    code import redis.clients.jedis.Jedis; import redis.clients.jedis.Pipeline; import java.util.List; p ...