虽然android本身给我们提供了形形色色的控件,基本能够满足日常开发的需求,但是面对日益同质化的app界面,和不同的业务需求.我们可能就需要自定义一些View来获得比较好的效果.自定义View是android开发者走向高级开发工程师必须要走的一关.

转载请标明出处:http://blog.csdn.net/unreliable_narrator/article/details/51274264


一,构造函数:

当我们创建一个类去继承View的时候,会要求我们 至少去实现一个构造函数. public MyView(Context context) 该构造函数是直接在代码里面进行创建控件的时候调用.如我们创建一个MyView myView=new MyView(this)的时候将会调用该函数.
public MyView(Context context, AttributeSet attrs) 这个是在xml创建但是没有指定style的时候被调用.多了一个AttributeSet类型的参数,在通过布局文件xml创建一个view时,会把XML内的参数通过AttributeSet带入到View内。
public MyView(Context context, AttributeSet attrs, int defStyleAttr) 构造函数中第三个参数是默认的Style,这里的默认的Style是指它在当前Application或Activity所用的Theme中的默认Style,且只有在明确调用的时候才会生效.
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public MyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
该构造函数是在api21的时候才添加上的,暂不考虑.
注意:即使你在View中使用了Style这个属性也不会调用三个参数的构造函数,所调用的依旧是两个参数的构造函数。 想要深入了解的详情可以查看这篇文章:http://blog.csdn.net/yuzhouxiang/article/details/6958017 android view构造函数研究
一般我们构造函数可以写成这样:
 public MyView(Context context) {        this(context, null);    }    public MyView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public MyView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }
二.自定义命名空间:
当我们自定义View的时候许多的属性我们当然不希望被写死.例如我自定义了一个圆.这个圆的颜色我更希望不在自定义控件里面写死,而是在使用的时候在布局文件中进 行指定 这个颜色的时候.我们就需要用到自定义命名空间来对自定义View的属性进行设置了.
步骤1:首先在Values文件夹里面新建attrs文件.
步骤2.编写attrs文件.attrs有两种写法.
( 1.)针对于单个View自己去定义不同的属性.
例如:
<?xml version="1.0" encoding="utf-8"?><resources>    <!--属性申明必须是自定义控件的名称-->    <declare-styleable name="MyView">        <!--采用驼峰命名规则,可以随意命名,format是属性的单位-->        <attr name="roundColor" format="color"></attr>    </declare-styleable></resources>
(2.)如果是有公共的属性部分,可以将属性包含在公共属性部分里面.也就是说公共属性可以被多个自定义控件属性样式使用.
例如:
<?xml version="1.0" encoding="utf-8"?><resources>    <!--采用驼峰命名规则,可以随意命名,format是属性的单位-->    <attr name="roundColor" format="color"></attr>    <!--属性申明必须是自定义控件的名称-->    <declare-styleable name="MyView">        <attr name="roundColor"></attr>    </declare-styleable></resources>
所有的format类型
reference 引用
color 颜色
boolean 布尔值
dimension 尺寸值
float 浮点值
integer 整型值
string 字符串
enum 枚举值
步骤3:在布局文件中队自定义的属性进行使用。
打开布局文件我们可以看到有很多的以xmlns开头的字段。其实这个就是XML name space 的缩写。我们仿照系统定义好的自己来定义一个命名空间。
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:上面说过了是XML name space 的缩写。
app :是命名空间的名称可随意书写
上方是在android studio里面万能的书写方式,在eclipse里面一般是这样写xmlns:app="http://schemas.android.com/apk/res/com.dapeng.viewdemo"
com.dapeng.viewdemo为本应用的包名.
步骤4.在自定义View中将我们定义好的属性拿到.
通过context.obtainStyledAttributes将构造函数中的attrs进行解析出来,就可以拿到相对应的属性.
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyView);
mColor = typedArray.getColor(R.styleable.MyView_roundColor, 0XFF00FF00);
需要注意的一点是:在我们获取尺寸的时候有三个函数进行使用,我们来看看他们之间的区别.
getDimension()是基于当前DisplayMetrics进行转换,获取指定资源id对应的尺寸。文档里并没说这里返回的就是像素,要注意这个函数的返回值是float,像素肯定 是int。
getDimensionPixelSize()与getDimension()功能类似,不同的是将结果转换为int,并且小数部分四舍五入。
getDimensionPixelOffset()与getDimension()功能类似,不同的是将结果转换为int,并且偏移转换(offset conversion,函数命名中的offset是这个意思)是直接截 断小数位,即取整(其实就是把float强制转化为int,注意不是四舍五入哦)。
由此可见,这三个函数返回的都是绝对尺寸,而不是相对尺寸(dp\sp等)。如果getDimension()返回结果是20.5f,那么getDimensionPixelSize()返回结果就是 21,getDimensionPixelOffset()返回结果就是20。
                            理论知识讲的有点多,可能有点空洞,下面通过一个小的例子,来测试一下我们的命名空间是否可以正常使用.                                                         例子:                我们自定义一个View,这个View的形状是一个圆形,并且我们不希望将圆的颜色写死,可以在布局文件中进行设置.                                                        其他的我们都先不管,只是测试一下自定义命名空间.                                                 步骤1.创建一个View继承自View.并且重写它的构造函数                             
