android 炫酷表格

android 自定义view实现炫酷表格,还是先来个效果图




直接上传代码:

public LineViewDemo(Context context, AttributeSet attrs) {
        super(context, attrs);
        inits(context, attrs);
    }

    public LineViewDemo(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        inits(context, attrs);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public LineViewDemo(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        inits(context, attrs);
    }

    private void inits(Context context, AttributeSet attrs) {
        this.mContext = context;
        mDivderPaint = new Paint();
        mDivderPaint.setAntiAlias(true);
        mDivderPaint.setStyle(Paint.Style.STROKE);
        mDivderPaint.setStrokeWidth(dp2px(0.5f));
        mDivderPaint.setColor(Color.GRAY);

        mPotinPaint = new Paint();
        mPotinPaint.setAntiAlias(true);
        mPotinPaint.setStyle(Paint.Style.FILL);

        mBgPaint = new Paint();
        mBgPaint.setAntiAlias(true);
        mBgPaint.setStyle(Paint.Style.FILL);

        mLinePaint = new Paint();
        mLinePaint.setAntiAlias(true);
        mLinePaint.setStyle(Paint.Style.FILL);
        mLinePaint.setStrokeWidth(dp2px(1f));
        mLinePaint.setColor(Color.parseColor("#42afff"));

        mHintPaint = new TextPaint();
        mHintPaint.setColor(Color.parseColor("#332b2c"));
        mHintPaint.setTextSize(sp2px(10));

        mTextPaint = new Paint();
        mTextPaint.setColor(Color.GRAY);
        mTextPaint.setTextSize(sp2px(12));
        //模拟数据
        getDatas();
    }

    private void getDatas() {

        mSpanY = dp2px(60);
        mSpanX = dp2px(60);
        mSpanTop = dp2px(40);
        mR = dp2px(10);
        mHintSpan = dp2px(10);
        mTextSpan = dp2px(5);
        mBottomR = dp2px(4);


        mValueX = new ArrayList<>();
        mValueY = new ArrayList<>();
        mPoints = new ArrayList<>();

        for (int i = 1; i <= 18; i++) {
            mValueX.add(i + "题");
        }
        for (int i = 0; i <= 5; i++) {
            mValueY.add(i * 2 + "");
        }
    }

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        this.mCanvas = canvas;

        drawLineX(canvas);

        drawLineY(canvas);

        drawLinePath(canvas);

        drawPoint(canvas);

        drawHint();
    }

/**
     * 绘制填充颜色
     */
    private void drawLinePath(Canvas canvas) {
        Path path = new Path();
        path.moveTo(mSpanX, mRow * (1 + 2 * 5) / 2 + mSpanTop);

        for (int i = 0; i < mValueX.size(); i++) {
            PointEntity pointS = mPoints.get(i);
            path.lineTo(pointS.getX(), pointS.getY());
        }
        path.lineTo(mSpanX + mCol * 17.f, mRow * (1 + 2 * 5) / 2 + mSpanTop);
        path.close();
        //绘制填充颜色
        //需完成颜色的渐变
        Shader shader = new LinearGradient(mSpanY, mRow, mSpanY, mRootH - mSpanX, Color.parseColor("#aa42afff"), Color.parseColor("#0042afff"), Shader.TileMode.REPEAT);
        mLinePaint.setShader(shader);
        canvas.drawPath(path, mLinePaint);
        //还原折线画笔  避免下次重新绘制颜色不对
        mLinePaint.reset();
        mLinePaint.setAntiAlias(true);
        mLinePaint.setStyle(Paint.Style.FILL);
        mLinePaint.setStrokeWidth(dp2px(1f));
        mLinePaint.setColor(Color.parseColor("#42afff"));
    }

