900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 自定义ViewGroup之游标卡尺的实现

自定义ViewGroup之游标卡尺的实现

时间:2024-01-17 22:14:55

相关推荐

自定义ViewGroup之游标卡尺的实现

效果图预览

1. 分析

1. 游标卡尺嘛首先得绘制一个尺子吧2. 有了尺子不得绘制刻度线3. 绘制具体刻度值4. 还要绘制能拨动的按钮,不然怎么叫游标卡尺5. 拨动尺子的时候应该是能实时看到数据

2. 技术实现原理

1. 尺子组成是一个长长的进度条加上带刻度线和刻度值的数据2. 进度条可以用canvas.drawRect画一个矩形3. 刻度线和刻度值分别用canvas.drawLine和canvas.drawText实现4. onTouchEvent处理手指拖动游标按钮拨动事件5. 按钮拨动的过程根据x轴的偏移值实时绘制拨动会的数据值

3.初始化一些东西

//刻度尺进度条的高度private int mPbHeight;//刻度长线的高度private float mLineMaxHeight;//刻度短线的高度private float mLineMinHeight;//每一小份刻度的宽度private float mPartWidth;//图片左右最小最大值private int mLeftMin;private int mRightMax;//刻度的左右间距private int mLeftMargin;private int mRightMargin;private Paint mValuePaint;//左右两边图片idprivate static final int LEFT_ICON_ID = 0x166666;private static final int RIGHT_ICON_ID = 0x166667;//文字大小private float mTextSize;//进度值的背景图片高度private int mValueBitmapHeight;//y轴上偏差值 防止高度太紧凑private int mOffsetY = dip2px(4);//控件的宽度private int mViewWidth;

3. onMeasure和onLayout处理

(一)onMeasure

//测量所有子控件

measureChildren(widthMeasureSpec,heightMeasureSpec);

@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);//测量所有子控件measureChildren(widthMeasureSpec,heightMeasureSpec);//得到当前控件的测量模式和测量大小int widthMode = MeasureSpec.getMode(widthMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);//wrap_contentint width = widthSize;int height = dip2px(120);width = widthMode == MeasureSpec.AT_MOST ? width : widthSize;height = heightMode == MeasureSpec.AT_MOST ? height : heightSize;setMeasuredDimension(width,height);this.mViewWidth = width;mLeftMin = mLeftMargin;mRightMax = width - mRightMargin;}

(二) onLayout

设置左右波动按钮的极限值

mLeftIcon.setLeftRightLimit(mLeftMargin,mRightMax);

mRightIcon.setLeftRightLimit(mLeftMargin,mRightMax);

//设置左右波动按钮的初始化中心点坐标

mLeftIcon.setCenterX(mLeftMargin + leftWidth / 2);

mRightIcon.setCenterX(mRightMax - rightWidth / 2 );

布局左右两个子View波动图片按钮的left,top,right,bottom值,放置好子View的位置

