【Android 应用开发】 自定义 View 组件 -- 圆形进度条

转载著名出处 : http://blog.csdn.net/shulianghan/article/details/40351487

代码下载 :

-- CSDN 下载地址http://download.csdn.net/detail/han1202012/8069497 ;

-- GitHub 地址https://github.com/han1202012/CircleProcess.git ;

-- 工程示例 :

一. 相关知识点解析

1. 自定义 View 组件构造方法

构造方法 : 自定义的 View 组件, 一般需要实现 三个构造方法, 分别有 一个, 两个, 三个参数;

-- 一个参数public CircleProcess(Context context);

-- 两个参数public CircleProcess(Context context, AttributeSet attrs);

-- 三个参数public CircleProcess(Context context, AttributeSet attrs, int defStyle);

构造方法注意点 :

-- 调用上级方法 : 每个构造方法中必须调用 super() 方法, 方法中的参数与该构造方法参数一样;

-- 常用构造方法 : 一般在2参数构造方法中实现逻辑;

构造方法示例 :

	/** 画笔 */
	private Paint mPaint;
	/** 上下文对象 */
	private Context mContext;
	/** 进度条的值 */
	private int mProcessValue;

	public CircleProcess(Context context, AttributeSet attrs) {
		super(context, attrs);
		// 初始化成员变量 Context
		mContext = context;
		// 创建画笔, 并设置画笔属性
		mPaint = new Paint();
		// 消除绘制时产生的锯齿
		mPaint.setAntiAlias(true);
		// 绘制空心圆形需要设置该样式
		mPaint.setStyle(Style.STROKE);
	}

	/**
	 * 自定义布局实现的 只有 Context 参数的构造方法
	 * @param context
	 */
	public CircleProcess(Context context) {
		super(context);
	}

	/**
	 * 自定义布局实现的 三个参数的构造方法
	 * @param context
	 * @param attrs
	 * @param defStyle
	 */
	public CircleProcess(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

2. dip 和 px 单位转换

(1) dip 转 px

公式 :

-- 基本公式px / dip = dpi / 160;

-- 计算公式 : px = dpi / 160 * dip;

一些概念解析 :

-- dpi 概念 : dpi (dot per inch), 每英寸像素数 归一化的值 120 160 240 320 480;

-- 区分 dpi 和 density : dpi 是归一化的值, density 是实际的值, 可能不是整数;

代码示例 :

	/**
	 * 将手机的 设备独立像素 转为 像素值
	 *
	 * 		公式 : px / dip = dpi / 160
	 * 			   px = dip * dpi / 160;
	 * @param context
	 * 				上下文对象
	 * @param dpValue
	 * 				设备独立像素值
	 * @return
	 * 				转化后的 像素值
	 */
	public static int dip2px(Context context, float dpValue) {
		final float scale = context.getResources().getDisplayMetrics().density;
		return (int) (dpValue * scale + 0.5f);
	}

(2) px 转 dip

公式 :

-- 基本公式 : px / dip = dpi / 160;

-- 计算公式 : dip = 160 / dpi * px;

代码 :

	/**
	 * 将手机的 像素值 转为 设备独立像素
	 * 		公式 : px/dip = dpi/160
	 * 			   dip = px * 160 / dpi
	 * 			   dpi (dot per inch) : 每英寸像素数 归一化的值 120 160 240 320 480;
	 * 			   density : 每英寸的像素数, 精准的像素数, 可以用来计算准确的值
	 * 			   从 DisplayMetics 中获取的
	 * @param context
	 * 				上下文对象
	 * @param pxValue
	 * 				像素值
	 * @return
	 * 				转化后的 设备独立像素值
	 */
	public static int px2dip(Context context, float pxValue) {
		final float scale = context.getResources().getDisplayMetrics().density;
		return (int) (pxValue / scale + 0.5f);
	}

3. 关于 组件 宽 和 高 计算

(1) MesureSpec 简介

MeasureSpec 组成 : 每个 MeasureSpec 都代表一个 int 类型数值, 共 32 位, 前两位是模式位, 后 30 位 是数值位;

-- 模式 : int 类型的前 2 位, 共有三种模式, 通过 MeasureSpec.getMode(int) 方法获取, 下面会详细介绍模式;

-- 大小 : int 类型的后 30 位, 通过 MeasureSpec.getSize(int) 方法获取大小;

MeasureSpec 模式简介 : 注意下面的数字是二进制的

-- 00 : MeasureSpec.UNSPECIFIED, 未指定模式;
-- 01 : MeasureSpec.EXACTLY, 精准模式;
-- 11 : MeasureSpec.AT_MOST, 最大模式;

MeasureSpec 常用方法介绍 :

-- MeasureSpec.getMode(int) : 获取模式;
-- MeasureSpec.getSize(int) : 获取大小;
-- MeasureSpec.makeMeasureSpec(int size, int mode) : 创建一个 MeasureSpec;
-- MeasureSpec.toString(int) : 模式 + 大小 字符串;

(2) 通过 MeasureSpec 计算组件大小

计算方法 :

-- 精准模式 : 该模式下 长度的大小 就是 从 MeasureSpec 中获取的 size 大小;

-- 最大模式 : 获取 默认大小 和 size 中的较小的那个;

-- 未定义模式 : 默认大小;

通用计算方法代码 :

	/**
	 * 获取组件宽度
	 *
	 * MeasureSpec : 该 int 类型有 32 位, 前两位是状态位, 后面 30 位是大小值;
	 * 		常用方法 :
	 * 		-- MeasureSpec.getMode(int) : 获取模式
	 *      -- MeasureSpec.getSize(int) : 获取大小
	 *      -- MeasureSpec.makeMeasureSpec(int size, int mode) : 创建一个 MeasureSpec;
	 *      -- MeasureSpec.toString(int) : 模式 + 大小 字符串
	 *
	 *      模式介绍 : 注意下面的数字是二进制的
	 *      -- 00 : MeasureSpec.UNSPECIFIED, 未指定模式;
	 *      -- 01 : MeasureSpec.EXACTLY, 精准模式;
	 *      -- 11 : MeasureSpec.AT_MOST, 最大模式;
	 *
	 *      注意 : 这个 MeasureSpec 模式是在 onMeasure 方法中自动生成的, 一般不用去创建这个对象
	 *
	 * @param widthMeasureSpec
	 * 				MeasureSpec 数值
	 * @return
	 * 				组件的宽度
	 */
	private int measure(int measureSpec) {
		//返回的结果, 即组件宽度
		int result = 0;
		//获取组件的宽度模式
		int mode = MeasureSpec.getMode(measureSpec);
		//获取组件的宽度大小 单位px
		int size = MeasureSpec.getSize(measureSpec);

		if(mode == MeasureSpec.EXACTLY){//精准模式
			result = size;
		}else{//未定义模式 或者 最大模式
			//注意 200 是默认大小, 在 warp_content 时使用这个值, 如果组件中定义了大小, 就不使用该值
			result = dip2px(mContext, 200);
			if(mode == MeasureSpec.AT_MOST){//最大模式
				//最大模式下获取一个稍小的值
				result = Math.min(result, size);
			}
		}

		return result;
	}

(3) 设置 组件大小方法

setMeasuredDimension() 方法 : 该方法决定 View 组件的大小;

-- 使用场所 : 在 onMeasure() 方法中调用该方法, 就设置了组件的宽 和 高, 然后在其它位置调用 getWidth() 和 getHeight() 方法时, 获取的就是 该方法设置的值;

-- 代码示例 :

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		/*
		 * setMeasuredDimension 方法 : 该方法决定当前的 View 的大小
		 * 根据 View 在布局中的显示, 动态获取 View 的宽高
		 *
		 * 当布局组件 warp_content 时 :
		 * 从 MeasureSpec 获取的宽度 : 492 高度 836 ,
		 * 默认 宽高 都是 120dip转化完毕后 180px
		 *
		 * 当将布局组件 的宽高设置为 240 dp :
		 * 宽度 和 高度 MeasureSpec 获取的都是 360, 此时 MeasureSpec 属于精准模式
		 *
		 */
		setMeasuredDimension(measure(widthMeasureSpec), measure(heightMeasureSpec));
	}

