SoFunction
Updated on 2025-04-10

Android implements a smooth curve diagram that can be slid

This article shares the specific code of Android to implement a smooth curve chart that can be used for your reference. The specific content is as follows

Directly upload the code, with detailed annotations

1 attr attribute writing

<!-- xyAxis color -->

<attr name="xy_line_color" format="color" />
    <!-- xyCoordinate axis width -->
    <attr name="xy_line_width" format="dimension" />
    <!-- xyAxis text color -->
    <attr name="xy_text_color" format="color" />
    <!-- xyAxis text size -->
    <attr name="xy_text_size" format="dimension" />
    <!-- Color of the line in the line chart -->
    <attr name="line_color" format="color" />
    <!-- xHorizontal spacing between each coordinate point of the axis -->
    <attr name="interval" format="dimension" />
    <!-- Background color -->
    <attr name="bg_color" format="color" />
    <!-- Select the external color of the curve -->
    <attr name="select_circle_color" format="color" />
    <!-- Select the internal color of the curve -->
    <attr name="select_reminder_color" format="color" />
    <!--Do you raise your hand and scroll-->
    <attr name="isScroll" format="boolean" />
    <declare-styleable name="ChartView">
        <attr name="xy_line_color" />
        <attr name="xy_line_width" />
        <attr name="xy_text_color" />
        <attr name="xy_text_size" />
        <attr name="line_color" />
        <attr name="interval" />
        <attr name="bg_color" />
        <attr name="select_circle_color" />
        <attr name="select_reminder_color" />
        <attr name="isScroll" />
        <!--The prompt box and the sliding display position-->
        <attr name="show_position">
            <enum name="first" value="1" />
            <enum name="middle" value="2" />
            <enum name="end" value="3" />
        </attr>
</declare-styleable>

2 ChartView

package ;

import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;

import ;

import ;
import ;
import ;
import ;

/**
 * Custom line chart
 */
public class ChartView extends View {
    private static final int FIRST = 1;
    private static final int MIDDLE = 2;
    private static final int END = 3;
    //xy axis color    private int xyLineColor = 0xffCFE2CF;
    //The round color selected by the polyline    private int selectCircleColor = 0xff00A8FF;
    //Select the color of the data prompt box    private int selectReminderColor = 0xff00A8FF;
    //The color of the inner circle in the fold line    private int xyTextColor = 0xff0014FF;
    //The color of the line in the line chart    private int lineColor = 0xffFD00FF;
    //xy coordinate axis width    private int xyLineWidth = dpToPx(1);
    //xy axis text size    private int xyTextSize = spToPx(12);
    //Horizontal spacing of each coordinate point of the x-axis    private int interval = dpToPx(40);
    //Background color    private int bgColor = 0xffffffff;
    //Is there any sliding feeling when starting    private boolean isScroll = false;
    //The prompt box display position    private int mShowPositionType = 3;
    //Draw the brush corresponding to the XY axis coordinates    private Paint mXYPaint;
    //Draw the brush corresponding to the text of the XY axis    private Paint mXYTextPaint;
    //Draw the corresponding brushes of the folded lines    private Paint mSpinnerLinePaint;
    private int width;
    private int height;
    //The origin coordinates of the x-axis    private int mXOri;
    //The origin coordinate of the y-axis    private int mYOri;
    //The coordinates of the first point X    private float mXInit;
    //The maximum X coordinate corresponding to the first point    private float maxXInit;
    //The minimum X coordinate corresponding to the first point    private float minXInit;
    //The data corresponding to the x-axis coordinates    private List<String> mXData = new ArrayList<>();
    //The data corresponding to the y-axis coordinates    private List<Integer> mYData = new ArrayList<>();
    //The data corresponding to the polyline    private Map<String, Integer> mSpinnerValue = new HashMap<>();
    //How many points in the X-axis corresponding to the clicked point are 1 by default    private int selectIndex = 1;
    //The maximum rectangle corresponding to the X-axis scale text. In order to select, the frame sizes drawn in the x-axis text are the same, and the x-axis data obtained from the data are obtained to obtain the longest data    private Rect xValueRect;
    //Speed ​​Detector    private VelocityTracker mTracker;
    //Is it a short distance sliding    private boolean isShortSlide = false;
    //Get the middle of the size    private int mSelectMiddle = 0;
    //Curve cut ratio    private float mLineSmoothness = 0.18f;

    public ChartView(Context context) {
        this(context, null);
    }

