赞
踩
自定义一个圆环进度条:
1.首页Android Studio创建一个项目
2.在项目src/xxx/目录下右键选择创建一个自定义view页面:new->UICompoent->customer view
3.输入自定义名称,选择开发语言
4.确定之后,自动生成3个文件一个是:
第一个是逻辑代码:com.lan.lanidemo.customeview.SuperCircleView.class 第二个是布局: src\main\res\layout\sample_super_circle_view.xml 第三个是view需要使用的属性:src\main\res\values\attrs_super_circle_view.xml (通过这种方式创建属性,多次创建可能造成一些变量重复定义。)
attrs_super_circle_view.xml源码:
- <resources>
- <declare-styleable name="SuperCircleView">
- <attr name="exampleString" format="string" />
- <attr name="exampleDimension" format="dimension" />
- <attr name="exampleColor" format="color" />
- <attr name="exampleDrawable" format="color|reference" />
- </declare-styleable>
- </resources>
其中declare-styeable节点的name属性值一般是你写的view的名字,如这里根据命名默认生成:SuperCirecleView。接下来定义可以在xml中定义的组件属性,在后面我会根据需要增加圆环宽度颜色等。其中format属性指定可接受值的类型,多个类型用“|”分隔。
sample_super_circle_view.xml布局源码
- <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <com.lan.lanidemo.customeview.SuperCircleView
- style="@style/Widget.Theme.LaniDemo.SuperCircleView"
- android:layout_width="300dp"
- android:layout_height="300dp"
- android:paddingLeft="20dp"
- android:paddingBottom="40dp"
- app:exampleDimension="24sp"
- app:exampleDrawable="@android:drawable/ic_menu_add"
- app:exampleString="Hello, SuperCircleView" />
-
- </FrameLayout>
SuperCircleView.class
- package com.lan.lanidemo.customeview;
-
- import android.content.Context;
- import android.content.res.TypedArray;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.graphics.drawable.Drawable;
- import android.text.TextPaint;
- import android.util.AttributeSet;
- import android.view.View;
-
- import com.lan.lanidemo.R;
-
- /**
- * TODO: document your custom view class.
- */
- public class SuperCircleView extends View {
- private String mExampleString; // TODO: use a default from R.string...
- private int mExampleColor = Color.RED; // TODO: use a default from R.color...
- private float mExampleDimension = 0; // TODO: use a default from R.dimen...
- private Drawable mExampleDrawable;
-
- private TextPaint mTextPaint;
- private float mTextWidth;
- private float mTextHeight;
-
- public SuperCircleView(Context context) {
- super( context );
- init( null, 0 );
- }
-
- public SuperCircleView(Context context, AttributeSet attrs) {
- super( context, attrs );
- init( attrs, 0 );
- }
-
- public SuperCircleView(Context context, AttributeSet attrs, int defStyle) {
- super( context, attrs, defStyle );
- init( attrs, defStyle );
- }
-
- private void init(AttributeSet attrs, int defStyle) {
- // Load attributes
- final TypedArray a = getContext().obtainStyledAttributes(
- attrs, R.styleable.SuperCircleView, defStyle, 0 );
-
- mExampleString = a.getString(
- R.styleable.SuperCircleView_exampleString );
- mExampleColor = a.getColor(
- R.styleable.SuperCircleView_exampleColor,
- mExampleColor );
- // Use getDimensionPixelSize or getDimensionPixelOffset when dealing with
- // values that should fall on pixel boundaries.
- mExampleDimension = a.getDimension(
- R.styleable.SuperCircleView_exampleDimension,
- mExampleDimension );
-
- if (a.hasValue( R.styleable.SuperCircleView_exampleDrawable )) {
- mExampleDrawable = a.getDrawable(
- R.styleable.SuperCircleView_exampleDrawable );
- mExampleDrawable.setCallback( this );
- }
-
- a.recycle();
-
- // Set up a default TextPaint object
- mTextPaint = new TextPaint();
- mTextPaint.setFlags( Paint.ANTI_ALIAS_FLAG );
- mTextPaint.setTextAlign( Paint.Align.LEFT );
-
- // Update TextPaint and text measurements from attributes
- invalidateTextPaintAndMeasurements();
- }
-
- private void invalidateTextPaintAndMeasurements() {
- mTextPaint.setTextSize( mExampleDimension );
- mTextPaint.setColor( mExampleColor );
- mTextWidth = mTextPaint.measureText( mExampleString );
-
- Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
- mTextHeight = fontMetrics.bottom;
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw( canvas );
-
- // TODO: consider storing these as member variables to reduce
- // allocations per draw cycle.
- int paddingLeft = getPaddingLeft();
- int paddingTop = getPaddingTop();
- int paddingRight = getPaddingRight();
- int paddingBottom = getPaddingBottom();
-
- int contentWidth = getWidth() - paddingLeft - paddingRight;
- int contentHeight = getHeight() - paddingTop - paddingBottom;
-
- // Draw the text.
- canvas.drawText( mExampleString,
- paddingLeft + (contentWidth - mTextWidth) / 2,
- paddingTop + (contentHeight + mTextHeight) / 2,
- mTextPaint );
-
- // Draw the example drawable on top of the text.
- if (mExampleDrawable != null) {
- mExampleDrawable.setBounds( paddingLeft, paddingTop,
- paddingLeft + contentWidth, paddingTop + contentHeight );
- mExampleDrawable.draw( canvas );
- }
- }
-
- /**
- * Gets the example string attribute value.
- *
- * @return The example string attribute value.
- */
- public String getExampleString() {
- return mExampleString;
- }
-
- /**
- * Sets the view"s example string attribute value. In the example view, this string
- * is the text to draw.
- *
- * @param exampleString The example string attribute value to use.
- */
- public void setExampleString(String exampleString) {
- mExampleString = exampleString;
- invalidateTextPaintAndMeasurements();
- }
-
- /**
- * Gets the example color attribute value.
- *
- * @return The example color attribute value.
- */
- public int getExampleColor() {
- return mExampleColor;
- }
-
- /**
- * Sets the view"s example color attribute value. In the example view, this color
- * is the font color.
- *
- * @param exampleColor The example color attribute value to use.
- */
- public void setExampleColor(int exampleColor) {
- mExampleColor = exampleColor;
- invalidateTextPaintAndMeasurements();
- }
-
- /**
- * Gets the example dimension attribute value.
- *
- * @return The example dimension attribute value.
- */
- public float getExampleDimension() {
- return mExampleDimension;
- }
-
- /**
- * Sets the view"s example dimension attribute value. In the example view, this dimension
- * is the font size.
- *
- * @param exampleDimension The example dimension attribute value to use.
- */
- public void setExampleDimension(float exampleDimension) {
- mExampleDimension = exampleDimension;
- invalidateTextPaintAndMeasurements();
- }
-
- /**
- * Gets the example drawable attribute value.
- *
- * @return The example drawable attribute value.
- */
- public Drawable getExampleDrawable() {
- return mExampleDrawable;
- }
-
- /**
- * Sets the view"s example drawable attribute value. In the example view, this drawable is
- * drawn above the text.
- *
- * @param exampleDrawable The example drawable attribute value to use.
- */
- public void setExampleDrawable(Drawable exampleDrawable) {
- mExampleDrawable = exampleDrawable;
- }
- }
5.在这里我是做一圆环进度条:如本文开始图片效果,更新代码如下。
6. 更新自定义属性:
attrs_super_circle_view.xml
- <resources>
- <declare-styleable name="SuperCircleView">
- <attr name="exampleString" format="string" />
- <attr name="exampleDimension" format="dimension" />
- <attr name="exampleColor" format="color" />
- <attr name="exampleDrawable" format="color|reference" />
- <!-- 圆的半径 -->
- <attr name="min_circle_radio" format="integer" />
-
- <!-- 圆环的宽度 -->
- <attr name="ring_width" format="float" />
-
- <!-- 内圆的颜色 -->
- <attr name="circle_color" format="color" />
-
- <!-- 外圆的颜色 -->
- <attr name="max_circle_color" format="color" />
-
- <!-- 圆环的默认颜色 -->
- <attr name="ring_normal_color" format="color" />
-
- <!-- 圆环要显示的彩色的区域(随着数值的改变,显示不同大小的彩色区域)-->
- <attr name="ring_color_select" format="integer" />
-
- <!-- 绘制内容的数值 -->
- <attr name="maxValue" format="integer" />
- <attr name="value" format="integer" />
- <attr name="ring_radius" format="float" />
-
- </declare-styleable>
- </resources>
7.更新自定义view控制代码:
SuperCircleView.class
- package com.lan.lanidemo.customeview;
-
- import android.animation.ValueAnimator;
- import android.content.Context;
- import android.content.res.TypedArray;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.graphics.RectF;
- import android.graphics.SweepGradient;
- import android.graphics.drawable.Drawable;
- import android.text.TextPaint;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.View;
- import android.widget.TextView;
-
- import com.lan.lanidemo.R;
-
- import static android.content.ContentValues.TAG;
-
- /**
- * TODO: document your custom view class.
- */
- public class SuperCircleView extends View {
- private String mExampleString; // TODO: use a default from R.string...
- private int mExampleColor = Color.RED; // TODO: use a default from R.color...
- private float mExampleDimension = 0; // TODO: use a default from R.dimen...
- private Drawable mExampleDrawable;
-
- private TextPaint mTextPaint;
- private float mTextWidth;
- private float mTextHeight;
- private ValueAnimator valueAnimator;
- private int mViewCenterX; //view宽的中心点(可以暂时理解为圆心)
- private int mViewCenterY; //view高的中心点(可以暂时理解为圆心)
-
- private int mMinRadio; //最里面白色圆的半径
- private float mRingWidth; //圆环的宽度
- private int mMinCircleColor; //最里面圆的颜色
- private int mRingNormalColor; //默认圆环的颜色
- private Paint mPaint;
- private int color[] = new int[3]; //渐变颜色
-
- private RectF mRectF; //圆环的矩形区域
- private int mSelectRing = 0; //要显示的彩色区域(岁数值变化)
- float ringRadius;
- private int mMaxValue;
-
- public SuperCircleView(Context context) {
- super( context );
- Log.d( TAG, "SuperCircleView: >>构造" );
-
- init( null, 0 );
- }
-
- public SuperCircleView(Context context, AttributeSet attrs) {
- super( context, attrs );
- Log.d( TAG, "SuperCircleView: >>构造2" );
-
- init( attrs, 0 );
-
- }
-
- public SuperCircleView(Context context, AttributeSet attrs, int defStyle) {
- super( context, attrs, defStyle );
- init( attrs, defStyle );
- }
-
- private void init(AttributeSet attrs, int defStyle) {
- // Load attributes
-
- TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.SuperCircleView);
- //最里面白色圆的半径
- mMinRadio = a.getInteger(R.styleable.SuperCircleView_min_circle_radio, 300);
- //圆环宽度
- mRingWidth = a.getFloat(R.styleable.SuperCircleView_ring_width, 40);
-
- //最里面的圆的颜色(绿色)
- mMinCircleColor = a.getColor(R.styleable.SuperCircleView_circle_color,
- getContext().getResources().getColor(R.color.green));
- //圆环的默认颜色(圆环占据的是里面的圆的空间)
- mRingNormalColor = a.getColor(R.styleable.SuperCircleView_ring_normal_color,
- getContext().getResources().getColor(R.color.gray));
- //圆环要显示的彩色的区域
- mSelectRing = a.getInt(R.styleable.SuperCircleView_ring_color_select, 0);
-
- mMaxValue = a.getInt(R.styleable.SuperCircleView_maxValue, 100);
- ringRadius = a.getDimension( R.styleable.SuperCircleView_ring_radius, dp2px(100) );
-
- a.recycle();
-
- //抗锯齿画笔
- mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- //防止边缘锯齿
- mPaint.setAntiAlias(true);
- //需要重写onDraw就得调用此
- this.setWillNotDraw(false);
-
- //圆环渐变的颜色
- color[0] = Color.parseColor("#FFD300");
- color[1] = Color.parseColor("#FF0084");
- color[2] = Color.parseColor("#16FF00");
- }
-
- public int dp2px(float dpValue) {
- final float scale = Resources.getSystem().getDisplayMetrics().density;
- return (int) (dpValue * scale + 0.5f);
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- //view的宽和高,相对于父布局(用于确定圆心)
- int viewWidth = getMeasuredWidth();
- int viewHeight = getMeasuredHeight();
- mViewCenterX = viewWidth / 2;
- mViewCenterY = viewHeight / 2;
- mRectF = new RectF(
- mViewCenterX - ringRadius,
- mViewCenterY - ringRadius,
- mViewCenterX + ringRadius,
- mViewCenterY + ringRadius
- );
- }
-
- private void invalidateTextPaintAndMeasurements() {
- mTextPaint.setTextSize( mExampleDimension );
- mTextPaint.setColor( mExampleColor );
- mTextWidth = mTextPaint.measureText( mExampleString );
-
- Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
- mTextHeight = fontMetrics.bottom;
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw( canvas );
- mPaint.setColor(mMinCircleColor);
- canvas.drawCircle(mViewCenterX, mViewCenterY, mMinRadio, mPaint);
- //画默认圆环
- drawNormalRing(canvas);
- //画彩色圆环
- drawColorRing(canvas);
- }
- /**
- * 画默认圆环
- *
- * @param canvas
- */
- private void drawNormalRing(Canvas canvas) {
- Paint ringNormalPaint = new Paint(mPaint);
- ringNormalPaint.setStyle(Paint.Style.STROKE);
- ringNormalPaint.setStrokeWidth(mRingWidth);
- ringNormalPaint.setColor(mRingNormalColor);//圆环默认颜色为灰色
- canvas.drawArc(mRectF, 360, 360, false, ringNormalPaint);
- }
-
- /**
- * 画彩色圆环
- *
- * @param canvas
- */
- private void drawColorRing(Canvas canvas) {
- Paint ringColorPaint = new Paint(mPaint);
- ringColorPaint.setStyle(Paint.Style.STROKE);
- ringColorPaint.setStrokeWidth(mRingWidth);
- ringColorPaint.setShader(new SweepGradient(mViewCenterX, mViewCenterX, color, null));
- //逆时针旋转90度
- canvas.rotate(-90, mViewCenterX, mViewCenterY);
- canvas.drawArc(mRectF, 360, mSelectRing, false, ringColorPaint);
- ringColorPaint.setShader(null);
- }
-
- //***************************************用于更新圆环表示的数值*****************************************************
- /**
- * 设置当前值
- *
- * @param value
- */
- public void setValue(int value,TextView textView) {
- if (value > mMaxValue) {
- value = mMaxValue;
- }
- int start = 0;
- int end = value;
- startAnimator(start, end, 2000,textView);
- }
-
- private void startAnimator(int start, int end, long animTime, final TextView textView) {
- valueAnimator = ValueAnimator.ofInt(start, end);
- valueAnimator.setDuration(animTime);
- valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- Log.i(TAG, "onAnimationUpdate: animation.getAnimatedValue()::"+animation.getAnimatedValue());
- int i = Integer.valueOf(String.valueOf(animation.getAnimatedValue()));
- textView.setText(i + "");
- //每个单位长度占多少度
- mSelectRing=(int) (360 * (i / 100f));
- Log.i(TAG, "onAnimationUpdate: mSelectRing::"+mSelectRing);
- invalidate();
- }
- });
- valueAnimator.start();
- }
-
-
- /**
- * Gets the example string attribute value.
- *
- * @return The example string attribute value.
- */
- public String getExampleString() {
- return mExampleString;
- }
-
- /**
- * Sets the view"s example string attribute value. In the example view, this string
- * is the text to draw.
- *
- * @param exampleString The example string attribute value to use.
- */
- public void setExampleString(String exampleString) {
- mExampleString = exampleString;
- invalidateTextPaintAndMeasurements();
- }
-
- /**
- * Gets the example color attribute value.
- *
- * @return The example color attribute value.
- */
- public int getExampleColor() {
- return mExampleColor;
- }
-
- /**
- * Sets the view"s example color attribute value. In the example view, this color
- * is the font color.
- *
- * @param exampleColor The example color attribute value to use.
- */
- public void setExampleColor(int exampleColor) {
- mExampleColor = exampleColor;
- invalidateTextPaintAndMeasurements();
- }
-
- /**
- * Gets the example dimension attribute value.
- *
- * @return The example dimension attribute value.
- */
- public float getExampleDimension() {
- return mExampleDimension;
- }
-
- /**
- * Sets the view"s example dimension attribute value. In the example view, this dimension
- * is the font size.
- *
- * @param exampleDimension The example dimension attribute value to use.
- */
- public void setExampleDimension(float exampleDimension) {
- mExampleDimension = exampleDimension;
- invalidateTextPaintAndMeasurements();
- }
-
- /**
- * Gets the example drawable attribute value.
- *
- * @return The example drawable attribute value.
- */
- public Drawable getExampleDrawable() {
- return mExampleDrawable;
- }
-
- /**
- * Sets the view"s example drawable attribute value. In the example view, this drawable is
- * drawn above the text.
- *
- * @param exampleDrawable The example drawable attribute value to use.
- */
- public void setExampleDrawable(Drawable exampleDrawable) {
- mExampleDrawable = exampleDrawable;
- }
- }
8.更新自定义布局:sample_super_circle_view.xml
- <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <com.lan.lanidemo.customeview.SuperCircleView
- style="@style/Widget.Theme.LaniDemo.MyView"
- android:layout_width="300dp"
- android:layout_height="300dp"
- android:paddingLeft="20dp"
- android:paddingBottom="40dp"
- app:exampleDimension="24sp"
- app:exampleDrawable="@android:drawable/ic_menu_add"
- app:exampleString="Hello, SuperCircleView" />
-
- </FrameLayout>
9.最后在新建一个页面:ThreeActivity, 并在AndroidManifest.xml,设置为启动页面。创建完成后,在xml添加自定义view:activity_three.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"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
-
-
- android:orientation="vertical">
-
- <TextView
- android:id="@+id/tv_three"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="This is Three page"
- android:textSize="30sp" />
-
- <FrameLayout
- android:layout_width="300dp"
- android:layout_height="300dp"
- android:layout_gravity="center">
-
- <com.lan.lanidemo.customeview.SuperCircleView
- android:id="@+id/superview"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- app:maxValue="100"
- app:ring_width="60"
- app:value="20" />
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:layout_marginBottom="60dp"
- android:text="信息完成度"
- android:textColor="#CFD5DE"
- android:textSize="18sp" />
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:layout_marginTop="10dp"
- android:orientation="horizontal">
-
- <TextView
- android:id="@+id/tv"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="0"
- android:textColor="#506946"
- android:textSize="80sp" />
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="%"
- android:textSize="28sp" />
- </LinearLayout>
-
- </FrameLayout>
-
- </LinearLayout>
10. ThreeActivity.class 在启动页设置百分比。 同时增加一个点击事件,点击view可以随机变化百分比值。
- package com.lan.lanidemo;
-
- import android.os.Bundle;
- import android.util.Log;
- import android.view.View;
- import android.widget.TextView;
-
- import com.lan.lanidemo.customeview.SuperCircleView;
-
- import java.util.Random;
-
- import androidx.appcompat.app.AppCompatActivity;
-
- public class ThreeActivity extends AppCompatActivity {
-
- private static final String TAG = "ThreeActivity";
- private TextView mTextView;
- SuperCircleView mSuperCircleView;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate( savedInstanceState );
- setContentView( R.layout.activity_three );
- initView();
-
-
- }
-
- private void initView() {
- mTextView = (TextView) findViewById( R.id.tv );
- mSuperCircleView = findViewById(R.id.superview);
- mSuperCircleView.setValue(70, mTextView);
- mSuperCircleView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- //随机设定圆环大小
- int i = new Random().nextInt(100) + 1;
- Log.i(TAG, "onClick: i::" + i);
- mSuperCircleView.setValue(i, mTextView);
- }
- });
- }
- }
11.最后运行,点击之后进度更新。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。