2019独角兽企业重金招聘Python工程师标准>>>
RegulatorView效果图:
RegulatorView实现步骤:
1.新建java类RegulatorView.java,继承View类
2.定义必要基础属性,及为其附初始值
private final static int BTN_RADIUS=20;//拖动按钮的半径 private final static int BTN_CIRCLE_RADIUS=6;//拖动按钮的圆心半径 private final static int BAR_HEIGHT=6;//进度条的高度 private String barColor="#a82894ff"; private String circleColor="#902894ff"; private String txtColor="#ff2894ff"; private float currentValue=50;//当前值 private float maxValue=100;//最大值 private float minValue=0;//最小值 private boolean isShowText=false;//是否显示文字提示 private boolean isCanAdjust=false;//是否可以调节
3.实现init()方法,实例化画笔等属性
private void init(){mPaint = new Paint(); mPaint.setAntiAlias(true); // mPaint.setTextSize(16); mBound = new Rect();//用于测量文字的宽度,以便准确无误地显示文字内容 mPaint.getTextBounds(maxValue+"",0,(maxValue+"").length(),mBound); }
4.实现onMeasure(int arg0,int arg1)方法,测量控件的高度和宽度(由于是横向调节器,所以只需重新测量高度值就可以了,高度值和拖动按钮的半径有关)
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int height ; if (heightMode == MeasureSpec.EXACTLY){height = heightSize; } else {height = getPaddingTop() + BTN_RADIUS*2 + getPaddingBottom(); }setMeasuredDimension(widthSize, height); }
5.实现onDraw()方法,根据相应的属性值绘制界面
绘制分为4步进行,具体实现请看文章后面的完整代码;这一步的实现已经可以看到控件的显示效果
@Override @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) protected void onDraw(Canvas canvas) {drawBg(canvas);//绘制整体背景 drawBar(canvas);//绘制当前值的占比条 drawBtn(canvas);//绘制当前值得调节按钮 drawTxt(canvas);//绘制文本值(显示最大最小值及当前值) }
6.实现onTouchEvent()方法以响应事件,实现调节功能,需要注意一点,界面的刷新操作是在设置当前值时才能调用(即:界面是否刷新取决于当前值是否改变,调节最大最小值时,当前值也需要调节,以确保整个控件逻辑的正确)
public void setCurrentValue(float currentValue) {this.currentValue = currentValue>maxValue?maxValue:currentValue; this.currentValue = this.currentValue<minValue?minValue:this.currentValue; if(onValueChangeListener!=null) onValueChangeListener.onValueChange(this.currentValue); invalidate(); }public void setMaxValue(float maxValue) {this.maxValue = maxValue<minValue?minValue:maxValue; setCurrentValue(currentValue); mPaint.getTextBounds(this.maxValue+"",0,(this.maxValue+"").length(),mBound); }public void setMinValue(float minValue) {this.minValue = minValue>maxValue?maxValue:minValue; setCurrentValue(currentValue); }
private float preX; private boolean isMoveEvent=false;//用于判断当前事件是否为滑动事件 private boolean isDownInBtn=false;//用于判断是不是点击在滑动按钮上 @Override public boolean onTouchEvent(MotionEvent event) {if(!isCanAdjust) return true; switch (event.getAction()) {case MotionEvent.ACTION_DOWN:preX=event.getX(); isMoveEvent=false; isDownInBtn=isDownInBtn(preX); break; case MotionEvent.ACTION_MOVE:int disX=(int) (event.getX() - preX); if(Math.abs(disX)>3) isMoveEvent=true; preX=event.getX(); if(isDownInBtn){//响应移动事件 //计算当前值时,先计算出占比值再加上最小值,这样可以兼容负值计算 setCurrentValue((preX-getPaddingLeft()-BTN_RADIUS)/getBarWidth()*(maxValue-minValue)+minValue); }break; case MotionEvent.ACTION_UP:preX=event.getX(); if(!isMoveEvent){//响应点击事件 if(!isDownInBtn){//计算当前值时,先计算出占比值再加上最小值,这样可以兼容负值计算 setCurrentValue((preX-getPaddingLeft()-BTN_RADIUS)/getBarWidth()*(maxValue-minValue)+minValue); }}break; default:break; }return true; }
7.实现当前值变更回掉及各个功能的开关接口
以下是完整代码:
package com.hss.regulator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.os.Build; import android.support.annotation.RequiresApi; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; /** * Created by Administrator on 2017/8/14. */ public class RegulatorView extends View {private final static int BTN_RADIUS=20;//拖动按钮的半径 private final static int BTN_CIRCLE_RADIUS=6;//拖动按钮的圆心半径 private final static int BAR_HEIGHT=6;//进度条的高度 private String barColor="#a82894ff"; private String circleColor="#902894ff"; private String txtColor="#ff2894ff"; private float currentValue=50;//当前值 private float maxValue=100;//最大值 private float minValue=0;//最小值 private boolean isShowText=false;//是否显示文字提示 private boolean isCanAdjust=false;//是否可以调节 private Paint mPaint; private Rect mBound; public RegulatorView(Context context) {super(context); init(); }public RegulatorView(Context context, AttributeSet attrs) {super(context, attrs); init(); }public RegulatorView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr); init(); }@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)public RegulatorView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes); init(); }private void init(){mPaint = new Paint(); mPaint.setAntiAlias(true); // mPaint.setTextSize(16); mBound = new Rect();//用于测量文字的宽度,以便准确无误地显示文字内容 mPaint.getTextBounds(maxValue+"",0,(maxValue+"").length(),mBound); }private float preX; private boolean isMoveEvent=false;//用于判断当前事件是否为滑动事件 private boolean isDownInBtn=false;//用于判断是不是点击在滑动按钮上 @Override public boolean onTouchEvent(MotionEvent event) {if(!isCanAdjust) return true; switch (event.getAction()) {case MotionEvent.ACTION_DOWN:preX=event.getX(); isMoveEvent=false; isDownInBtn=isDownInBtn(preX); break; case MotionEvent.ACTION_MOVE:int disX=(int) (event.getX() - preX); if(Math.abs(disX)>3) isMoveEvent=true; preX=event.getX(); if(isDownInBtn){//响应移动事件 //计算当前值时,先计算出占比值再加上最小值,这样可以兼容负值计算 setCurrentValue((preX-getPaddingLeft()-BTN_RADIUS)/getBarWidth()*(maxValue-minValue)+minValue); }break; case MotionEvent.ACTION_UP:preX=event.getX(); if(!isMoveEvent){//响应点击事件 if(!isDownInBtn){//计算当前值时,先计算出占比值再加上最小值,这样可以兼容负值计算 setCurrentValue((preX-getPaddingLeft()-BTN_RADIUS)/getBarWidth()*(maxValue-minValue)+minValue); }}break; default:break; }return true; }private boolean isDownInBtn(float x){float left=getBarWidth()*(currentValue-minValue)/(maxValue-minValue)+getPaddingLeft(); float right=getBarWidth()*(currentValue-minValue)/(maxValue-minValue)+getPaddingLeft()+BTN_RADIUS*2; if(x>=left&&x<=right) return true; return false; }@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ // int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); // int width; int height ; if (heightMode == MeasureSpec.EXACTLY){height = heightSize; } else {height = getPaddingTop() + BTN_RADIUS*2 + getPaddingBottom(); }setMeasuredDimension(widthSize, height); }@Override @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)protected void onDraw(Canvas canvas) {drawBg(canvas);//绘制整体背景 drawBar(canvas);//绘制当前值的占比条 drawBtn(canvas);//绘制当前值得调节按钮 drawTxt(canvas);//绘制文本值(显示最大最小值及当前值) }@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)private void drawBg(Canvas canvas){mPaint.setColor(Color.WHITE); float left=getPaddingLeft()+BTN_RADIUS; float top=(getMeasuredHeight()-BAR_HEIGHT)/2.0f; float right= getBarWidth()+left; float bottom=top+BAR_HEIGHT; canvas.drawRoundRect(left,top,right,bottom,2,2,mPaint); // canvas.drawRect(left,top,right,bottom,mPaint); }@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)private void drawBar(Canvas canvas){mPaint.setColor(Color.parseColor(barColor)); float left=getPaddingLeft()+BTN_RADIUS; float top=(getMeasuredHeight()-BAR_HEIGHT)/2; float right; if(maxValue!=minValue)//处理最大和最小值相等的情况 right=getBarWidth()*(currentValue-minValue)/(maxValue-minValue)+left; else right= getBarWidth()+left; float bottom=top+BAR_HEIGHT; canvas.drawRoundRect(left,top,right,bottom,2,2,mPaint); // canvas.drawRect(left,top,right,bottom,mPaint); }private void drawBtn(Canvas canvas){mPaint.setColor(Color.parseColor(circleColor)); float cx; if(maxValue!=minValue)//处理最大和最小值相等的情况 cx=getBarWidth()*(currentValue-minValue)/(maxValue-minValue)+getPaddingLeft()+BTN_RADIUS; else cx=getBarWidth()+getPaddingLeft()+BTN_RADIUS; float cy=getMeasuredHeight()/2; canvas.drawCircle(cx,cy,BTN_RADIUS,mPaint); mPaint.setColor(Color.parseColor(barColor)); canvas.drawCircle(cx,cy,BTN_CIRCLE_RADIUS,mPaint); }private void drawTxt(Canvas canvas){if(!isShowText) return; mPaint.setColor(Color.parseColor(txtColor)); float x=getPaddingLeft()+BTN_RADIUS; float y=mPaint.getTextSize(); canvas.drawText(minValue+"",x,y,mPaint); float textWidth = mBound.width(); x=getWidth()-getPaddingRight()-BTN_RADIUS-textWidth; canvas.drawText(maxValue+"",x,y,mPaint); if(maxValue!=minValue)//处理最大和最小值相等的情况 x=getBarWidth()*(currentValue-minValue)/(maxValue-minValue)+getPaddingLeft()+BTN_RADIUS*2; else x=getBarWidth()+getPaddingLeft()+BTN_RADIUS*2; canvas.drawText(currentValue+"",x,y,mPaint); }private int getBarWidth(){return getMeasuredWidth()-getPaddingLeft()-getPaddingRight()-BTN_RADIUS*2; }public float getCurrentValue() {return currentValue; }public void setCurrentValue(float currentValue) {this.currentValue = currentValue>maxValue?maxValue:currentValue; this.currentValue = this.currentValue<minValue?minValue:this.currentValue; if(onValueChangeListener!=null) onValueChangeListener.onValueChange(this.currentValue); invalidate(); }public float getMaxValue() {return maxValue; }public void setMaxValue(float maxValue) {this.maxValue = maxValue<minValue?minValue:maxValue; setCurrentValue(currentValue); mPaint.getTextBounds(this.maxValue+"",0,(this.maxValue+"").length(),mBound); }public float getMinValue() {return minValue; }public void setMinValue(float minValue) {this.minValue = minValue>maxValue?maxValue:minValue; setCurrentValue(currentValue); }public boolean isShowText() {return isShowText; }public void setShowText(boolean showText) {isShowText = showText; }public boolean isCanAdjust() {return isCanAdjust; }public void setCanAdjust(boolean canAdjust) {isCanAdjust = canAdjust; }private OnValueChangeListener onValueChangeListener=null; public OnValueChangeListener getOnValueChangeListener() {return onValueChangeListener; }public void setOnValueChangeListener(OnValueChangeListener onValueChangeListener) {this.onValueChangeListener = onValueChangeListener; }public interface OnValueChangeListener{void onValueChange(float value); } }