\u8fd9\u7bc7\u6587\u7ae0\u4e3b\u8981\u4e3a\u5927\u5bb6\u8be6\u7ec6\u4ecb\u7ecd\u4e86android\u5b9e\u73b0\u53ef\u4ee5\u6ed1\u52a8\u7684\u5e73\u6ed1\u66f2\u7ebf\u56fe\uff0c\u6587\u4e2d\u793a\u4f8b\u4ee3\u7801\u4ecb\u7ecd\u7684\u975e\u5e38\u8be6\u7ec6\uff0c\u5177\u6709\u4e00\u5b9a\u7684\u53c2\u8003\u4ef7\u503c\uff0c\u611f\u5174\u8da3\u7684\u5c0f\u4f19\u4f34\u4eec\u53ef\u4ee5\u53c2\u8003\u4e00\u4e0b<\/strong><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n\u672c\u6587\u5b9e\u4f8b\u4e3a\u5927\u5bb6\u5206\u4eab\u4e86android\u5b9e\u73b0\u53ef\u4ee5\u6ed1\u52a8\u7684\u5e73\u6ed1\u66f2\u7ebf\u56fe\u7684\u5177\u4f53\u4ee3\u7801\uff0c\u4f9b\u5927\u5bb6\u53c2\u8003\uff0c\u5177\u4f53\u5185\u5bb9\u5982\u4e0b<\/p>\n
\u76f4\u63a5\u4e0a\u4ee3\u7801\uff0c\u91cc\u9762\u6709\u8be6\u7ec6\u6ce8\u89e3<\/p>\n
1 attr \u5c5e\u6027\u7f16\u5199 <\/p>\n
\r\n \r\n< attr name=\"xy_line_color\" format=\"color\" \/>\r\n < !-- xy\u5750\u6807\u8f74\u5bbd\u5ea6 -->\r\n < attr name=\"xy_line_width\" format=\"dimension\" \/>\r\n < !-- xy\u5750\u6807\u8f74\u6587\u5b57\u989c\u8272 -->\r\n < attr name=\"xy_text_color\" format=\"color\" \/>\r\n < !-- xy\u5750\u6807\u8f74\u6587\u5b57\u5927\u5c0f -->\r\n < attr name=\"xy_text_size\" format=\"dimension\" \/>\r\n < !-- \u6298\u7ebf\u56fe\u4e2d\u6298\u7ebf\u7684\u989c\u8272 -->\r\n < attr name=\"line_color\" format=\"color\" \/>\r\n \r\n < attr name=\"interval\" format=\"dimension\" \/>\r\n < !-- \u80cc\u666f\u989c\u8272 -->\r\n < attr name=\"bg_color\" format=\"color\" \/>\r\n < !-- \u66f2\u7ebf\u9009\u4e2d\u5916\u90e8\u989c\u8272 -->\r\n < attr name=\"select_circle_color\" format=\"color\" \/>\r\n < !-- \u66f2\u7ebf\u9009\u4e2d\u5185\u90e8\u989c\u8272 -->\r\n < attr name=\"select_reminder_color\" format=\"color\" \/>\r\n < !--\u662f\u5426\u62ac\u624b\u6eda\u52a8-->\r\n < attr name=\"isScroll\" format=\"boolean\" \/>\r\n < declare-styleable name=\"ChartView\">\r\n < attr name=\"xy_line_color\" \/>\r\n < attr name=\"xy_line_width\" \/>\r\n < attr name=\"xy_text_color\" \/>\r\n < attr name=\"xy_text_size\" \/>\r\n < attr name=\"line_color\" \/>\r\n < attr name=\"interval\" \/>\r\n < attr name=\"bg_color\" \/>\r\n < attr name=\"select_circle_color\" \/>\r\n < attr name=\"select_reminder_color\" \/>\r\n < attr name=\"isScroll\" \/>\r\n < !--\u63d0\u793a\u6846\u8ddf\u6ed1\u52a8\u663e\u793a\u7684\u4f4d\u7f6e-->\r\n < attr name=\"show_position\">\r\n < enum name=\"first\" value=\"1\" \/>\r\n < enum name=\"middle\" value=\"2\" \/>\r\n < enum name=\"end\" value=\"3\" \/>\r\n < \/attr>\r\n< \/declare-styleable><\/pre>\n2 ChartView<\/p>\n
package com.laisontech.commonuilibrary.customviews;\r\n \r\nimport android.animation.Animator;\r\nimport android.animation.ValueAnimator;\r\nimport android.content.Context;\r\nimport android.content.res.TypedArray;\r\nimport android.graphics.Canvas;\r\nimport android.graphics.Color;\r\nimport android.graphics.Paint;\r\nimport android.graphics.Path;\r\nimport android.graphics.PorterDuff;\r\nimport android.graphics.PorterDuffXfermode;\r\nimport android.graphics.Rect;\r\nimport android.graphics.RectF;\r\nimport android.util.AttributeSet;\r\nimport android.util.Log;\r\nimport android.util.TypedValue;\r\nimport android.view.MotionEvent;\r\nimport android.view.VelocityTracker;\r\nimport android.view.View;\r\nimport android.view.animation.DecelerateInterpolator;\r\n \r\nimport com.laisontech.commonuilibrary.R;\r\n \r\nimport java.util.ArrayList;\r\nimport java.util.HashMap;\r\nimport java.util.List;\r\nimport java.util.Map;\r\n \r\n\/**\r\n * \u81ea\u5b9a\u4e49\u6298\u7ebf\u56fe\r\n *\/\r\npublic class ChartView extends View {\r\n private static final int FIRST = 1;\r\n private static final int MIDDLE = 2;\r\n private static final int END = 3;\r\n \/\/xy\u5750\u6807\u8f74\u989c\u8272\r\n private int xyLineColor = 0xffCFE2CF;\r\n \/\/\u6298\u7ebf\u9009\u4e2d\u7684\u5706\u5f62\u989c\u8272\r\n private int selectCircleColor = 0xff00A8FF;\r\n \/\/\u9009\u4e2d\u6570\u636e\u63d0\u793a\u6846\u989c\u8272\r\n private int selectReminderColor = 0xff00A8FF;\r\n \/\/\u6298\u7ebf\u4e2d\u5706\u5f62\u5185\u90e8\u90e8\u989c\u8272\r\n private int xyTextColor = 0xff0014FF;\r\n \/\/\u6298\u7ebf\u56fe\u4e2d\u6298\u7ebf\u7684\u989c\u8272\r\n private int lineColor = 0xffFD00FF;\r\n \/\/xy\u5750\u6807\u8f74\u5bbd\u5ea6\r\n private int xyLineWidth = dpToPx(1);\r\n \/\/xy\u5750\u6807\u8f74\u6587\u5b57\u5927\u5c0f\r\n private int xyTextSize = spToPx(12);\r\n \/\/x\u8f74\u5404\u4e2a\u5750\u6807\u70b9\u6c34\u5e73\u95f4\u8ddd\r\n private int interval = dpToPx(40);\r\n \/\/\u80cc\u666f\u989c\u8272\r\n private int bgColor = 0xffffffff;\r\n \/\/\u662f\u5426\u6709\u8d77\u624b\u65f6\u7684\u6ed1\u52a8\u611f\r\n private boolean isScroll = false;\r\n \/\/\u63d0\u793a\u6846\u663e\u793a\u4f4d\u7f6e\r\n private int mShowPositionType = 3;\r\n \/\/\u7ed8\u5236XY\u8f74\u5750\u6807\u5bf9\u5e94\u7684\u753b\u7b14\r\n private Paint mXYPaint;\r\n \/\/\u7ed8\u5236XY\u8f74\u7684\u6587\u672c\u5bf9\u5e94\u7684\u753b\u7b14\r\n private Paint mXYTextPaint;\r\n \/\/\u753b\u6298\u7ebf\u5bf9\u5e94\u7684\u753b\u7b14\r\n private Paint mSpinnerLinePaint;\r\n private int width;\r\n private int height;\r\n \/\/x\u8f74\u7684\u539f\u70b9\u5750\u6807\r\n private int mXOri;\r\n \/\/y\u8f74\u7684\u539f\u70b9\u5750\u6807\r\n private int mYOri;\r\n \/\/\u7b2c\u4e00\u4e2a\u70b9X\u7684\u5750\u6807\r\n private float mXInit;\r\n \/\/\u7b2c\u4e00\u4e2a\u70b9\u5bf9\u5e94\u7684\u6700\u5927X\u5750\u6807\r\n private float maxXInit;\r\n \/\/\u7b2c\u4e00\u4e2a\u70b9\u5bf9\u5e94\u7684\u6700\u5c0fX\u5750\u6807\r\n private float minXInit;\r\n \/\/x\u8f74\u5750\u6807\u5bf9\u5e94\u7684\u6570\u636e\r\n private List mXData = new ArrayList<>();\r\n \/\/y\u8f74\u5750\u6807\u5bf9\u5e94\u7684\u6570\u636e\r\n private List mYData = new ArrayList<>();\r\n \/\/\u6298\u7ebf\u5bf9\u5e94\u7684\u6570\u636e\r\n private Map mSpinnerValue = new HashMap<>();\r\n \/\/\u70b9\u51fb\u7684\u70b9\u5bf9\u5e94\u7684X\u8f74\u7684\u7b2c\u51e0\u4e2a\u70b9\uff0c\u9ed8\u8ba41\r\n private int selectIndex = 1;\r\n \/\/X\u8f74\u523b\u5ea6\u6587\u672c\u5bf9\u5e94\u7684\u6700\u5927\u77e9\u5f62\uff0c\u4e3a\u4e86\u9009\u4e2d\u65f6\uff0c\u5728x\u8f74\u6587\u672c\u753b\u7684\u6846\u6846\u5927\u5c0f\u4e00\u81f4\uff0c\u83b7\u53d6\u4ece\u6570\u636e\u4e2d\u5f97\u5230\u7684x\u8f74\u6570\u636e\uff0c\u83b7\u5f97\u6700\u957f\u6570\u636e\r\n private Rect xValueRect;\r\n \/\/\u901f\u5ea6\u68c0\u6d4b\u5668\r\n private VelocityTracker mTracker;\r\n \/\/\u662f\u5426\u4e3a\u77ed\u8ddd\u79bb\u6ed1\u52a8\r\n private boolean isShortSlide = false;\r\n \/\/\u83b7\u53d6\u5c3a\u5bf8\u7684\u7684\u4e2d\u95f4\r\n private int mSelectMiddle = 0;\r\n \/\/\u66f2\u7ebf\u5207\u7387\r\n private float mLineSmoothness = 0.18f;\r\n \r\n public ChartView(Context context) {\r\n this(context, null);\r\n }\r\n \r\n public ChartView(Context context, AttributeSet attrs) {\r\n this(context, attrs, 0);\r\n }\r\n \r\n public ChartView(Context context, AttributeSet attrs, int defStyleAttr) {\r\n super(context, attrs, defStyleAttr);\r\n init(context, attrs, defStyleAttr);\r\n initPaint();\r\n }\r\n \r\n \/\/\u8bbe\u7f6e\u5207\u7387\r\n public void setLineSmoothness(float lineSmoothness) {\r\n if (lineSmoothness != this.mLineSmoothness) {\r\n this.mLineSmoothness = lineSmoothness;\r\n }\r\n }\r\n \r\n \/**\r\n * \u521d\u59cb\u5316\r\n *\/\r\n private void initPaint() {\r\n mXYPaint = new Paint();\r\n mXYPaint.setAntiAlias(true);\r\n mXYPaint.setStrokeWidth(xyLineWidth);\r\n mXYPaint.setStrokeJoin(Paint.Join.ROUND);\r\n mXYPaint.setColor(xyLineColor);\r\n \r\n mXYTextPaint = new Paint();\r\n mXYTextPaint.setAntiAlias(true);\r\n mXYTextPaint.setTextSize(xyTextSize);\r\n mXYTextPaint.setStrokeJoin(Paint.Join.ROUND);\r\n mXYTextPaint.setColor(xyTextColor);\r\n mXYTextPaint.setStyle(Paint.Style.STROKE);\r\n \r\n mSpinnerLinePaint = new Paint();\r\n mSpinnerLinePaint.setAntiAlias(true);\r\n mSpinnerLinePaint.setStrokeWidth(xyLineWidth);\r\n mSpinnerLinePaint.setColor(lineColor);\r\n mSpinnerLinePaint.setStyle(Paint.Style.STROKE);\r\n mSpinnerLinePaint.setStrokeJoin(Paint.Join.ROUND);\r\n }\r\n \r\n \/**\r\n * \u521d\u59cb\u5316\r\n *\r\n * @param context\r\n * @param attrs\r\n * @param defStyleAttr\r\n *\/\r\n private void init(Context context, AttributeSet attrs, int defStyleAttr) {\r\n TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ChartView, defStyleAttr, 0);\r\n int count = array.getIndexCount();\r\n for (int i = 0; i < count; i++) {\r\n int attr = array.getIndex(i);\r\n if (attr == R.styleable.ChartView_xy_line_color) {\r\n xyLineColor = array.getColor(attr, xyLineColor);\r\n \r\n } else if (attr == R.styleable.ChartView_xy_line_width) {\r\n xyLineWidth = (int) array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, xyLineWidth, getResources().getDisplayMetrics()));\r\n \r\n } else if (attr == R.styleable.ChartView_xy_text_color) {\r\n xyTextColor = array.getColor(attr, xyTextColor);\r\n \r\n } else if (attr == R.styleable.ChartView_xy_text_size) {\r\n xyTextSize = (int) array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, xyTextSize, getResources().getDisplayMetrics()));\r\n \r\n } else if (attr == R.styleable.ChartView_line_color) {\r\n lineColor = array.getColor(attr, lineColor);\r\n \r\n } else if (attr == R.styleable.ChartView_interval) {\r\n interval = (int) array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, interval, getResources().getDisplayMetrics()));\r\n \r\n } else if (attr == R.styleable.ChartView_bg_color) {\r\n bgColor = array.getColor(attr, bgColor);\r\n \r\n } else if (attr == R.styleable.ChartView_select_circle_color) {\r\n selectCircleColor = array.getColor(attr, selectCircleColor);\r\n \r\n } else if (attr == R.styleable.ChartView_select_reminder_color) {\r\n selectReminderColor = array.getColor(attr, selectReminderColor);\r\n \r\n } else if (attr == R.styleable.ChartView_isScroll) {\r\n isScroll = array.getBoolean(attr, isScroll);\r\n } else if (attr == R.styleable.ChartView_show_position) {\r\n mShowPositionType = array.getInt(attr, mShowPositionType);\r\n }\r\n }\r\n array.recycle();\r\n }\r\n \r\n @Override\r\n protected void onLayout(boolean changed, int left, int top, int right, int bottom) {\r\n if (changed) {\r\n width = getWidth();\r\n height = getHeight();\r\n \/\/Y\u8f74\u6587\u672c\u7684\u6700\u5927\u5bbd\u5ea6\r\n float textYWdith = getTextBounds(mYData.get(getListItemMaxIndex(mYData)) + \"\", mXYTextPaint).width();\r\n for (int i = 0; i < mYData.size(); i++) {\/\/\u6c42\u53d6y\u8f74\u6587\u672c\u6700\u5927\u7684\u5bbd\u5ea6\r\n float temp = getTextBounds(mYData.get(i) + \"\", mXYTextPaint).width();\r\n if (temp > textYWdith)\r\n textYWdith = temp;\r\n }\r\n int dp2 = dpToPx(2);\r\n int dp3 = dpToPx(3);\r\n mXOri = (int) (dp2 + textYWdith + dp2 + xyLineWidth);\r\n \/\/\u83b7\u53d6x\u8f74\u7684\u6700\u957f\u6587\u672c\u7684\u5bbd\u5ea6\u6240\u5360\u7684\u77e9\u5f62\r\n xValueRect = getTextBounds(mXData.get(getListItemMaxIndex(mXData)), mXYTextPaint);\r\n \/\/X\u8f74\u6587\u672c\u9ad8\u5ea6\r\n float textXHeight = xValueRect.height();\r\n for (int i = 0; i < mXData.size(); i++) {\r\n Rect rect = getTextBounds(mXData.get(i) + \"\", mXYTextPaint);\r\n if (rect.height() > textXHeight)\r\n textXHeight = rect.height();\r\n if (rect.width() > xValueRect.width())\r\n xValueRect = rect;\r\n }\r\n mYOri = (int) (height - dp2 - textXHeight - dp3 - xyLineWidth);\r\n mXInit = mXOri + xValueRect.width() \/ 2 + dpToPx(5);\r\n minXInit = width - (width - mXOri) * 0.1f - interval * (mXData.size() - 1);\r\n maxXInit = mXInit;\r\n }\r\n selectIndex = getSelectIndexFromShowType(mShowPositionType);\r\n super.onLayout(changed, left, top, right, bottom);\r\n }\r\n \r\n @Override\r\n protected void onDraw(Canvas canvas) {\r\n canvas.drawColor(bgColor);\r\n drawXY(canvas);\r\n drawBrokenLineAndPoint(canvas);\r\n }\r\n \r\n \/**\r\n * \u7ed8\u5236\u4ea4\u70b9\u5904\u5bf9\u5e94\u7684\u70b9\r\n *\/\r\n private void drawBrokenLineAndPoint(Canvas canvas) {\r\n if (mXData.size() <= 0)\r\n return;\r\n int layerId = canvas.saveLayer(0, 0, width, height, null, Canvas.ALL_SAVE_FLAG);\r\n drawBrokenLine(canvas);\r\n drawBrokenPoint(canvas);\r\n \/\/ \u5c06\u8d85\u51fax\u8f74\u5750\u6807\u7684\u90e8\u5206\u622a\u6389\r\n mSpinnerLinePaint.setStyle(Paint.Style.FILL);\r\n mSpinnerLinePaint.setColor(bgColor);\r\n mSpinnerLinePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));\r\n RectF rectF = new RectF(0, 0, mXOri, height);\r\n canvas.drawRect(rectF, mSpinnerLinePaint);\r\n mSpinnerLinePaint.setXfermode(null);\r\n \r\n canvas.restoreToCount(layerId);\r\n }\r\n \r\n \/**\r\n * \u7ed8\u5236\u66f2\u7ebf\u5bf9\u5e94\u7684\u70b9\r\n *\/\r\n private void drawBrokenPoint(Canvas canvas) {\r\n float dp2 = dpToPx(2);\r\n float dp4 = dpToPx(4);\r\n float dp7 = dpToPx(7);\r\n Log.e(\"selectIndex\", \"index:\" + selectIndex);\r\n \/\/\u7ed8\u5236\u8282\u70b9\r\n for (int i = 0; i < mXData.size(); i++) {\r\n float x = mXInit + interval * i;\r\n float y = mYOri - mYOri * (1 - 0.1f) * mSpinnerValue.get(mXData.get(i)) \/ mYData.get(mYData.size() - 1);\r\n \/\/\u7ed8\u5236\u9009\u4e2d\u70b9\r\n if (i == selectIndex - 1) {\r\n mSpinnerLinePaint.setStyle(Paint.Style.FILL);\r\n \/\/\u8bbe\u7f6e\u9009\u4e2d\u989c\u8272\r\n mSpinnerLinePaint.setColor(selectCircleColor);\r\n canvas.drawCircle(x, y, dp7, mSpinnerLinePaint);\r\n mSpinnerLinePaint.setColor(selectReminderColor);\r\n canvas.drawCircle(x, y, dp4, mSpinnerLinePaint);\r\n drawFloatTextBox(canvas, x, y - dp7, mSpinnerValue.get(mXData.get(i)));\r\n }\r\n \/\/\u7ed8\u5236\u666e\u901a\u8282\u70b9\r\n mSpinnerLinePaint.setStyle(Paint.Style.FILL);\r\n mSpinnerLinePaint.setColor(Color.WHITE);\r\n canvas.drawCircle(x, y, dp2, mSpinnerLinePaint);\r\n mSpinnerLinePaint.setStyle(Paint.Style.STROKE);\r\n mSpinnerLinePaint.setColor(lineColor);\r\n canvas.drawCircle(x, y, dp2, mSpinnerLinePaint);\r\n \r\n }\r\n }\r\n \r\n \/**\r\n * \u7ed8\u5236\u6d6e\u52a8\u6846\r\n * *\/\r\n private void drawFloatTextBox(Canvas canvas, float x, float y, int text) {\r\n int dp6 = dpToPx(6);\r\n int dp18 = dpToPx(18);\r\n \/\/p1\r\n Path path = new Path();\r\n path.moveTo(x, y);\r\n \/\/p2\r\n path.lineTo(x - dp6, y - dp6);\r\n \/\/p3\r\n path.lineTo(x - dp18, y - dp6);\r\n \/\/p4\r\n path.lineTo(x - dp18, y - dp6 - dp18);\r\n \/\/p5\r\n path.lineTo(x + dp18, y - dp6 - dp18);\r\n \/\/p6\r\n path.lineTo(x + dp18, y - dp6);\r\n \/\/p7\r\n path.lineTo(x + dp6, y - dp6);\r\n \/\/p1\r\n path.lineTo(x, y);\r\n canvas.drawPath(path, mSpinnerLinePaint);\r\n mSpinnerLinePaint.setColor(Color.WHITE);\r\n mSpinnerLinePaint.setTextSize(spToPx(14));\r\n Rect rect = getTextBounds(text + \"\", mSpinnerLinePaint);\r\n canvas.drawText(text + \"\", x - rect.width() \/ 2, y - dp6 - (dp18 - rect.height()) \/ 2, mSpinnerLinePaint);\r\n }\r\n \r\n \/**\r\n * \u7ed8\u5236\u5e73\u6ed1\u66f2\u7ebf\r\n *\/\r\n private void drawBrokenLine(Canvas canvas) {\r\n mSpinnerLinePaint.setStyle(Paint.Style.STROKE);\r\n mSpinnerLinePaint.setColor(lineColor);\r\n \/\/\u7ed8\u5236\u6298\u7ebf\r\n Path path = new Path();\r\n float prePreviousPointX = Float.NaN;\r\n float prePreviousPointY = Float.NaN;\r\n float previousPointX = Float.NaN;\r\n float previousPointY = Float.NaN;\r\n float currentPointX = Float.NaN;\r\n float currentPointY = Float.NaN;\r\n float nextPointX;\r\n float nextPointY;\r\n int lineSize = mXData.size();\r\n for (int i = 0; i < lineSize; i++) {\r\n float x;\r\n float y;\r\n if (Float.isNaN(currentPointX)) {\r\n currentPointX = getSpinnerPoint(i).x;\r\n currentPointY = getSpinnerPoint(i).y;\r\n }\r\n if (Float.isNaN(previousPointX)) {\r\n \/\/\u662f\u7b2c\u4e00\u4e2a\u70b9?\r\n if (i > 0) {\r\n previousPointX = getSpinnerPoint(i - 1).x;\r\n previousPointY = getSpinnerPoint(i - 1).y;\r\n } else {\r\n \/\/\u7528\u5f53\u524d\u70b9\u8868\u793a\u4e0a\u4e00\u4e2a\u70b9\r\n previousPointX = currentPointX;\r\n previousPointY = currentPointY;\r\n }\r\n }\r\n \r\n if (Float.isNaN(prePreviousPointX)) {\r\n \/\/\u662f\u524d\u4e24\u4e2a\u70b9?\r\n if (i > 1) {\r\n prePreviousPointX = getSpinnerPoint(i - 2).x;\r\n prePreviousPointY = getSpinnerPoint(i - 2).y;\r\n } else {\r\n \/\/\u5f53\u524d\u70b9\u8868\u793a\u4e0a\u4e0a\u4e2a\u70b9\r\n prePreviousPointX = previousPointX;\r\n prePreviousPointY = previousPointY;\r\n }\r\n }\r\n \r\n \/\/ \u5224\u65ad\u662f\u4e0d\u662f\u6700\u540e\u4e00\u4e2a\u70b9\u4e86\r\n if (i < lineSize - 1) {\r\n nextPointX = getSpinnerPoint(i + 1).x;\r\n nextPointY = getSpinnerPoint(i + 1).y;\r\n } else {\r\n \/\/\u7528\u5f53\u524d\u70b9\u8868\u793a\u4e0b\u4e00\u4e2a\u70b9\r\n nextPointX = currentPointX;\r\n nextPointY = currentPointY;\r\n }\r\n \r\n if (i == 0) {\r\n \/\/ \u5c06Path\u79fb\u52a8\u5230\u5f00\u59cb\u70b9\r\n path.moveTo(currentPointX, currentPointY);\r\n } else {\r\n \/\/ \u6c42\u51fa\u63a7\u5236\u70b9\u5750\u6807\r\n final float firstDiffX = (currentPointX - prePreviousPointX);\r\n final float firstDiffY = (currentPointY - prePreviousPointY);\r\n final float secondDiffX = (nextPointX - previousPointX);\r\n final float secondDiffY = (nextPointY - previousPointY);\r\n final float firstControlPointX = previousPointX + (mLineSmoothness * firstDiffX);\r\n final float firstControlPointY = previousPointY + (mLineSmoothness * firstDiffY);\r\n final float secondControlPointX = currentPointX - (mLineSmoothness * secondDiffX);\r\n final float secondControlPointY = currentPointY - (mLineSmoothness * secondDiffY);\r\n \/\/\u753b\u51fa\u66f2\u7ebf\r\n path.cubicTo(firstControlPointX, firstControlPointY, secondControlPointX, secondControlPointY,\r\n currentPointX, currentPointY);\r\n }\r\n \r\n \/\/ \u66f4\u65b0\r\n prePreviousPointX = previousPointX;\r\n prePreviousPointY = previousPointY;\r\n previousPointX = currentPointX;\r\n previousPointY = currentPointY;\r\n currentPointX = nextPointX;\r\n currentPointY = nextPointY;\r\n }\r\n canvas.drawPath(path, mSpinnerLinePaint);\r\n }\r\n \r\n \/**\r\n * \u7ed8\u5236XY\u5750\u6807\r\n *\/\r\n private void drawXY(Canvas canvas) {\r\n int length = dpToPx(5);\/\/\u523b\u5ea6\u7684\u957f\u5ea6\r\n \/\/\u7ed8\u5236Y\u5750\u6807\r\n canvas.drawLine(mXOri - xyLineWidth \/ 2, 0, mXOri - xyLineWidth \/ 2, mYOri, mXYPaint);\r\n \/\/\u7ed8\u5236\u7bad\u5934\r\n mXYPaint.setStyle(Paint.Style.STROKE);\r\n Path path = new Path();\r\n path.moveTo(mXOri - xyLineWidth \/ 2 - dpToPx(5), dpToPx(12));\r\n path.lineTo(mXOri - xyLineWidth \/ 2, xyLineWidth \/ 2);\r\n path.lineTo(mXOri - xyLineWidth \/ 2 + dpToPx(5), dpToPx(12));\r\n canvas.drawPath(path, mXYPaint);\r\n \/\/\u7ed8\u5236\u523b\u5ea6\r\n int yLength = (int) (mYOri * (1 - 0.1f) \/ (mYData.size() - 1));\/\/y\u8f74\u4e0a\u9762\u7a7a\u51fa10%,\u8ba1\u7b97\u51fay\u8f74\u523b\u5ea6\u95f4\u8ddd\r\n for (int i = 0; i < mYData.size(); i++) {\r\n \/\/\u7ed8\u5236\u523b\u5ea6\r\n canvas.drawLine(mXOri, mYOri - yLength * i + xyLineWidth \/ 2, mXOri + length, mYOri - yLength * i + xyLineWidth \/ 2, mXYPaint);\r\n mXYTextPaint.setColor(xyTextColor);\r\n \/\/\u7ed8\u5236\u6587\u672c\r\n String text = mYData.get(i) + \"\";\r\n Rect rect = getTextBounds(text, mXYTextPaint);\r\n canvas.drawText(text, 0, text.length(), mXOri - xyLineWidth - dpToPx(2) - rect.width(), mYOri - yLength * i + rect.height() \/ 2, mXYTextPaint);\r\n }\r\n \/\/\u7ed8\u5236\u5750\u6807\r\n canvas.drawLine(mXOri, mYOri + xyLineWidth \/ 2, width, mYOri + xyLineWidth \/ 2, mXYPaint);\r\n \/\/\u7ed8\u5236\u7bad\u5934\r\n mXYPaint.setStyle(Paint.Style.STROKE);\r\n path = new Path();\r\n \/\/\u6574\u4e2a\u957f\u5ea6\r\n float xLength = mXInit + interval * (mXData.size() - 1) + (width - mXOri) * 0.1f;\r\n if (xLength < width)\r\n xLength = width;\r\n path.moveTo(xLength - dpToPx(12), mYOri + xyLineWidth \/ 2 - dpToPx(5));\r\n path.lineTo(xLength - xyLineWidth \/ 2, mYOri + xyLineWidth \/ 2);\r\n path.lineTo(xLength - dpToPx(12), mYOri + xyLineWidth \/ 2 + dpToPx(5));\r\n canvas.drawPath(path, mXYPaint);\r\n \/\/\u7ed8\u5236x\u8f74\u523b\u5ea6\r\n for (int i = 0; i < mXData.size(); i++) {\r\n float x = mXInit + interval * i;\r\n if (x >= mXOri) {\/\/\u53ea\u7ed8\u5236\u4ece\u539f\u70b9\u5f00\u59cb\u7684\u533a\u57df\r\n mXYTextPaint.setColor(xyTextColor);\r\n canvas.drawLine(x, mYOri, x, mYOri - length, mXYPaint);\r\n \/\/\u7ed8\u5236X\u8f74\u6587\u672c\r\n String text = mXData.get(i);\r\n Rect rect = getTextBounds(text, mXYTextPaint);\r\n if (i == selectIndex - 1) {\r\n mXYTextPaint.setColor(lineColor);\r\n canvas.drawText(text, 0, text.length(), x - rect.width() \/ 2, mYOri + xyLineWidth + dpToPx(2) + rect.height(), mXYTextPaint);\r\n canvas.drawRoundRect(x - xValueRect.width() \/ 2 - dpToPx(3), mYOri + xyLineWidth + dpToPx(1), x + xValueRect.width() \/ 2 + dpToPx(3), mYOri + xyLineWidth + dpToPx(2) + xValueRect.height() + dpToPx(2), dpToPx(2), dpToPx(2), mXYTextPaint);\r\n } else {\r\n canvas.drawText(text, 0, text.length(), x - rect.width() \/ 2, mYOri + xyLineWidth + dpToPx(2) + rect.height(), mXYTextPaint);\r\n }\r\n }\r\n }\r\n }\r\n \r\n private float startX;\r\n private float startx;\r\n \r\n @Override\r\n public boolean onTouchEvent(MotionEvent event) {\r\n if (isScrolling)\r\n return super.onTouchEvent(event);\r\n \/\/\u5f53\u8be5view\u83b7\u5f97\u70b9\u51fb\u4e8b\u4ef6\uff0c\u5c31\u8bf7\u6c42\u7236\u63a7\u4ef6\u4e0d\u62e6\u622a\u4e8b\u4ef6\r\n this.getParent().requestDisallowInterceptTouchEvent(true);\r\n obtainVelocityTracker(event);\r\n switch (event.getAction()) {\r\n case MotionEvent.ACTION_DOWN:\r\n startX = event.getX();\r\n startx = event.getX();\r\n Log.e(\"XXXX\", \"down:\" + startX + \"\");\r\n break;\r\n case MotionEvent.ACTION_MOVE:\r\n \/\/\u6ed1\u52a8\u8ddd\u79bb\u5c0f\u4e8e\u7b49\u4e8e8\u7684\u65f6\u5019\u4efb\u52a1\u4e3a\u77ed\u8ddd\u79bb\u6ed1\u52a8\r\n \/\/\u5f53\u524dx\u8f74\u7684\u5c3a\u5bf8\u4e0e\u8bbe\u7f6e\u7684x\u8f74\u95f4\u9694\u7684\u8ddd\u79bb\u4e4b\u4e58\u79ef\u5927\u4e8e \u5c4f\u5e55\u4e2d\u7684\u663e\u793a\u5e03\u5c40\u5bbd\u5ea6\u4e0ex\u8f74\u4e03\u70b9\u4e4b\u5dee\u65f6\uff0c\u5f00\u59cb\u79fb\u52a8\r\n if (interval * mXData.size() > width - mXOri) {\r\n \/\/\u83b7\u53d6\u6ed1\u52a8\u7684\u8ddd\u79bb\r\n float dis = event.getX() - startX;\r\n \/\/\u91cd\u65b0\u8d4b\u503c\u7ed9startX\r\n startX = event.getX();\r\n \/\/\u5f53\u524dx\u539f\u70b9\u8ddd\u79bb\u4e0e\u5de6\u53f3\u6ed1\u52a8\u7684\u8ddd\u79bb\u4e4b\u548c\u6ca1\u6709\u6700\u5c0f\u503c\u5927\uff0c\u5219\u5c06\u5f53\u524dx\u8ddd\u79bb\u8d4b\u503c\u4e3a\u6700\u5c0f\uff0c\u4ee5\u4e0b\u76f8\u4f3c\r\n if (mXInit + dis < minXInit) {\r\n mXInit = minXInit;\r\n } else if (mXInit + dis > maxXInit) {\r\n mXInit = maxXInit;\r\n } else {\r\n mXInit = mXInit + dis;\r\n }\r\n invalidate();\r\n }\r\n break;\r\n case MotionEvent.ACTION_UP:\r\n isShortSlide = Math.abs(event.getX() - startx) <= dpToPx(8);\r\n clickAction(event);\r\n scrollAfterActionUp();\r\n this.getParent().requestDisallowInterceptTouchEvent(false);\r\n recycleVelocityTracker();\r\n break;\r\n case MotionEvent.ACTION_CANCEL:\r\n \/\/\u589e\u52a0\u8fd9\u884c\u4ee3\u7801\u9632\u6b62\u4e0e\u7236\u7c7b\u7684\u6ed1\u52a8\u4e8b\u4ef6\u51b2\u7a81\r\n this.getParent().requestDisallowInterceptTouchEvent(false);\r\n recycleVelocityTracker();\r\n break;\r\n }\r\n return true;\r\n }\r\n \r\n \/\/\u662f\u5426\u6b63\u5728\u6ed1\u52a8\r\n private boolean isScrolling = false;\r\n \r\n \/**\r\n * \u624b\u6307\u62ac\u8d77\u540e\u7684\u6ed1\u52a8\u5904\u7406\r\n *\/\r\n private void scrollAfterActionUp() {\r\n if (!isScroll)\r\n return;\r\n final float velocity = getVelocity();\r\n float scrollLength = maxXInit - minXInit;\r\n if (Math.abs(velocity) < 10000)\r\n scrollLength = (maxXInit - minXInit) * Math.abs(velocity) \/ 10000;\r\n ValueAnimator animator = ValueAnimator.ofFloat(0, scrollLength);\r\n animator.setDuration((long) (scrollLength \/ (maxXInit - minXInit) * 1000));\/\/\u65f6\u95f4\u6700\u5927\u4e3a1000\u6beb\u79d2\uff0c\u6b64\u5904\u4f7f\u7528\u6bd4\u4f8b\u8fdb\u884c\u6362\u7b97\r\n animator.setInterpolator(new DecelerateInterpolator());\r\n animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {\r\n @Override\r\n public void onAnimationUpdate(ValueAnimator valueAnimator) {\r\n float value = (float) valueAnimator.getAnimatedValue();\r\n if (velocity < 0 && mXInit > minXInit) {\/\/\u5411\u5de6\u6ed1\u52a8\r\n if (mXInit - value <= minXInit)\r\n mXInit = minXInit;\r\n else\r\n mXInit = mXInit - value;\r\n } else if (velocity > 0 && mXInit < maxXInit) {\/\/\u5411\u53f3\u6ed1\u52a8\r\n if (mXInit + value >= maxXInit)\r\n mXInit = maxXInit;\r\n else\r\n mXInit = mXInit + value;\r\n }\r\n invalidate();\r\n }\r\n });\r\n animator.addListener(new Animator.AnimatorListener() {\r\n @Override\r\n public void onAnimationStart(Animator animator) {\r\n isScrolling = true;\r\n }\r\n \r\n @Override\r\n public void onAnimationEnd(Animator animator) {\r\n isScrolling = false;\r\n }\r\n \r\n @Override\r\n public void onAnimationCancel(Animator animator) {\r\n isScrolling = false;\r\n }\r\n \r\n @Override\r\n public void onAnimationRepeat(Animator animator) {\r\n \r\n }\r\n });\r\n animator.start();\r\n \r\n }\r\n \r\n \/**\r\n * \u83b7\u53d6\u901f\u5ea6\r\n *\r\n * @return\r\n *\/\r\n private float getVelocity() {\r\n if (mTracker != null) {\r\n mTracker.computeCurrentVelocity(1000);\r\n return mTracker.getXVelocity();\r\n }\r\n return 0;\r\n }\r\n \r\n \/**\r\n * \u70b9\u51fbX\u8f74\u5750\u6807\u6216\u8005\u6298\u7ebf\u8282\u70b9\r\n * *\/\r\n \/\/ 44 142 139\r\n private void clickAction(MotionEvent event) {\r\n int dp8 = dpToPx(8);\r\n float eventX = event.getX();\r\n float eventY = event.getY();\r\n if (!isShortSlide) {\r\n for (int i = 0; i < mXData.size(); i++) {\r\n float x = mXInit + interval * i;\r\n float start = mXOri;\r\n if (x >= start + (mSelectMiddle - 1) * interval && x < start + mSelectMiddle * interval) {\r\n selectIndex = i + 1;\r\n invalidate();\r\n }\r\n }\r\n return;\r\n }\r\n for (int i = 0; i < mXData.size(); i++) {\r\n \/\/\u8282\u70b9\r\n float x = mXInit + interval * i;\r\n float y = mYOri - mYOri * (1 - 0.1f) * mSpinnerValue.get(mXData.get(i)) \/ mYData.get(mYData.size() - 1);\r\n if (eventX >= x - dp8 && eventX <= x + dp8 &&\r\n eventY >= y - dp8 && eventY <= y + dp8 && selectIndex != i + 1) {\/\/\u6bcf\u4e2a\u8282\u70b9\u5468\u56f4\u8303\u56f4\u5185\u90fd\u662f\u53ef\u70b9\u51fb\u533a\u57df\r\n selectIndex = i + 1;\r\n invalidate();\r\n return;\r\n }\r\n \/\/X\u8f74\u523b\u5ea6\r\n String text = mXData.get(i);\r\n Rect rect = getTextBounds(text, mXYTextPaint);\r\n x = mXInit + interval * i;\r\n y = mYOri + xyLineWidth + dpToPx(2);\r\n if (eventX >= x - rect.width() \/ 2 - dp8 && eventX <= x + rect.width() + dp8 \/ 2 &&\r\n eventY >= y - dp8 && eventY <= y + rect.height() + dp8 && selectIndex != i + 1) {\r\n selectIndex = i + 1;\r\n invalidate();\r\n return;\r\n }\r\n }\r\n }\r\n \r\n \r\n \/**\r\n * \u83b7\u53d6\u901f\u5ea6\u8ddf\u8e2a\u5668\r\n *\r\n * @param event\r\n *\/\r\n private void obtainVelocityTracker(MotionEvent event) {\r\n if (!isScroll)\r\n return;\r\n if (mTracker == null) {\r\n mTracker = VelocityTracker.obtain();\r\n }\r\n mTracker.addMovement(event);\r\n }\r\n \r\n \/**\r\n * \u56de\u6536\u901f\u5ea6\u8ddf\u8e2a\u5668\r\n *\/\r\n private void recycleVelocityTracker() {\r\n if (mTracker != null) {\r\n mTracker.recycle();\r\n mTracker = null;\r\n }\r\n }\r\n \r\n \/**\r\n * \u6839\u636e\u7528\u6237\u8f93\u5165\u663e\u793a\u7c7b\u578b\uff0c\u5728\u6ed1\u52a8\u65f6\u5728\u4e0d\u540c\u7684\u4f4d\u7f6e\u663e\u793a\u63d0\u793a\u6846\r\n *\/\r\n private int getSelectIndexFromShowType(int showPositionType) {\r\n int visibleScale = (width - mXOri) \/ interval;\r\n switch (showPositionType) {\r\n case FIRST:\r\n mSelectMiddle = 1;\r\n return mSelectMiddle;\r\n case MIDDLE:\r\n if (mXData.size() <= visibleScale) {\r\n mSelectMiddle = middleIndex(mXData.size());\r\n } else {\r\n mSelectMiddle = middleIndex(visibleScale);\r\n }\r\n return mSelectMiddle; \/\/\u5c4f\u5e55\u53ef\u663e\u793a\u7684\u523b\u5ea6\r\n case END:\r\n if (mXData.size() <= visibleScale) {\r\n mSelectMiddle = mXData.size();\r\n } else {\r\n mSelectMiddle = visibleScale;\r\n }\r\n return visibleScale;\r\n default:\r\n mSelectMiddle = 0;\r\n return mSelectMiddle;\r\n }\r\n }\r\n \r\n public void setValue(Map value) {\r\n this.mSpinnerValue = value;\r\n invalidate();\r\n }\r\n \r\n public void setValue(Map value, List xValue, List yValue) {\r\n this.mSpinnerValue = value;\r\n this.mXData = xValue;\r\n this.mYData = yValue;\r\n invalidate();\r\n }\r\n \r\n \r\n public Map getValue() {\r\n return mSpinnerValue;\r\n }\r\n \r\n \/**\r\n * \u83b7\u53d6\u4e08\u91cf\u6587\u672c\u7684\u77e9\u5f62\r\n *\r\n * @param text\r\n * @param paint\r\n * @return\r\n *\/\r\n private Rect getTextBounds(String text, Paint paint) {\r\n Rect rect = new Rect();\r\n paint.getTextBounds(text, 0, text.length(), rect);\r\n return rect;\r\n }\r\n \r\n \/**\r\n * dp\u8f6c\u5316\u6210\u4e3apx\r\n *\r\n * @param dp\r\n * @return\r\n *\/\r\n private int dpToPx(int dp) {\r\n float density = getContext().getResources().getDisplayMetrics().density;\r\n return (int) (dp * density + 0.5f * (dp >= 0 ? 1 : -1));\r\n }\r\n \r\n \/**\r\n * sp\u8f6c\u5316\u4e3apx\r\n *\r\n * @param sp\r\n * @return\r\n *\/\r\n private int spToPx(int sp) {\r\n float scaledDensity = getContext().getResources().getDisplayMetrics().scaledDensity;\r\n return (int) (scaledDensity * sp + 0.5f * (sp >= 0 ? 1 : -1));\r\n }\r\n \r\n \/**\r\n * \u83b7\u53d6\u96c6\u5408\u4e2d\u6700\u957f\u7684index\r\n *\/\r\n private static final int NULL_INDEX = -1;\r\n \r\n public int getListItemMaxIndex(List> data) {\r\n if (data == null || data.size() < 1) {\r\n return NULL_INDEX;\r\n }\r\n int max = (data.get(0) + \"\").length();\r\n for (int i = 0; i < data.size(); i++) {\r\n String s = data.get(i) + \"\";\r\n if (s.length() > max) {\r\n return i;\r\n }\r\n }\r\n return NULL_INDEX;\r\n }\r\n \r\n \/\/\u83b7\u5f97\u5728\u6ed1\u52a8\u7ed3\u675f\u7684\u65f6\u5019\u5728\u5c4f\u5e55\u5185\u7684\u70b9\r\n private int middleIndex(int size) {\r\n if (size % 2 == 0) {\r\n return size \/ 2;\r\n } else {\r\n return size \/ 2 + 1;\r\n }\r\n }\r\n \r\n \r\n \/**\r\n * \u6839\u636e\u4e24\u70b9\u5750\u6807\u83b7\u53d6\u4e2d\u95f4\u67d0\u4e2a\u70b9\r\n *\r\n * @param from \u5750\u68071\r\n * @param to \u5750\u68072\r\n *\/\r\n \r\n \/\/\u83b7\u53d6\u5df2\u77e5\u70b9\u7684\u659c\u7387 y = kx+b\r\n private float getSlope(Point from, Point to) {\r\n float k = (to.y - from.y) \/ (to.x - from.x);\r\n Log.e(\"Point\", \"\u53c2\u6570b\uff1a\" + k);\r\n return k;\r\n }\r\n \r\n \/\/\u83b7\u53d6\u53c2\u6570 b\r\n private float getParams(Point from, Point to) {\r\n float b = from.y - (getSlope(from, to) * from.x);\r\n Log.e(\"Point\", \"\u53c2\u6570b\uff1a\" + b);\r\n return b;\r\n }\r\n \r\n \/\/\u6839\u636e\u4e24\u70b9\u95f4\u7684\u5750\u6807\u83b7\u53d6x\u8f74\u7684\u4efb\u610f\u4e00\u4e2a\u5750\u6807x\u503c,\r\n private float getArbitrarilyX(Point from, Point to, int grade, int needGrade) {\r\n \/\/\u83b7\u5f97\u8f93\u5165\u7684\u65b0\u5750\u6807\r\n float x = ((to.x - from.x) * needGrade) \/ grade + from.x;\r\n Log.e(\"Point\", \"x\u5750\u6807\u503c\uff1a\" + x);\r\n return x;\r\n }\r\n \r\n \/\/\u83b7\u53d6\u5750\u6807\u503c\r\n private Point getPoint(Point from, Point to, int grade, int needGrade) {\r\n Point point = new Point();\r\n point.setX(getArbitrarilyX(from, to, grade, needGrade));\r\n float slope = getSlope(from, to);\r\n point.setY(slope * point.x + getParams(from, to));\r\n return point;\r\n }\r\n \r\n \/\/\u83b7\u53d6\u7ed8\u5236\u6298\u7ebf\u7684\u70b9\r\n private Point getSpinnerPoint(int valueIndex) {\r\n float x = mXInit + interval * (valueIndex);\r\n float y = mYOri - mYOri * (1 - 0.1f) * mSpinnerValue.get(mXData.get(valueIndex)) \/ mYData.get(mYData.size() - 1);\r\n return new Point(x, y);\r\n }\r\n \r\n private class Point {\r\n float x;\r\n float y;\r\n \r\n public Point() {\r\n }\r\n \r\n public float getX() {\r\n return x;\r\n }\r\n \r\n public void setX(float x) {\r\n this.x = x;\r\n }\r\n \r\n public float getY() {\r\n return y;\r\n }\r\n \r\n public void setY(float y) {\r\n this.y = y;\r\n }\r\n \r\n public Point(float x, float y) {\r\n this.x = x;\r\n this.y = y;\r\n }\r\n \r\n @Override\r\n public String toString() {\r\n return \"Point{\" +\r\n \"x=\" + x +\r\n \", y=\" + y +\r\n '}';\r\n }\r\n }\r\n}<\/integer><\/string><\/integer><\/string><\/pre>\n\u4ee5\u4e0a\u5c31\u662f\u672c\u6587\u7684\u5168\u90e8\u5185\u5bb9\uff0c\u5e0c\u671b\u5bf9\u5927\u5bb6\u7684\u5b66\u4e60\u6709\u6240\u5e2e\u52a9\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"
\u672c\u6587\u5b9e\u4f8b\u4e3a\u5927\u5bb6\u5206\u4eab\u4e86android\u5b9e\u73b0\u53ef\u4ee5\u6ed1\u52a8\u7684\u5e73\u6ed1\u66f2\u7ebf\u56fe\u7684\u5177\u4f53\u4ee3\u7801\uff0c\u4f9b\u5927\u5bb6\u53c2\u8003\uff0c\u5177\u4f53\u5185\u5bb9\u5982\u4e0b \u76f4\u63a5\u4e0a\u4ee3\u7801\uff0c\u91cc […]<\/p>\n","protected":false},"author":1479,"featured_media":167959,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[55],"tags":[],"class_list":["post-246648","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-thread"],"acf":[],"_links":{"self":[{"href":"https:\/\/lrxjmw.cn\/wp-json\/wp\/v2\/posts\/246648","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lrxjmw.cn\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lrxjmw.cn\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lrxjmw.cn\/wp-json\/wp\/v2\/users\/1479"}],"replies":[{"embeddable":true,"href":"https:\/\/lrxjmw.cn\/wp-json\/wp\/v2\/comments?post=246648"}],"version-history":[{"count":3,"href":"https:\/\/lrxjmw.cn\/wp-json\/wp\/v2\/posts\/246648\/revisions"}],"predecessor-version":[{"id":246651,"href":"https:\/\/lrxjmw.cn\/wp-json\/wp\/v2\/posts\/246648\/revisions\/246651"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/lrxjmw.cn\/wp-json\/wp\/v2\/media\/167959"}],"wp:attachment":[{"href":"https:\/\/lrxjmw.cn\/wp-json\/wp\/v2\/media?parent=246648"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lrxjmw.cn\/wp-json\/wp\/v2\/categories?post=246648"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lrxjmw.cn\/wp-json\/wp\/v2\/tags?post=246648"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}