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 ...
随机推荐
- EFCore.MySql当模型遇到int[]怎么办
我使用的是Pomole.EntityFrameworkCore.MySql 需要将旧项目中的excels表转成实体,其中有一列是json格式的int[] 当遇到第一张表的时候,我使用了这样的方法来读取 ...
- crontab命令使用文档.txt
基本格式 : * * * * * command 分 时 日 月 周 命令 第1列表示分钟1-59 每分钟用*或者 */1表示 第2列表示小时1-23(0表示0点) 第3列表示日期1-31 第4列表示 ...
- 如何在Notepad++里正确设置java环境(图文环境)
不多说,直接上干货! 这款软件非常好用!!! Notepad++软件的下载与安装步骤(图文详解) 欢迎大家,加入我的微信公众号:大数据躺过的坑 人工智能躺过的坑 同时,大家可 ...
- typedef在C和C++的区别?
一.struct定义结构体1.先声明结构体类型再定义变量名struct name{ member ..};name A;... 如:struct student{ int a;};student st ...
- 一学期积累下来的SQL语句写法的学习
整合了一下上学期学习的积累,希望可以帮到初学者! 可能以后会有用吧! A 基本语句的运用 操作基于emp表1.按工资从高到低排列SQL> select rownum as 次序,ename,sa ...
- java EE第一周博客
一,课程目标 能够完成javaee开发框架的深入学习,能够熟练的构建出基本开发框架,熟练掌握配置文件以及各种插件的应用.实现一个较为复杂的javaee项目 二.企业级应用与互联网应用的区别 企业级应用 ...
- Tomcat学习总结(7)——Tomcat与Jetty比较
Jetty 基本架构 Jetty目前的是一个比较被看好的 Servlet 引擎,它的架构比较简单,也是一个可扩展性和非常灵活的应用服务器. 它有一个基本数据模型,这个数据模型就是 Handler(处理 ...
- js的轮播效果
图片的轮播效果!主要运用了元素的style样式属性,与 setInterval(); <!DOCTYPE html> <html> <head lang="en ...
- mac 上位Idea 配置Project SDK
问题 刚开始没有Project SDK 方法 添加SDK: /Library/Java/JavaVirtualMachines/jdkXYZ_VERSION.jdk/Contents/Home/jre ...
- Java设计模式学习记录-简单工厂模式、工厂方法模式
前言 之前介绍了设计模式的原则和分类等概述.今天开启设计模式的学习,首先要介绍的就是工厂模式,在介绍工厂模式前会先介绍一下简单工厂模式,这样由浅入深来介绍. 简单工厂模式 做法:创建一个工厂(方法或类 ...