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

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

                                

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

     回归正题,看到这样一个效果会想到如何实现呢,帧动画也是可以的,但是不平滑,放很多帧又会卡,所以我们先观察这个动画,底部是一个蓝色的线段,中间有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() {
			@Override
			public 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先调用
	}
	
	@Override
	protected 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值