项目中用到自定义尺子的样式:

原代码在github上找的,地址:https://github.com/QQabby/HorizontalRuler
原效果为

因为跟自己要使用的view稍有不同 所以做了一些修改,修改的注释都放在代码中了,特此记录一下。
首先是一个自定义View:
1 public class RuleView extends View {
2
3 private Paint paint;
4
5 private Context context;
6
7 private int maxValue = 500;
8 /**
9 * 起点x的坐标
10 */
11 private float startX ;
12
13 private float startY ;
14 /**
15 * 刻度线的长度
16 */
17 private float yLenght ;
18 /**
19 * 刻度的间隙
20 */
21 // private float gap = 8f;
22 private float gap = 10;
23 /**
24 * 文本的间隙
25 */
26 private float textGap = 10f;
27 /**
28 * 短竖线的高度
29 */
30 private float smallHeight = 10f;
31 /**
32 * 长竖线的高度
33 */
34 private float largeHeight = 22f;
35
36 /**
37 * 文本显示格式化
38 */
39 private DecimalFormat format;
40
41 private DisplayMetrics metrics = null;
42 /**
43 * 文本的字体大小
44 */
45 private float mFontSize;
46
47 private Handler mScrollHandler = null;
48
49 private MyHorizontalScrollView horizontalScrollView;
50
51 private int mCurrentX = -999999999;
52 /**
53 * 刻度进制
54 */
55 // private float unit = 10f;
56 private int unit = 10;//隔unit个刻度写一个数字
57 //每个大刻度代表值iValue
58 private int iValue = 10;
59
60 boolean isDraw = true;
61
62 public RuleView(Context context) {
63 super(context);
64 this.context = context;
65 init();
66 }
67
68 public void setHorizontalScrollView(
69 MyHorizontalScrollView horizontalScrollView) {
70 this.horizontalScrollView = horizontalScrollView;
71
72 this.horizontalScrollView.setOnTouchListener(new OnTouchListener() {
73
74 @Override
75 public boolean onTouch(View v, MotionEvent event) {
76
77 final int action = event.getAction();
78 switch (action) {
79 case MotionEvent.ACTION_DOWN:
80
81 break;
82 case MotionEvent.ACTION_MOVE:
83
84 mScrollHandler.removeCallbacks(mScrollRunnable);
85 break;
86 case MotionEvent.ACTION_UP:
87
88 mScrollHandler.post(mScrollRunnable);
89 break;
90 }
91 return false;
92 }
93 });
94 }
95
96 public RuleView(Context context, AttributeSet attrs) {
97 super(context, attrs);
98 this.context = context;
99
100 init();
101 }
102
103 public void init() {
104
105 // format = new DecimalFormat("0.0");
106 format = new DecimalFormat("0");//不使用浮点数格式
107
108 metrics = new DisplayMetrics();
109 WindowManager wmg = (WindowManager) context
110 .getSystemService(Context.WINDOW_SERVICE);
111 wmg.getDefaultDisplay().getMetrics(metrics);
112
113 paint = new Paint(Paint.ANTI_ALIAS_FLAG);
114 paint.setStyle(Paint.Style.FILL);
115 paint.setStrokeWidth(getResources().getDimension(R.dimen.ui_1_dip));
116 // paint.setStrokeWidth(2);
117 paint.setColor(Color.parseColor("#999999"));
118
119 mFontSize = ScreenUtil.dip2px(context, 16);
120 // startY = ScreenUtil.dip2px(context, 20f);
121 startY = ScreenUtil.dip2px(context, 0);//Y轴由0开始,即最顶端,不用设置适配布局文件RuleView的android:layout_marginTop="-20dp"
122 yLenght = ScreenUtil.dip2px(context, 10);
123 // gap = ScreenUtil.dip2px(context, 8f);
124 gap = ScreenUtil.dip2px(context, 10);
125 // startX = ScreenUtil.getScreenWidth(context)/ 2.0f- getResources().getDimension(R.dimen.ui_10_dip) ;
126 startX = ScreenUtil.getScreenWidth(context)/ 2.0f;//X轴不减去10dp,则三角形顶点可以刚好最准0位置
127
128 // + getResources().getDimension(R.dimen.text_h2)/2.0f
129 // Util.dip2px(context, 13f) +
130
131 mScrollHandler = new Handler(context.getMainLooper());
132
133 }
134
135 @Override
136 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
137
138 float width = maxValue * gap + ScreenUtil.getScreenWidth(context) - getResources().getDimension(R.dimen.ui_10_dip)*2.0f ;
139
140 // int widthMode = MeasureSpec.getMode(heightMeasureSpec);
141 // if(widthMode == MeasureSpec.AT_MOST){
142 // Log.d("TAG", "mode::AT_MOST");
143 // }else if(widthMode == MeasureSpec.EXACTLY){
144 // Log.d("TAG", "mode::EXACTLY");
145 // }else if(widthMode == MeasureSpec.UNSPECIFIED){
146 // Log.d("TAG", "mode::UNSPECIFIED");
147 // }
148
149 setMeasuredDimension((int) width, heightMeasureSpec);
150 }
151
152 @Override
153 protected void onDraw(final Canvas canvas) {
154 super.onDraw(canvas);
155
156 // 画刻度线
157 paint.setColor(getResources().getColor(R.color.gray_bg_high));// 刻度颜色
158 for (int i = 0; i <= maxValue; i++) {
159
160 if (i % 5 == 0) {
161 yLenght = ScreenUtil.dip2px(context, largeHeight);
162 } else {
163 yLenght = ScreenUtil.dip2px(context, smallHeight);
164 }
165 canvas.drawLine(i * gap + startX, startY, i * gap + startX, yLenght
166 + startY, paint);
167 }
168
169 paint.setTextSize(mFontSize);
170
171 // 每10个刻度写一个数字
172 textGap = gap * unit;
173
174 // 画刻度文字30
175 paint.setColor(getResources().getColor(R.color.textGray));// 文字颜色
176 for (int i = 0; i <= maxValue / unit; i++) {
177
178 // String text = format.format(i + 1) + "";//从0开始计数时不用加1
179 String text = format.format(i * iValue) + "";//乘以每刻度的值iValue
180 // 获取文本的宽度
181 float width = ScreenUtil.px2dip(context, calculateTextWidth(text)) / 2f;
182
183 canvas.drawText(
184 text,
185 startX - width + i * textGap,
186 (startY + ScreenUtil.dip2px(context, largeHeight))
187 + ScreenUtil.dip2px(context, 24), paint);//字体大小
188 }
189 }
190
191 /**
192 * 获取TextView中文本的宽度
193 */
194 private float calculateTextWidth(String text) {
195 if (TextUtils.isEmpty(text)) {
196 return 0;
197 }
198 TextPaint textPaint = new TextPaint();
199 textPaint.setTextSize(mFontSize * metrics.scaledDensity);
200 final float textWidth = textPaint.measureText(text);
201
202 return textWidth;
203 }
204
205 DecimalFormat df = new DecimalFormat("0.0");
206
207 /**
208 * 当滑动尺子的时候
209 */
210 int scrollWidth = 0;
211
212 public void setScrollerChanaged(int l, int t, int oldl, int oldt) {
213 // 滑动的距离
214 scrollWidth = l;
215
216 float number = scrollWidth / gap;
217 float result = number / unit;
218
219 listener.onSlide(result);
220 }
221
222 public onChangedListener listener;
223
224 public interface onChangedListener {
225
226 void onSlide(float number);
227 }
228
229 public void onChangedListener(onChangedListener listener) {
230 this.listener = listener;
231 }
232
233 /**
234 * 滚动监听线程
235 */
236 private Runnable mScrollRunnable = new Runnable() {
237
238 @Override
239 public void run() {
240 if (mCurrentX == horizontalScrollView.getScrollX()) {// 滚动停止了
241
242 try {
243
244 float x = horizontalScrollView.getScrollX();
245 float value = (x / (gap * unit));// 当前的值
246 String s = df.format(value);
247
248 // 滑动到11.0 ok
249 int scrollX = (int) (Double.parseDouble(s) * gap * unit);
250
251 horizontalScrollView.smoothScrollTo(scrollX, 0);
252
253 } catch (NumberFormatException numExp) {
254 numExp.printStackTrace();
255 }
256 mScrollHandler.removeCallbacks(this);
257 } else {
258 mCurrentX = horizontalScrollView.getScrollX();
259 mScrollHandler.postDelayed(this, 50);
260 }
261 }
262 };
263
264 /**
265 * 设置默认刻度尺的刻度值,不会滚动到相应的位置
266 *
267 * @param scaleValue
268 */
269 public void setDefaultScaleValue(float scaleValue) {
270
271 // final int scrollX = (int) ((scaleValue - 1.0f) * gap * unit);//从0开始计数时不用减去1
272 final int scrollX = (int) (scaleValue * gap * unit / 10);//每个值在设置刻度时会乘以10,所以除去
273
274 new Handler().postDelayed(new Runnable() {
275
276 @Override
277 public void run() {
278
279 horizontalScrollView.smoothScrollTo(scrollX, 0);
280 }
281 }, 100);
282 }
283
284 /**
285 * 设置刻度值
286 */
287 public void setScaleValue(int iValue) {
288 this.iValue = iValue;
289 }
290
291 /**
292 * 设置刻度最小值
293 */
294 public void setMinScaleValue(Float minScaleValue) {
295 // this.minScaleValue = minScaleValue;
296 }
297
298 /**
299 * 获取刻度最大值
300 */
301 public Float getMaxScaleValue() {
302 // return maxScaleValue;
303 return 33.0f;
304 }
305
306 /**
307 * 设置刻度最大值
308 */
309 public void setMaxScaleValue(Float maxScaleValue) {
310 // this.maxScaleValue = maxScaleValue;
311 }
312
313 /**
314 * 设置当前刻度尺的刻度值,并滚动到相应的位置
315 *
316 * @param scaleValue
317 */
318 public void setScaleScroll(float scaleValue) {
319
320 int scrollX = (int) ((scaleValue - 1.0f) * gap * unit);
321
322 horizontalScrollView.smoothScrollTo(scrollX, 0);
323 }
324 }
另外用到一个自定义的scrollView:
1 public class MyHorizontalScrollView extends HorizontalScrollView {
2
3 private OnScrollListener onScrollListener = null;
4
5 public MyHorizontalScrollView(Context context) {
6 this(context, null);
7 }
8 public MyHorizontalScrollView(Context context, AttributeSet attrs) {
9 this(context, attrs, 0);
10 }
11 public MyHorizontalScrollView(Context context, AttributeSet attrs,
12 int defStyleAttr) {
13 super(context, attrs, defStyleAttr);
14 }
15
16 @Override
17 protected void onScrollChanged(int l, int t, int oldl, int oldt) {
18 super.onScrollChanged(l, t, oldl, oldt);
19 if(onScrollListener != null){
20 onScrollListener.onScrollChanged(l, t, oldl, oldt);
21 }
22 }
23
24 public interface OnScrollListener {
25 public void onScrollChanged(int l, int t, int oldl, int oldt);
26 }
27
28 public void setOnScrollListener(OnScrollListener onScrollListener) {
29 this.onScrollListener = onScrollListener;
30 }
31 }
直尺上的黄色三角标其实是嵌在布局上的,在drawble文件中实现

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/shape_id">
<!--<!– 正三角 –>-->
<!--<rotate-->
<!--android:fromDegrees="45"-->
<!--android:toDegrees="45"-->
<!--android:pivotX="-40%"-->
<!--android:pivotY="80%">-->
<!-- 倒三角 -->
<rotate
android:fromDegrees="45"
android:toDegrees="45"
android:pivotX="135%"
android:pivotY="15%"
>
<shape android:shape="rectangle">
<solid android:color="@color/main_yellow"/>
</shape>
</rotate>
</item>
</layer-list>
下面是布局文件,注意RuleView是嵌在ScrollView中的:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="300px"
android:layout_marginTop="30px"
android:background="#fff">
<MyHorizontalScrollView
android:id="@+id/hor_scrollview"
android:layout_width="match_parent"
android:layout_height="300px"
android:scrollbars="none" >
<RuleView
android:id="@+id/rule_view"
android:background="@color/main_white"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="top"/>
</MyHorizontalScrollView>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/gray_bg"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true" />
<View
android:layout_width="30px"
android:layout_height="30px"
android:layout_centerHorizontal="true"
android:layout_alignParentTop="true"
android:background="@drawable/shape_triangle" />
</RelativeLayout>
最后在界面中的使用:
ruleView = (RuleView) findViewById(R.id.rule_view);
horizontalScrollView = (MyHorizontalScrollView) findViewById(R.id.hor_scrollview);
horizontalScrollView.setOverScrollMode(View.OVER_SCROLL_NEVER);// 去掉超出滑动后出现的阴影效果
// 设置水平滑动
ruleView.setHorizontalScrollView(horizontalScrollView);
ruleView.setDefaultScaleValue(num);
// 当滑动尺子的时候
horizontalScrollView.setOnScrollListener(new MyHorizontalScrollView.OnScrollListener() {
@Override
public void onScrollChanged(int l, int t, int oldl, int oldt) {
ruleView.setScrollerChanaged(l, t, oldl, oldt);
}
});
ruleView.onChangedListener(new RuleView.onChangedListener() {
@Override
public void onSlide(float number) {
int num = (int) (number * 10);
tvNum.setText(num+"");
}
});
来源:https://www.cnblogs.com/Sharley/p/9229907.html