@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {for (int i = 0; i < getChildCount(); i++) {View childView = getChildAt(i);int cWidth = childView.getMeasuredWidth();int cHeight = childView.getMeasuredHeight();int left = 0;//左右可以拖动的图片距上面的高度=进度条的高度 + 最长刻度线的高度// + 刻度值字体大小的高度// + 拖动显示刻度值背景图片的高度 + 偏移量int top = (int) (mPbHeight + mLineMaxHeight + mTextSize+ mValueBitmapHeight + mOffsetY);int right = 0;//距底部的高度 = top + 图片的高度 - 距离底部的padding值int bottom = top + cHeight - getPaddingBottom();if(i == 0){left = mLeftMargin + getPaddingLeft();right = left + cWidth;}else if(i == 1){left = (mViewWidth - mRightMargin - cWidth - getPaddingRight());right = left + cWidth;}childView.layout(left,top,right,bottom);}int leftWidth = mLeftIcon.getMeasuredWidth();int rightWidth = mRightIcon.getMeasuredWidth();mPartWidth = (mViewWidth - (mLeftMargin + leftWidth / 2)- (mRightMargin + rightWidth / 2)) / (float) mRulerMax;mLeftIcon.setLeftRightLimit(mLeftMargin,mRightMax);mRightIcon.setLeftRightLimit(mLeftMargin,mRightMax);mLeftIcon.setCenterX(mLeftMargin + leftWidth / 2);mRightIcon.setCenterX(mRightMax - rightWidth / 2 );}

4. 绘制尺子进度条

mLeftIcon.getCenterX: 获取左边拨动按钮的x轴中心坐标值

mRightIcon.getCenterX(): 获取右边拨动按钮的x轴中心坐标值

//画进度条private void drawProgressBar(Canvas canvas) {//画进度条mPbPaint.setColor(Color.GRAY);int left = 0;int top = (int) (mLineMaxHeight + mTextSize + mValueBitmapHeight + mOffsetY);int right = mViewWidth;int bottom = top + mPbHeight;Rect rect = new Rect(left ,top,right,bottom);canvas.drawRect(rect, mPbPaint);//游标卡尺拨动过程中 实时进度条的绘制mPbPaint.setColor(Color.YELLOW);rect = new Rect(mLeftIcon.getCenterX(),top,mRightIcon.getCenterX(),bottom);canvas.drawRect(rect, mPbPaint);}

5. 画刻度线和刻度值

mRulerMax:代表最多画多少根刻度线

i % 10 == 0 & i+=2:代表每5根线画一个刻值

每10根线绘制一个具体数值

canvas.drawText(String.valueOf(i),startX,startY - mOffsetY,mRulerPaint);

//画刻度尺和刻度值private void drawRuler(Canvas canvas) {for (int i = 0; i <= mRulerMax; i+=2) {float startX = mLeftMargin + mLeftIcon.getMeasuredWidth() / 2 + i * mPartWidth;float startY,stopY;if(i % 10 == 0){mRulerPaint.setColor(ContextCompat.getColor(getContext(),R.color.color_333333));startY = mValueBitmapHeight + mTextSize + mOffsetY;stopY = startY + mLineMaxHeight;canvas.drawText(String.valueOf(i),startX,startY - mOffsetY,mRulerPaint);}else{startY = mValueBitmapHeight + (mLineMaxHeight - mLineMinHeight) + mTextSize + mOffsetY;stopY = startY + mLineMinHeight;}mRulerPaint.setColor(ContextCompat.getColor(getContext(),R.color.color_666666));canvas.drawLine(startX,startY,startX,stopY,mRulerPaint);}}

6. 绘制游标拨动过程中带背景图片实时刻度值的文字

private void drawRulerValue(Canvas canvas,ThumbImageView imageView) {int centerX = imageView.getCenterX();Bitmap valueBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.rod_place_icon);int top = 0;canvas.drawBitmap(valueBitmap,centerX - valueBitmap.getWidth() / 2,top,mValuePaint);canvas.drawText(String.valueOf(getValue(imageView)),centerX,top + valueBitmap.getHeight() / 2 + dip2px(3),mValuePaint);}

7. onTouchEvent触摸事件处理

根据手指的拖动范围实时计算波动图片按钮的中心点坐标,从而实时刷新具体刻度值范围,显示实时具体刻度值

private int mDownX = 0;@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()){case MotionEvent.ACTION_DOWN:mDownX = (int) event.getX();mIsMoving=false;break;case MotionEvent.ACTION_MOVE:mIsMoving = true;int moveX = (int) event.getX();int distanceX = moveX - mDownX;int left = mRect.left + distanceX;int right = mRect.right + distanceX;setCenterX((left + right) / 2);break;case MotionEvent.ACTION_UP:mIsMoving = false;mRangeSeekBar.postInvalidate();break;default:}return true;}/*** 设置图片中心位置,不超过左右的limit,就刷新整个控件,并且回调计算value值* @param centerX*/public void setCenterX(int centerX) {int left = centerX - mWidth / 2;int right = centerX + mWidth / 2;//左边极限值处理if(centerX < mLeftMin + mWidth / 2){Log.e("setCenterX",centerX+" : "+mLeftMin);left = mLeftMin;right = left + mWidth;}//右边极限值处理if(centerX > mRightMax - mWidth / 2){Log.e("setCenterX",centerX+" : "+mRightMax);left = mRightMax - mWidth;right = left + mWidth;}this.mCenterX = (left + right) / 2;//确保拨动过才刷新控件if(left != mRect.left || right != mRect.right){mRect.union(left,mRect.top,right,mRect.bottom);layout(left, mRect.top, right, mRect.bottom);mRangeSeekBar.postInvalidate();//回调处理 计算value值if(mOnScrollListener != null){int value = 100 * (mCenterX - mLeftMin - mWidth / 2) / (mRightMax - mLeftMin - mWidth);mOnScrollListener.onValue(value);}}}//回调接口定义//滑动监听接口public interface OnScrollListener{void onValue(int value);}private OnScrollListener mOnScrollListener;public void setOnScrollListener(OnScrollListener onScrollListener) {mOnScrollListener = onScrollListener;}

8. 小结和源码下载

小结:绘制并不难,主要还是需要计算边界范围,实时计算游标拨动过程中的数据值,然后绘制带背景的数据展示源码下载:最后统一提供下载地址

9.联系方式

QQ:1509815887

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。