public class MyView extends View {    public MyView(Context context) {        this(context, null);    }    public MyView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public MyView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }}
步骤2:在Values文件夹下面创建一个attrs的文件,写上自定义的属性.
<?xml version="1.0" encoding="utf-8"?><resources>    <!--属性申明必须是自定义控件的名称-->    <declare-styleable name="MyView">        <!--采用驼峰命名规则,可以随意命名,format是属性的单位-->        <attr name="roundColor" format="color"></attr>        <attr name="radius" format="dimension"></attr>    </declare-styleable></resources>
步骤3:在布局文件中进行引用自定义命名空间.这里给设置的颜色是橘黄色.
<?xml version="1.0" encoding="utf-8"?><RelativeLayout    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"    tools:context="com.dapeng.viewdemo.MainActivity">    <com.dapeng.viewdemo.MyView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:background="@android:color/holo_red_light"        app:roundColor="@android:color/holo_blue_bright"        app:radius="50dp"        /></RelativeLayout>
步骤4:在自定义View中设置我们自定义的属性.
public class MyView extends View {    private int mColor;    private Paint mP;    private float mRadius;    public MyView(Context context) {        this(context, null);    }    public MyView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public MyView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        //拿到自定义属性        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyView);        mColor = typedArray.getColor(R.styleable.MyView_roundColor, 0XFF00FF00);        mRadius = typedArray.getDimension(R.styleable.MyView_radius, 50);        //回收资源        typedArray.recycle();        //创建画笔        mP = new Paint();        //设置画笔颜色        mP.setColor(mColor);        //设置抗锯齿        mP.setAntiAlias(true);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        //画圆        canvas.drawCircle(mRadius, mRadius, mRadius, mP);    }}
Ok代码书写完毕,我们来看看实现的效果是怎么样的.
如果将颜色设置为蓝色就是如下效果:


                                当然,这里只是实现了自定义控件的一小部分功能,接着我们来看看一个问题:                                            我们将我们自定义控件的                background设置为红色来看看效果.这里控件都是                设置包裹内容的.              
<?xml version="1.0" encoding="utf-8"?><RelativeLayout    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"    tools:context="com.dapeng.viewdemo.MainActivity">    <com.dapeng.viewdemo.MyView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:background="@android:color/holo_red_light"        app:roundColor="@android:color/holo_blue_bright"        /></RelativeLayout>
效果如下图所示:
                            看到这个效果可能会有点惊奇了,明明我设置的是包裹内容的,为什么控件确实填充了父窗体?带着这样的疑问我们接下来学习,自定义控件的另外一个非常重要的函数:onmeasure();                                        onmeuse()方法                :                测量自己的大小,为正式布局提供建议。(注意,只是建议,至于用不用,要看onLayout);                                                              主要的作用就是处理自定义VIewgroup的时候是                wrap_content的时候该ViewGrop的大小.                                                             定义:如果                layout_widhtlayout_heightmatch_parent或具体的xxxdp,那就非常简单了,直接调用                setMeasuredDimension()方    法,设置ViewGroup的宽高即可.                But如果是                wrap_content,就比较麻烦了,                如果不重写                onMeasure()                方法,系统则会不知道该默认多     大尺寸                ,就会默认填充整个父布局,所以,                重写                onMeasure()                方法的目的,就是为了能够给 View 一个wrap_content属性下的默认大    小                                                             调用此方法会传进来的两个参数:                int widthMeasureSpec,                int heightMeasureSpec.他们是父类传递过来给当前view的一个建议值,    即把当前view的尺寸设置为宽                widthMeasureSpec,高                heightMeasureSpec                虽然表面上看起来他们是int类型的数字,其实他们是由       mode+size两部分组成的。widthMeasureSpec和heightMeasureSpec转化成二进制数字表示,他们都是30位的。前两位代表mode(测量模  式),后面28位才是他们的实际数值(size)。                                                             MeasureSpec.getMode(                )获取模式                                           MeasureSpec.getSize(                )获取尺寸                                                        mode的值有三种为:                                                           EXACTLY:表示设置了精确的值,一般当childView设置其宽、高为精确值(也就是我们在布局文件中设定的值如50dp)、match_parent时,ViewGroup会将其设置为EXACTLY;            

AT_MOST:表示子布局被限制在一个最大值内,一般当childView设置其宽、高为wrap_content时,ViewGroup会将其设置为AT_MOST;

UNSPECIFIED:表示子布局想要多大就多大,一般出现在AadapterView的item的heightMode中、ScrollView的childView的heightMode中;此种模式比较少见。

我们需要判断当布局文件中设置控件为包裹内容的时候,控件的大小的值就可以了.因此重写onmeasure()方法如下:
 @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        //获取测量的模式        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        //获取测量的值        int withSize = MeasureSpec.getSize(widthMeasureSpec);        int heightSize = MeasureSpec.getSize(heightMeasureSpec);        //设置控件的大小        setMeasuredDimension(widthMode == MeasureSpec.AT_MOST ? (int) mRadius * 2 : withSize, heightMode == MeasureSpec.AT_MOST ? (int) mRadius * 2 : heightSize);    }
设置成功以后,直接将工程运行起来就可以看到效果了:

                                 上面的例子都是演示的画圆,如果想画其他的形状应该怎么办呢?我们需要通过重写                onDraw() 方法对控件重写进行绘制就可以了.                                         Ondraw().                                              draw就是画的意思从字面意思我们也可以知道.通过重写该方法我们可以对绘制出相关的控件.那么绘制的时候在是在什么上面进行绘制呢?我们    先来重写ondraw()看看:            
@Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);           }
                                  我们可以看到通过重写ondraw()会传过来一个Canvas类,这个类实际上就是一块儿画布,我们可以创建画笔在上面进行绘图.                                             Canvas的使用.                                        

这个类相当于一个画布,你可以在里面画很多东西;

我们可以把这个Canvas理解成系统提供给我们的一块内存区域(但实际上它只是一套画图的API,真正的内存是下面的 Bitmap),而且它还提供了一整套对这个内存区域进行操作的方法,所有的这些操作都是画图API。也就是说在这种方式

下我们已经能一笔一划或者使用画笔来画我们所需要的东西了,要画什么要显示什么都由我们自己控制。这种方式根据环 境还分为两种:一种就是使用普通View的canvas画图,还有一种就是使用专门的SurfaceView的canvas来画图。两种的 主要是区别就是可以在SurfaceView中定义一个专门的线程来完成画图工作,应用程序不需要等待View的刷图,提高性 能。前面一种适合处理量比较小,帧率比较小的动画,比如说简单的View样式或者是象棋游戏之类的;而后一种主要用 在游戏,高品质动画方面的画图。

