服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Android - Android自定义标尺滑动选择值效果

Android自定义标尺滑动选择值效果

2022-08-07 13:37676598624 Android

这篇文章主要为大家详细介绍了Android自定义标尺滑动选择值效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了Android实现滑动标尺选择值,效果图

Android自定义标尺滑动选择值效果

1.自定义属性attrs.xml

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<declare-styleable name="RulerView">
    <attr name="textColor" format="color" />
    <attr name="textSize" format="dimension" />
    <attr name="lineColor" format="color" />
    <attr name="lineSpaceWidth" format="dimension" />
    <attr name="lineWidth" format="dimension" />
    <attr name="lineMaxHeight" format="dimension" />
    <attr name="lineMidHeight" format="dimension" />
    <attr name="lineMinHeight" format="dimension" />
    <attr name="textMarginTop" format="dimension" />
    <attr name="alphaEnable" format="boolean" />
    <attr name="minValue" format="float"/>
    <attr name="maxValue" format="float"/>
    <attr name="selectorValue" format="float"/>
    <attr name="perValue" format="float"/>
</declare-styleable>

2.自定义RulerView

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.Scroller;
 
 
public class RulerView extends View {
 
  private int mMinVelocity;
  private Scroller mScroller; //Scroller是一个专门用于处理滚动效果的工具类  用mScroller记录/计算View滚动的位置,再重写View的computeScroll(),完成实际的滚动
  private VelocityTracker mVelocityTracker; //主要用跟踪触摸屏事件(flinging事件和其他gestures手势事件)的速率。
  private int mWidth;
  private int mHeight;
 
  private float mSelectorValue = 50.0f; // 未选择时 默认的值 滑动后表示当前中间指针正在指着的值
  private float mMaxValue = 200;    // 最大数值
  private float mMinValue = 100.0f;   //最小的数值
  private float mPerValue = 1;     //最小单位 如 1:表示 每2条刻度差为1.  0.1:表示 每2条刻度差为0.1
  // 在demo中 身高mPerValue为1 体重mPerValue 为0.1
 
  private float mLineSpaceWidth = 5// 尺子刻度2条线之间的距离
  private float mLineWidth = 4;     // 尺子刻度的宽度
 
  private float mLineMaxHeight = 420// 尺子刻度分为3中不同的高度。 mLineMaxHeight表示最长的那根(也就是 10的倍数时的高度)
  private float mLineMidHeight = 30// mLineMidHeight 表示中间的高度(也就是 5 15 25 等时的高度)
  private float mLineMinHeight = 17// mLineMinHeight 表示最短的那个高度(也就是 1 2 3 4 等时的高度)
 
  private float mTextMarginTop = 10//o
  private float mTextSize = 30;     //尺子刻度下方数字 textsize
 
  private boolean mAlphaEnable = false; // 尺子 最左边 最后边是否需要透明 (透明效果更好点)
 
  private float mTextHeight;      //尺子刻度下方数字 的高度
 
  private Paint mTextPaint;       // 尺子刻度下方数字( 也就是每隔10个出现的数值) paint
  private Paint mLinePaint;       // 尺子刻度 paint
 
  private int mTotalLine;        //共有多少条 刻度
  private int mMaxOffset;        //所有刻度 共有多长
  private float mOffset;        // 默认状态下,mSelectorValue所在的位置 位于尺子总刻度的位置
  private int mLastX, mMove;
  private OnValueChangeListener mListener; // 滑动后数值回调
 
  private int mLineColor = Color.GRAY;  //刻度的颜色
  private int mTextColor = Color.BLACK;  //文字的颜色
 
 
  public RulerView(Context context) {
    this(context, null);
 
  }
 
