Question

I'm trying to do something like this, but I have a little bit of flexibility with how it looks. Essentially either a pie chart with only part of the pie filled (and the rest left blank), or some sort of dial chart.

It would also be relatively easy to use a polar graph to draw two arrows, one at 0 degrees and one at -92 degrees, but I can't find any libraries that will let you do this for Android. I do need it to make 0 degrees actually look like 0 polar degrees.

I've used an AChartEngine DialChart and managed to get something close, but I can't figure out how to get the labels to show up for each arrow. I've tried renderer.setDisplayValues(true); and series.setDisplayChartValues(true); but it won't show the values for my two arrows, so I'm not sure if it's even possible with a DialChart. I realize that if I showed labels for the dial in the background, my users wouldn't need to have labels on the arrows, but I'm rotating the LinearLayout that the DialChart is added to in order to get 0 to look like 0 degrees in a polar graph. I am also struggling to hide labels for the dial in the background, despite using renderer.setShowLabels(false); and setting just about every other thing you can show to false. My hack is to set the label color to the background color, but if there is a better way to do it, please let me know.

Here is my code for the DialChart.

CategorySeries category = new CategorySeries("Angle");
category.add("Extension", 0);
category.add("Flexion", 90);

renderer = new DialRenderer();
renderer.setLabelsColor(getActivity().getResources().getColor(R.color.background));

renderer.setInScroll(true);
renderer.setDisplayValues(true);

renderer.setShowLegend(false);
renderer.setShowAxes(false);
renderer.setShowLabels(false);
renderer.setShowGrid(false);
renderer.setMargins(new int[] {20, 30, 15, 0});
renderer.setVisualTypes(new DialRenderer.Type[] {Type.ARROW, Type.ARROW});
renderer.setMinValue(-20);
renderer.setMaxValue(280);
renderer.setPanEnabled(false);
renderer.setZoomEnabled(false);

SimpleSeriesRenderer r = new SimpleSeriesRenderer();
series.setColor(getActivity().getResources().getColor(R.color.green));
series.setDisplayChartValues(true);
series.setChartValuesTextSize(30);
visualizationRenderer.addSeriesRenderer(r);

r = new SimpleSeriesRenderer();
series.setColor(getActivity().getResources().getColor(R.color.green));
series.setDisplayChartValues(true);
series.setChartValuesTextSize(30);
renderer.addSeriesRenderer(r);

visualization = ChartFactory.getDialChartView(getActivity(), category, renderer);

LinearLayout layout = (LinearLayout) this.getView().findViewById(R.id.sessions_visualization);
layout.addView(visualization);

layout.setRotation(220.0f);

I'm open to either modifying this code to get something that works, or other libraries that will help me accomplish what I'm trying to do. Thanks!

Était-ce utile?

La solution

I'm answering my own question for anyone who wants to do something like this later.

You can create custom views in Android and draw whatever you want to display. There is good documentation here.

Here's a relevant code snippet. It's not perfect but it does the job.

public class AngleVisualization extends View {
    private Paint textPaint;
    private Paint arcPaint;
    private Paint linePaint;
    RectF oval;
    private float extension;
    private float flexion;
    private int textColor;
    private int arcColor;
    private float extensionLabelX;
    private float extensionLabelY;
    private float flexionLabelX;
    private float flexionLabelY;

    private Rect extensionBounds = new Rect();


    public AngleVisualization(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = context.getTheme().obtainStyledAttributes(
            attrs,
            R.styleable.AngleVisualization,
            0, 0);

    try {
        extension = a.getFloat(R.styleable.AngleVisualization_extensionValue, 0);
        flexion = a.getFloat(R.styleable.AngleVisualization_flexionValue, 0);
        textColor = a.getColor(R.styleable.AngleVisualization_textColor, Color.BLACK);
        arcColor = a.getColor(R.styleable.AngleVisualization_arcColor, context.getResources().getColor(R.color.green));
        extensionLabelX = a.getDimension(R.styleable.AngleVisualization_extensionLabelX, 190);
        extensionLabelY = a.getDimension(R.styleable.AngleVisualization_extensionLabelY, 150);
        flexionLabelX = a.getDimension(R.styleable.AngleVisualization_flexionLabelX, 50);
        extensionLabelY = a.getDimension(R.styleable.AngleVisualization_flexionLabelY, 190);

    } finally {
        a.recycle();
    }

    oval = new RectF();

    init();
}

private void init() {
    textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    textPaint.setColor(textColor);
    textPaint.setTextSize(30);

    arcPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    arcPaint.setColor(arcColor);

    linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    linePaint.setColor(arcColor);
    linePaint.setStrokeWidth(3);
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    String extensionString = decimalFormat.format(extension) + "˚";
    textPaint.getTextBounds(extensionString, 0, extensionString.length(), extensionBounds);

    canvas.drawArc(oval, extension, flexion - extension, true, arcPaint);
    canvas.drawLine(0.0f, extensionBounds.height(), oval.right / 2, extensionBounds.height(), linePaint);
    canvas.drawText(extensionString, extensionLabelX, extensionLabelY, textPaint);
    canvas.drawText(decimalFormat.format(flexion) + "˚", flexionLabelX, flexionLabelY, textPaint);
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    // Account for padding
    float xpad = (float)(getPaddingLeft() + getPaddingRight());
    float ypad = (float)(getPaddingTop() + getPaddingBottom());

    float ww = (float)w - xpad;
    float hh = (float)h - ypad;

    String extensionString = decimalFormat.format(extension) + "˚";
    textPaint.getTextBounds(extensionString, 0, extensionString.length(), extensionBounds);
    float diameter = Math.min(ww, (hh - extensionBounds.height()) * 2.0f) - extensionBounds.height();

    oval = new RectF(
            0,
            diameter / -2.0f,
            diameter,
            diameter / 2.0f);
    oval.offsetTo(getPaddingLeft(), getPaddingTop() - diameter / 2.0f + extensionBounds.height());
    flexionLabelY = diameter / 2.0f + extensionBounds.height();
    flexionLabelX = 0;
    extensionLabelY = extensionBounds.height();
    extensionLabelX = ww / 2;
}
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top