Canvas可以绘制的对象有: 弧线(arcs)、填充颜色(argb和color)、 Bitmap、圆(circle和oval)、点(point)、线(line)、矩形 (Rect)、图片(Picture)、圆角矩形 (RoundRect)、文本(text)、顶点(Vertices)、路径(path) 。通过组合这些对象我们可以画出一 些简单有趣的界面出来,但是光有这些功能还是不够的,如果我要画一个仪表盘(数字围绕显示在一个圆圈中)呢? 幸好Android 还提供了一些对Canvas位置转换的方法:rorate、scale、translate、skew(扭曲)等,而且它允许你通过获得它的转换矩阵对象 (getMatrix方法 ) 直接操作它。这些操作就像是虽然你的笔还是原来的地方画,但是画纸旋转或者移动了,所以你画的东西的方 位就产生变化。为了方便一些转换操作,Canvas 还提供了保存和回滚属性的方法(save和restore),比如你可以先保存目前画纸 的位置(save),然后旋转90度,向下移动100像素后画一些图形,画完后调用restore方法返回到刚才保存的位置. 画一些比较常见的几何图形:
画圆:canvas.drawCircle()
 canvas.drawCircle(100, 100, 90, paint);   
画弧形:canvas.drawArc();
 //绘制弧线区域       //先要绘制矩形                                                                                                                                  RectF rect = new RectF(0, 0, 100, 100);                                                                                                                                         canvas.drawArc(rect, //弧线所使用的矩形区域大小               270,  //开始角度               90, //扫过的角度               true, //是否使用中心               paint); //画笔  
颜色填充:canvas.drawColor();
 canvas.drawColor(Color.BLUE);   