4. 图形绘制

(1) 设置画笔

画笔相关方法 :

-- 消除锯齿 : setAntiAlias(boolean);

		// 消除绘制时产生的锯齿
		mPaint.setAntiAlias(true);

-- 绘制空心圆设置的样式 : setStyle(Style.STROKE);

		// 绘制空心圆形需要设置该样式
		mPaint.setStyle(Style.STROKE);

-- 绘制实心图形文字需要设置的样式 : mPaint.setStrokeWidth(0);

-- 设置画笔颜色 : setColor(Color.BLUE);

-- 设置文字大小 : setTextSize(float);

		//设置数字的大小, 注意要根据 内圆半径设置
		mPaint.setTextSize(innerRadius / 2);

(2) 绘制图形

绘制圆 : canvas.drawCircle(float cx, float cy, float radius, Paint paint);

-- cx 参数 : 圆心的 x 轴距离;

-- cy 参数 : 圆心的 y 轴距离;

-- radius 参数 : 半径;

-- paint : 画笔;

绘制圆弧 :

-- 创建圆弧 : RectF rectf = new RectF(left, top, right, bottom);

-- 绘制 : canvas.drawArc(rectf, 270, mProcessValue, false, mPaint);

-- 示例 :

		//创建圆弧对象
		RectF rectf = new RectF(left, top, right, bottom);
		//绘制圆弧 参数介绍 : 圆弧, 开始度数, 累加度数, 是否闭合圆弧, 画笔
		canvas.drawArc(rectf, 270, mProcessValue, false, mPaint);

