自定义view实现一个游标效果(增强)

来源:互联网 发布:tcp和udp端口号区别 编辑:程序博客网 时间:2024/06/08 11:11

继上一篇:自定义view实现一个游标效果,在此基础上新增支持功能:

当手指点击某个时间域时,也可以触发游标滑动到当前点击选择的时间域。


下面贴代码:

package com.baicells.omcserver.view;import android.animation.ValueAnimator;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.LinearGradient;import android.graphics.Paint;import android.graphics.RectF;import android.graphics.Shader;import android.support.annotation.Nullable;import android.support.v4.view.ViewPager;import android.util.AttributeSet;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.View;import android.view.ViewParent;import com.baicells.omcserver.R;import java.util.ArrayList;public class CursorView extends View {    private int width;    private int height;    private int radius;    private int strokeWidth;    private int curTextColor;    private int inCurTextColor;    private ArrayList<String> cursorText;    private Paint borderPaint;    private Paint innerBgPaint;    private Paint textPaint;    private int current;    private float offsetX;    private RectF currentRectF;    private boolean isInCurrent;    private GestureDetector mDetector;    private OnItemSelectListener mListener;    public CursorView(Context context) {        super(context);    }    public CursorView(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);        mDetector = new GestureDetector(context, mGestureListener);        borderPaint = new Paint();        borderPaint.setAntiAlias(true);        borderPaint.setStyle(Paint.Style.FILL.STROKE);        innerBgPaint = new Paint();        innerBgPaint.setAntiAlias(true);        innerBgPaint.setStyle(Paint.Style.FILL_AND_STROKE);        textPaint = new Paint();        textPaint.setAntiAlias(true);        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CursorView);        int indexCount = typedArray.getIndexCount();        for (int i = 0; i < indexCount; i++) {            int index = typedArray.getIndex(i);            switch (index) {                case R.styleable.CursorView_current_bg_color:                    innerBgPaint.setColor(typedArray.getColor(index, Color.GREEN));                    break;                case R.styleable.CursorView_current_text_color:                    curTextColor = typedArray.getColor(index, Color.WHITE);                    break;                case R.styleable.CursorView_incurrent_text_color:                    inCurTextColor = typedArray.getColor(index, Color.BLACK);                    break;                case R.styleable.CursorView_stroke_color:                    borderPaint.setColor(typedArray.getColor(index, Color.RED));                    break;                case R.styleable.CursorView_textsize:                    textPaint.setTextSize(typedArray.getDimensionPixelSize(index, 20));                    break;                case R.styleable.CursorView_stroke_width:                    strokeWidth = typedArray.getDimensionPixelSize(index, 3);                    break;            }        }        typedArray.recycle();        borderPaint.setStrokeWidth(strokeWidth);        setLayerType(LAYER_TYPE_SOFTWARE, null);    }    public CursorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    public void setOnItemSelectListener(OnItemSelectListener listener) {        this.mListener = listener;    }    public void setCursorText(ArrayList<String> cursorText) {        this.cursorText = cursorText;        invalidate();    }    public void setCurrent(int current) {        this.current = current;        invalidate();    }    public int getCurrent() {        return current;    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);        int modeWidth = MeasureSpec.getMode(widthMeasureSpec);        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);        int modeHeight = MeasureSpec.getMode(heightMeasureSpec);        width = 300;        height = 20;        if (modeWidth == MeasureSpec.EXACTLY) {            width = sizeWidth;        }        if (modeHeight == MeasureSpec.EXACTLY) {            height = sizeHeight;        }        setMeasuredDimension(width, height);        radius = height / 2;    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        //画整个大背景        RectF rect = new RectF(strokeWidth / 2, strokeWidth / 2, width - strokeWidth / 2, height - strokeWidth / 2);        canvas.drawRoundRect(rect, radius, radius, borderPaint);        if (cursorText != null) {            int size = cursorText.size();            float everyWidth = width * 1.0f / size;            //画当前选中时间维度的背景            RectF currBgRectF = getCurrBgRectF(everyWidth);            currentRectF = currBgRectF;            canvas.drawRoundRect(currBgRectF, radius, radius, innerBgPaint);            //循环画时间维度文本            for (int i = 0; i < size; i++) {                textPaint.setShader(null);                String text = cursorText.get(i);                Paint.FontMetricsInt metricsInt = textPaint.getFontMetricsInt();                float textwidth = textPaint.measureText(text);                float preblank = (everyWidth - textwidth) / 2.0f;                float x = everyWidth * i + preblank;                float y = (height - metricsInt.bottom + metricsInt.top) / 2.0f - metricsInt.top;                if (currBgRectF.left >= x && currBgRectF.left <= x + textwidth) {                    float split = (currBgRectF.left - x) / textwidth;                    LinearGradient shader = new LinearGradient(x, 0, x + textwidth,                            0, new int[]{inCurTextColor, curTextColor}, new float[]{                            split, split + 0.01f}, Shader.TileMode.CLAMP);                    textPaint.setShader(shader);                }                if (currBgRectF.right >= x && currBgRectF.right <= x + textwidth) {                    float split = (currBgRectF.right - x) / textwidth;                    LinearGradient shader = new LinearGradient(x, 0, x + textwidth,                            0, new int[]{curTextColor, inCurTextColor}, new float[]{                            split, split + 0.01f}, Shader.TileMode.CLAMP);                    textPaint.setShader(shader);                }                if (currBgRectF.left < x && currBgRectF.right > x + textwidth) {                    textPaint.setColor(curTextColor);                } else {                    textPaint.setColor(inCurTextColor);                }                canvas.drawText(text, x, y, textPaint);            }        }    }    private RectF getCurrBgRectF(float everyWidth) {        float left = everyWidth * current + offsetX;        float right = everyWidth * (current + 1) + offsetX;        if (left < 0) {            left = 0;            right = everyWidth;        }        if (right > width) {            left = width - everyWidth;            right = width;        }        return new RectF(left, 0, right, height);    }    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        ViewParent parent = null;        while (true) {            if (parent != null && parent instanceof ViewPager) {                break;            }            if (parent != null) {                parent = parent.getParent();            } else {                parent = getParent();            }        }        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:            case MotionEvent.ACTION_MOVE:            case MotionEvent.ACTION_UP:                parent.requestDisallowInterceptTouchEvent(true);                break;            default:                parent.requestDisallowInterceptTouchEvent(false);                break;        }        return super.dispatchTouchEvent(ev);    }    private float downX = 0;    private float downY = 0;    @Override    public boolean onTouchEvent(MotionEvent event) {        float x = event.getX();        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                downX = event.getX();                downY = event.getY();                isInCurrent = currentRectF.contains(downX, downY);                break;            case MotionEvent.ACTION_MOVE:                if (isInCurrent) {                    offsetX = x - downX;                    invalidate();                }                break;            case MotionEvent.ACTION_UP:                if (isInCurrent) {                    final NextCurrent nextCurrent = computeScrollX(currentRectF.left);                    final float lastX = offsetX;                    ValueAnimator anim = ValueAnimator.ofFloat(0, nextCurrent.getX());                    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {                        @Override                        public void onAnimationUpdate(ValueAnimator animation) {                            float value = (float) animation.getAnimatedValue();                            offsetX = lastX + value;                            invalidate();                            float fraction = animation.getAnimatedFraction();                            if (fraction == 1.0f) {                                current = nextCurrent.getIndex();                                offsetX = 0;                                if (mListener != null) {                                    mListener.onItemSelect(nextCurrent.getIndex());                                }                            }                        }                    });                    anim.setDuration(100);                    anim.start();                }                break;        }        mDetector.onTouchEvent(event);        return true;    }    private NextCurrent getNeedScroll(float pointX) {        if (cursorText != null) {            NextCurrent next = new NextCurrent();            int size = cursorText.size();            float everyWidth = width * 1.0f / size;            int index = 0;            for (int i = 0; i < size; i++) {                if (pointX > everyWidth * i && pointX < everyWidth * (i + 1)) {                    index = i;                    break;                }            }            next.setIndex(index);            next.setX(everyWidth * index - currentRectF.left);            return next;        }        return null;    }    private NextCurrent computeScrollX(float left) {        NextCurrent next = new NextCurrent();        int index = 0;        if (cursorText != null) {            int size = cursorText.size();            float everyWidth = width * 1.0f / size;            float min = everyWidth + 1;            for (int i = 0; i < size; i++) {                float abs = Math.abs(left - everyWidth * i);                if (abs < min) {                    min = abs;                    index = i;                }            }            if (everyWidth * index > left) {                next.setX(min);            } else {                next.setX(-min);            }            next.setIndex(index);        }        return next;    }    private GestureDetector.SimpleOnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() {        @Override        public boolean onSingleTapConfirmed(MotionEvent e) {            if (!isInCurrent) {                final NextCurrent needScroll = getNeedScroll(e.getX());                ValueAnimator anim = ValueAnimator.ofFloat(0, needScroll.getX());                anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {                    @Override                    public void onAnimationUpdate(ValueAnimator animation) {                        offsetX = (float) animation.getAnimatedValue();                        invalidate();                        float fraction = animation.getAnimatedFraction();                        if (fraction == 1.0f) {                            current = needScroll.getIndex();                            offsetX = 0;                            if (mListener != null) {                                mListener.onItemSelect(current);                            }                        }                    }                });                anim.setDuration(300);                anim.start();            }            return super.onSingleTapConfirmed(e);        }    };    private class NextCurrent {        private int index;        private float x;        public int getIndex() {            return index;        }        public void setIndex(int index) {            this.index = index;        }        public float getX() {            return x;        }        public void setX(float x) {            this.x = x;        }    }    public interface OnItemSelectListener {        void onItemSelect(int item);    }}



原创粉丝点击