画一条线:canvas.drawLine()
canvas.drawLine(10,//x起点位置                10, //y起点位置                100, //x终点位置                100, //y终点位置                paint); //画笔
画椭圆:
                                                                                                                                 //定义一个矩形区域       RectF oval = new RectF(0,0,200,300);       //矩形区域内切椭圆       canvas.drawOval(oval, paint);   
画带有弧度的文字:canvas.drawPosText();
//按照既定点 绘制文本内容       canvas.drawPosText("Android", new float[]{               10,10, //第一个字母在坐标10,10               20,20, //第二个字母在坐标20,20               30,30, //....               40,40,               50,50,               60,60,               70,70,       }, paint);   
画矩形:canvas.drawRect();
 RectF rect = new RectF(50, 50, 200, 200);                                                                                                                                             canvas.drawRect(rect, paint);  
画带有弧度的矩形:canvas.drawRoundRect();
  RectF rect = new RectF(50, 50, 200, 200);                                                                                                                                         canvas.drawRoundRect(rect,                           30, //x轴的半径                           30, //y轴的半径                           paint);   
画封闭的图形:
  Path path = new Path(); //定义一条路径       path.moveTo(10, 10); //移动到 坐标10,10       path.lineTo(50, 60);       path.lineTo(200,80);       path.lineTo(10, 10);                                                                                                                                         canvas.drawPath(path, paint);   
画文字跟随一条线:
  Path path = new Path(); //定义一条路径               path.moveTo(10, 10); //移动到 坐标10,10               path.lineTo(50, 60);               path.lineTo(200,80);               path.lineTo(10, 10);                                                                                                                                             canvas.drawTextOnPath("Android", path, 10, 10, paint);
画图片:
drawBitmap(Bitmap bitmap, float left, float top, Paint paint)
canvas的一些常规的方法:
 canvas.rotate(360 / count,//旋转的角度                         0f, x轴的坐标                        0f); //旋转画纸 canvas.translate(200, 200); //将位置移动画纸的坐标点到x为200,y为200canvas.save();              //保存画布的状态canvas.restore();           //取出保存的状态 

canvas.save();和canvas.restore();是两个相互匹配出现的,作用是用来保存画布的状态和取出保存的状态的。这里稍微解释一下,

当我们对画布进行旋转,缩放,平移等操作的时候其实我们是想对特定的元素进行操作,比如图片,一个矩形等,但是当你用canvas的方法来进行这些操作的时候,其实是对整个画布进行了操作,那么之后在画布上的元素都会受到影响,所以我们在操作之前调用canvas.save()来保存画布当前的状态,当操作之后取出之前保存过的状态,这样就不会对其他的元素进行影响.

画笔Paint

  从上面列举的几个Canvas.drawXxx()的方法看到,其中都有一个类型为paint的参数,可以把它理解为一个"画笔",通过这个画笔,在Canvas这张画布上作画。它位于"android.graphics.Paint"包下,主要用于设置绘图风格,包括画笔颜色、画笔粗细、填充风格等。

  Paint中提供了大量设置绘图风格的方法,这里仅列出一些常用的:

  • setARGB(int a,int r,int g,int b):设置ARGB颜色。
  • setColor(int color):设置颜色。
  • setAlpha(int a):设置透明度。
  • setPathEffect(PathEffect effect):设置绘制路径时的路径效果。
  • setShader(Shader shader):设置Paint的填充效果。
  • setAntiAlias(boolean aa):设置是否抗锯齿。
  • setStrokeWidth(float width):设置Paint的笔触宽度。
  • setStyle(Paint.Style style):设置Paint的填充风格。
  • setTextSize(float textSize):设置绘制文本时的文字大小。

invalidate()和postInvalidate()的区别.

通过上面的讲解,我在自定义一个静态的View已经是一件非常容易的事情了,但是我们使用的自定义的View有很多是需要根据一个变量去不断绘制的,这个时候就引出了新的函数invalidate()和postinvalidate(),使用此函数可以是的ondraw()不断的去执行从而达到不断绘制的效果.

Android中实现view的更新有两组方法,一组是invalidate,另一组是postInvalidate,其中前者是在UI线程自身中使用,而后者在非UI线程中使用。

接下来通过一个稍微综合一点的例子来对自定义View做一个总结:

先来看看实现的效果:


我们先来分析一下,这个效果实际上就是外面是不断的去绘制一个扇形,然后中间盖了一个小的圆:


好了,接下来我们来讲一讲实现的步骤:

步骤一:首先定义attrs文件:

<?xml version="1.0" encoding="utf-8"?><resources>    <declare-styleable name="ProgressView">        <attr name="smallRoundColor" format="color"></attr>        <attr name="smallRoundRadius" format="dimension"></attr>        <attr name="arcRadius" format="dimension"></attr>        <attr name="arcColor" format="color"></attr>        <attr name="textColor" format="color"></attr>        <attr name="textSize" format="dimension"></attr>    </declare-styleable></resources>
步骤二:编写自定义View:

public class ProgressView extends View {    private float mArcRadius;    private float mSmallRoundRadius;    private int mArcColor;    private int mSmallRoundColor;    private Paint mRoundpaint;    private Paint mArcpaint;    private float sweepAngle;    private int mTextColor;    private Paint mTextPaint;    private int mTextSize;    public ProgressView(Context context) {        this(context, null);    }    public ProgressView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public ProgressView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ProgressView);        //扇形半径        mArcRadius = array.getDimension(R.styleable.ProgressView_arcRadius, 50);        //小圆半径        mSmallRoundRadius = array.getDimension(R.styleable.ProgressView_smallRoundRadius, 50);        //扇形颜色        mArcColor = array.getColor(R.styleable.ProgressView_arcColor, 0XFF00FF00);        //小圆颜色        mSmallRoundColor = array.getColor(R.styleable.ProgressView_smallRoundColor, 0XFF00FF00);        //百分比字体颜色        mTextColor = array.getColor(R.styleable.ProgressView_textColor, 0XFF00FF00);        //百分比字体大小        mTextSize = array.getDimensionPixelSize(R.styleable.ProgressView_textSize, 15);        //释放资源        array.recycle();        //画圆的画笔        mRoundpaint = new Paint();        mRoundpaint.setColor(mSmallRoundColor);        mRoundpaint.setAntiAlias(true);        //画扇形的画笔        mArcpaint = new Paint();        mArcpaint.setColor(mArcColor);        mArcpaint.setAntiAlias(true);        //绘制中间文字部分的画笔文本        mTextPaint = new Paint();        mTextPaint.setColor(mTextColor);        mTextPaint.setAntiAlias(true);        mTextPaint.setTextSize(mTextSize);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        //设置View的大小        int withMode = MeasureSpec.getMode(widthMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        int withSize = MeasureSpec.getSize(widthMeasureSpec);        int heightsize = MeasureSpec.getSize(heightMeasureSpec);        setMeasuredDimension(withMode == MeasureSpec.AT_MOST ? (int) mArcRadius * 2 : withSize, heightMode == MeasureSpec.AT_MOST ? (int) mArcRadius * 2 : heightsize);    }    @Override    protected void onDraw(Canvas canvas) {        //画圆弧        RectF rect = new RectF(0, 0, (int) mArcRadius * 2, (int) mArcRadius * 2);        canvas.drawArc(rect, 270, (float) (sweepAngle * 3.6), true, mArcpaint);        //画小圆        canvas.drawCircle(mArcRadius, mArcRadius, mSmallRoundRadius, mRoundpaint);        String text = (int) (sweepAngle) + "%";        float textLength = mTextPaint.measureText(text);        //把文本画在圆心居中        canvas.drawText(text, mArcRadius - textLength / 2, mArcRadius, mTextPaint);        super.onDraw(canvas);    }    //提供一个给外界的方法可以不断的去设置扇形的弧度    public void percent(float sweepAngle) {        if (sweepAngle <= 100) {            this.sweepAngle = sweepAngle;            //刷新界面            postInvalidate();        }    }}
步骤三:在布局文件中进行使用:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout    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"    tools:context="com.dapeng.viewdemo.SecondActivity">    <com.dapeng.viewdemo.ProgressView        android:id="@+id/pv"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        app:arcColor="@android:color/holo_blue_bright"        app:arcRadius="120dp"        app:textSize="20sp"        app:smallRoundColor="@android:color/transparent"        app:textColor="@android:color/holo_orange_light"        app:smallRoundRadius="100dp"/>    <Button        android:id="@+id/btn"        android:text="开始绘制"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_centerInParent="true"/></RelativeLayout>
步骤四:在需要用到的地方模拟数据去使用自定义的View.
public class SecondActivity extends AppCompatActivity {    private int mTotalProgress;    private int mCurrentProgress;    private ProgressView mPv;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_second);        mPv = (ProgressView) findViewById(R.id.pv);        initVariable();        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                mCurrentProgress=0;                new Thread(new ProgressRunable()).start();            }        });    }    private void initVariable() {        mTotalProgress = 100;        mCurrentProgress = 0;    }    class ProgressRunable implements Runnable {        @Override        public void run() {            while (mCurrentProgress < mTotalProgress) {                mCurrentProgress += 1;                mPv.percent((float) mCurrentProgress);                try {                    Thread.sleep(50);                } catch (Exception e) {                    e.printStackTrace();                }            }        }    }}

至此大功告成.

更多相关文章

  1. Android开发学习:ImageView的scaletype属性
  2. Android(安卓)Animation之frame animation
  3. eclipse导入已存在的android工程时遇到AndroidManifest.xml文件
  4. 设置Button背景渐变效果和点击效果
  5. Android(安卓)Studio 使用笔记(1) -- 设置自动生成serialVersionUI
  6. Android(安卓)Spinner
  7. 详解android shape的使用总结
  8. 详解android四种布局之LinearLayout
  9. Android(安卓)HDMI输出设置流程

随机推荐

  1. android jni操作数组
  2. Android使用本地缓存解析远程服务器JSON
  3. android ListView本行控件操作本行其它控
  4. Android获取系统可用内存
  5. ubuntu android 环境变量的配置
  6. PUSH机制
  7. 动态修改ViewPagerIndicator CustomTabPa
  8. Android设计开发要必用的Color.xml文件整
  9. Android(安卓)ScrollView嵌套ScrollView
  10. Android常用的多渠道打包方式整理(不断更