话不多说,公司接到的项目中有个效果是上下拉的窗帘,本来是用seekbar旋转90°做的,但是seekbar的属性太多,而且seekbar的滑块会直接显示最底层的颜色(我也不知道为什么), 所有就写了一个自定义view,其实就是一个垂直的seekbar,实现一些简单的操作,例如设置进度,设置前景色和背景色、滑块图片。
首先先看看这个最终效果是什么样的:
然后我们再分析一下这个效果的构成:
1.最底层是白色的。
2.上一层是绿色的(管他什么绿,反正就是绿)。
3.在上层颜色的底部中间有一个滑块。
分析之后,我们就可以开始考虑怎么写了,下面直接上代码。
<declare-styleable name="WindowBarView">
<!--bgcolor:背景颜色-->
<!--cendiagram:中心原点的图片-->
<!--foreground:前景颜色-->
<!--maxprogress:最大进度-->
<!--nowrogress:当前进度-->
<attr name="bgcolor" format="color" />
<attr name="cendiagram" format="color|reference" />
<attr name="foreground" format="color" />
<attr name="maxprogress" format="integer" />
<attr name="nowrogress" format="integer" />
</declare-styleable>
因为需要给控件设置一些属性,我们就先在attrs文件中加入属性(没有这个文件就先创建一个)。
然后就是java文件了,我们让这个自定义view集成自view,代码是酱婶儿的。
public class WindowBarView extends View {
private int progress = 0;
private int maxprogress = 0;
private int nowrogress = 0;
private int bgcolor = 0;
private int Foreground = 0; //窗帘下拉的覆盖的颜色
private Paint paint;
private Paint foregrodpaint;
private Drawable cendiagram = null; //中心圆点的图片
private Bitmap cendiagrambp = null;
// 获得图片的宽高
int widthbm = 0;
int heightbm = 0;
// 取得想要缩放的matrix参数
Matrix matrix;
Bitmap newbm;
private float mPreX, mPreY;
int width, height;
Rect rect;
Rect rectforegroud;
public setonBarTouthnListener touthnListener = null;
public interface setonBarTouthnListener {
public void GetProgress(int progress);
}
public void getonBarProgressListener(setonBarTouthnListener touthnListener) {
this.touthnListener = touthnListener;
}
public WindowBarView(Context context) {
super(context);
}
public WindowBarView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView(context, attrs);
}
public WindowBarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context, attrs);
}
public WindowBarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initView(context, attrs);
}
private void initView(Context context, AttributeSet attrs) {
paint = new Paint();
foregrodpaint = new Paint();
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.WindowBarView);
Foreground = array.getInteger(R.styleable.WindowBarView_foreground, Color.WHITE);
cendiagram = array.getDrawable(R.styleable.WindowBarView_cendiagram);
maxprogress = array.getInteger(R.styleable.WindowBarView_maxprogress, 100);
nowrogress = array.getInteger(R.styleable.WindowBarView_nowrogress, 0);
bgcolor = array.getInteger(R.styleable.WindowBarView_bgcolor, Color.WHITE);
setProgress(array.getInteger(R.styleable.WindowBarView_nowrogress, nowrogress));
array.recycle();
cendiagrambp = drawableToBitmap(cendiagram);
// 获得图片的宽高
widthbm = cendiagrambp.getWidth();
heightbm = cendiagrambp.getHeight();
// 设置想要的大小
int newWidth = 100;
int newHeight = 100;
// 计算缩放比例
float scaleWidth = ((float) newWidth) / widthbm;
float scaleHeight = ((float) newHeight) / heightbm;
// 取得想要缩放的matrix参数
matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
// 得到新的图片
newbm = Bitmap.createBitmap(cendiagrambp, 0,
0, widthbm, heightbm, matrix, true);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int wideSize = MeasureSpec.getSize(widthMeasureSpec);
int wideMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (wideMode == MeasureSpec.EXACTLY) { //精确值 或matchParent
width = wideSize;
} else {
width = getPaddingLeft() + getPaddingRight();
if (wideMode == MeasureSpec.AT_MOST) {
width = Math.min(width, wideSize);
}
}
if (heightMode == MeasureSpec.EXACTLY) { //精确值 或matchParent
height = heightSize;
} else {
height = getPaddingTop() + getPaddingBottom();
if (heightMode == MeasureSpec.AT_MOST) {
height = Math.min(height, heightSize);
}
}
setMeasuredDimension(width, height);
rect = new Rect(0, 0, width, height);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
rectforegroud = new Rect(0, 0, width, (int) mPreY);
paint.setStyle(Paint.Style.FILL);
paint.setColor(bgcolor);
paint.setAntiAlias(true);
canvas.drawRect(rect, paint);
foregrodpaint.setStyle(Paint.Style.FILL);
foregrodpaint.setAntiAlias(true);
foregrodpaint.setColor(Foreground);
canvas.drawRect(rectforegroud, foregrodpaint);
canvas.drawBitmap(newbm, width / 2 - newbm.getWidth() / 2, (int) mPreY - newbm.getHeight() / 2, paint); //绘制滑块
}
/**
* 获取当前位置
*/
public int getProgress() {
if(mPreY==0){
progress = (int) ((float) nowrogress / (float) maxprogress * 100); //当前进度
}else{
progress = Math.round(mPreY / height*(float) maxprogress); //当前进度
}
return progress;
}
/**
* 设置当前进度
*/
public synchronized void setProgress(final int nowrogress) {
if(height != 0){
mPreY = ((int) ((float) nowrogress / (float) maxprogress * height));
invalidate();
}else{
new Thread() {
@Override
public void run() {
super.run();
try {
Thread.sleep(100);
if (height != 0) {
mPreY = ((int) ((float) nowrogress / (float) maxprogress * height));
postInvalidate();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
/**
* 判断,如果滑动的位置大于控件的高度,说明此事滑块已经滑到下面
* 如果小于0说明在上面
*
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mPreX = event.getX();
mPreY = event.getY();
touthnListener.GetProgress((int) (mPreY / height * maxprogress));
invalidate();
return true;
case MotionEvent.ACTION_MOVE:
mPreY = event.getY();
if (mPreY < 0) {
mPreY = 0;
} else if (mPreY > height) {
mPreY = height;
} else {
mPreY = event.getY() + 8;
}
touthnListener.GetProgress((int) (mPreY / height * maxprogress));
invalidate();
break;
}
return super.onTouchEvent(event);
}
/**
* drawable转bitmap
*
* @param drawable
* @return
*/
public static Bitmap drawableToBitmap(Drawable drawable) {
Bitmap bitmap = Bitmap.createBitmap(
drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight(),
drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
: Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
//canvas.setBitmap(bitmap);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
drawable.draw(canvas);
return bitmap;
}
}
主要就是onDraw中的内容。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
rectforegroud = new Rect(0, 0, width, (int) mPreY);
paint.setStyle(Paint.Style.FILL);
paint.setColor(bgcolor);
paint.setAntiAlias(true);
canvas.drawRect(rect, paint);
foregrodpaint.setStyle(Paint.Style.FILL);
foregrodpaint.setAntiAlias(true);
foregrodpaint.setColor(Foreground);
canvas.drawRect(rectforegroud, foregrodpaint);
canvas.drawBitmap(newbm, width / 2 - newbm.getWidth() / 2, (int) mPreY - newbm.getHeight() / 2, paint); //绘制滑块
}
这个控件我将它分为了三层,这样我就需要在画布上画三次,第一次,绘制最底层颜色,第二次,绘制上一层颜色,第三次绘制滑块,这样才能得到想要的效果。
下面就是使用方法。
<com.tianer.dooya.weight.WindowBarView
android:id="@+id/timeline"
android:layout_width="200dp"
android:layout_height="300dp"
app:bgcolor="@color/white"
app:foreground="@color/windowbar"
app:cendiagram="@drawable/bgg"
app:maxprogress="100"/>
最后,上个效果图。
上个源码地址
https://github.com/dzghxs/WindowBarView点击打开链接