问题是当我更改数据集时,我的mpandroidchart条形图会垂直调整大小。我的底部x轴标签是45度旋转,这是什么原因的问题。如果不旋转底部x标签-则不会调整大小。
我附上了一张柱状图在更新数据集前后的外观图片。
有人知道如何摆脱图表的无意调整大小吗?
编辑(+代码)
在此,我附上说明问题的代码:
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.github.mikephil.charting.charts.BarChart;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.formatter.DefaultValueFormatter;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.renderer.XAxisRenderer;
import com.github.mikephil.charting.utils.MPPointF;
import com.github.mikephil.charting.utils.Transformer;
import com.github.mikephil.charting.utils.Utils;
import com.github.mikephil.charting.utils.ViewPortHandler;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Random;
public class MainActivityB extends AppCompatActivity {
private BarChart barChart;
private BarDataSet barDataSet;
private Button button;
private Random random = new Random();
private int xEntries = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_b);
setupStackedBarChart();
initButton();
}
private void initButton() {
button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
chartsRenew();
}
});
}
private void setupStackedBarChart(){
barChart = findViewById(R.id.stackedbarchart_statistics_b);
barChart.animateY(600);
barChart.getDescription().setEnabled(false); // disable description text
barChart.setPinchZoom(true);
barChart.getLegend().setEnabled(false);
barChart.setMinimumHeight(600);
ArrayList<BarEntry> barEntries = fillBarEntries();
// Create Data Set
barDataSet = new BarDataSet(barEntries, "Bar Set");
barDataSet.setAxisDependency(YAxis.AxisDependency.LEFT);
barDataSet.setColors(createColors());
barDataSet.setValueFormatter(new MyValueFormatterBarChart(0)); // rounds off values on the bars
barDataSet.setValueTextSize(14);
// Refine the chart
BarData barData = new BarData(barDataSet);
barChart.setData(barData);
// Formatter for the top x-axis
barChart.setXAxisRenderer(new DoubleXLabelAxisRenderer(
barChart.getViewPortHandler(),
barChart.getXAxis(),
barChart.getTransformer(YAxis.AxisDependency.LEFT),
new ValueFormatter() {
@Override
public String getFormattedValue(float value) {
return "blahbla";
}
})
);
// Formatter for the bottom x-axis
ValueFormatter bottomXFormatter = new ValueFormatter() {
private DecimalFormat mFormat = new DecimalFormat("###,###,##0");
@Override
public String getFormattedValue(float value) {
int MAX_LENGTH = 15;
if ((int) value >= xEntries) return ""; // Sometimes formatter fails. This check helps.
String number = mFormat.format(value + 1) + ") ";
int repetitions = 1 + random.nextInt(16);
String name = new String(new char[repetitions]).replace("\0", "a");
String xLabel = number + name;
if (xLabel.length() > MAX_LENGTH){
xLabel = xLabel.substring(0, MAX_LENGTH - 2) + "..";
Log.d("try", "size >: " + xLabel.length());
}
return xLabel;
}
};
final XAxis xAxis = barChart.getXAxis();
xAxis.setPosition(XAxis.XAxisPosition.BOTH_SIDED);
//xAxis.setGranularity(1f);
xAxis.setGranularityEnabled(true); // To remove the extra labels appearing when zooming into the bar chart
xAxis.setValueFormatter(bottomXFormatter);
xAxis.setLabelRotationAngle(-45);
final YAxis leftYAxis = barChart.getAxisLeft();
leftYAxis.setAxisMinimum(0);
leftYAxis.setGranularity(1f);
leftYAxis.setTextSize(12f);
final YAxis rightYAxis = barChart.getAxisRight();
rightYAxis.setEnabled(false);
barChart.setVisibleXRangeMaximum(3f); // Needs invalidate() before changes take place
barChart.moveViewToX(barEntries.size()); // Includes invalidate in it
barChart.setDragDecelerationFrictionCoef(0.6f);
}
private void chartsRenew(){
ArrayList<BarEntry> barEntries = fillBarEntries();
if (barEntries.isEmpty()) {
barChart.clear();
} else {
barDataSet.setValues(barEntries);
barChart.setData(new BarData(barDataSet));
}
barChart.notifyDataSetChanged();
barChart.fitScreen(); // Without it the following methods work faulty
barChart.setVisibleXRangeMaximum(3f); // Needs invalidate() before changes take place
barChart.moveViewToX(barEntries.size()); // Includes invalidate in it
Log.d("try", "0: " + barChart.getXAxis().mLabelRotatedHeight);
Log.d("try", "0: " + barChart.getXAxis().mLabelHeight);
Log.d("try", "Y: " + barChart.getAxisLeft().mAxisMaximum);
Log.d("try", "0: " + barChart.getXAxis().getSpaceMax());
Log.d("try", "0: " + barChart.getXAxis().getSpaceMin());
Log.d("try", "1: " + barChart.getViewPortHandler().getContentRect().left);
Log.d("try", "2: " + barChart.getViewPortHandler().getContentRect().top);
Log.d("try", "3: " + barChart.getViewPortHandler().getContentRect().right);
Log.d("try", "4: " + barChart.getViewPortHandler().getContentRect().bottom);
Log.d("try", "bug: " + barChart.getViewPortHandler().getContentRect().height()); //TODO here it is !!!! bug
//barChart.getViewPortHandler().getContentRect().set(43.25f, 100f, 988.625f, 500f);
//barChart.invalidate();
}
private ArrayList<BarEntry> fillBarEntries() {
ArrayList<BarEntry> barEntries = new ArrayList<>();
xEntries = random.nextInt(7);
for (int i = 0; i < xEntries; i++) {
barEntries.add(new BarEntry(i, random.nextInt(4)));
}
return barEntries;
}
//Additional Method-----------------------------------------------------------------------------
public int[] createColors(){
int[] colors = new int[11];
colors[0] = Color.parseColor("#006884");
colors[1] = Color.parseColor("#00909E");
colors[2] = Color.parseColor("#80DBEC");
colors[3] = Color.parseColor("#FFD09D");
colors[4] = Color.parseColor("#B00051");
colors[5] = Color.parseColor("#F68370");
colors[6] = Color.parseColor("#FEABB9");
colors[7] = Color.parseColor("#6E006C");
colors[8] = Color.parseColor("#CE9C48");
colors[9] = Color.parseColor("#CF97D7");
colors[10] = Color.parseColor("#FEDD27");
//colors[11] = Color.parseColor("#91278F");
return colors;
}
//CLASSES--------------------------------------------------------------------------------------
public class MyValueFormatterBarChart extends DefaultValueFormatter {
private DecimalFormat mFormat;
public MyValueFormatterBarChart(int digits) {
super(digits);
mFormat = new DecimalFormat("###,###,###,##0");
}
@Override
public String getFormattedValue(float value) {
return mFormat.format(value);
}
}
public class DoubleXLabelAxisRenderer extends XAxisRenderer {
private ValueFormatter topValueFormatter;
public DoubleXLabelAxisRenderer(ViewPortHandler viewPortHandler, XAxis xAxis, Transformer transformer, ValueFormatter topValueFormatter) {
super(viewPortHandler, xAxis, transformer);
this.topValueFormatter = topValueFormatter;
}
@Override
public void renderAxisLabels(Canvas c) {
if (!mXAxis.isEnabled() || !mXAxis.isDrawLabelsEnabled())
return;
float yOffset = mXAxis.getYOffset();
mAxisLabelPaint.setTypeface(mXAxis.getTypeface());
mAxisLabelPaint.setTextSize(mXAxis.getTextSize());
mAxisLabelPaint.setColor(mXAxis.getTextColor());
MPPointF pointF = MPPointF.getInstance(0, 0);
if (mXAxis.getPosition() == XAxis.XAxisPosition.TOP) {
pointF.x = 0.5f;
pointF.y = 1.0f;
drawLabels(c, mViewPortHandler.contentTop() - yOffset, pointF);
} else if (mXAxis.getPosition() == XAxis.XAxisPosition.TOP_INSIDE) {
pointF.x = 0.5f;
pointF.y = 1.0f;
drawLabels(c, mViewPortHandler.contentTop() + yOffset + mXAxis.mLabelRotatedHeight, pointF);
} else if (mXAxis.getPosition() == XAxis.XAxisPosition.BOTTOM) {
pointF.x = 0.5f;
pointF.y = 0.0f;
drawLabels(c, mViewPortHandler.contentBottom() + yOffset, pointF);
} else if (mXAxis.getPosition() == XAxis.XAxisPosition.BOTTOM_INSIDE) {
pointF.x = 0.5f;
pointF.y = 0.0f;
drawLabels(c, mViewPortHandler.contentBottom() - yOffset - mXAxis.mLabelRotatedHeight, pointF);
} else { // BOTH SIDED
pointF.x = 0.5f;
pointF.y = 1.0f;
drawLabelsTop(c, mViewPortHandler.contentTop() - yOffset, pointF);
pointF.x = 0.5f;
pointF.y = 0.0f;
drawLabels(c, mViewPortHandler.contentBottom() + yOffset, pointF);
}
MPPointF.recycleInstance(pointF);
}
private void drawLabelsTop(Canvas c, float pos, MPPointF anchor) {
final float labelRotationAngleDegrees = mXAxis.getLabelRotationAngle();
boolean centeringEnabled = mXAxis.isCenterAxisLabelsEnabled();
float[] positions = new float[mXAxis.mEntryCount * 2];
for (int i = 0; i < positions.length; i += 2) {
// only fill x values
if (centeringEnabled) {
positions[i] = mXAxis.mCenteredEntries[i / 2];
} else {
positions[i] = mXAxis.mEntries[i / 2];
}
}
mTrans.pointValuesToPixel(positions);
for (int i = 0; i < positions.length; i += 2) {
float x = positions[i];
if (mViewPortHandler.isInBoundsX(x)) {
String label = topValueFormatter.getFormattedValue(mXAxis.mEntries[i / 2]);
if (mXAxis.isAvoidFirstLastClippingEnabled()) {
// avoid clipping of the last
if (i == mXAxis.mEntryCount - 1 && mXAxis.mEntryCount > 1) {
float width = Utils.calcTextWidth(mAxisLabelPaint, label);
if (width > mViewPortHandler.offsetRight() * 2
&& x + width > mViewPortHandler.getChartWidth())
x -= width / 2;
// avoid clipping of the first
} else if (i == 0) {
float width = Utils.calcTextWidth(mAxisLabelPaint, label);
x += width / 2;
}
}
drawLabel(c, label, x, pos, anchor, labelRotationAngleDegrees);
}
}
}
}
}
布局:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:paddingBottom="16dp">
<com.github.mikephil.charting.charts.BarChart
android:id="@+id/stackedbarchart_statistics_b"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_marginTop="226dp"/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Refresh data set"
android:layout_gravity="center_horizontal"
android:layout_marginTop="100dp"/>
</FrameLayout>
添加 implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
在grad尔。
1条答案
按热度按时间pokxtpni1#
就我的知识和测试结果而言,如果不修改库,这里似乎没有任何简单的解决方案。不精确的解决办法是
all XAxis label
在类似宽度(不能始终100%精确)中:Left padding
带有非空格字符的xaxis标签文本应用合理的最大yaxis值通过
leftYAxis.setAxisMaximum()
使用Monospace
字体,这样至少对于字母数字字符,宽度会相似。测试代码更新:
和