欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

自定义标尺控件

程序员文章站 2022-06-07 15:33:51
...

原文地址:https://blog.csdn.net/qq_31433525/article/details/79107871


示例

自定义标尺控件

功能描述

通过输入的list节点表示标尺刻度,不规定每一个相同,当长度相同,取得的值只能是节点上的值,没有中间值。支持左滑右滑,滑动有动画,并且划过一般自动滑到节点,未满一半返回原节点。

代码

public class RulerView extends View {
    /**屏幕宽度*/
    private int screenWidth;
    /**控件高度*/
    private int viewHeight;
    /**view宽度*/
    private int viewWidth;
    /**m每一小格的长度*/
    private int oneItemValue;
    /**端点节点*/
    private List<String> list =new ArrayList<>();
    /**滑动监听器*/
    private OnRulerChangeListener rulerListener;
    /**滚动计算类*/
    private Scroller              scroller;
    /**手势监听*/
    private GestureDetector       gestureDetector;
    /**偏移量*/
    private int                   offset;
    /**绘制的开始位置*/
    private int                   location;
    /**显示哪个list值*/
    private int                   distanceInteger;
    /**游标颜色*/
    private int                   cursorColor;
    /**刻度颜色*/
    private int                   scaleColor;
    /**刻度字体颜色*/
    private int                   scaleTextColor;
    /**刻度字体大小*/
    private int                   scaleTextSize;
    /**手指抬起时的偏移量*/
    private int                   upOffset;
    /**是否标尺往回走*/
    private boolean               isBack;
    /**字体所处高度比例*/
    private float                 scaleTextHeight;
    /**游标长度比例*/
    private float cursorHeight;

    public void setList(List<String> list) {
        this.list = list;
        invalidate();
    }

    public void setRulerListener(OnRulerChangeListener rulerListener) {
        this.rulerListener = rulerListener;
    }