绘制文字 : canvas.drawText(str, textX, textY, mPaint);

二. 代码示例

1. 自定义 View 代码

package cn.org.octopus.circle;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.ImageView;

public class CircleProcess extends ImageView {

	/** 画笔 */
	private Paint mPaint;
	/** 上下文对象 */
	private Context mContext;
	/** 进度条的值 */
	private int mProcessValue;

	public CircleProcess(Context context, AttributeSet attrs) {
		super(context, attrs);
		// 初始化成员变量 Context
		mContext = context;
		// 创建画笔, 并设置画笔属性
		mPaint = new Paint();
		// 消除绘制时产生的锯齿
		mPaint.setAntiAlias(true);
		// 绘制空心圆形需要设置该样式
		mPaint.setStyle(Style.STROKE);
	}

	/**
	 * 自定义布局实现的 只有 Context 参数的构造方法
	 * @param context
	 */
	public CircleProcess(Context context) {
		super(context);
	}

	/**
	 * 自定义布局实现的 三个参数的构造方法
	 * @param context
	 * @param attrs
	 * @param defStyle
	 */
	public CircleProcess(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);

		//获取圆心的 x 轴位置
		int center = getWidth() / 2;
		/*
		 * 中间位置 x 减去左侧位置 的绝对值就是圆半径,
		 * 注意 : 由于 padding 属性存在, |left - right| 可能与 width 不同
		 */
		int outerRadius = Math.abs(getLeft() - center);
		//计算内圆半径大小, 内圆半径 是 外圆半径的一般
		int innerRadius = outerRadius / 2;

		//设置画笔颜色
		mPaint.setColor(Color.BLUE);
		//设置画笔宽度
		mPaint.setStrokeWidth(2);
		//绘制内圆方法 前两个参数是 x, y 轴坐标, 第三个是内圆半径, 第四个参数是 画笔
		canvas.drawCircle(center, center, innerRadius, mPaint);

		/*
		 * 绘制进度条的圆弧
		 *
		 * 绘制图形需要 left top right bottom 坐标, 下面需要计算这个坐标
		 */

		//计算圆弧宽度
		int width = outerRadius - innerRadius;
		//将圆弧的宽度设置给 画笔
		mPaint.setStrokeWidth(width);
		/*
		 * 计算画布绘制圆弧填入的 top left bottom right 值,
		 * 这里注意给的值要在圆弧的一半位置, 绘制的时候参数是从中间开始绘制
		 */
		int top = center - (innerRadius + width/2);
		int left = top;
		int bottom = center + (innerRadius + width/2);
		int right = bottom;

