6

似乎 Androidplot (androidplot.com) 网站/论坛已关闭,所以我会尝试在这里问这个问题。

我有多点触控缩放和滚动。与http://mlepicki.com/2012/03/androidplot-multitouch-zoom-scroll/类似的代码,只是我有一个条形图。但是,对于 100 个数据点,它有明显的滞后。即使有 10 个酒吧也只是显示。听起来像它的绘图/计算/等所有条形图。

关于如何优化它的任何想法?

我不能使用硬件渲染,因为我想支持 Android 2.1 并且库不支持它(它坏了)。

4

2 回答 2

6

我制作了一个自定义渲染器来解决我的滞后问题。似乎流畅了许多。此代码基于版本 0.5。不知道它是否适用于 v0.51。

import android.graphics.*;
import com.androidplot.exception.PlotRenderException;
import com.androidplot.series.XYSeries;
import com.androidplot.util.ValPixConverter;
import com.androidplot.xy.BarFormatter;
import com.androidplot.xy.XYPlot;
import com.androidplot.xy.XYSeriesRenderer;

import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * Renders a point as a Bar
 */
public class OptimisedBarRenderer extends XYSeriesRenderer<BarFormatter> {

    private BarWidthStyle style = BarWidthStyle.FIXED_WIDTH;
    private float barWidth = 5;

    public OptimisedBarRenderer(XYPlot plot) {
        super(plot);
    }

    /**
     * Sets the width of the bars draw.
     * @param barWidth
     */
    public void setBarWidth(float barWidth) {
        this.barWidth = barWidth;
    }

    private final TreeMap<Number, XYSeries> tempSeriesMap = new TreeMap<Number, XYSeries>();

    @Override
    public void onRender(Canvas canvas, RectF plotArea) throws PlotRenderException {
        int longest = getLongestSeries();
        if(longest == 0) {
            return;  // no data, nothing to do.
        }
        tempSeriesMap.clear();

        for(int i = 0; i < longest; i++) {
            tempSeriesMap.clear();
            List<XYSeries> seriesList = getPlot().getSeriesListForRenderer(this.getClass());
            for(XYSeries series : seriesList) {
                if(i < series.size()) {
                    tempSeriesMap.put(series.getY(i), series);
                }
            }
            drawBars(canvas, plotArea, tempSeriesMap, i);
        }
    }

    @Override
    public void doDrawLegendIcon(Canvas canvas, RectF rect, BarFormatter formatter) {
        canvas.drawRect(rect, formatter.getFillPaint());
        canvas.drawRect(rect, formatter.getBorderPaint());
    }

    private int getLongestSeries() {
        int longest = 0;
        List<XYSeries> seriesList = getPlot().getSeriesListForRenderer(this.getClass());

        if(seriesList == null)
            return 0;

        for(XYSeries series :seriesList) {
            int seriesSize = series.size();
            if(seriesSize > longest) {
                longest = seriesSize;
            }
        }
        return longest;
    }

    private void drawBars(Canvas canvas, RectF plotArea, TreeMap<Number, XYSeries> seriesMap, int x) {
//        Paint p = new Paint();
//        p.setColor(Color.RED);

        Object[] oa = seriesMap.entrySet().toArray();
        Map.Entry<Number, XYSeries> entry;
        Number yVal = null;
        Number xVal = null;

        float halfWidth = barWidth * 0.5f;

        for(int i = oa.length-1; i >= 0; i--) {
            entry = (Map.Entry<Number, XYSeries>) oa[i];
            XYSeries tempEntry = entry.getValue();

            if(tempEntry != null) {
                yVal = tempEntry.getY(x);
                xVal = tempEntry.getX(x);

                if (yVal != null && xVal != null) {  // make sure there's a real value to draw
                    switch (style) {
                        case FIXED_WIDTH:
                            float pixX = ValPixConverter.valToPix(xVal.doubleValue(), getPlot().getCalculatedMinX().doubleValue(), getPlot().getCalculatedMaxX().doubleValue(), plotArea.width(), false) + plotArea.left;

                            float left = pixX - halfWidth;
                            float right = pixX + halfWidth;

                            boolean offScreen = left > plotArea.right || right < plotArea.left;

                            if(!offScreen){
                                float pixY = ValPixConverter.valToPix(yVal.doubleValue(), getPlot().getCalculatedMinY().doubleValue(), getPlot().getCalculatedMaxY().doubleValue(), plotArea.height(), true) + plotArea.top;

                                BarFormatter formatter = getFormatter(tempEntry);
                                if(Math.abs (left - right) > 1f){//Don't draw as it will be hidden anyway.
                                    canvas.drawRect(left, pixY, right, plotArea.bottom, formatter.getFillPaint());
                                }
                                canvas.drawRect(left, pixY, right, plotArea.bottom, formatter.getBorderPaint());

                            }
                            break;
                        default:
                            throw new UnsupportedOperationException("Not yet implemented.");
                    }
                }
            }
        }
    }
}
于 2012-04-18T04:35:14.243 回答
1

BarRenderer在 Androidplot 1.4.0 中进行了相当多的优化,因此不再需要自定义渲染器。

于 2016-12-16T18:09:10.697 回答