垂直和水平滑动刻度尺
2016-07-28 15:07
501 查看
公司有个需求需要自定义的滑动设置升高体重的界面。首先感谢github上的这个开源让我学习。https://github.com/LichFaker/ScaleView。因为需求有点不一样。需要自定义颜色。所以在它的基础上改了画线的位置和刻度的颜色。看一下界面。
上代码。首先需要有个基础的基类BaseScaleView。
接下来是水平的刻度尺。
对了,忘了加上刻度尺的几个自定义属性。在values文件夹中加上scale_attrs.xml属性文件
目前支持的自定义属性:
因为无法设置默认选中刻度。这点有点不好。公司需求是需要默认选中170厘米和60公斤。后来通过各种方法把默认选中的问题解决了。这个后面说。下面是在布局中的使用,添加使用下面代码。
水平刻度尺跟垂直刻度尺的用法也是一样的。就不一一贴代码了。
接下来说说默认选中的问题,就比如要选中170厘米来说,一开始我是去算最小值到170的每一个刻度指尖的距离。然后还要得到这个控件的高度。就是这个高度问题困扰了我很久。
直接用scaleScrollView.getHeight();scaleScrollView.getMeasuredHeight();无法得到控件的高度。试过好多方法还是不行。后来查到了是控件还没初始化完全无法得到高度。后来查到了一个方法,是控件画完之后的回调接口。在该接口里面获取了控件的高度。
就写到这里了,因为工作有点忙,代码也没好好整理。请多多指出不对的地方,共勉。
上代码。首先需要有个基础的基类BaseScaleView。
public abstract class BaseScaleView extends View { public static final int[] ATTR = { R.attr.scale_view_min, R.attr.scale_view_max, R.attr.scale_view_margin, R.attr.scale_view_height, }; public static final int SCALE_MIN = 0; public static final int SCALE_MAX = 1; public static final int SCALE_MARGIN = 2; public static final int SCALE_HEIGHT = 3; private static final String TAG = null; protected int mMax; //最大刻度 protected int mMin; // 最小刻度 protected int mCountScale; //滑动的总刻度 protected int mScaleScrollViewRange; protected int mScaleMargin; //刻度间距 protected int mScaleHeight; //刻度线的高度 public int getmScaleMargin() { return mScaleMargin; } public void setmScaleMargin(int mScaleMargin) { this.mScaleMargin = mScaleMargin; } public int getmScaleHeight() { return mScaleHeight; } public void setmScaleHeight(int mScaleHeight) { this.mScaleHeight = mScaleHeight; } protected int mScaleMaxHeight; //整刻度线高度 protected int mRectWidth; //总宽度 protected int mRectHeight; //高度 protected Scroller mScroller; protected int mScrollLastX; protected int mTempScale; // 用于判断滑动方向 protected int mMidCountScale; //中间刻度 private int width; protected OnScrollListener mScrollListener; public interface OnScrollListener { void onScaleScroll(int scale); } public BaseScaleView(Context context) { super(context); init(null); } public BaseScaleView(Context context, AttributeSet attrs) { super(context, attrs); init(attrs); } public BaseScaleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(attrs); } // @TargetApi(Build.VERSION_CODES.LOLLIPOP) // public BaseScaleView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { // super(context, attrs, defStyleAttr, defStyleRes); // init(attrs); // } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub super.onMeasure(widthMeasureSpec, heightMeasureSpec); } protected void init(AttributeSet attrs) { // 获取自定义属性 TypedArray ta = getContext().obtainStyledAttributes(attrs, ATTR); mMin = ta.getInteger(SCALE_MIN, 0); mMax = ta.getInteger(SCALE_MAX, 240); mScaleMargin = ta.getDimensionPixelOffset(SCALE_MARGIN, 15); mScaleHeight = ta.getDimensionPixelOffset(SCALE_HEIGHT, 20); WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); width = wm.getDefaultDisplay().getWidth(); ta.recycle(); mScroller = new Scroller(getContext()); initVar(); } @Override protected void onDraw(Canvas canvas) { // 画笔 Paint paint = new Paint(); paint.setColor(Color.GRAY); // 抗锯齿 paint.setAntiAlias(true); // 设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰 paint.setDither(true); // 空心 paint.setStyle(Paint.Style.STROKE); // 文字居中 paint.setTextAlign(Paint.Align.CENTER); onDrawLine(canvas, paint); onDrawScale(canvas, paint); //画刻度 onDrawPointer(canvas, paint); //画指针 super.onDraw(canvas); } protected abstract void initVar(); // 画线 protected abstract void onDrawLine(Canvas canvas, Paint paint); // 画刻度 protected abstract void onDrawScale(Canvas canvas, Paint paint); // 画指针 protected abstract void onDrawPointer(Canvas canvas, Paint paint); /** * 使用Scroller时需重写 */ @Override public void computeScroll() { super.computeScroll(); // 判断Scroller是否执行完毕 if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); // 通过重绘来不断调用computeScroll invalidate(); } } public void smoothScrollBy(int dx, int dy) { mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy); } public void smoothScrollTo(int fx, int fy) { int dx = fx - mScroller.getFinalX(); int dy = fy - mScroller.getFinalY(); smoothScrollBy(dx, dy); } /** * 设置回调监听 * * @param listener */ public void setOnScrollListener(OnScrollListener listener) { this.mScrollListener = listener; } public void setmMidCountScale(int mMidCountScale) { this.mMidCountScale = mMidCountScale; } public int getmMidCountScale() { return mMidCountScale; } public int getmScaleScrollViewRange() { return mScaleScrollViewRange; } }其中垂直刻度尺和水平刻度尺都继承于它。首先看一下垂直刻度尺的类。
public class VerticalScaleScrollView extends BaseScaleView { private static final String TAG = "VerticalScaleScrollView"; public static int defaultY = 0; public VerticalScaleScrollView(Context context) { super(context); } public VerticalScaleScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public VerticalScaleScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } //@TargetApi(Build.VERSION_CODES.LOLLIPOP) // public VerticalScaleScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { // super(context, attrs, defStyleAttr, defStyleRes); // } @Override protected void initVar() { mRectHeight = (mMax - mMin) * mScaleMargin; Log.e(TAG, "mRectHeight"+mRectHeight+"mMax"+mMax+"mMin"+mMin+":::"+mScaleScrollViewRange); mRectWidth = mScaleHeight * 8; mScaleMaxHeight = mScaleHeight * 2; // 设置layoutParams ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(mRectWidth, mRectHeight); this.setLayoutParams(lp); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // int width = MeasureSpec.makeMeasureSpec(mRectWidth, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, heightMeasureSpec); mScaleScrollViewRange = getMeasuredHeight(); mTempScale = mScaleScrollViewRange / mScaleMargin / 2 + mMin; mMidCountScale = mScaleScrollVie 4000 wRange / mScaleMargin / 2 + mMin; } @Override protected void onDrawLine(Canvas canvas, Paint paint) { //canvas.drawLine(0, 0, 0, mRectHeight, paint); } @Override protected void onDrawScale(Canvas canvas, Paint paint) { paint.setTextSize(mRectWidth / 4); Paint linePaint = new Paint(); WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); int width = wm.getDefaultDisplay().getWidth(); int height = wm.getDefaultDisplay().getHeight(); for (int i = 0, k = mMin; i <= mMax - mMin; i++) { if (i % 10 == 0) { //整值,第三个参数可以修改线的长短 linePaint.setTextSize(mRectWidth / 6); linePaint.setColor(Color.GREEN); linePaint.setStrokeWidth(10); //画字的笔 Paint textPaint = new Paint(); textPaint.setTextSize(mRectWidth /5); textPaint.setColor(Color.BLACK); textPaint.setAntiAlias(true); textPaint.setStrokeWidth(7); canvas.drawLine(width-130, i * mScaleMargin, width, i * mScaleMargin, linePaint); //整值文字 canvas.drawText(String.valueOf(k), width-150, i * mScaleMargin + paint.getTextSize()+paint.getTextSize()/3, textPaint); canvas.drawText("cm", width-100, i * mScaleMargin + paint.getTextSize()+paint.getTextSize()/3, textPaint); k += 10; } else if(i%5==0){ linePaint.setColor(Color.GRAY); linePaint.setTextSize(mRectWidth/4); linePaint.setStrokeWidth(5); canvas.drawLine(width-50, i *mScaleMargin, width, i * mScaleMargin, linePaint); } else { linePaint.setColor(Color.GRAY); linePaint.setTextSize(mRectWidth/4); linePaint.setStrokeWidth(5); canvas.drawLine(width-20, i * mScaleMargin, width, i * mScaleMargin, linePaint); } } } private boolean flag = true; @Override protected void onDrawPointer(Canvas canvas, Paint paint) { paint.setColor(Color.RED); paint.setStrokeWidth(7); WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); int width = wm.getDefaultDisplay().getWidth(); //每一屏幕刻度的个数/2 int countScale = mScaleScrollViewRange / mScaleMargin / 2; //根据滑动的距离,计算指针的位置【指针始终位于屏幕中间】 int finalY = mScroller.getFinalY(); int tmpCountScale = 0; //滑动的刻度 tmpCountScale = (int) Math.rint((double) finalY / (double) mScaleMargin); //四舍五入取整 //总刻度 countScale mCountScale = tmpCountScale + countScale + mMin; if (mScrollListener != null) { //回调方法 mScrollListener.onScaleScroll(mCountScale); } canvas.drawLine(width-150, countScale * mScaleMargin + finalY, //mScaleMaxHeight + mScaleHeight, width, countScale * mScaleMargin + finalY, paint); } @Override public boolean onTouchEvent(MotionEvent event) { int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (mScroller != null && !mScroller.isFinished()) { mScroller.abortAnimation(); } mScrollLastX = y; return true; case MotionEvent.ACTION_MOVE: int dataY = mScrollLastX - y; if (mCountScale - mTempScale < 0) { //向下边滑动 if (mCountScale <= mMin && dataY <= 0) //禁止继续向下滑动 return super.onTouchEvent(event); } else if (mCountScale - mTempScale > 0) { //向上边滑动 if (mCountScale >= mMax && dataY >= 0) //禁止继续向上滑动 return super.onTouchEvent(event); } smoothScrollBy(0, dataY); mScrollLastX = y; postInvalidate(); mTempScale = mCountScale; return true; case MotionEvent.ACTION_UP: if (mCountScale < mMin) mCountScale = mMin; if (mCountScale > mMax) mCountScale = mMax; int finalY = (mCountScale - mMidCountScale) * mScaleMargin; mScroller.setFinalY(finalY); //纠正指针位置 postInvalidate(); return true; } return super.onTouchEvent(event); } }其中onDrawScale()方法是画刻度和数字的方法。而onDrawPointer()是画中间红色指标的方法。
接下来是水平的刻度尺。
public class HorizontalScaleScrollView extends BaseScaleView { public HorizontalScaleScrollView(Context context) { super(context); } public HorizontalScaleScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public HorizontalScaleScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } // public HorizontalScaleScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { // super(context, attrs, defStyleAttr, defStyleRes); // } @Override protected void initVar() { mRectWidth = (mMax - mMin) * mScaleMargin; mRectHeight = mScaleHeight * 8; mScaleMaxHeight = mScaleHeight * 2; // 设置layoutParams ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(mRectWidth, mRectHeight); this.setLayoutParams(lp); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int height=MeasureSpec.makeMeasureSpec(mRectHeight, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, height); mScaleScrollViewRange = getMeasuredWidth(); mTempScale = mScaleScrollViewRange / mScaleMargin / 2 + mMin; mMidCountScale = mScaleScrollViewRange / mScaleMargin / 2 + mMin; } @Override protected void onDrawLine(Canvas canvas, Paint paint) { //canvas.drawLine(0, mRectHeight, mRectWidth, mRectHeight, paint); } @Override protected void onDrawScale(Canvas canvas, Paint paint) { paint.setTextSize(mRectHeight / 4); paint.setStrokeWidth(5); paint.setColor(Color.GRAY); WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); int height = wm.getDefaultDisplay().getHeight(); Paint linePaint = new Paint(); for (int i = 0, k = mMin; i <= mMax - mMin; i++) { if (i % 10 == 0) { //整值 linePaint.setTextSize(mRectHeight / 6); linePaint.setColor(Color.GREEN); linePaint.setStrokeWidth(10); Paint textPaint = new Paint(); textPaint.setTextSize(30); textPaint.setAntiAlias(true); textPaint.setColor(Color.BLACK); canvas.drawLine(i * mScaleMargin, height/2, i * mScaleMargin, mRectHeight - mScaleMaxHeight-20, linePaint); //整值文字 canvas.drawText(String.valueOf(k), i * mScaleMargin-textPaint.getTextSize()+linePaint.getStrokeWidth(), mRectHeight - mScaleMaxHeight - 20, textPaint); k += 10; }else if(i%5==0){ canvas.drawLine(i * mScaleMargin, mRectHeight, i * mScaleMargin, mRectHeight - mScaleHeight-10, paint); } else { canvas.drawLine(i * mScaleMargin, mRectHeight, i * mScaleMargin, mRectHeight - mScaleHeight, paint); } } } @Override protected void onDrawPointer(Canvas canvas, Paint paint) { paint.setColor(Color.RED); //每一屏幕刻度的个数/2 int countScale = mScaleScrollViewRange / mScaleMargin / 2; Log.e("TAG", "屏幕刻度的个数"+countScale); //根据滑动的距离,计算指针的位置【指针始终位于屏幕中间】 int finalX = mScroller.getFinalX(); //滑动的刻度 int tmpCountScale = (int) Math.rint((double) finalX / (double) mScaleMargin); //四舍五入取整 //总刻度 mCountScale = tmpCountScale + countScale + mMin; if (mScrollListener != null) { //回调方法 mScrollListener.onScaleScroll(mCountScale); } canvas.drawLine(countScale * mScaleMargin + finalX, mRectHeight, countScale * mScaleMargin + finalX, mRectHeight - mScaleMaxHeight - mScaleHeight-30, paint); } @Override public boolean onTouchEvent(MotionEvent event) { int x = (int) event.getX(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (mScroller != null && !mScroller.isFinished()) { mScroller.abortAnimation(); } mScrollLastX = x; return true; case MotionEvent.ACTION_MOVE: int dataX = mScrollLastX - x; if (mCountScale - mTempScale < 0) { //向右边滑动 if (mCountScale <= mMin && dataX <= 0) //禁止继续向右滑动 return super.onTouchEvent(event); } else if (mCountScale - mTempScale > 0) { //向左边滑动 if (mCountScale >= mMax && dataX >= 0) //禁止继续向左滑动 return super.onTouchEvent(event); } smoothScrollBy(dataX, 0); mScrollLastX = x; postInvalidate(); mTempScale = mCountScale; return true; case MotionEvent.ACTION_UP: if (mCountScale < mMin) mCountScale = mMin; if (mCountScale > mMax) mCountScale = mMax; int finalX = (mCountScale - mMidCountScale) * mScaleMargin; mScroller.setFinalX(finalX); //纠正指针位置 postInvalidate(); return true; } return super.onTouchEvent(event); } }其实垂直和水平的刻度尺的写法都大同小异。只是把刻度和文字的画的位置不同而已。线的粗细长短颜色都可以根据需求自己修改。
对了,忘了加上刻度尺的几个自定义属性。在values文件夹中加上scale_attrs.xml属性文件
<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="scale_view_max" format="integer" /> <attr name="scale_view_min" format="integer" /> <attr name="scale_view_height" format="dimension" /> <attr name="scale_view_margin" format="dimension" /> </resources>
目前支持的自定义属性:
scale_view_max最大值
scale_view_min最小值
scale_view_height刻度的高度
scale_view_margin刻度的间距
layout_width可动态调整
因为无法设置默认选中刻度。这点有点不好。公司需求是需要默认选中170厘米和60公斤。后来通过各种方法把默认选中的问题解决了。这个后面说。下面是在布局中的使用,添加使用下面代码。
<com.hyx.fitbit.view.VerticalScaleScrollView android:id="@+id/verticalScale" android:layout_marginTop="60dp" app:scale_view_max="240" app:scale_view_min="140" app:scale_view_height="15dip" app:scale_view_margin="15dip" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" />下面是在代码中使用垂直刻度尺
VerticalScaleScrollView scaleScrollView = (VerticalScaleScrollView) findViewById(R.id.verticalScale);下面是滑动时间刻度的监听
scaleScrollView.setOnScrollListener(new HorizontalScaleScrollView.OnScrollListener() { @Override public void onScaleScroll(int scale) { height_text.setText(String.valueOf(scale)); //float y = scaleScrollView.getScaleY(); } });
水平刻度尺跟垂直刻度尺的用法也是一样的。就不一一贴代码了。
接下来说说默认选中的问题,就比如要选中170厘米来说,一开始我是去算最小值到170的每一个刻度指尖的距离。然后还要得到这个控件的高度。就是这个高度问题困扰了我很久。
直接用scaleScrollView.getHeight();scaleScrollView.getMeasuredHeight();无法得到控件的高度。试过好多方法还是不行。后来查到了是控件还没初始化完全无法得到高度。后来查到了一个方法,是控件画完之后的回调接口。在该接口里面获取了控件的高度。
ViewTreeObserver vto = scaleScrollView.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { scaleScrollView.getViewTreeObserver().removeGlobalOnLayoutListener(this); viewHeight = scaleScrollView.getHeight(); countScale = viewHeight/ getmScaleMargin / 2; countScale = 30-countScale; scaleScrollView.smoothScrollTo(0, countScale*getmScaleMargin); Log.e(TAG, "高:"+viewHeight); scaleScrollView.getWidth(); } });这样设置了的话。刻度尺就会默认滑动到170。其中的30是最小值140到默认选中170间的值。然后水平公斤刻度尺的那个 也是同样的做法让它默认选中60公斤。代码如下
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { scaleScrollView.getViewTreeObserver().removeGlobalOnLayoutListener(this); width = scaleScrollView.getWidth(); countScale = width/getmScaleMargin/2; countScale = 30 - countScale; scaleScrollView.smoothScrollTo(countScale*getmScaleMargin, 0); } });其实原理一样。只不过获取高度变成了获取宽度。
就写到这里了,因为工作有点忙,代码也没好好整理。请多多指出不对的地方,共勉。
相关文章推荐
- 查看github pages文档的方式
- 介绍一款信息管理系统的开源框架---jeecg
- 源码被倒卖,大厂薅羊毛,开源真的只能被予取予求?
- 使用BAE的基于Web.py的简单博客程序
- 专家解读:开源软件项目是否会被限制出口?
- 专家解读:开源软件项目是否会被限制出口?
- fuse-dfs的设定手册
- Centos下***(pptpd)的部署
- 6 个托管 git 仓库的地方
- jquery mobile 实现自定义confirm确认框效果的简单实例
- C#实现自定义双击事件
- WinForm实现自定义右下角提示效果的方法
- 开源MySQL高效数据仓库解决方案:Infobright详细介绍
- 一款超酷的Android自定义加载控件
- Android自定义View实现照片裁剪框与照片裁剪功能
- MFC自定义消息的实现方法
- C#实现ProperTyGrid自定义属性的方法
- 两分钟学会如何在github托管代码