//画点及折线
    private void drawPoint(Canvas canvas) {

        for (int i = 0; i < mValueX.size(); i++) {
            PointEntity pointS = mPoints.get(i);
            //先画线
            if (i + 1 < mValueX.size()) {
                PointEntity pointE = mPoints.get(i + 1);
                canvas.drawLine(pointS.getX(), pointS.getY(), pointE.getX(), pointE.getY(), mLinePaint);
            }
            //在画点
            Shader shader;
            if (i == mSelectInde) {
//                int[] colors:表示所需要的渐变颜色数组 float[] stops:表示每个渐变颜色所在的位置百分点,取值0-1,数量必须与colors数组保持一致,不然直接crash,一般第一个数值取0,最后一个数值取1;如果第一个数值和最后一个数值并没有取0和1,比如我们这里取一个位置数组:{0.2,0.5,0.8},起始点是0.2百分比位置,结束点是0.8百分比位置,而0-0.2百分比位置和0.8-1.0百分比的位置都是没有指定颜色的。而这些位置的颜色就是根据我们指定的TileMode空白区域填充模式来自行填充!!!
                shader = new RadialGradient(pointS.getX(), pointS.getY(), dp2px(6),
                        new int[]{Color.parseColor("#42afff"), Color.parseColor("#ffffff"), Color.parseColor("#42afff")},
                        new float[]{0, 0.8f, 1},
                        Shader.TileMode.CLAMP);
                mPotinPaint.setShader(shader);
                canvas.drawCircle(pointS.getX(), pointS.getY(), dp2px(6), mPotinPaint);
            } else {
                shader = new RadialGradient(pointS.getX(), pointS.getY(), dp2px(4),
                        new int[]{Color.parseColor("#42afff"), Color.parseColor("#42afff"), Color.parseColor("#ffffff")},
                        new float[]{0, 0.7f, 1},
                        Shader.TileMode.CLAMP);
                mPotinPaint.setShader(shader);
                canvas.drawCircle(pointS.getX(), pointS.getY(), dp2px(4), mPotinPaint);
            }
        }
    }

  /**
     * 绘制提示文本
     */
    private void drawHint() {
        int marBottom = dp2px(6);
        int radio = dp2px(2);

        boolean isEnable = mSelectInde>=0&&mSelectInde<mPoints.size();
        if (!isEnable){
            return;
        }
        PointEntity p = mPoints.get(mSelectInde);
        int x = p.getX();
        int y = p.getY();
        String msg = "而这些位置的颜色就是根据我们指定的TileMode空白区域填充模式来自行填充!!!有时效果我们是不可控的。所以为了方便起见,建议大家st";
        int textW = getTextW(msg);
        int textH = getTextH(msg);
        Log.e(TAG, "drawHint: textw="+textW +"\ntextH="+textH+"\nx="+x+"\ny="+y);

        if (textW>=mMaxHintW){
            int n = textW/mMaxHintW;
            n = n>3? 3:n;
            textW = mMaxHintW;
            textH = textH*n;
        }
        Log.e(TAG, "drawHint: textw="+textW +"\ntextH="+textH);
        int left ;
        int top = y-textH-dp2px(20);
        if (textW/2>=x){
            //左侧显示不下 ,从最左边开始
            left = mHintSpan;
        }else if (x+textW/2>=mRootW){
            //右侧显示不下 ,从最右边开始
            left = mRootW-mHintSpan-textW;
        }else {
            left = x-textW/2;
        }
        //画白色填充
        Path path = new Path();
        path.moveTo(left-mTextSpan,top-mTextSpan);
        path.lineTo(left+textW+mTextSpan,top-mTextSpan);
        path.lineTo(left+textW+mTextSpan,top+textH+mTextSpan);
        path.lineTo(x-mBottomR,top+textH+mTextSpan);
        path.lineTo(x,y-marBottom);
        path.lineTo(x+mBottomR,top+textH+mTextSpan);
        path.lineTo(left-mTextSpan,top+textH+mTextSpan);
        path.close();
        mBgPaint.setColor(Color.WHITE);
        mCanvas.drawPath(path,mBgPaint);
        //画红色边框
        float[] pts = new float[]{
                left-mTextSpan,top-mTextSpan,left+textW+mTextSpan,top-mTextSpan,
                left+textW+mTextSpan,top-mTextSpan,left+textW+mTextSpan,top+textH+mTextSpan,
                left+textW+mTextSpan,top+textH+mTextSpan,x-mBottomR,top+textH+mTextSpan,
                x-mBottomR,top+textH+mTextSpan,x,y-marBottom,
                x,y-marBottom,x+mBottomR,top+textH+mTextSpan,
                x+mBottomR,top+textH+mTextSpan,left-mTextSpan,top+textH+mTextSpan,
                left-mTextSpan,top+textH+mTextSpan,left-mTextSpan,top-mTextSpan
        };
        mBgPaint.setColor(Color.RED);
        mCanvas.drawLines(pts, mBgPaint);
        mBgPaint.setColor(Color.WHITE);
        mCanvas.drawLine(x-mBottomR,top+textH+mTextSpan,x+mBottomR,top+textH+mTextSpan,mBgPaint);
        StaticLayout layout = new StaticLayout(msg,mHintPaint,textW, Layout.Alignment.ALIGN_NORMAL,1f,0f,true);
        Log.e(TAG, "drawHint: left="+left +"\ntop="+top);
        mCanvas.translate(left,top);
        layout.draw(mCanvas);
        mCanvas.restore();
    }

    //画横线及y轴刻度
    private void drawLineY(Canvas canvas) {
        int width = getTextH(mValueY.get(0));
        int heigt = getTextH(mValueY.get(0));
        for (int i = 0; i < mValueY.size(); i++) {
            //横线
            canvas.drawLine(mSpanY - dp2px(10), mRow * (1 + 2 * i) / 2 + mSpanTop, mRootW, mRow * (1 + 2 * i) / 2 + mSpanTop, mDivderPaint);
            //画文字
            String text = mValueY.get(mValueY.size() - i - 1);
            int x = mSpanY - width - dp2px(20);
            if (i == 0) {
                x -= dp2px(3);
            }
            canvas.drawText(text, x, mRow * (1 + 2 * i) / 2 + heigt / 2 + mSpanTop, mTextPaint);
        }
        width = getTextH("正确数");
        heigt = getTextH("正确数");
        canvas.drawText("正确数", mSpanX - width - dp2px(4), mSpanTop / 2 + heigt, mTextPaint);
    }

 //画竖线及x轴刻度
    private void drawLineX(Canvas canvas) {
        int width = getTextH(mValueX.get(0));
        int heigt = getTextH(mValueX.get(0));
        for (int i = 0; i < mValueX.size(); i++) {
            //竖线
            canvas.drawLine(mSpanX + mCol * i, mSpanTop, mSpanX + mCol * i, mRootH - dp2px(10) - mSpanX, mDivderPaint);
            //画文字
            canvas.drawText(mValueX.get(i), mSpanX + mCol * i - width, mRootH - mSpanX + heigt, mTextPaint);
        }
    }

    //第一次才加载模拟数据
    private boolean isFirst = true;

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mRootH = getMeasuredHeight();
        mRootW = getMeasuredWidth();

        mCol = (int) ((mRootW - mSpanY) * 1.0f / mValueX.size() + 0.5f);
        mRow = (int) ((mRootH - mSpanX - mSpanTop) * 1.0f / mValueY.size() + 0.5f);

        mMaxHintW = mRootW/3;

        Log.e(TAG, "mRootH=" + mRootH +
                "\nmRootW=" + mRootW +
                "\nmCol=" + mCol +
                "\nmRow=" + mRow+
                "\nmMaxHintW=" + mMaxHintW);

        //第一次才加载模拟数据
        if (!isFirst){
            return;
        }else {
            isFirst = false;
        }
        /**
         * 模拟数据
         */
        Random random = new Random();
        mPoints.clear();
        for (int i = 0; i < 18; i++) {
            PointEntity p = new PointEntity(mSpanX + mCol * i, (8 - random.nextInt(8)) * mRow / 2 + mRow / 2 + mSpanTop);
            Log.e(TAG, "index=" + i + "\np.x=" + p.getX() + "\np.y=" + p.getY());
            mPoints.add(p);
        }

    }

@Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                actionDown(event);
                break;
            case MotionEvent.ACTION_UP:
                actionUp(event);
                break;
            case MotionEvent.ACTION_MOVE:
                actionMove(event);
                break;
        }
        return super.onTouchEvent(event);
    }

    //按下
    private void actionDown(MotionEvent event) {
            float x = event.getX();
            float y = event.getY();

            for (int i = 0; i < mPoints.size(); i++) {
                PointEntity p = mPoints.get(i);
                int left = p.getX() - mR;
                int right = p.getX() + mR;
                int top = p.getY() - mR;
                int bottom = p.getY() + mR;

                boolean isInner = left <= x && right >= x && top <= y && bottom >= y;

                if (isInner) {
                    if (mClickListener != null) {
                        mClickListener.onClickPoint(i,(int)x,(int)y);
                    }
                    upDataView(i);
                }
            }

    }

    private void upDataView(int position) {
        mSelectInde = position;
        invalidate();
        Log.e(TAG, "upDataView: -----------------------------------------"+position );
    }

    private int dp2px(float d) {
        float scale = mContext.getResources().getDisplayMetrics().density;
        return (int) (d * scale + 0.5f);
    }

    private int sp2px(float s) {
        float fontScale = mContext.getResources().getDisplayMetrics().scaledDensity;
        return (int) (s * fontScale + 0.5f);
    }

    private int getTextW(String text) {
        Rect textBounds = new Rect();
        mTextPaint.getTextBounds(text, 0, text.length(), textBounds);
        return textBounds.width();
    }

    private int getTextH(String text) {
        Rect textBounds = new Rect();
        mTextPaint.getTextBounds(text, 0, text.length(), textBounds);
        mTextPaint.measureText(text);
        return textBounds.height();
    }


说明:再次并没有对数据源进行封装,应为需求不一样,进行统一封装比较麻烦,在实际应用中使用频率一般,用的时候只需要根据自己需求修改即可;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值