自定义控件是进阶高级必须掌握的知识点。自定义控件可以做到系统自带的控件做不到的效果。学习自定义控件也可以加深对View的理解。之后会写一系列博客,从图形绘制到控件的交互一步步分析如何做出自定义控件。这里先放一个例子,
源码在我的github:https://github.com/SingleShadowBlade/MySeekBar
欢迎star
这个是自定义控件,有详细注释
public class DoubleSeekBar extends View {
private int preX,preY;private int currentX,currentX2,currentY;//进度条左右位置private Bitmap bitmap1,bitmap2,bitmap3;private Canvas canvas;private Paint paint;private int mScollBarWidth,mScollBarHeight; //控件宽度=滑动条宽度+滑动块宽度private int thumbTop,thunbBootom;//滑块顶部与底部高private int offset;//控件的偏移量private int progressLow,progressHigh;private OnSeekBarChangeListener mBarChangeListener;public DoubleSeekBar(Context context, AttributeSet attrs) { super(context, attrs);
paint=new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.RED);
paint.setStrokeWidth(20);
bitmap1= BitmapFactory.decodeResource(getResources(),R.mipmap.back);
bitmap2= BitmapFactory.decodeResource(getResources(),R.mipmap.red);
bitmap3= BitmapFactory.decodeResource(getResources(),R.mipmap.thumb);
}//默认执行,计算view的宽高,在onDraw()之前protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = measureWidth(widthMeasureSpec); int height = measureHeight(heightMeasureSpec);
mScollBarWidth = width-offset;
mScollBarHeight=20;
currentX=offset;
currentX2=width-offset;
offset=20;
thumbTop=40;
thunbBootom=100;
progressLow =0;
progressHigh=100;
setMeasuredDimension(width, height);
}private int measureWidth(int measureSpec) { int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); // 声明一个临时变量来存储计算出的测量值int resultWidth = 0;
//wrap_contentif (specMode == MeasureSpec.AT_MOST) {
} //fill_parent或者精确值else if (specMode == MeasureSpec.EXACTLY) {
} return specSize;
}private int measureHeight(int measureSpec) { int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); int defaultHeight = 100; //wrap_contentif (specMode == MeasureSpec.AT_MOST) {
} //fill_parent或者精确值else if (specMode == MeasureSpec.EXACTLY) {
// defaultHeight = specSize-getPaddingLeft()-getPaddingRight();defaultHeight = specSize;
} return defaultHeight;
}//处理控件位置// @Override// public void layout(int l, int t, int r, int b) {// super.layout(l, t, r, b);// } //处理手势@Overridepublic boolean onTouchEvent(MotionEvent event) { int x= (int) event.getX(); switch (event.getAction()){ case MotionEvent.ACTION_DOWN:
preX=x; break; case MotionEvent.ACTION_MOVE: if(preX>mScollBarWidth/2){ if(x>mScollBarWidth){
currentX2=mScollBarWidth;
}else{
currentX2=x;
} //右滑块进度progressHigh=(currentX2)*100/mScollBarWidth;//// Log.e("tag","currentX2"+currentX2);// Log.e("tag","mScollBarWidth"+mScollBarWidth);// Log.e("tag","progressHigh"+progressHigh);}else {
if(x<offset){
currentX=offset;
}else{
currentX=x;
} //左滑块进度progressLow = (currentX-offset)*100/mScollBarWidth;// Log.e("tag","currentX"+currentX);// Log.e("tag","mScollBarWidth"+mScollBarWidth);// Log.e("tag","progressLow"+progressLow);}
if(mBarChangeListener!=null){
mBarChangeListener.onProgressChanged(this,progressLow,progressHigh);
} break; case MotionEvent.ACTION_UP:
invalidate(); break;
} return true;
}@Overrideprotected void onDraw(Canvas canvas) { super.onDraw(canvas); //绘制背景Rect rectBack=new Rect(offset+getPaddingLeft(),0,mScollBarWidth-getPaddingRight(),mScollBarHeight);
canvas.drawBitmap(bitmap1,null,rectBack,paint); //绘制前景Rect rectRed=new Rect(currentX+getPaddingLeft(),0,currentX2-getPaddingRight(),mScollBarHeight);
canvas.drawBitmap(bitmap2,null,rectRed,paint); //绘制左滑块Rect rect1=new Rect(currentX-offset+getPaddingLeft(),thumbTop,currentX+offset+getPaddingLeft(),thunbBootom);
canvas.drawBitmap(bitmap3,null,rect1,paint); //绘制右滑块、getPaddingRight()设置paddingRight,其他同理Rect rect2=new Rect(currentX2-offset-getPaddingRight(),thumbTop,currentX2+offset-getPaddingRight(),thunbBootom);
canvas.drawBitmap(bitmap3,null,rect2,paint);
invalidate();
}public void setOnSeekBarChangeListener(OnSeekBarChangeListener mListener) { this.mBarChangeListener = mListener;
}//回调函数,在滑动时实时调用,改变输入框的值public interface OnSeekBarChangeListener {
//滑动前public void onProgressBefore();
//滑动时public void onProgressChanged(DoubleSeekBar seekBar, int progressLow,
int progressHigh); //滑动后public void onProgressAfter();}}
使用方法:
<com.gjl.myseekbar.DoubleSeekBarandroid:id="@+id/dsb"android:layout_width="300dp"android:layout_height="50dp"/>
MainActivity
public class MainActivity extends AppCompatActivity implements DoubleSeekBar.OnSeekBarChangeListener {
private DoubleSeekBar dsb;private TextView tv_low,tv_high;@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dsb = (DoubleSeekBar) findViewById(R.id.dsb);
dsb.setOnSeekBarChangeListener(this);
tv_low= (TextView) findViewById(R.id.tv_low);
tv_high= (TextView) findViewById(R.id.tv_high);
}@Overridepublic void onProgressBefore() {
}@Overridepublic void onProgressChanged(DoubleSeekBar seekBar, int progressLow, int progressHigh) {
Log.e("tag","progressLow"+progressLow);
Log.e("tag","progressHigh"+progressHigh);
tv_low.setText(""+progressLow);
tv_high.setText(""+progressHigh);
}@Overridepublic void onProgressAfter() {
}}
共同學習,寫下你的評論
評論加載中...
作者其他優質文章