android尺子的自定义view——RulerView

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

原代码在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">
        <!--&lt;!&ndash; 正三角 &ndash;&gt;-->
        <!--<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>
shape_triangle

下面是布局文件,注意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+"");
            }
        });

 

posted @ 2018-06-26 16:45  Sharley  阅读(2415)  评论(0编辑  收藏  举报