  public RulerView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
  }
 
  public RulerView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context, attrs);
  }
 
  protected void init(Context context, AttributeSet attrs) {
    mScroller = new Scroller(context);
    this.mLineSpaceWidth = myfloat(25.0F);
    this.mLineWidth = myfloat(2.0F);
    this.mLineMaxHeight = myfloat(100.0F);
    this.mLineMidHeight = myfloat(60.0F);
    this.mLineMinHeight = myfloat(40.0F);
    this.mTextHeight = myfloat(40.0F);
 
 
    final TypedArray typedArray = context.obtainStyledAttributes(attrs,
        R.styleable.RulerView);
 
    mAlphaEnable = typedArray.getBoolean(R.styleable.RulerView_alphaEnable, mAlphaEnable);
 
    mLineSpaceWidth = typedArray.getDimension(R.styleable.RulerView_lineSpaceWidth, mLineSpaceWidth);
    mLineWidth = typedArray.getDimension(R.styleable.RulerView_lineWidth, mLineWidth);
    mLineMaxHeight = typedArray.getDimension(R.styleable.RulerView_lineMaxHeight, mLineMaxHeight);
    mLineMidHeight = typedArray.getDimension(R.styleable.RulerView_lineMidHeight, mLineMidHeight);
    mLineMinHeight = typedArray.getDimension(R.styleable.RulerView_lineMinHeight, mLineMinHeight);
    mLineColor = typedArray.getColor(R.styleable.RulerView_lineColor, mLineColor);
 
    mTextSize = typedArray.getDimension(R.styleable.RulerView_textSize, mTextSize);
    mTextColor = typedArray.getColor(R.styleable.RulerView_textColor, mTextColor);
    mTextMarginTop = typedArray.getDimension(R.styleable.RulerView_textMarginTop, mTextMarginTop);
 
    mSelectorValue = typedArray.getFloat(R.styleable.RulerView_selectorValue, 0.0f);
    mMinValue = typedArray.getFloat(R.styleable.RulerView_minValue, 0.0f);
    mMaxValue = typedArray.getFloat(R.styleable.RulerView_maxValue, 100.0f);
    mPerValue = typedArray.getFloat(R.styleable.RulerView_perValue, 0.1f);
 
 
    mMinVelocity = ViewConfiguration.get(getContext()).getScaledMinimumFlingVelocity();
 
    mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mTextPaint.setTextSize(mTextSize);
    mTextPaint.setColor(mTextColor);
    mTextHeight = getFontHeight(mTextPaint);
 
    mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mLinePaint.setStrokeWidth(mLineWidth);
    mLinePaint.setColor(mLineColor);
 
 
    // setValue(1990, 1940, 2016, 1);
 
  }
 
 
  public static int myfloat(float paramFloat) {
    return (int) (0.5F + paramFloat * 1.0f);
  }
 
  private float getFontHeight(Paint paint) {
    Paint.FontMetrics fm = paint.getFontMetrics();
    return fm.descent - fm.ascent;
  }
 
 
  /**
   * @param selectorValue 未选择时 默认的值 滑动后表示当前中间指针正在指着的值
   * @param minValue   最大数值
   * @param maxValue   最小的数值
   * @param per      最小单位 如 1:表示 每2条刻度差为1.  0.1:表示 每2条刻度差为0.1 在demo中 身高mPerValue为1 体重mPerValue 为0.1
   */
  public void setValue(float selectorValue, float minValue, float maxValue, float per) {
    this.mSelectorValue = selectorValue;
    this.mMaxValue = maxValue;
    this.mMinValue = minValue;
    this.mPerValue = (int) (per * 10.0f);
    this.mTotalLine = ((int) ((mMaxValue * 10 - mMinValue * 10) / mPerValue)) + 1;
 
 
    mMaxOffset = (int) (-(mTotalLine - 1) * mLineSpaceWidth);
    mOffset = (mMinValue - mSelectorValue) / mPerValue * mLineSpaceWidth * 10;
    invalidate();
    setVisibility(VISIBLE);
  }
 
  public void setOnValueChangeListener(OnValueChangeListener listener) {
    mListener = listener;
  }
 
  @Override
  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
 
    super.onSizeChanged(w, h, oldw, oldh);
    if (w > 0 && h > 0) {
      mWidth = w;
      mHeight = h;
    }
  }
 
  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
 
    float left, height;
    String value;
    int alpha = 0;
    float scale;
    int srcPointX = mWidth / 2;
    for (int i = 0; i < mTotalLine; i++) {
      left = srcPointX + mOffset + i * mLineSpaceWidth;
 
      if (left < 0 || left > mWidth) {
        continue; // 先画默认值在正中间,左右各一半的view。 多余部分暂时不画(也就是从默认值在中间,画旁边左右的刻度线)
      }
 
      /*文字*/
      if (i % 10 == 0) {
        value = String.valueOf((int) (mMinValue + i * mPerValue / 10));
        if (mAlphaEnable) {
          mTextPaint.setAlpha(alpha);
        }
        canvas.drawText(value, left - mTextPaint.measureText(value) / 2,
            mTextHeight, mTextPaint);  // 在为整数时,画 数值
      }
 
      /*线条*/
      if (i % 10 == 0) {
        height = mLineMinHeight;
      } else if (i % 5 == 0) {
        height = mLineMidHeight;
      } else {
        height = mLineMaxHeight;
      }
      if (mAlphaEnable) {
        scale = 1 - Math.abs(left - srcPointX) / srcPointX;
        alpha = (int) (255 * scale * scale);
 
        mLinePaint.setAlpha(alpha);
      }
      canvas.drawLine(left, mLineMaxHeight + mTextMarginTop + mTextHeight, left, height, mLinePaint);
 
    }
  }
 
  @Override
  public boolean onTouchEvent(MotionEvent event) {
    int action = event.getAction();
    int xPosition = (int) event.getX();
 
    if (mVelocityTracker == null) {
      mVelocityTracker = VelocityTracker.obtain();
    }
    mVelocityTracker.addMovement(event);
 
    switch (action) {
      case MotionEvent.ACTION_DOWN:
        mScroller.forceFinished(true);
        mLastX = xPosition;
        mMove = 0;
        break;
      case MotionEvent.ACTION_MOVE:
        mMove = (mLastX - xPosition);
        changeMoveAndValue();
        break;
      case MotionEvent.ACTION_UP:
      case MotionEvent.ACTION_CANCEL:
        countMoveEnd();
        countVelocityTracker();
        return false;
      default:
        break;
    }
 
    mLastX = xPosition;
    return true;
  }
 
  private void countVelocityTracker() {
    mVelocityTracker.computeCurrentVelocity(1000); //初始化速率的单位
    float xVelocity = mVelocityTracker.getXVelocity(); //当前的速度
    if (Math.abs(xVelocity) > mMinVelocity) {
      mScroller.fling(0, 0, (int) xVelocity, 0, Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0);
    }
  }
 
 
  /**
   * 滑动结束后,若是指针在2条刻度之间时,改变mOffset 让指针正好在刻度上。
   */
  private void countMoveEnd() {
 
    mOffset -= mMove;
    if (mOffset <= mMaxOffset) {
      mOffset = mMaxOffset;
    } else if (mOffset >= 0) {
      mOffset = 0;
    }
 
    mLastX = 0;
    mMove = 0;
 
    mSelectorValue = mMinValue + Math.round(Math.abs(mOffset) * 1.0f / mLineSpaceWidth) * mPerValue / 10.0f;
    mOffset = (mMinValue - mSelectorValue) * 10.0f / mPerValue * mLineSpaceWidth;
 
 
    notifyValueChange();
    postInvalidate();
  }
 
 
  /**
   * 滑动后的操作
   */
  private void changeMoveAndValue() {
    mOffset -= mMove;
 
    if (mOffset <= mMaxOffset) {
      mOffset = mMaxOffset;
      mMove = 0;
      mScroller.forceFinished(true);
    } else if (mOffset >= 0) {
      mOffset = 0;
      mMove = 0;
      mScroller.forceFinished(true);
    }
    mSelectorValue = mMinValue + Math.round(Math.abs(mOffset) * 1.0f / mLineSpaceWidth) * mPerValue / 10.0f;
 
 
    notifyValueChange();
    postInvalidate();
  }
 
  private void notifyValueChange() {
    if (null != mListener) {
      mListener.onValueChange(mSelectorValue);
    }
  }
 
 
  /**
   * 滑动后的回调
   */
  public interface OnValueChangeListener {
    void onValueChange(float value);
  }
 
  @Override
  public void computeScroll() {
    super.computeScroll();
    if (mScroller.computeScrollOffset()) {   //mScroller.computeScrollOffset()返回 true表示滑动还没有结束
      if (mScroller.getCurrX() == mScroller.getFinalX()) {
        countMoveEnd();
      } else {
        int xPosition = mScroller.getCurrX();
        mMove = (mLastX - xPosition);
        changeMoveAndValue();
        mLastX = xPosition;
      }
    }
  }
}

