自定义的滚动条RainbowBar
前言:getDimension和getDimensionPixelOffset的功能类似,获取某个dimen的值,但是如果单位是dp或sp,则需要将其乘以density.getDimensionPixelSize则不管写的是dp还是sp还是px,都会乘以denstiy.
思路:
自定义attrs属性文件,eg:`
<declare-styleable name="rainbowbar"> <attr name="rainbowbar_hspace" format="dimension"/> <attr name="rainbowbar_vspace" format="dimension"/> <attr name="rainbowbar_color" format="color"/> </declare-styleable>
`
前面name属性代表长宽高等,后面format代表其属性对应的值
在有style的参数里面获取上述属性值,并且初始化画笔之类
public RainbowBar(Contex context,AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //read custom attrs 从上面加载资源 TypedArray t = context.obtainStyledAttributes(attrs, R.styleable.rainbowbar,0,0); hSpace = t.getDimensionPixelSize(R.styleable.rainbowbar_rainbowbar_hspace,hSpace); vSpace = t.getDimensionPixelSize(R.styleable.rainbowbar_rainbowbar_vspace,vSpace); barColor = t.getColor(R.styleable.rainbowbar_rainbowbar_color,barColor); t.recycle();//使用过后清理资源 mPaint = new Paint(); mPaint.setAntiAlias(true);//设置清除锯齿形 mPaint.setColor(barColors[0]); mPaint.setStrokeWidth(vSpace);//高度 描边 }
最重要的一步就是onDraw()方法
- 首先计算屏幕宽度,用来计算起始位置
eg:`
float sw = this.getMeasuredWidth(); //屏幕宽度 + (宽度 + 间隔)- 求余 即超出屏幕宽度 if(startX >= sw+(hSpace+space) -(sw%(hSpace +space))){ startX = 0; }
`
假如屏幕可以容纳4个半,则为5个半减去超出屏幕的宽度(也就画最后一个时需要这样判断),当然可以认为屏幕只能容乃整数个分割条,例如4条,这样容易理解。
====-(5个半)减去 半个-,还有5个。因为超出屏幕的最后一个也要画,反之在屏幕最左端亦然,也要从屏幕外开始画.
接上述代码:`
else{ startX += delta;//每条view开始绘制的坐标 index ++; flag ++; if(flag > 8){//此处是动态改变颜色 flag = 0; mPaint.setColor(barColors[1]); }else{ if(index >barColors.length-1){ index = 0; mPaint.setColor(barColors[0]); }else { mPaint.setColor(barColors[2]); } } }
`
最重要的来了onDraw里面的绘图
首先绘制向前的view。如果起始位置小于屏幕宽度,则用循环控制,让它不断向前绘制,每次起始位置start变为StartX - spce - 每条分割条的宽度.最后一次start += (分割条宽度 + 间隔)还会执行一次.
其次绘制向后的view。如果起始位置大于负的分割条的宽度(因为每次都得从屏幕最左端或者屏幕前画起),
重绘一下即可
`
//画的条数 int index = 0; int flag = 0; @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //获取屏幕宽度 float sw = this.getMeasuredWidth(); //屏幕宽度 + (宽度 + 空间)- 求余 即超出屏幕宽度 if(startX >= sw+(hSpace+space) -(sw%(hSpace+space))){ startX = 0; }else{ startX += delta;//每条view开始绘制的坐标 index ++; flag ++; if(flag > 8){ flag = 0; mPaint.setColor(barColors[1]); }else{ if(index >barColors.length-1){ index = 0; mPaint.setColor(barColors[0]); }else { mPaint.setColor(barColors[2]); } } } float start = startX; //后 while(start < sw){ canvas.drawLine(start,5,start+hSpace,5,mPaint); start+= (hSpace+space); } start = startX - space - hSpace;//后面进度条的起点 //进度条一直在向前绘制的效果 while (start >= - hSpace){ //超出屏幕外,从屏幕外开始画 canvas.drawLine(start,5,start+hSpace,5,mPaint); start -= (hSpace+space); } invalidate(); }
`
最后附上布局
首先是values/attr.xml
`<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="rainbowbar"> <attr name="rainbowbar_hspace" format="dimension"/> <attr name="rainbowbar_vspace" format="dimension"/> <attr name="rainbowbar_color" format="color"/> </declare-styleable> </resources>`
*其次是布局
`<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:layout_marginTop="40dp" android:orientation="vertical" tools:context="com.example.project081601_view.MainActivity"> <custom.RainbowBar android:layout_width="match_parent" android:layout_height="wrap_content" app:rainbowbar_hspace="80dp" app:rainbowbar_color="@android:color/holo_blue_bright" app:rainbowbar_vspace="10dp"/> </LinearLayout>
`