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 ...
随机推荐
- 深入浅出zeptojs中tap事件
1.tap事件实现 zepto 源码里面看关于tap的实现方法: $(document).ready(function(){ var now, delta, deltaX = 0, deltaY = ...
- 04 - JavaSE之异常处理
异常的概念(运行期出现的错误) java 异常是 java 提供的用于处理程序中错误的一种机制. 所谓的错误是指在程序运行的过程中发生的一些异常事件.(如:除0溢出,数组下标越界,所要读取的文件不存在 ...
- mysql的sql执行计划详解(非常有用)
以前没有怎么了解mysql执行计划,以及sql 优化方面,今天算学习了. https://blog.csdn.net/heng_yan/article/details/78324176 https:/ ...
- scala-传名函数和传值函数
Scala的解释器在解析函数参数(function arguments)时有两种方式:先计算参数表达式的值(reduce the arguments),再应用到函数内部:或者是将未计算的参数表达式直接 ...
- MVC源码分析 - Error过滤器
接 上一篇 内容, 这里先看一下错误处理过滤器. 在看此部分之前, 先看看MVC已经提供的功能吧. 一. MVC 自带功能 1. 配置方法 <system.web> <!--mode ...
- Android so 文件进阶<三> so文件的简单加密
0x00 前言 之前的两篇文章从链接视图和执行视图分析了elf文件的大致结构,这篇文章主要内容是对于so文件进行简单的加密工作,针对Ida等静态分析工具的分析,一旦开始动态调试就应该很容易就可以du ...
- win 7 64 mysql 5.6.4 安装
windows 7 64位下配置mysql64位免安装版1.官方网站下载mysql-5.6.10-winx64.zip2.解压到E:\MYSQL(路径自己指定)3.在E:\MYSQL下新建my.ini ...
- Spring 环境与profile(二)——Properties with Spring
1. 简述 Spring profile用例,分3个场景(Test, Dev, Prod)相对Spring 环境与profile(一)——超简用例多了根据具体的profile获取对应的Properti ...
- multiset多重集合容器(常用的使用方法总结)
关于C++STL中multiset集合容器的学习,看别人的代码一百遍,不如自己动手写一遍. multiset多重集合容器和set集合容器的使用方法大多相同,不同的是multiset多重集合容器允许重复 ...
- 分布式理论(二)——Base 理论
前言 在前文 分布式理论(一) -- CAP 定理 中,我们说,CAP 不可能同时满足,而分区容错是对于分布式系统而言,是必须的.最后,我们说,如果系统能够同时实现 CAP 是再好不过的了,所以出现了 ...