3.xml中使用activity_main.xml

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">
 
  <LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:visibility="visible">
 
    <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:includeFontPadding="false"
      android:maxHeight="17.0sp"
      android:text="身高(cm)"
      android:textColor="#cc222222"
      android:textSize="15.0sp" />
 
    <TextView
      android:id="@+id/tv_info_height_value"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginTop="11.0dip"
      android:includeFontPadding="false"
      android:maxHeight="24.0sp"
      android:textColor="#cc222222"
      android:textSize="24.0sp" />
 
    <RelativeLayout
      android:layout_width="fill_parent"
      android:layout_height="wrap_content">
 
      <com.demo.ruleview.RulerView
        android:id="@+id/ruler_height"
        android:layout_width="fill_parent"
        android:layout_height="68.0dip"
        android:layout_marginTop="24.0dip"
        app:alphaEnable="true"
        app:lineColor="@color/gray"
        app:lineMaxHeight="40dp"
        app:lineMidHeight="30dp"
        app:lineMinHeight="20dp"
        app:lineSpaceWidth="10dp"
        app:lineWidth="2dip"
        app:maxValue="250.0"
        app:minValue="80.0"
        app:perValue="1"
        app:textColor="@color/black" />
 
      <ImageView
        android:layout_width="14.0dip"
        android:layout_height="46.0dip"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="40.0dip"
        android:scaleType="fitXY"
        android:src="@drawable/info_ruler" />
    </RelativeLayout>
 
 
    <Button
      android:id="@+id/click"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_marginTop="10dp"
      android:text="点击改变" />
 
  </LinearLayout>
</LinearLayout>

4.Activity中使用MainActivity

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class MainActivity extends AppCompatActivity {
 
  private int maxValue = 250;
  private int minValue = 80;
 
  private RulerView rulerHeight;
  private TextView tvHeightValue;
 
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
 
    rulerHeight = (RulerView) findViewById(R.id.ruler_height);
    tvHeightValue = (TextView) findViewById(R.id.tv_info_height_value);
 
    showNumInt();
 
    findViewById(R.id.click).setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
 
        showNumInt();
 
      }
    });
 
    rulerHeight.setOnValueChangeListener(new RulerView.OnValueChangeListener() {
      @Override
      public void onValueChange(float value) {
        tvHeightValue.setText(String.valueOf(value));
      }
    });
  }
 
  private void showNumInt() {
    Random rand = new Random();
    int value = rand.nextInt(maxValue - minValue + 1) + minValue;
    rulerHeight.setValue(value, minValue, maxValue, 1);
    tvHeightValue.setText(String.valueOf(Integer.valueOf(value)));
  }
}

PS:可自行根据需要绘制线条和文字,上下选择文字位置。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/qq_26761229/article/details/80815138

延伸 · 阅读

精彩推荐