自定义控件之仿知乎进度条

来源:互联网 发布:男士钱包网络代理 编辑:程序博客网 时间:2024/06/03 04:54

        自定义控件系列开始连载了,今天我们要做的是知乎的进度条的效果,先上图

                                

刚开始不太会做动态图,自己截了几张图合在一起,看起来会比较卡,自己运行源码就比较流畅了。

     回归正题,看到这样一个效果会想到如何实现呢,帧动画也是可以的,但是不平滑,放很多帧又会卡,所以我们先观察这个动画,底部是一个蓝色的线段,中间有4个白色滑块向右移动,所以我们可以用两个画笔来进行绘制,一个绘制底部的线条,一个绘制白色的滑块。

     View和SurfaceView不一样,view是运行在UI线程也就是主线程上的,而SurfaceView通过一个callback回调,在surfaceCreated中可以启动一个工作线程,如果我们在view中直接绘制的话就会阻塞UI线程,程序就会ANR了,所以我们可以声明一个定时器,然后在其中去进行更新滑块的位置,然后postInvalidate,这样就能onDraw更新了,而且不会阻塞主线程。

public class LoadingView extends View {private Paint mBgPaint;private Paint mBlockPaint1;private Timer timer;private Rect rect1;private Rect rect2;private Rect rect3;private Rect rect4;int left1,right1;int left2,right2;int left3,right3;int left4,right4;public LoadingView(Context context) {super(context ,null);}public LoadingView(Context context, AttributeSet attrs) {super(context, attrs);Log.i("---LoadingView", "LoadingView");//int w = getWidth();left1 =0;right1 =10;left2 = 1080/4;right2 =1080/4 +10;left3 =1080/2;right3 = 1080/2 +10;left4 = 1080*3/4;right4 = 1080*3/4+10;mBgPaint = new Paint();mBgPaint.setAntiAlias(true);mBgPaint.setColor(Color.BLUE);mBlockPaint1= new Paint();mBlockPaint1.setAntiAlias(true);mBlockPaint1.setColor(Color.WHITE);rect1 = new Rect(left1, 0, right1, 10);rect2 = new Rect(left2, 0, right2, 10);rect3 = new Rect(left3, 0,right3, 10);rect4 = new Rect(left4, 0, right4, 10);timer = new Timer();newThread();}public void newThread(){timer.schedule(new TimerTask() {@Overridepublic void run() {Log.i("---width", ""+getWidth());if (right4 < getWidth()) {left1 =left1+20;left2 =left2+20;left3 =left3+20;left4 = left4+20;right1 =right1+20;right2=right2+20;right3 = right3+20;right4 =right4+20;}else {left1= 0;right1 = 10;left2= getWidth()/4;right2 = getWidth()/4+10;left3= getWidth()/2;right3 = getWidth()/2+10;left4 =getWidth()*3/4;right4 =getWidth()*3/4+10;}rect1 = new Rect(left1, 0, right1, 10);rect2 = new Rect(left2, 0, right2, 10);rect3 = new Rect(left3, 0, right3, 10);rect4 = new Rect(left4, 0, right4, 10);postInvalidate();}}, 200, 30); //设置延迟是为了使onDraw先调用}@Overrideprotected void onDraw(Canvas canvas) {Log.i("---ondraw", "ondraw");super.onDraw(canvas);canvas.drawRect(new Rect(0, 0, getWidth(), 10), mBgPaint);canvas.drawRect(rect1, mBlockPaint1);canvas.drawRect(rect2, mBlockPaint1);canvas.drawRect(rect3, mBlockPaint1);canvas.drawRect(rect4, mBlockPaint1);}}
写这个之后才发现一个问题,在构造函数中我们调用getWidth()是不会返回手机的宽度的,而是会返回0,这是因为onDraw方法还没有调用,查阅了很多资料,基本上都是在onCreate中取直接获取width,除此之外没有比较好的办法,知道的话可以评论一句。这里我直接写死了数据。

其实写到这里已经可以算完成任务了,因为效果已经实现了,但是自定义控件,不能自定义当然感觉缺点什么,比如知乎也有两种皮肤,滑块的颜色并不一样,所以我们再继续完善一下。

先在values下面建立一个attrs.xml文件

<?xml version="1.0" encoding="utf-8"?><resources>        <declare-styleable name="LoadingView">        <attr name="blockcolor" format="color"/>        <attr name="bgcolor" format="color"/>    </declare-styleable>    </resources>

然后我们就能在代码里调用了

TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.LoadingView);int bgColor = array.getColor(R.styleable.LoadingView_bgcolor, 0xFF0000FF);int blockColor = array.getColor(R.styleable.LoadingView_blockcolor, 0xFFFFFFFF);mBgPaint = new Paint();mBgPaint.setAntiAlias(true);mBgPaint.setColor(bgColor);mBlockPaint1= new Paint();mBlockPaint1.setAntiAlias(true);mBlockPaint1.setColor(blockColor);
最后在布局文件里面使用

  xmlns:sheepm="http://schemas.android.com/apk/res/com.example.zhihuloading"

 <com.example.zhihuloading.LoadingView         android:layout_width="wrap_content"        android:layout_height="wrap_content"        sheepm:blockcolor ="#FFFF00"        sheepm:bgcolor ="#FF0000"        />


到这里就大功告成了,源码下载链接:点击打开链接



0 0