Android绘图机制(四)——使用HelloCharts开源框架搭建一系列炫酷图表,柱形图,折线图,饼状图和动画特效,抽丝剥茧带你认识图表之美

这里为什么不继续把自定义View写下去呢,因为最近项目很急,个人能力也有限,所以就在网上找到一些开源的框架使用,不是MPAndroidChart,也不是AChartEngine ,而是HelloCharts

开源地址:https://github.com/lecho/hellocharts-android

这次主要是翻译了一些注释和简化了一下项目的结构,我也是照着开源项目来的,但是我相信你看完本篇,也是可以直接把项目拿过来用的,最好是使用我提供的的Demo,这样就跟本文一一对照了,我们一步步来

首先我们来看看官方的

一.官方截图

1.Bubble Chart

2.Combo Chart

3.Line Column Dependency

4.Pie Chart

5.Preview Column Chart

6.Tempo line chart

二.项目架构

这里我们首先来看一下我排版的思维导图

上面比较明确的说明了,首先我们主页是一个ListView

然后跳转一个Activity

@Override        public void onItemClick(AdapterView<?> adapter, View view,                int position, long id) {            Intent intent;            switch (position) {            case 0:                // Line Chart;                intent = new Intent(getActivity(), LineChartActivity.class);                startActivity(intent);                break;            case 1:                // Column Chart;                intent = new Intent(getActivity(), ColumnChartActivity.class);                startActivity(intent);                break;            case 2:                // Pie Chart;                intent = new Intent(getActivity(), PieChartActivity.class);                startActivity(intent);                break;            case 3:                // Bubble Chart;                intent = new Intent(getActivity(), BubbleChartActivity.class);                startActivity(intent);                break;            case 4:                // Preview Line Chart;                intent = new Intent(getActivity(),                        PreviewLineChartActivity.class);                startActivity(intent);                break;            case 5:                // Preview Column Chart;                intent = new Intent(getActivity(),                        PreviewColumnChartActivity.class);                startActivity(intent);                break;            case 6:                // Combo Chart;                intent = new Intent(getActivity(),                        ComboLineColumnChartActivity.class);                startActivity(intent);                break;            case 7:                // Line Column Dependency;                intent = new Intent(getActivity(),                        LineColumnDependencyActivity.class);                startActivity(intent);                break;            case 8:                // Tempo line chart;                intent = new Intent(getActivity(), TempoChartActivity.class);                startActivity(intent);                break;            case 9:                // Speed line chart;                intent = new Intent(getActivity(), SpeedChartActivity.class);                startActivity(intent);                break;            case 10:                // Good Bad filled line chart;                intent = new Intent(getActivity(), GoodBadChartActivity.class);                startActivity(intent);                break;            case 11:                // Good Bad filled line chart;                intent = new Intent(getActivity(),                        ViewPagerChartsActivity.class);                startActivity(intent);                break;            default:                break;            }        }

Activity继承的是FragmentActivity,我们在FragmentActivity内部编写一个Fragment这样就可以绑定主Activity而不用继承自View去多写一个类了

public static class PlaceholderFragment extends Fragment 

所以你看到的项目也是非常简洁的

项目只有一个主Activity——MainActivity和一个关于软件的AboutActivity,然后就是十二个对应的类了
好了,我们可以编写了

三,实现图标

1.折线图

简单的实现折线图是可以的,这里多了几个注意的地方

从这里我们就可以看出,其实图表操作主要还是看menu菜单,所以,我们先实现
我们fragment要绑定的布局

fragment_line_chart

<lecho.lib.hellocharts.view.LineChartView        android:id="@+id/chart"        android:layout_width="match_parent"        android:layout_height="match_parent" >    </lecho.lib.hellocharts.view.LineChartView>

LineChartActivity

package lecho.lib.hellocharts.samples;import java.util.ArrayList;import java.util.List;import lecho.lib.hellocharts.animation.ChartAnimationListener;import lecho.lib.hellocharts.gesture.ZoomType;import lecho.lib.hellocharts.listener.LineChartOnValueSelectListener;import lecho.lib.hellocharts.model.Axis;import lecho.lib.hellocharts.model.Line;import lecho.lib.hellocharts.model.LineChartData;import lecho.lib.hellocharts.model.PointValue;import lecho.lib.hellocharts.model.ValueShape;import lecho.lib.hellocharts.model.Viewport;import lecho.lib.hellocharts.util.ChartUtils;import lecho.lib.hellocharts.view.Chart;import lecho.lib.hellocharts.view.LineChartView;import android.os.Bundle;import android.support.v4.app.Fragment;import android.support.v4.app.FragmentActivity;import android.view.LayoutInflater;import android.view.Menu;import android.view.MenuInflater;import android.view.MenuItem;import android.view.View;import android.view.ViewGroup;import android.widget.Toast;public class LineChartActivity extends FragmentActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_line_chart);        if (savedInstanceState == null) {            getSupportFragmentManager().beginTransaction()                    .add(R.id.container, new PlaceholderFragment()).commit();        }    }    /** * A fragment containing a line chart. */    public static class PlaceholderFragment extends Fragment {        private LineChartView chart;        private LineChartData data;        private int numberOfLines = 1;        private int maxNumberOfLines = 4;        private int numberOfPoints = 12;        float[][] randomNumbersTab = new float[maxNumberOfLines][numberOfPoints];        private boolean hasAxes = true;        private boolean hasAxesNames = true;        private boolean hasLines = true;        private boolean hasPoints = true;        private ValueShape shape = ValueShape.CIRCLE;        private boolean isFilled = false;        private boolean hasLabels = false;        private boolean isCubic = false;        private boolean hasLabelForSelected = false;        private boolean pointsHaveDifferentColor;        public PlaceholderFragment() {        }        @Override        public View onCreateView(LayoutInflater inflater, ViewGroup container,                Bundle savedInstanceState) {            setHasOptionsMenu(true);            View rootView = inflater.inflate(R.layout.fragment_line_chart,                    container, false);            chart = (LineChartView) rootView.findViewById(R.id.chart);            chart.setOnValueTouchListener(new ValueTouchListener());            // Generate some randome values.            generateValues();            generateData();            // Disable viewpirt recalculations, see toggleCubic() method for            // more info.            chart.setViewportCalculationEnabled(false);            resetViewport();            return rootView;        }        // MENU        @Override        public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {            inflater.inflate(R.menu.line_chart, menu);        }    //menu的操作        @Override        public boolean onOptionsItemSelected(MenuItem item) {            int id = item.getItemId();            if (id == R.id.action_reset) {                reset();                generateData();                return true;            }            if (id == R.id.action_add_line) {                addLineToData();                return true;            }            if (id == R.id.action_toggle_lines) {                toggleLines();                return true;            }            if (id == R.id.action_toggle_points) {                togglePoints();                return true;            }            if (id == R.id.action_toggle_cubic) {                toggleCubic();                return true;            }            if (id == R.id.action_toggle_area) {                toggleFilled();                return true;            }            if (id == R.id.action_point_color) {                togglePointColor();                return true;            }            if (id == R.id.action_shape_circles) {                setCircles();                return true;            }            if (id == R.id.action_shape_square) {                setSquares();                return true;            }            if (id == R.id.action_shape_diamond) {                setDiamonds();                return true;            }            if (id == R.id.action_toggle_labels) {                toggleLabels();                return true;            }            if (id == R.id.action_toggle_axes) {                toggleAxes();                return true;            }            if (id == R.id.action_toggle_axes_names) {                toggleAxesNames();                return true;            }            if (id == R.id.action_animate) {                prepareDataAnimation();                chart.startDataAnimation();                return true;            }            if (id == R.id.action_toggle_selection_mode) {                toggleLabelForSelected();                Toast.makeText(                        getActivity(),                        "Selection mode set to "                                + chart.isValueSelectionEnabled()                                + " select any point.", Toast.LENGTH_SHORT)                        .show();                return true;            }            if (id == R.id.action_toggle_touch_zoom) {                chart.setZoomEnabled(!chart.isZoomEnabled());                Toast.makeText(getActivity(),                        "IsZoomEnabled " + chart.isZoomEnabled(),                        Toast.LENGTH_SHORT).show();                return true;            }            if (id == R.id.action_zoom_both) {                chart.setZoomType(ZoomType.HORIZONTAL_AND_VERTICAL);                return true;            }            if (id == R.id.action_zoom_horizontal) {                chart.setZoomType(ZoomType.HORIZONTAL);                return true;            }            if (id == R.id.action_zoom_vertical) {                chart.setZoomType(ZoomType.VERTICAL);                return true;            }            return super.onOptionsItemSelected(item);        }        private void generateValues() {            for (int i = 0; i < maxNumberOfLines; ++i) {                for (int j = 0; j < numberOfPoints; ++j) {                    randomNumbersTab[i][j] = (float) Math.random() * 100f;                }            }        }        private void reset() {            numberOfLines = 1;            hasAxes = true;            hasAxesNames = true;            hasLines = true;            hasPoints = true;            shape = ValueShape.CIRCLE;            isFilled = false;            hasLabels = false;            isCubic = false;            hasLabelForSelected = false;            pointsHaveDifferentColor = false;            chart.setValueSelectionEnabled(hasLabelForSelected);            resetViewport();        }        private void resetViewport() {            // Reset viewport height range to (0,100)            final Viewport v = new Viewport(chart.getMaximumViewport());            v.bottom = 0;            v.top = 100;            v.left = 0;            v.right = numberOfPoints - 1;            chart.setMaximumViewport(v);            chart.setCurrentViewport(v);        }        private void generateData() {            List<Line> lines = new ArrayList<Line>();            for (int i = 0; i < numberOfLines; ++i) {                List<PointValue> values = new ArrayList<PointValue>();                for (int j = 0; j < numberOfPoints; ++j) {                    values.add(new PointValue(j, randomNumbersTab[i][j]));                }                Line line = new Line(values);                line.setColor(ChartUtils.COLORS[i]);                line.setShape(shape);                line.setCubic(isCubic);                line.setFilled(isFilled);                line.setHasLabels(hasLabels);                line.setHasLabelsOnlyForSelected(hasLabelForSelected);                line.setHasLines(hasLines);                line.setHasPoints(hasPoints);                if (pointsHaveDifferentColor) {                    line.setPointColor(ChartUtils.COLORS[(i + 1)                            % ChartUtils.COLORS.length]);                }                lines.add(line);            }            data = new LineChartData(lines);            if (hasAxes) {                Axis axisX = new Axis();                Axis axisY = new Axis().setHasLines(true);                if (hasAxesNames) {                    axisX.setName("Axis X");                    axisY.setName("Axis Y");                }                data.setAxisXBottom(axisX);                data.setAxisYLeft(axisY);            } else {                data.setAxisXBottom(null);                data.setAxisYLeft(null);            }            data.setBaseValue(Float.NEGATIVE_INFINITY);            chart.setLineChartData(data);        }        /** * Adds lines to data, after that data should be set again with * {@link LineChartView#setLineChartData(LineChartData)}. Last 4th line * has non-monotonically x values. */        private void addLineToData() {            if (data.getLines().size() >= maxNumberOfLines) {                Toast.makeText(getActivity(), "Samples app uses max 4 lines!",                        Toast.LENGTH_SHORT).show();                return;            } else {                ++numberOfLines;            }            generateData();        }        private void toggleLines() {            hasLines = !hasLines;            generateData();        }        private void togglePoints() {            hasPoints = !hasPoints;            generateData();        }        private void toggleCubic() {            isCubic = !isCubic;            generateData();            if (isCubic) {                /** * 手动设置高一点最大立方行,因为有时超过或低于最大值/最小值。为此使用Viewport.inest() * 方法并传递负值作为dy参数或手动设置顶部和底部的值 * 。在这个例子中我知道Y值(0100)范围内我手动设置视口高度范围(105) * 。让这个作品在动画应该使用Chart.setViewportCalculationEnabled * (false)之前修改窗口。记住你叫setLineChartData后设置窗口()。 */                final Viewport v = new Viewport(chart.getMaximumViewport());                v.bottom = -5;                v.top = 105;                // You have to set max and current viewports separately.                chart.setMaximumViewport(v);                // I changing current viewport with animation in this case.                chart.setCurrentViewportWithAnimation(v);            } else {                // If not cubic restore viewport to (0,100) range.                final Viewport v = new Viewport(chart.getMaximumViewport());                v.bottom = 0;                v.top = 100;                /** * 你必须单独设置最大和当前视窗。在这种情况下,如果我想要动画我必须先设置currentviewport和使用动画侦听器。 * 最大视窗将onAnimationFinished方法。 */                chart.setViewportAnimationListener(new ChartAnimationListener() {                    @Override                    public void onAnimationStarted() {                        // TODO Auto-generated method stub                    }                    @Override                    public void onAnimationFinished() {                        // 设置最大viewpirt和删除侦听器。                        chart.setMaximumViewport(v);                        chart.setViewportAnimationListener(null);                    }                });                // 设置当前viewpirt动画;                chart.setCurrentViewportWithAnimation(v);            }        }        private void toggleFilled() {            isFilled = !isFilled;            generateData();        }        private void togglePointColor() {            pointsHaveDifferentColor = !pointsHaveDifferentColor;            generateData();        }        private void setCircles() {            shape = ValueShape.CIRCLE;            generateData();        }        private void setSquares() {            shape = ValueShape.SQUARE;            generateData();        }        private void setDiamonds() {            shape = ValueShape.DIAMOND;            generateData();        }        private void toggleLabels() {            hasLabels = !hasLabels;            if (hasLabels) {                hasLabelForSelected = false;                chart.setValueSelectionEnabled(hasLabelForSelected);            }            generateData();        }        private void toggleLabelForSelected() {            hasLabelForSelected = !hasLabelForSelected;            chart.setValueSelectionEnabled(hasLabelForSelected);            if (hasLabelForSelected) {                hasLabels = false;            }            generateData();        }        private void toggleAxes() {            hasAxes = !hasAxes;            generateData();        }        private void toggleAxesNames() {            hasAxesNames = !hasAxesNames;            generateData();        }        /** * 动画值你必须改变目标的值,然后调用{ @link图表# * startDataAnimation()}方法(不要混淆View.animate())。如果你操作数据之前设置你不必叫{ @link * LineChartView # setLineChartData(LineChartData)}。 */        private void prepareDataAnimation() {            for (Line line : data.getLines()) {                for (PointValue value : line.getValues()) {                    // 这里我只修改目标X Y值,但可以修改目标。                    value.setTarget(value.getX(), (float) Math.random() * 100);                }            }        }        private class ValueTouchListener implements LineChartOnValueSelectListener {            @Override            public void onValueSelected(int lineIndex, int pointIndex,                    PointValue value) {                Toast.makeText(getActivity(), "选择: " + value,                        Toast.LENGTH_SHORT).show();            }            @Override            public void onValueDeselected() {                // TODO Auto-generated method stub            }        }    }}

从上面其实可以很容易的就看出,我们一个activity然后add了一个fragment,而一个fragment的实现,有一个xml,在xml中就要用上自定义的view的标签了,而所有的操作,都在menu的菜单上,每个菜单对应的是一个方法,看上去是很多的代码,其实只要你耐心一下,你会发现很多的规律,而且这里也只是才去了随机数,项目中的数据可改性还是很大的,下面的就不一一说明了,现在打字都很卡,编辑器的原因,然道是内容太多了?可是这个原理也不好分章节去写,毕竟有12个重复的写法,那样就太无聊了,我们还是来直接说一下我上次的这个demo的结构


这个我整理过,所以你只要导入hellocharts-library和hellocharts-samples,然后让hellocharts-samples依赖hellocharts-library就可以直接运行了

我们接下来再放几张运行图就直接上Demo吧

Demo下载地址:http://download.csdn.net/detail/qq_26787115/9406897

更多相关文章

  1. 没有一行代码,「2020 新冠肺炎记忆」这个项目却登上了 GitHub 中
  2. 不吹不黑!GitHub 上帮助人们学习编码的 12 个资源,错过血亏...
  3. 开始我的Android开发之路
  4. ant编译android
  5. Animation动画平移和旋转的结合使用
  6. Android(安卓)中不同项目共用通用库Module方法
  7. 如何使用Android命令
  8. Android(安卓)API 实验记录(一)
  9. Android(安卓)Studio 项目导入的正确姿势

随机推荐

  1. Android控件复习之TextView与EditText
  2. Android(安卓)Support Library-FloatingA
  3. Android下使用正则表达式
  4. android 运行时生成dex文件,并装载调用
  5. Android(安卓)Studio gradle 使用最新版
  6. Android实际开发中遇到的问题和部分解决
  7. 遇到Android(安卓)SDK Build-tools V19
  8. Android之webView入门
  9. android sensor framework
  10. 全志A40i Android7永不休眠及不锁屏的修