		//创建圆弧对象
		RectF rectf = new RectF(left, top, right, bottom);
		//绘制圆弧 参数介绍 : 圆弧, 开始度数, 累加度数, 是否闭合圆弧, 画笔
		canvas.drawArc(rectf, 270, mProcessValue, false, mPaint);

		//绘制外圆
		mPaint.setStrokeWidth(2);
		canvas.drawCircle(center, center, innerRadius + width, mPaint);

		/*
		 * 在内部正中央绘制一个数字
		 */
		//生成百分比数字
		String str = (int)(mProcessValue * 1.0 / 360 * 100) + "%";
		/*
		 * 测量这个数字的宽 和 高
		 */
		//创建数字的边界对象
		Rect textRect = new Rect();
		//设置数字的大小, 注意要根据 内圆半径设置
		mPaint.setTextSize(innerRadius / 2);
		mPaint.setStrokeWidth(0);
		//获取数字边界
		mPaint.getTextBounds(str, 0, str.length(), textRect);
		int textWidth = textRect.width();
		int textHeight = textRect.height();

		//根据数字大小获取绘制位置, 以便数字能够在正中央绘制出来
		int textX = center - textWidth / 2;
		int textY = center + textHeight / 2;

		//正式开始绘制数字
		canvas.drawText(str, textX, textY, mPaint);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		/*
		 * setMeasuredDimension 方法 : 该方法决定当前的 View 的大小
		 * 根据 View 在布局中的显示, 动态获取 View 的宽高
		 *
		 * 当布局组件 warp_content 时 :
		 * 从 MeasureSpec 获取的宽度 : 492 高度 836 ,
		 * 默认 宽高 都是 120dip转化完毕后 180px
		 *
		 * 当将布局组件 的宽高设置为 240 dp :
		 * 宽度 和 高度 MeasureSpec 获取的都是 360, 此时 MeasureSpec 属于精准模式
		 *
		 */
		setMeasuredDimension(measure(widthMeasureSpec), measure(heightMeasureSpec));
	}

	/**
	 * 获取组件宽度
	 *
	 * MeasureSpec : 该 int 类型有 32 位, 前两位是状态位, 后面 30 位是大小值;
	 * 		常用方法 :
	 * 		-- MeasureSpec.getMode(int) : 获取模式
	 *      -- MeasureSpec.getSize(int) : 获取大小
	 *      -- MeasureSpec.makeMeasureSpec(int size, int mode) : 创建一个 MeasureSpec;
	 *      -- MeasureSpec.toString(int) : 模式 + 大小 字符串
	 *
	 *      模式介绍 : 注意下面的数字是二进制的
	 *      -- 00 : MeasureSpec.UNSPECIFIED, 未指定模式;
	 *      -- 01 : MeasureSpec.EXACTLY, 精准模式;
	 *      -- 11 : MeasureSpec.AT_MOST, 最大模式;
	 *
	 *      注意 : 这个 MeasureSpec 模式是在 onMeasure 方法中自动生成的, 一般不用去创建这个对象
	 *
	 * @param widthMeasureSpec
	 * 				MeasureSpec 数值
	 * @return
	 * 				组件的宽度
	 */
	private int measure(int measureSpec) {
		//返回的结果, 即组件宽度
		int result = 0;
		//获取组件的宽度模式
		int mode = MeasureSpec.getMode(measureSpec);
		//获取组件的宽度大小 单位px
		int size = MeasureSpec.getSize(measureSpec);

		if(mode == MeasureSpec.EXACTLY){//精准模式
			result = size;
		}else{//未定义模式 或者 最大模式
			//注意 200 是默认大小, 在 warp_content 时使用这个值, 如果组件中定义了大小, 就不使用该值
			result = dip2px(mContext, 200);
			if(mode == MeasureSpec.AT_MOST){//最大模式
				//最大模式下获取一个稍小的值
				result = Math.min(result, size);
			}
		}

		return result;
	}

	/**
	 * 将手机的 设备独立像素 转为 像素值
	 *
	 * 		公式 : px / dip = dpi / 160
	 * 			   px = dip * dpi / 160;
	 * @param context
	 * 				上下文对象
	 * @param dpValue
	 * 				设备独立像素值
	 * @return
	 * 				转化后的 像素值
	 */
	public static int dip2px(Context context, float dpValue) {
		final float scale = context.getResources().getDisplayMetrics().density;
		return (int) (dpValue * scale + 0.5f);
	}

	/**
	 * 将手机的 像素值 转为 设备独立像素
	 * 		公式 : px/dip = dpi/160
	 * 			   dip = px * 160 / dpi
	 * 			   dpi (dot per inch) : 每英寸像素数 归一化的值 120 160 240 320 480;
	 * 			   density : 每英寸的像素数, 精准的像素数, 可以用来计算准确的值
	 * 			   从 DisplayMetics 中获取的
	 * @param context
	 * 				上下文对象
	 * @param pxValue
	 * 				像素值
	 * @return
	 * 				转化后的 设备独立像素值
	 */
	public static int px2dip(Context context, float pxValue) {
		final float scale = context.getResources().getDisplayMetrics().density;
		return (int) (pxValue / scale + 0.5f);
	}

	/**
	 * 获取当前进度值
	 * @return
	 * 				返回当前进度值
	 */
	public int getmProcessValue() {
		return mProcessValue;
	}

	/**
	 * 为该组件设置进度值
	 * @param mProcessValue
	 * 				设置的进度值参数
	 */
	public void setmProcessValue(int mProcessValue) {
		this.mProcessValue = mProcessValue;
	}

}

