这里有新鲜出炉的精品教程,程序狗速度看过来!
Android 是一种基于 Linux 的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由 Google 公司和开放手机联盟领导及开发。尚未有统一中文名称,中国大陆地区较多人使用 "安卓" 或 "安致"。
本篇文章主要介绍了 Android 实现滚动刻度尺效果,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
缘起
最近在帮人做一个计步器,其中涉及到身高、体重等信息的采集;我参考了众多 app 的实现,觉得 "乐动力" 中滑动刻度的方式比较优雅。于是乎,反编译了该 app,结果发现它是采用图片的方式实现的,即 ScrollView 内嵌了一张带刻度的图片。
个人觉得该方式太不灵活,且对美工的依赖较大,于是便想自定义一个刻度尺控件。
需求分析
涉及的知识点
最终效果
由于简书上无法嵌入 gif,为不影响效果,请移步 github 查看,如果觉得不错,帮忙给个 star ^_^https://github.com/LichFaker/ScaleView
实现过程
1、新建一个 class:HorizontalScaleScrollView, 继承自 View
2、在构造方法中获取自定义属性:
- protected void init(AttributeSet attrs) {
- // 获取自定义属性
- TypedArray ta = getContext().obtainStyledAttributes(attrs, ATTR);
- mMin = ta.getInteger(LF_SCALE_MIN, 0);
- mMax = ta.getInteger(LF_SCALE_MAX, 200);
- mScaleMargin = ta.getDimensionPixelOffset(LF_SCALE_MARGIN, 15);
- mScaleHeight = ta.getDimensionPixelOffset(LF_SCALE_HEIGHT, 20);
- ta.recycle();
- mScroller = new Scroller(getContext());
- }
3、重写 onMeasure,计算中间刻度
- @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;
- }
4、重写 onDraw,绘制刻度和指针
- protected void onDrawScale(Canvas canvas, Paint paint) {
- paint.setTextSize(mRectHeight / 4);
- for (int i = 0, k = mMin; i <= mMax - mMin; i++) {
- if (i % 10 == 0) {
- //整值
- canvas.drawLine(i * mScaleMargin, mRectHeight, i * mScaleMargin, mRectHeight - mScaleMaxHeight, paint);
- //整值文字
- canvas.drawText(String.valueOf(k), i * mScaleMargin, mRectHeight - mScaleMaxHeight - 20, paint);
- k += 10;
- } else {
- canvas.drawLine(i * mScaleMargin, mRectHeight, i * mScaleMargin, mRectHeight - mScaleHeight, paint);
- }
- }
- }
- protected void onDrawPointer(Canvas canvas, Paint paint) {
- paint.setColor(Color.RED);
- //每一屏幕刻度的个数/2
- int countScale = mScaleScrollViewRange / mScaleMargin / 2;
- //根据滑动的距离,计算指针的位置【指针始终位于屏幕中间】
- 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, 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);
- }
最后的说明
以上只是针对水平滑动刻度的实现,垂直滑动原理一致,在源码中已经实现,其中也有许多不够完善的地方,如:
来源: http://www.phperz.com/article/17/0822/337613.html