这节中,我们我们来讨论微盾上界面上实现的二三事。这也是这个项目的重头戏。
界面上我们要做一个什么效果,一个倒计时的效果了,这个倒计时效果以后用的很多,希望对大家有帮助。
我这里布局方式用到了帧布局的方式,一个是所谓的表盘的情况,一个是倒计时的秒针, 相应的布局文件如下了:
<FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" > <com.itcast.vdunx.RingView android:layout_width="@dimen/ring_view_width" android:layout_height="@dimen/ring_view_height" > </com.itcast.vdunx.RingView> <com.itcast.vdunx.CountdownIndicator android:id="@+id/pb_progress" android:layout_width="@dimen/countdown_indicator_width" android:layout_height="@dimen/countdown_indicator_height" android:layout_gravity="center" > </com.itcast.vdunx.CountdownIndicator> </FrameLayout>
那个RingView是我自定义的表盘控件,它即在手机的界面上画了一个园,而这个CountdownIndicator即是一个倒计时控件,它是一个什么,一个扇形,一个随着时间的变化而不断改变自己大小的扇形。这两个控件的原理是什么了,我们来窥探它一下原貌了。
首先看一下RingVieW的源代码:
Paint paint; Context ctx; public RingView(Context context, AttributeSet attrs) { super(context, attrs); paint = new Paint(); this.paint.setAntiAlias(true);//没有锯齿 this.paint.setStyle(Paint.Style.STROKE);//画空心 ctx = context; } @Override protected void onDraw(Canvas paramCanvas) { float center = getWidth()/2; int innerCircle = dip2px(ctx,83); //设置内圆半径 int ringWidth = dip2px(ctx,5); //设置圆环宽度 //绘制内圆 this.paint.setARGB(155, 167, 190, 206); this.paint.setStrokeWidth(2);//设置线条宽度 paramCanvas.drawCircle(center,center, innerCircle, this.paint);//innerCircle:半径 //绘制圆环 this.paint.setARGB(255, 212 ,225, 233); this.paint.setStrokeWidth(ringWidth);//中间圆环宽度 paramCanvas.drawCircle(center,center, innerCircle+1+ringWidth/2, this.paint); //绘制外圆 this.paint.setARGB(155, 167, 190, 206); this.paint.setStrokeWidth(2); paramCanvas.drawCircle(center,center, innerCircle+ringWidth, this.paint); } /** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) */ public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); }
通过上面的源代码,我们可以清晰看出来了,这个只是通过相应画笔在指定的圆心位置按照固定位置来画出来相应的圆环。
而CountdownIndicator控件则比上述的控件园复杂一点了,首先还是看代码:
public class CountdownIndicator extends View { Paint paint; double phase; public CountdownIndicator(Context context, AttributeSet attrs) { super(context, attrs); this.paint = new Paint(); this.paint.setAntiAlias(true); // 在此处无法直接获得控件的宽高,只能从资源文件中读取 float x = context.getResources().getDimension( R.dimen.countdown_indicator_width) / 2;// 返回的是像素值 float y = context.getResources().getDimension( R.dimen.countdown_indicator_height) / 2; RadialGradient rg = new RadialGradient(x, y, y, Color.argb(255, 143, 201, 233), Color.argb(255, 166, 212, 235), TileMode.MIRROR);// 渐变 this.paint.setShader(rg); } @Override protected void onDraw(Canvas canvas) { float f1 = (float) (phase * 360); float f2 = 270 - f1; RectF localRectF = new RectF(0, 0, getWidth(), getHeight()); canvas.drawArc(localRectF, f2, f1, true, paint);// f2:起始角度,f1:扫描幅度 } public void setPhase(double phase) { if (phase < 0 || phase > 1) { throw new IllegalArgumentException(); } this.phase = phase; invalidate(); }
这个类主要就是Phase这个角度,而他扫描的幅度这是一个起始角度,起始角度是一个o-1的浮点数*360,而相应的扫描的幅度根据相应数据三角函数的方法是270-起始角度了,这样就得到一个倒计时秒盘的结果。
有了这两个类之后,根据相应的时间控件计时之后,最终的计时的效果是这样的:
这个动画制作过程大家明白吧。