2. Activity 代码

package cn.org.octopus.circle;

import android.app.Activity;
import android.app.ActionBar;
import android.app.Fragment;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.os.Build;

public class MainActivity extends Activity {

	private static CircleProcess circle_process;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //加载 Fragment
        if (savedInstanceState == null) {
            getFragmentManager().beginTransaction()
                    .add(R.id.container, new PlaceholderFragment())
                    .commit();
        }

        new CircleProcessAnimation().execute();
    }

    /**
     * 设置 异步任务, 在这个任务中 设置 圆形进度条的进度值
     * @author octopus
     *
     */
    class CircleProcessAnimation extends AsyncTask<Void, Integer, Void>{

		@Override
		protected Void doInBackground(Void... arg0) {
			for(int i = 1; i <= 360; i ++){
				try {
					//激活圆形进度条显示方法
					publishProgress(i);
					//每隔 50 毫秒更新一次数据
					Thread.sleep(50);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			return null;
		}

		@Override
		protected void onProgressUpdate(Integer... values) {
			super.onProgressUpdate(values);

			//为圆形进度条组件设置进度值
			circle_process.setmProcessValue(values[0]);
			//刷新圆形进度条显示
			circle_process.invalidate();
		}

    }

    /**
     * 界面显示的 Fragment
     * @author octopus
     */
    public static class PlaceholderFragment extends Fragment {

        public PlaceholderFragment() {
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_main, container, false);
            circle_process = (CircleProcess) rootView.findViewById(R.id.circle_process);
            return rootView;
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

3. 布局文件代码

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="cn.org.octopus.circle.MainActivity$PlaceholderFragment"
    android:gravity="center">

    <cn.org.octopus.circle.CircleProcess
        android:id="@+id/circle_process"
        android:layout_width="300dip"
        android:layout_height="300dip"/>

</RelativeLayout>

代码下载 :

-- CSDN 下载地址 : http://download.csdn.net/detail/han1202012/8069497 ;

-- GitHub 地址 : https://github.com/han1202012/CircleProcess.git ;

-- 工程示例 :

时间: 2024-12-09 04:56:27

【Android 应用开发】 自定义 View 组件 -- 圆形进度条的相关文章

自定义view之圆形进度条

本节介绍自定义view-圆形进度条 思路: 根据前面介绍的自定义view内容可拓展得之: 1:新建类继承自View 2:添加自定义view属性 3:重写onDraw(Canvas canvas) 4:实现功能 下面上代码 1.自定义view代码: public class CustomView extends View { //背景圆环颜色 private int circleColor; //进度条颜色&字体颜色(为了美观,所以设计字体颜色和进度条颜色值一致) private int seco

Android 高手进阶,自己定义圆形进度条

背景介绍 在Android 开发中,我们常常遇到各种各样绚丽的控件,所以,依靠我们Android本身所带的控件是远远不够的,许多时候须要我们自定义控件,在开发的过程中.我们公司遇到了一种须要自己写的一个自定义带进度的圆形进度条,看起来很的绚丽,当然另一些其它的.比方:水纹形的圆形进度条等效果都是很nice的.假设哪位朋友有实现,希望分享出来,我也好学习学习. 好了多的不说.接下来,我们就来看看来怎样实现圆形进度条. 原文地址:http://blog.csdn.net/xiaanming/arti

Android自定义控件系列之应用篇——圆形进度条

一.概述 在上一篇博文中,我们给大家介绍了Android自定义控件系列的基础篇.链接:http://www.cnblogs.com/jerehedu/p/4360066.html 这一篇博文中,我们将在基础篇的基础上,再通过重写ondraw()方法和自定义属性实现圆形进度条,效果如图所示: 二.实现步骤   1.  编写自定义组件MyCircleProgress扩展View public class MyCircleProgress extends View { - } 2.  在MyCircl

Android中使用自定义View实现下载进度的显示

一般有下载功能的应用都会有这样一个场景,需要一个图标来标识不同的状态.之前在公司的项目中写过一个,今天抽空来整理一下. 一般下载都会有这么几种状态:未开始.等待.正在下载.下载结束,当然有时候会有下载出错的状态.等待状态是指用户点击开始下载,但是线程池中没有空闲的线程来处理该次下载,所以状态为等待. 效果图: 这里我只是演示了一下下载和暂停的状态,其他状态没有演示,在代码中设置就可以了. 实现代码: 1.自定义View 1 public class DownloadPercentView ext

Android 自定义漂亮的圆形进度条

这几天对Android中实现画圆弧及圆弧效果中所实现的效果进行了修改,改为进度圆心进度条,效果如图所示 TasksCompletedView.java 代码如下 import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; impo

Android Studio开发基础之自定义View组件

一般情况下,不直接使用View和ViewGroup类,而是使用使用其子类.例如要显示一张图片可以用View类的子类ImageView,开发自定义View组件可分为两个主要步骤: 一.创建一个继承自android.view.View类的View类,并且重写构造方法. 如下,新建一个名为MyView.Java的Java类文件,重写一个带Context的构造方法和onDraw()方法(用来重新绘制Activity窗口的背景). package com.example.lhb.contentprovid

Android自定义View——圆形进度条式按钮

介绍 今天上班的时候有个哥们问我怎么去实现一个按钮式的进度条,先来看看他需要实现的效果图. 和普通的圆形进度条类似,只是中间的地方有两个状态表示,未开始,暂停状态.而且他说圆形进度的功能已经实现了.那么我们只需要对中间的两个状态做处理就行了. 先来看看实现的效果图: 上面说了我们只需要处理中间状态的变化就可以了,对于进度的处理直接使用了弘洋文章中实现: http://blog.csdn.net/lmj623565791/article/details/43371299 下面开始具体实现. 具体实

Android 高手进阶之自定义View,自定义属性(带进度的圆形进度条)

转载请注明地址:http://blog.csdn.net/xiaanming/article/details/10298163 很多的时候,系统自带的View满足不了我们功能的需求,那么我们就需要自己来自定义一个能满足我们需求的View,自定义View我们需要先继承View,添加类的构造方法,重写父类View的一些方法,例如onDraw,为了我们自定义的View在一个项目中能够重用,有时候我们需要自定义其属性,举个很简单的例子,我在项目中的多个界面使用我自定义的View,每个界面该自定义View

Android 高手进阶,自定义圆形进度条

背景介绍 在Android 开发中,我们经常遇到各种各样绚丽的控件,所以,依靠我们Android本身所带的控件是远远不够的,很多时候需要我们自己定义控件,在开发的过程中,我们公司遇到了一种需要自己写的一个自定义带进度的圆形进度条,看起来非常的绚丽,当然还有一些其他的,比如:水纹形的圆形进度条等效果都是非常nice的.如果哪位朋友有实现,希望分享出来,我也好学习学习.好了多的不说,接下来,我们就来看看来如何实现圆形进度条. 原文地址:http://blog.csdn.net/xiaanming/a