问题
Is it possible to replace LimitLine
with custom layout? So it looks something like this:
I see few solutions for that:
- Perhaps there're methods inside library for customizations like this, are there any?
- Get coordinates of
TextView
where the value is stored and add custom layout on that place. But how can I reach thisTextView
?
Perhaps someone faced that problem. Please share your experience.
EDIT: latest partial solution
After long searching of solution I came up to adding custom view programmatically by coordinates of Limit Line.
General layout of screen as follows:
Coordinates are calculated pretty straightforward. X
is known from Chart coordinates and Y
:
Y = ((max - lastValue) * height) / ((max + min) + y)
So at this point I basically know the position I need. Although I'm not sure it's right due to parent ScrollView
.
The next step is to add custom layout at those coordinates (x, y)
And here comes the new problem. I tried to add view to top RelativeLayout
. It is added but it doesn't move together with ScrollView
. Therefore its needed to add that view exactly on Chart. Look how I tried to achieve this:
private void addCustomLayoutOnLimitLine(final double lastValue) {
mChart.post(new Runnable() { //check location when view is created
public void run() {
int[] chartLocationOnScreen = new int[2];
mChart.getLocationOnScreen(chartLocationOnScreen);
int x = chartLocationOnScreen[0];
int y = chartLocationOnScreen[1];
int width = mChart.getWidth();
int height = mChart.getHeight();
double max = mChart.getYMax();
double min = mChart.getYMin();
int limitXPoint = x + width;
int limitYPoint = (int) ((((max - lastValue) * height) / (max + min))+ y);
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
RelativeLayout rlValue = (RelativeLayout) inflater.inflate(R.layout.item_chart_value, null);
TextView tvValue = (TextView) rlValue.findViewById(R.id.tv_value);
tvValue.setText(String.valueOf(lastValue));
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(50, 50);
params.leftMargin = limitXPoint - 100;
params.topMargin = limitYPoint;
mChart.addView(rlValue, params); //this doesn't seem to be working
rlValue.bringToFront();
}
});
}
Perhaps I should reach the parent layout of Chart and inflate my custom layout there. But how?
EDIT 2: added custom view over chart but can't find proper location due to scroll view
Now the situation looks like that :
Perhaps I'm somewhere wrong in calculations. But at least that View changes its position with the new value although it never hits at right coordinations.
private void addCustomLayoutOnLimitLine() {
if (mChart == null){
return;
}
mChart.post(new Runnable() { //check location when view is created
public void run() {
int[] chartLocationOnScreen = new int[2];
mChart.getLocationOnScreen(chartLocationOnScreen);
int xChart = chartLocationOnScreen[0];
int yChart = chartLocationOnScreen[1];
int chartWidth = mChart.getWidth();
int chartHeight = mChart.getHeight();
int rootWidth = rlSvContent.getWidth();
int rootHeight = rlSvContent.getHeight(); //this is height of ScrollView
int infoWidth = llInfoWrapper.getWidth(); //width of info panel ABOVE chart
int infoHeight = llInfoWrapper.getHeight();
double lastValue = mSingleAsset.getGraph().get(mSingleAsset.getGraph().size() - 1).getValue();
double maxValue = mChart.getYMax();
double minValue = mChart.getYMin();
int limitXPoint = (rootWidth - chartWidth) / 2 + chartWidth;
int limitYPoint = (int) ((maxValue - lastValue) * chartHeight/(maxValue - minValue)) + yChart;
tvCustomValue.setText(SingleAsset.round((float) lastValue, 2).toString()); //display last value on custom view
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.leftMargin = limitXPoint - xChart - 50; //move custom view. xChart = right margin value and 50 is taken to count values bar to the right of chart
params.topMargin = limitYPoint;
rlCustomValue.setLayoutParams(params);
rlCustomValue.bringToFront();
rlCustomValue.invalidate();
}
});
}
回答1:
<ScrollView>
<LinearLayout/>
<FrameLayout>
<Chart/>
<TextView/>
<FrameLauyout>
</ScrollView>
Use ViewPortHandler to get offset of chart
float offsetTop = mChart.getViewPortHandler().offsetTop();
float offsetLeft = mChart.getViewPortHandler().offsetLeft();
float offsetRight = mChart.getViewPortHandler().offsetRight();
float chartHeight = mChart.getViewPortHandler().contentHeight();
回答2:
This is not a good way of doing it. I've done it by extending the YAxisRenderer.java file where the labels are actually drawn. They are not views, they are drawn on canvas. Here is my code for the labels:
`
protected void drawYLabels(Canvas c, float fixedPosition, float[] positions, float offset) {
// draw labels
for (int i = 0; i < mYAxis.mEntryCount; i++) {
String text = mYAxis.getFormattedLabel(i);
if (!mYAxis.isDrawTopYLabelEntryEnabled() && i >= mYAxis.mEntryCount - 1)
return;
c.drawText(text, fixedPosition, positions[i * 2 + 1] + offset, mAxisLabelPaint);
}
// limitline labels
List<LimitLine> limitLines = mYAxis.getLimitLines();
float[] pts = new float[2];
for (LimitLine l : limitLines) {
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(l.getTextColor());
Paint textPaint = mAxisLabelPaint;
textPaint.setColor(l.getLineLabelTextColor());
textPaint.setTextSize(mAxisLabelPaint.getTextSize());
textPaint.setPathEffect(null);
textPaint.setTypeface(l.getTypeface());
textPaint.setStrokeWidth(0.5f);
textPaint.setStyle(l.getTextStyle());
pts[1] = l.getLimit();
mTrans.pointValuesToPixel(pts);
float paddingVert = Utils.convertDpToPixel(3);
float paddingHoriz = Utils.convertDpToPixel(5);
float height = Utils.calcTextHeight(textPaint, l.getLabel());
float width = Utils.calcTextWidth(textPaint, l.getLabel());
float posY = pts[1] + height / 2;
c.drawRect(fixedPosition - paddingHoriz, posY - height - paddingVert, fixedPosition + width + paddingHoriz*2, posY + paddingVert, paint);
c.drawText(l.getLabel(), fixedPosition, posY, textPaint);
}
}
`
Please note that you must use mTrans.pointValuesToPixel(pts)
to convert your Y values to pixels.
来源:https://stackoverflow.com/questions/36083802/custom-view-of-limit-line-in-mpandroidchart