android 带刻度的滑动条_Android实现滚动刻度尺效果

缘起

最近在帮人做一个计步器,其中涉及到身高、体重等信息的采集;我参考了众多app的实现,觉得"乐动力"中滑动刻度的方式比较优雅。于是乎,反编译了该app,结果发现它是采用图片的方式实现的,即ScrollView内嵌了一张带刻度的图片。

个人觉得该方式太不灵活,且对美工的依赖较大,于是便想自定义一个刻度尺控件。

需求分析

绘制刻度,区分整值刻度和普通刻度

红色指针始终在刻度尺的中间,表示当前的刻度

刻度的最大值和最小值可动态设置

刻度尺的高度或宽度可设置,设置后中间刻度不变

可滑动,滑动后当前刻度随之改变

涉及的知识点

View的机制

canvas绘图

Scroller工具类的使用

自定义View的属性

点击、滑动事件的处理

最终效果

由于简书上无法嵌入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);

}

处理滑动事件

在手指按下时,记录当前的x坐标(针对水平刻度尺)。

在手指滑动过程中,判断当前指针所指的刻度是否已经超出了边界,如果超出,则禁止滑动,同时刷新当前界面。

在手指抬起时,校正当前的刻度。

@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);

}

最后的说明

以上只是针对水平滑动刻度的实现,垂直滑动原理一致,在源码中已经实现,其中也有许多不够完善的地方,如:

第一次快速滑动时,可以超出边界,之后则不会;

开放的自定义属性不够(根据具体情况);

可以考虑将水平和垂直的实现,在一个类中完成,因为在实现过程中发现其实有很多代码都是类似的,只是个别参数属性的不同,在坐标系中,垂直可以看成是水平旋转了90°,之后有时间可以朝这个方向尝试下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Android应用中实现滑动刻度尺效果,可以使用SeekBar控件。SeekBar是一个滑动控件,可以让用户通过滑动选择数值。我们可以通过自定义SeekBar的样式来实现滑动刻度尺效果,以便用户可以方便地选择身高和体重。 以下是一个实现滑动刻度尺效果的示例代码: 1. 首先,在layout文件中添加SeekBar控件,例如: ``` <SeekBar android:id="@+id/height_seekbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:max="220" android:progress="170" android:progressDrawable="@drawable/custom_seekbar" android:thumb="@drawable/custom_thumb" /> ``` 在这个示例中,我们创建了一个id为height_seekbar的SeekBar控件,并设置了它的最大值和初始值。我们还指定了SeekBar的样式,包括进度和拇指图标,这些样式可以通过自定义drawable来实现。 2. 在drawable文件夹中创建custom_seekbar.xml文件,定义SeekBar的进度样式,例如: ``` <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@android:id/background"> <shape android:shape="rectangle"> <corners android:radius="8dp" /> <solid android:color="#EFEFEF" /> </shape> </item> <item android:id="@android:id/progress"> <clip> <shape android:shape="rectangle"> <corners android:radius="8dp" /> <solid android:color="#FF4081" /> </shape> </clip> </item> </layer-list> ``` 在这个示例中,我们创建了一个layer-list来定义SeekBar的进度样式。进度由两个矩形组成,一个代表背景,另一个代表进度。我们通过设置shape来定义矩形的圆角和颜色。 3. 在drawable文件夹中创建custom_thumb.xml文件,定义SeekBar的拇指图标样式,例如: ``` <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <size android:width="30dp" android:height="30dp" /> <solid android:color="#FF4081" /> </shape> ``` 在这个示例中,我们创建了一个圆形的拇指图标,设置了它的大小和颜色。 4. 在Java代码中添加SeekBar的监听器,例如: ``` SeekBar heightSeekBar = findViewById(R.id.height_seekbar); heightSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { // 在这里处理身高值的变化 } @Override public void onStartTrackingTouch(SeekBar seekBar) { // 在这里处理开始滑动SeekBar的事件 } @Override public void onStopTrackingTouch(SeekBar seekBar) { // 在这里处理停止滑动SeekBar的事件 } }); ``` 在这个示例中,我们获取了SeekBar控件的实例,并设置了它的监听器。当用户拖动SeekBar时,会回调onProgressChanged方法,并传递新的进度值。我们可以在这个方法中处理身高值的变化。在onStartTrackingTouch和onStopTrackingTouch方法中,我们可以处理开始和停止滑动SeekBar的事件。 希望这个示例能够对你有帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值