    public RulerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        WindowManager  windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics dm            = new DisplayMetrics();
        windowManager.getDefaultDisplay().getMetrics(dm);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RulerView);
        cursorColor = typedArray.getColor(R.styleable.RulerView_cursor_color, Color.rgb(255,0,0));
        scaleColor = typedArray.getColor(R.styleable.RulerView_scale_color,Color.argb(255,102,102,102));
        scaleTextColor = typedArray.getColor(R.styleable.RulerView_scale_text_color,Color.argb(255,102,102,102));
        scaleTextSize = typedArray.getDimensionPixelOffset(R.styleable.RulerView_scale_text_size,36);
        scaleTextHeight = typedArray.getFloat(R.styleable.RulerView_scale_text_height,(float)0.25);
        cursorHeight = typedArray.getFloat(R.styleable.RulerView_cursor_height,(float) 0);
        screenWidth = dm.widthPixels;
        oneItemValue = screenWidth/20;
        //滚动计算器
        scroller = new Scroller(context);
        //一定要加,不然只会收到onDown,onShowPress,onLongPress3个事件
        setClickable(true);
        //手势解析
        gestureDetector = new GestureDetector(context, gestureListener);
        //是否允许长点击
        gestureDetector.setIsLongpressEnabled(false);
        location=screenWidth/2;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        viewHeight = MeasureSpec.getSize(heightMeasureSpec);
        if(list.size() == 0){
            list.add("0");
        }
        viewWidth=oneItemValue*(list.size()-1)*5;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        viewWidth=oneItemValue*(list.size()-1)*5;
        drawBottomLine(canvas);
        drawScale(canvas);
        drawCursor(canvas);
    }
    /**绘制刻度*/
    private void drawScale(Canvas canvas) {
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStrokeWidth(3);
        paint.setColor(scaleColor);
        Paint paintText = new Paint(Paint.ANTI_ALIAS_FLAG);
        paintText.setTextSize(scaleTextSize);
        paintText.setColor(scaleTextColor);
        for(int i=0;i <= (list.size()-1)*5;i++){
            int currentLocation=location+i*oneItemValue;
            if(i % 5 == 0){
                String drawStr;
                drawStr = list.get(i/5);
                Rect bounds = new Rect();
                paintText.getTextBounds(drawStr, 0, drawStr.length(), bounds);
                canvas.drawText(drawStr, currentLocation - bounds.width() / 2, viewHeight-viewHeight*scaleTextHeight, paintText);
                canvas.drawLine(currentLocation, viewHeight-viewHeight/5, currentLocation, viewHeight, paint);
            }else{
                canvas.drawLine(currentLocation, viewHeight-viewHeight/8, currentLocation, viewHeight, paint);
            }
        }
    }

    /**绘制游标*/
    private void drawCursor(Canvas canvas) {
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStrokeWidth(3);
        paint.setColor(cursorColor);
        if(scroller.computeScrollOffset()){
            canvas.drawLine(screenWidth/2+scroller.getCurrX(), viewHeight*cursorHeight, screenWidth/2+scroller.getCurrX(), viewHeight, paint);
        }else{
            canvas.drawLine(screenWidth/2+offset, viewHeight*cursorHeight, screenWidth/2+offset, viewHeight, paint);
        }
    }

    /**绘制底部横线*/
    private void drawBottomLine(Canvas canvas) {
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStrokeWidth(3);
        paint.setColor(Color.rgb(102,102,102));
        if(scroller.computeScrollOffset()){
            canvas.drawLine(scroller.getCurrX(),viewHeight,screenWidth+scroller.getCurrX(), viewHeight, paint);
        }else{
            canvas.drawLine(offset, viewHeight, screenWidth+offset, viewHeight, paint);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        gestureDetector.onTouchEvent(event);
        if(event.getAction() == MotionEvent.ACTION_UP){
            changeValue();
            upOffset = offset;
            offset = distanceInteger *5*oneItemValue;
            if(isBack){
                scroller.startScroll(upOffset,0,-(upOffset-offset),0,1000);
            }else{
                scroller.startScroll(upOffset,0,(offset-upOffset),0,1000);
            }
            invalidate();
        }
        return super.onTouchEvent(event);
    }
    /**改变textView*/
    private void changeValue(){
        distanceInteger= offset/(oneItemValue*5);
        int distanceRemainder = offset % (oneItemValue*5);
        if(distanceRemainder >=oneItemValue*5/2){
            distanceInteger=distanceInteger+1;
            isBack=false;
        }else{
            isBack=true;
        }
        if(rulerListener != null){
            if(distanceInteger >= list.size()){
                distanceInteger = list.size() -1;
            }
            rulerListener.setValue(Integer.valueOf(list.get(distanceInteger)));
        }
    }
    private GestureDetector.SimpleOnGestureListener gestureListener = new GestureDetector.SimpleOnGestureListener(){
        /**
         * @param e1 滑动事件的起点(也就是说onDown()的时候)
         * @param e2 当前滑动位置点(手指的位置)
         * @param distanceX 上次滑动(调用onScroll)到这次滑动的X轴的距离px
         * @param distanceY 上次滑动(调用onScroll)到这次滑动的Y轴的距离px
         */
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            if(offset >= viewWidth && distanceX >= 0){
                distanceX =0;
                offset=viewWidth;
            }else if(offset <= 0 && distanceX <= 0){
                distanceX = 0;
                offset =0;
            }
            scroller.forceFinished(true);
            offset=offset+(int)distanceX;
            scrollTo(offset,0);
            return super.onScroll(e1, e2, distanceX, distanceY);
        }

        /***
         * @param e1 拖动动事件的起点(也就是说onDown()的时候)
         * @param e2 onFling()调用时,手指的位置
         * @param velocityX X轴上每秒滑动像素值
         * @param velocityY Y轴上每秒滑动像素值
         * 当拖动速率velocityX或velocityY超过ViewConfiguration.getMinimumFlingVelocity()最小拖动速率时,才会调用onFling(),
         * 也就是如果只拖动一点,或是慢慢的拖动,是不会触发该方法
         */
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            scroller.fling(offset, 0, (int) (-velocityX / 1.5), 0, 0, viewWidth, 0, 0);
            return super.onFling(e1, e2, velocityX, velocityY);

        }
    };
    @Override
    public void computeScroll() {
        super.computeScroll();
        if(scroller.computeScrollOffset()){
            scrollTo(scroller.getCurrX(),0);
            invalidate();
        }else{
            scrollTo(offset,0);
        }
    }
}
  • 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
public interface OnRulerChangeListener {
    /**设置值*/
    void setValue(int value);
}
  • 1
  • 2
  • 3
  • 4
  • 5
<resources>
    <declare-styleable name="RulerView">
        <!--游标的颜色-->
        <attr name="cursor_color" format="color"></attr>
        <!--刻度颜色-->
        <attr name="scale_color" format="color"></attr>
        <!--刻度字体颜色-->
        <attr name="scale_text_color" format="color"></attr>
        <!--刻度字体大小-->
        <attr name="scale_text_size" format="dimension"></attr>
        <!--字体所处高度-->
        <attr name="scale_text_height" format="float"></attr>
        <!--游标长度比例-->
        <attr name="cursor_height" format="float"></attr>
    </declare-styleable>
</resources>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

使用

<com.example.RulerView
        android:id="@+id/rulerview"
        android:layout_width="match_parent"
        android:layout_height="70dp"
        android:layout_marginTop="10dp"
        app:cursor_color="#ff0000"
        app:scale_color="#333333"
        app:scale_text_color="#333333"
        app:scale_text_size="20sp" />
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
public class MainActivity extends AppCompatActivity implements OnRulerChangeListener {
    TextView  textView;
    RulerView rulerView;
    int       num;
    private int currLocation = 500;
    private List<String> list=new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        list.add(0,"500");
        list.add(1,"1000");
        list.add(2,"1400");
        rulerView = (RulerView) findViewById(R.id.rulerview);
        rulerView.setRulerListener(this);
        rulerView.setList(list);
        textView = (TextView) findViewById(R.id.tvValue);
        textView.setText(currLocation + "");

    }

    @Override
    public void setValue(int value) {
        textView.setText(value+"");
    }
}