    public ChartView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ChartView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs, defStyleAttr);
        initPaint();
    }

    //Set the cut rate    public void setLineSmoothness(float lineSmoothness) {
        if (lineSmoothness != ) {
             = lineSmoothness;
        }
    }

    /**
 * Initialization
 */
    private void initPaint() {
        mXYPaint = new Paint();
        (true);
        (xyLineWidth);
        ();
        (xyLineColor);

        mXYTextPaint = new Paint();
        (true);
        (xyTextSize);
        ();
        (xyTextColor);
        ();

        mSpinnerLinePaint = new Paint();
        (true);
        (xyLineWidth);
        (lineColor);
        ();
        ();
    }

    /**
 * Initialization
      *
 * @param context
 * @param attrs
 * @param defStyleAttr
 */
    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
        TypedArray array = (attrs, , defStyleAttr, 0);
        int count = ();
        for (int i = 0; i < count; i++) {
            int attr = (i);
            if (attr == .ChartView_xy_line_color) {
                xyLineColor = (attr, xyLineColor);

            } else if (attr == .ChartView_xy_line_width) {
                xyLineWidth = (int) (attr, (TypedValue.COMPLEX_UNIT_PX, xyLineWidth, getResources().getDisplayMetrics()));

            } else if (attr == .ChartView_xy_text_color) {
                xyTextColor = (attr, xyTextColor);

            } else if (attr == .ChartView_xy_text_size) {
                xyTextSize = (int) (attr, (TypedValue.COMPLEX_UNIT_PX, xyTextSize, getResources().getDisplayMetrics()));

            } else if (attr == .ChartView_line_color) {
                lineColor = (attr, lineColor);

            } else if (attr == .ChartView_interval) {
                interval = (int) (attr, (TypedValue.COMPLEX_UNIT_PX, interval, getResources().getDisplayMetrics()));

            } else if (attr == .ChartView_bg_color) {
                bgColor = (attr, bgColor);

            } else if (attr == .ChartView_select_circle_color) {
                selectCircleColor = (attr, selectCircleColor);

            } else if (attr == .ChartView_select_reminder_color) {
                selectReminderColor = (attr, selectReminderColor);

            } else if (attr == .ChartView_isScroll) {
                isScroll = (attr, isScroll);
            } else if (attr == .ChartView_show_position) {
                mShowPositionType = (attr, mShowPositionType);
            }
        }
        ();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        if (changed) {
            width = getWidth();
            height = getHeight();
            //The maximum width of Y-axis text            float textYWdith = getTextBounds((getListItemMaxIndex(mYData)) + "", mXYTextPaint).width();
            for (int i = 0; i < (); i++) {//Finding the maximum width of the y-axis text                float temp = getTextBounds((i) + "", mXYTextPaint).width();
                if (temp > textYWdith)
                    textYWdith = temp;
            }
            int dp2 = dpToPx(2);
            int dp3 = dpToPx(3);
            mXOri = (int) (dp2 + textYWdith + dp2 + xyLineWidth);
            //Get the rectangle occupied by the longest text width of the x-axis            xValueRect = getTextBounds((getListItemMaxIndex(mXData)), mXYTextPaint);
            //X-axis text height            float textXHeight = ();
            for (int i = 0; i < (); i++) {
                Rect rect = getTextBounds((i) + "", mXYTextPaint);
                if (() > textXHeight)
                    textXHeight = ();
                if (() > ())
                    xValueRect = rect;
            }
            mYOri = (int) (height - dp2 - textXHeight - dp3 - xyLineWidth);
            mXInit = mXOri + () / 2 + dpToPx(5);
            minXInit = width - (width - mXOri) * 0.1f - interval * (() - 1);
            maxXInit = mXInit;
        }
        selectIndex = getSelectIndexFromShowType(mShowPositionType);
        (changed, left, top, right, bottom);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        (bgColor);
        drawXY(canvas);
        drawBrokenLineAndPoint(canvas);
    }

    /**
 * Draw the corresponding point at the intersection
 */
    private void drawBrokenLineAndPoint(Canvas canvas) {
        if (() <= 0)
            return;
        int layerId = (0, 0, width, height, null, Canvas.ALL_SAVE_FLAG);
        drawBrokenLine(canvas);
        drawBrokenPoint(canvas);
        // Cut off the part beyond the x-axis coordinates        ();
        (bgColor);
        (new PorterDuffXfermode());
        RectF rectF = new RectF(0, 0, mXOri, height);
        (rectF, mSpinnerLinePaint);
        (null);

        (layerId);
    }

    /**
 * Draw the corresponding points of the curve
 */
    private void drawBrokenPoint(Canvas canvas) {
        float dp2 = dpToPx(2);
        float dp4 = dpToPx(4);
        float dp7 = dpToPx(7);
        ("selectIndex", "index:" + selectIndex);
        //Draw node        for (int i = 0; i < (); i++) {
            float x = mXInit + interval * i;
            float y = mYOri - mYOri * (1 - 0.1f) * ((i)) / (() - 1);
            //Draw the selected point            if (i == selectIndex - 1) {
                ();
                //Set the selected color                (selectCircleColor);
                (x, y, dp7, mSpinnerLinePaint);
                (selectReminderColor);
                (x, y, dp4, mSpinnerLinePaint);
                drawFloatTextBox(canvas, x, y - dp7, ((i)));
            }
            //Draw ordinary nodes            ();
            ();
            (x, y, dp2, mSpinnerLinePaint);
            ();
            (lineColor);
            (x, y, dp2, mSpinnerLinePaint);

        }
    }

    /**
 * Draw floating boxes
       * */
    private void drawFloatTextBox(Canvas canvas, float x, float y, int text) {
        int dp6 = dpToPx(6);
        int dp18 = dpToPx(18);
        //p1
        Path path = new Path();
        (x, y);
        //p2
        (x - dp6, y - dp6);
        //p3
        (x - dp18, y - dp6);
        //p4
        (x - dp18, y - dp6 - dp18);
        //p5
        (x + dp18, y - dp6 - dp18);
        //p6
        (x + dp18, y - dp6);
        //p7
        (x + dp6, y - dp6);
        //p1
        (x, y);
        (path, mSpinnerLinePaint);
        ();
        (spToPx(14));
        Rect rect = getTextBounds(text + "", mSpinnerLinePaint);
        (text + "", x - () / 2, y - dp6 - (dp18 - ()) / 2, mSpinnerLinePaint);
    }

    /**
 * Draw smooth curves
 */
    private void drawBrokenLine(Canvas canvas) {
        ();
        (lineColor);
        //Draw the folded lines        Path path = new Path();
        float prePreviousPointX = ;
        float prePreviousPointY = ;
        float previousPointX = ;
        float previousPointY = ;
        float currentPointX = ;
        float currentPointY = ;
        float nextPointX;
        float nextPointY;
        int lineSize = ();
        for (int i = 0; i < lineSize; i++) {
            float x;
            float y;
            if ((currentPointX)) {
                currentPointX = getSpinnerPoint(i).x;
                currentPointY = getSpinnerPoint(i).y;
            }
            if ((previousPointX)) {
                //Is it the first point?                if (i > 0) {
                    previousPointX = getSpinnerPoint(i - 1).x;
                    previousPointY = getSpinnerPoint(i - 1).y;
                } else {
                    //Denote the previous point with the current point                    previousPointX = currentPointX;
                    previousPointY = currentPointY;
                }
            }

            if ((prePreviousPointX)) {
                //The first two points?                if (i > 1) {
                    prePreviousPointX = getSpinnerPoint(i - 2).x;
                    prePreviousPointY = getSpinnerPoint(i - 2).y;
                } else {
                    //The current point indicates the previous point                    prePreviousPointX = previousPointX;
                    prePreviousPointY = previousPointY;
                }
            }

            // Determine if it is the last point            if (i < lineSize - 1) {
                nextPointX = getSpinnerPoint(i + 1).x;
                nextPointY = getSpinnerPoint(i + 1).y;
            } else {
                //Denote the next point with the current point                nextPointX = currentPointX;
                nextPointY = currentPointY;
            }

            if (i == 0) {
                // Move the Path to the start point                (currentPointX, currentPointY);
            } else {
                // Find the coordinates of the control point                final float firstDiffX = (currentPointX - prePreviousPointX);
                final float firstDiffY = (currentPointY - prePreviousPointY);
                final float secondDiffX = (nextPointX - previousPointX);
                final float secondDiffY = (nextPointY - previousPointY);
                final float firstControlPointX = previousPointX + (mLineSmoothness * firstDiffX);
                final float firstControlPointY = previousPointY + (mLineSmoothness * firstDiffY);
                final float secondControlPointX = currentPointX - (mLineSmoothness * secondDiffX);
                final float secondControlPointY = currentPointY - (mLineSmoothness * secondDiffY);
                //Draw the curve                (firstControlPointX, firstControlPointY, secondControlPointX, secondControlPointY,
                        currentPointX, currentPointY);
            }

            // renew            prePreviousPointX = previousPointX;
            prePreviousPointY = previousPointY;
            previousPointX = currentPointX;
            previousPointY = currentPointY;
            currentPointX = nextPointX;
            currentPointY = nextPointY;
        }
        (path, mSpinnerLinePaint);
    }

    /**
 * Draw XY coordinates
 */
    private void drawXY(Canvas canvas) {
        int length = dpToPx(5);//The length of the scale        //Draw Y coordinates        (mXOri - xyLineWidth / 2, 0, mXOri - xyLineWidth / 2, mYOri, mXYPaint);
        //Draw arrows        ();
        Path path = new Path();
        (mXOri - xyLineWidth / 2 - dpToPx(5), dpToPx(12));
        (mXOri - xyLineWidth / 2, xyLineWidth / 2);
        (mXOri - xyLineWidth / 2 + dpToPx(5), dpToPx(12));
        (path, mXYPaint);
        //Draw the scale        int yLength = (int) (mYOri * (1 - 0.1f) / (() - 1));//10% empty on the y-axis, calculate the y-axis scale spacing        for (int i = 0; i < (); i++) {
            //Draw the scale            (mXOri, mYOri - yLength * i + xyLineWidth / 2, mXOri + length, mYOri - yLength * i + xyLineWidth / 2, mXYPaint);
            (xyTextColor);
            //Draw text            String text = (i) + "";
            Rect rect = getTextBounds(text, mXYTextPaint);
            (text, 0, (), mXOri - xyLineWidth - dpToPx(2) - (), mYOri - yLength * i + () / 2, mXYTextPaint);
        }
        //Draw coordinates        (mXOri, mYOri + xyLineWidth / 2, width, mYOri + xyLineWidth / 2, mXYPaint);
        //Draw arrows        ();
        path = new Path();
        //The entire length        float xLength = mXInit + interval * (() - 1) + (width - mXOri) * 0.1f;
        if (xLength < width)
            xLength = width;
        (xLength - dpToPx(12), mYOri + xyLineWidth / 2 - dpToPx(5));
        (xLength - xyLineWidth / 2, mYOri + xyLineWidth / 2);
        (xLength - dpToPx(12), mYOri + xyLineWidth / 2 + dpToPx(5));
        (path, mXYPaint);
        //Draw the x-axis scale        for (int i = 0; i < (); i++) {
            float x = mXInit + interval * i;
            if (x >= mXOri) {//Plot only the area starting from the origin                (xyTextColor);
                (x, mYOri, x, mYOri - length, mXYPaint);
                //Draw X-axis text                String text = (i);
                Rect rect = getTextBounds(text, mXYTextPaint);
                if (i == selectIndex - 1) {
                    (lineColor);
                    (text, 0, (), x - () / 2, mYOri + xyLineWidth + dpToPx(2) + (), mXYTextPaint);
                    (x - () / 2 - dpToPx(3), mYOri + xyLineWidth + dpToPx(1), x + () / 2 + dpToPx(3), mYOri + xyLineWidth + dpToPx(2) + () + dpToPx(2), dpToPx(2), dpToPx(2), mXYTextPaint);
                } else {
                    (text, 0, (), x - () / 2, mYOri + xyLineWidth + dpToPx(2) + (), mXYTextPaint);
                }
            }
        }
    }

    private float startX;
    private float startx;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (isScrolling)
            return (event);
            //When the view gets a click event, the parent control requests not to intercept the event        ().requestDisallowInterceptTouchEvent(true);
        obtainVelocityTracker(event);
        switch (()) {
            case MotionEvent.ACTION_DOWN:
                startX = ();
                startx = ();
                ("XXXX", "down:" + startX + "");
                break;
            case MotionEvent.ACTION_MOVE:
                // When the sliding distance is less than or equal to 8, the task is short-distance sliding                //The product of the current x-axis size and the set x-axis distance is greater than the difference between the width of the display layout on the screen and the seven points in the x-axis, start moving.                if (interval * () > width - mXOri) {
                    //Get the sliding distance                    float dis = () - startX;
                    //Reassign value to startX                    startX = ();
                    //The sum of the current x origin distance and the distance sliding left and right is not large, then the current x distance is assigned to the minimum, and the following is similar                    if (mXInit + dis < minXInit) {
                        mXInit = minXInit;
                    } else if (mXInit + dis > maxXInit) {
                        mXInit = maxXInit;
                    } else {
                        mXInit = mXInit + dis;
                    }
                    invalidate();
                }
                break;
            case MotionEvent.ACTION_UP:
                isShortSlide = (() - startx) <= dpToPx(8);
                clickAction(event);
                scrollAfterActionUp();
                ().requestDisallowInterceptTouchEvent(false);
                recycleVelocityTracker();
                break;
            case MotionEvent.ACTION_CANCEL:
                //Add this line of code to prevent conflicts with the sliding event of the parent class                ().requestDisallowInterceptTouchEvent(false);
                recycleVelocityTracker();
                break;
        }
        return true;
    }

    //Is it sliding    private boolean isScrolling = false;

    /**
 * Sliding treatment after finger lifting
 */
    private void scrollAfterActionUp() {
        if (!isScroll)
            return;
        final float velocity = getVelocity();
        float scrollLength = maxXInit - minXInit;
        if ((velocity) < 10000)
            scrollLength = (maxXInit - minXInit) * (velocity) / 10000;
        ValueAnimator animator = (0, scrollLength);
        ((long) (scrollLength / (maxXInit - minXInit) * 1000));//The maximum time is 1000 milliseconds, and the ratio is used for conversion here        (new DecelerateInterpolator());
        (new () {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                float value = (float) ();
                if (velocity < 0 && mXInit > minXInit) {//Swipe left                    if (mXInit - value <= minXInit)
                        mXInit = minXInit;
                    else
                        mXInit = mXInit - value;
                } else if (velocity > 0 && mXInit < maxXInit) {//Swipe right                    if (mXInit + value >= maxXInit)
                        mXInit = maxXInit;
                    else
                        mXInit = mXInit + value;
                }
                invalidate();
            }
        });
        (new () {
            @Override
            public void onAnimationStart(Animator animator) {
                isScrolling = true;
            }

            @Override
            public void onAnimationEnd(Animator animator) {
                isScrolling = false;
            }

            @Override
            public void onAnimationCancel(Animator animator) {
                isScrolling = false;
            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });
        ();

    }

    /**
 * Get speed
      *
 * @return
 */
    private float getVelocity() {
        if (mTracker != null) {
            (1000);
            return ();
        }
        return 0;
    }

    /**
 * Click on the X-axis coordinate or polyline node
        *  */
    // 44  142  139
    private void clickAction(MotionEvent event) {
        int dp8 = dpToPx(8);
        float eventX = ();
        float eventY = ();
        if (!isShortSlide) {
            for (int i = 0; i < (); i++) {
                float x = mXInit + interval * i;
                float start = mXOri;
                if (x >= start + (mSelectMiddle - 1) * interval && x < start + mSelectMiddle * interval) {
                    selectIndex = i + 1;
                    invalidate();
                }
            }
            return;
        }
        for (int i = 0; i < (); i++) {
            //node            float x = mXInit + interval * i;
            float y = mYOri - mYOri * (1 - 0.1f) * ((i)) / (() - 1);
            if (eventX >= x - dp8 && eventX <= x + dp8 &&
                    eventY >= y - dp8 && eventY <= y + dp8 && selectIndex != i + 1) {//There is a clickable area around each node                selectIndex = i + 1;
                invalidate();
                return;
            }
            //X-axis scale            String text = (i);
            Rect rect = getTextBounds(text, mXYTextPaint);
            x = mXInit + interval * i;
            y = mYOri + xyLineWidth + dpToPx(2);
            if (eventX >= x - () / 2 - dp8 && eventX <= x + () + dp8 / 2 &&
                    eventY >= y - dp8 && eventY <= y + () + dp8 && selectIndex != i + 1) {
                selectIndex = i + 1;
                invalidate();
                return;
            }
        }
    }


    /**
 * Get the speed tracker
      *
 * @param event
 */
    private void obtainVelocityTracker(MotionEvent event) {
        if (!isScroll)
            return;
        if (mTracker == null) {
            mTracker = ();
        }
        (event);
    }

    /**
 * Recycling speed tracker
 */
    private void recycleVelocityTracker() {
        if (mTracker != null) {
            ();
            mTracker = null;
        }
    }

    /**
 * According to the display type of user input, the prompt box is displayed at different positions when sliding
 */
    private int getSelectIndexFromShowType(int showPositionType) {
        int visibleScale = (width - mXOri) / interval;
        switch (showPositionType) {
            case FIRST:
                mSelectMiddle = 1;
                return mSelectMiddle;
            case MIDDLE:
                if (() <= visibleScale) {
                    mSelectMiddle = middleIndex(());
                } else {
                    mSelectMiddle = middleIndex(visibleScale);
                }
                return mSelectMiddle;  //The scale that can be displayed on the screen            case END:
                if (() <= visibleScale) {
                    mSelectMiddle = ();
                } else {
                    mSelectMiddle = visibleScale;
                }
                return visibleScale;
            default:
                mSelectMiddle = 0;
                return mSelectMiddle;
        }
    }

    public void setValue(Map<String, Integer> value) {
         = value;
        invalidate();
    }

    public void setValue(Map<String, Integer> value, List<String> xValue, List<Integer> yValue) {
         = value;
         = xValue;
         = yValue;
        invalidate();
    }


    public Map<String, Integer> getValue() {
        return mSpinnerValue;
    }

    /**
 * Get the rectangle that measures the text
      *
 * @param text
 * @param paint
 * @return
 */
    private Rect getTextBounds(String text, Paint paint) {
        Rect rect = new Rect();
        (text, 0, (), rect);
        return rect;
    }

    /**
 * dp converts to px
      *
 * @param dp
 * @return
 */
    private int dpToPx(int dp) {
        float density = getContext().getResources().getDisplayMetrics().density;
        return (int) (dp * density + 0.5f * (dp >= 0 ? 1 : -1));
    }

    /**
 * sp to px
      *
 * @param sp
 * @return
 */
    private int spToPx(int sp) {
        float scaledDensity = getContext().getResources().getDisplayMetrics().scaledDensity;
        return (int) (scaledDensity * sp + 0.5f * (sp >= 0 ? 1 : -1));
    }

    /**
 * Get the longest index in the collection
 */
    private static final int NULL_INDEX = -1;

    public int getListItemMaxIndex(List<?> data) {
        if (data == null || () < 1) {
            return NULL_INDEX;
        }
        int max = ((0) + "").length();
        for (int i = 0; i < (); i++) {
            String s = (i) + "";
            if (() > max) {
                return i;
            }
        }
        return NULL_INDEX;
    }

    //Get the point in the screen at the end of the slide    private int middleIndex(int size) {
        if (size % 2 == 0) {
            return size / 2;
        } else {
            return size / 2 + 1;
        }
    }


    /**
 * Get a point in the middle based on the coordinates of two points
      *
 * @param from coordinate 1
 * @param to   Coordinate 2
 */

    //Get the slope of the known point y = kx+b    private float getSlope(Point from, Point to) {
        float k = ( - ) / ( - );
        ("Point", "Parameter b:" + k);
        return k;
    }

    //Get parameter b    private float getParams(Point from, Point to) {
        float b =  - (getSlope(from, to) * );
        ("Point", "Parameter b:" + b);
        return b;
    }

    //Get any coordinate x value of the x axis based on the coordinates between two points,    private float getArbitrarilyX(Point from, Point to, int grade, int needGrade) {
        //Get the new coordinates of the input        float x = (( - ) * needGrade) / grade + ;
        ("Point", "x coordinate value:" + x);
        return x;
    }

    //Get coordinate value    private Point getPoint(Point from, Point to, int grade, int needGrade) {
        Point point = new Point();
        (getArbitrarilyX(from, to, grade, needGrade));
        float slope = getSlope(from, to);
        (slope *  + getParams(from, to));
        return point;
    }

    //Get the point where the polyline is drawn    private Point getSpinnerPoint(int valueIndex) {
        float x = mXInit + interval * (valueIndex);
        float y = mYOri - mYOri * (1 - 0.1f) * ((valueIndex)) / (() - 1);
        return new Point(x, y);
    }

    private class Point {
        float x;
        float y;

        public Point() {
        }

        public float getX() {
            return x;
        }

        public void setX(float x) {
             = x;
        }

        public float getY() {
            return y;
        }

        public void setY(float y) {
             = y;
        }

        public Point(float x, float y) {
             = x;
             = y;
        }

        @Override
        public String toString() {
            return "Point{" +
                    "x=" + x +
                    ", y=" + y +
                    '}';
        }
    }
}

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.