安卓运动圆环自定义View
记得这个东西原来有个同事问过我,当时正在自学自定义View和属性动画这一块,对这个功能也没有写过,所以就google了一下,发了几个类似效果的github项目给朋友,今天礼拜天难得有心情写写代码,所以想想实现一下这个自定义View的效果。
首先,我们从这个gif的效果图中就可以得知这个自定义View我们需要哪些自定义属性,内部圆环的颜色、外部圆环的颜色、圆环的宽度、字体的大小、颜色,话不多说,直接撸码。
<!-- 运动圆环自定义属性 -->
<declare-styleable name="MotionCrcle">
<attr name="outerCrcleColor" format="color"></attr>
<attr name="innerCrcleColor" format="color"></attr>
<attr name="crcleTextColor" format="color"></attr>
<attr name="crcleTextSize" format="integer"></attr>
<attr name="crcleWidth" format="integer"></attr>
</declare-styleable>
/**
* Created by Administrator on 2018/5/13.
* 运动圆环自定义View
*/
public class MotionCrcle extends View {
/**
* 外部圆环颜色
*/
private int mOuterColor = Color.BLUE;
/**
* 里面圆环颜色
*/
private int mInnerColor = Color.RED;
/**
* 跑步数的文字大小
*/
private int mTextSize = 30;
/**
* 跑步文字的颜色
*/
private int mTextColor = Color.BLACK;
/**
* 圆环的宽度
*/
private int mCrcleWidth = 45;
private Paint mOuterPaint, mInnerPaint, mTextPaint;
private float mMaxSteps = 0;
private int mCurrentSteps = 0;
public MotionCrcle(Context context) {
this(context, null);
}
public MotionCrcle(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MotionCrcle(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MotionCrcle);
mOuterColor = array.getColor(R.styleable.MotionCrcle_outerCrcleColor, mOuterColor);
mInnerColor = array.getColor(R.styleable.MotionCrcle_innerCrcleColor, mInnerColor);
mCrcleWidth = array.getInt(R.styleable.MotionCrcle_crcleWidth, mCrcleWidth);
mTextColor = array.getColor(R.styleable.MotionCrcle_crcleTextColor, mTextColor);
mTextSize = array.getInt(R.styleable.MotionCrcle_crcleTextSize, mTextSize);
initPaint();
array.recycle();
}
public synchronized void setmMaxSteps(float mMaxSteps) {
this.mMaxSteps = mMaxSteps;
}
public synchronized void setmCurrentSteps(int mCurrentSteps) {
this.mCurrentSteps = mCurrentSteps;
invalidate();
}
private void initPaint() {
mOuterPaint = new Paint();
mOuterPaint.setAntiAlias(true);
mOuterPaint.setStrokeWidth(mCrcleWidth);
mOuterPaint.setStrokeCap(Paint.Cap.ROUND);
mOuterPaint.setStyle(Paint.Style.STROKE);
mOuterPaint.setColor(mOuterColor);
mInnerPaint = new Paint();
mInnerPaint.setAntiAlias(true);
mInnerPaint.setStrokeWidth(mCrcleWidth);
mInnerPaint.setStrokeCap(Paint.Cap.ROUND);
mInnerPaint.setStyle(Paint.Style.STROKE);
mInnerPaint.setColor(mInnerColor);
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(mTextSize);
mTextPaint.setColor(mTextColor);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if(width != height){
/**
* 因为运动圆环是一个正方形,所以我们要设置一个最小值作为View的长度
*/
int min = Math.min(width, height);
widthMeasureSpec = MeasureSpec.makeMeasureSpec(min, MeasureSpec.EXACTLY);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(min, MeasureSpec.EXACTLY);
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
}
@Override
protected void onDraw(Canvas canvas) {
//因为圆环本身是具有宽度的,所以我们这里左边的顶点要往右mCrcleWidth个距离,右边底部的点要往左,所以要减去mCrcleWidth
RectF recf = new RectF(mCrcleWidth, mCrcleWidth,
getWidth() - mCrcleWidth, getHeight() - mCrcleWidth);
//135是外部圆环的初始角度,270是所画的总角度数
canvas.drawArc(recf, 135, 270, false, mOuterPaint);
if(mCurrentSteps == 0){
return;
}
//算出当前步数是最大步数的比值
float angle = mCurrentSteps / mMaxSteps;
canvas.drawArc(recf, 135, 270 * angle, false, mInnerPaint);
String stepText = mCurrentSteps+"";
Rect bounds = new Rect();
//算出步数文字的baseLine,也就是基准线
mTextPaint.getTextBounds(stepText, 0, stepText.length(), bounds);
int x = getWidth() / 2 - bounds.width() / 2;
Paint.FontMetricsInt metrices = mTextPaint.getFontMetricsInt();
int diffY = (metrices.bottom - metrices.top) / 2 - metrices.bottom;
int baseLine = getHeight() / 2 + diffY;
canvas.drawText(stepText, x, baseLine, mTextPaint);
}
}
文字的绘制和画圆画弧不一样,其实仔细想想也明白,如果绘制按照左上角开始的话是不现实的,因为文字不可能是简单的顶部或底部对其,应该是重心对齐,简单说就是基准线,所以代码中基准线的算法是bottom-top再除以2减去bottom,以基准线开始绘制,top就是负数,bottom是正数。
public class MainActivity extends AppCompatActivity {
private Button mBtn;
private baohuo.rzj.com.myapplication.Views.MotionCrcle mCrcle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBtn = (Button) findViewById(R.id.btn);
mCrcle = (MotionCrcle) findViewById(R.id.motion_crcle);
mCrcle.setmMaxSteps(10000);
final ValueAnimator animator = ObjectAnimator.ofFloat(0,4500);
animator.setDuration(2000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float value = (float) valueAnimator.getAnimatedValue();
mCrcle.setmCurrentSteps((int) value);
}
});
mBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
animator.start();
}
});
}
}
以上是Activity的代码,非常简单,不做解释,这个值得一提的是,我在写的时候内部圆环一直没有绘制,文字在不断变化,通过debug发现,我把步数最大值和当前步数设置为int,一个小的int除以大的int的到的只有0,所以我把最大步数改为float,这样得出的值就有小数位,最后附上xml代码。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="baohuo.rzj.com.myapplication.MainActivity">
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="30dp"
android:text="运动圆环开启"
android:gravity="center"/>
<baohuo.rzj.com.myapplication.Views.MotionCrcle
android:id="@+id/motion_crcle"
android:layout_below="@+id/btn"
android:layout_width="200dp"
android:layout_height="200dp"
app:outerCrcleColor="@color/colorPrimary"
app:innerCrcleColor="@color/colorAccent"
app:crcleTextColor="@color/colorPrimaryDark"
app:crcleTextSize="40"
app:crcleWidth="20"/>
</RelativeLayout>

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
Android/iOS及设计中ARGB颜色值百分比透明度换算
Android/iOS及设计中ARGB颜色值百分比透明度换算 设计上经常要求对一个颜色值进行一定百分比的透明度,比如给定一个颜色0xFF0000FF(蓝色)要求80%透明,该如何处理呢?80%透明的蓝色值是多少呢? 常见的颜色是RGB表示的,就比如上面的蓝色0xFF0000FF,这个颜色值是16进制表示的,其中0x后面接着的两个16进制数字‘FF’就是ARGB中的‘A’,即alpha。A表示该颜色的不透明度。 A = 00(转为十进制是0)是完全透明;A = FF(转换为十进制是255)是完全不透明。 接着到的后面的每两位表示一个颜色,RGB(R,red;G,green;B,blue)。A值控制着对后面颜色的透明度处理。 计算机中表示颜色的透明度范围是(0 ~ 255,即16进制的00-FF)。0(00)表示完全透明。255(FF)表示完全不透明。 其实透明和不透明是一个硬币的两面,描述的都是一回事。比如说把一个颜色透明80%,换一个角度说是把这个颜色不透明20%。 假设设计要求对某一个颜色的透明80%,也就是说不透明度20% ( 1 - 80% = 20% ),那么就是255 x 2...
-
下一篇
实战LitePal(Android_Persistent Technology)
LitePal是GitHub上一款开源的Android数据库框架。LitePal是一款开源的Android数据库框架,采用了对象关系映射(ORM)的模式,将平时开发时最常用的一些数据库功能进行了封装,使得开发者不用编写一行SQL语句就可以完成各种建表、増删改查的操作。并且LitePal很"轻",jar包大小不到100k,而且近乎零配置,这一点和Hibernate这类的框架有很大区别。目前LitePal的源码已经托管到了GitHub上。 主要内容: 0.准备工作(布局) 1.配置LitePal 2.创建和升级数据库 3.使用LitePal添加数据 4.使用LitePal更新数据 5.使用LitePal删除数据 6.使用LitePal查询数据 参考文献:《第一行代码(第2版)》!!! 相关Debug参考文章: 1.Debugexperience about SQLite & LitePal:创建数据库闪退?注意小括号 2.Android Device Monitor--File Explorer 中的/data/data/..无法访问的问题 步骤概要: 0.准备工作 布局这...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- MySQL数据库在高并发下的优化方案
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- Docker容器配置,解决镜像无法拉取问题
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- 2048小游戏-低调大师作品
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作