您现在的位置是:首页 > 文章详情

安卓运动圆环自定义View

日期:2018-05-12点击:344
运动圆环自定义View.gif

记得这个东西原来有个同事问过我,当时正在自学自定义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); } } 
文字基准线说明图.jpg

文字的绘制和画圆画弧不一样,其实仔细想想也明白,如果绘制按照左上角开始的话是不现实的,因为文字不可能是简单的顶部或底部对其,应该是重心对齐,简单说就是基准线,所以代码中基准线的算法是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> 
原文链接:https://yq.aliyun.com/articles/631156
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章