使用百度前端EChart框架封装的Android版TAndroidEChart

bar-stack.png
screen1.gif
更多实例见: http://echarts.baidu.com/examples.html

前言

使用百度前度Echart框架:
http://echarts.baidu.com/
https://gitee.com/free/ECharts
参考iOS封装实现:
https://github.com/Pluto-Y/iOS-Echarts
等资料对Android版本的实现进行简单的封装
时间不是很充裕,只能在零碎时间上来一点一点补充,因此肯定会出现许多不足之处
希望在未来的某一天自己能封装的很完善

项目GitHub地址 https://github.com/tikeyc/TAndroidEChart

添加依赖:

  • 方式一
Step 1:添加maven { url '[https://jitpack.io](https://jitpack.io/)' } 到project的build.gradle     
allprojects {
     repositories {
          ...
          maven { url '[https://jitpack.io](https://jitpack.io/)' }
     }
}
versionNum为最新版本的值 如:v1.2.1
Step 2: 添加compile 'com.github.tikeyc:TAndroidEChart:versionNum'到你app的build.gradle
dependencies {   
       compile 'com.github.tikeyc:TAndroidEChart:versionNum'
}
  • 方式二
    直接下载完整项目,import一个module:tandroidechartlibrary

如何使用:

具体代码:
xml:
<com.tikeyc.tandroidechartlibrary.TEChartWebView
        android:id="@+id/barChartWebView"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </com.tikeyc.tandroidechartlibrary.TEChartWebView>
 可能后续操作需要刷新图表,可以这样调用   
(注意:不能在第一时间就用此方法来显示图表,因为第一时间html的标签还未加载完成,不能获取到标签值)      

 barChartWebView. refreshEchartsWithOption(getLineAndBarChartOption());
public class TBarChartActivity extends TBaseActivity {

    @ViewInject(R.id.barChartWebView)
    private TEChartWebView barChartWebView;

    @Event(R.id.navigationBar_title_tv)
    private void titleClick(View view) {
        if (!view.isSelected()) {
            barChartWebView.refreshEchartsWithOption(getLineChartOptions());
        } else {
            barChartWebView.refreshEchartsWithOption(getLineAndBarChartOption());
        }
        view.setSelected(!view.isSelected());
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        this.isLandScape = true;
        super.onCreate(savedInstanceState);
        //设置横屏
        if(this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT){
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        }
        setContentView(R.layout.activity_tbar_chart);

        initData();

        initView();
    }



    private void initData() {

    }


    private void initView() {
        x.view().inject(this);

        //
        //navigationBar_title_tv.setText("BarChart");
        //开启调试模式默认false
        barChartWebView.setDebug(true);
        //设置数据源
        barChartWebView.setDataSource(new TEChartWebView.DataSource() {
            @Override
            public GsonOption markChartOptions() {
                return getLineAndBarChartOption();
            }
        });

        //添加事件监听
        TEChartConstant.PYEchartAction[] echartActions = {TEChartConstant.PYEchartAction.PYEchartActionLegendSelected, TEChartConstant.PYEchartAction.PYEchartActionClick};
        barChartWebView.addEchartActionHandler(echartActions, new TEChartWebView.OnAddEchartActionHandlerResponseResultListener() {
            @Override
            public void actionHandlerResponseResult(String result) {
                //查看事件信息 处理事件
                /*TEChartConstant.PYEchartAction.PYEchartActionLegendSelected
                 *
                 *{"selected":{"蒸发量":true,"降水量":true,"平均温度":true},"target":"蒸发量","type":"legendSelected","event":{"zrenderX":220.33299255371094,"zrenderY":8.666999816894531,"zrenderFixed":1},"__echartsId":1512031135165}
                 */


                /*TEChartConstant.PYEchartAction.PYEchartActionClick
                 *
                 *{"seriesIndex":1,"seriesName":"降水量","dataIndex":4,"data":28.7,"name":"5月","value":28.7,"type":"click","event":{"zrenderX":261,"zrenderY":209,"zrenderFixed":1}}
                 */
            }
        });

    }



    /**根据https://mvnrepository.com/artifact/com.github.abel533/ECharts
     * 结合http://echarts.baidu.com/examples.html官方实例
     * 配置json数据
     * @return
     */
    public GsonOption getLineAndBarChartOption() {
        //http://echarts.baidu.com/echarts2/doc/example/mix1.html
        GsonOption option = new GsonOption();
        //title
        String text = "text";
        String subText = "subText";
        option.title(text,subText);
        //tooltip
        Tooltip tooltip = new Tooltip();
        tooltip.trigger(Trigger.axis);
        option.tooltip(tooltip);
        //toolbox
        Toolbox toolbox = new Toolbox();
        toolbox.show(true);
        Map<String, Feature> feature = new HashMap<String, Feature>();
        feature.put("mark",new Feature().show(true));
        feature.put("dataView",new DataView().show(true).readOnly(false));
        feature.put("magicType",new MagicType(Magic.line, Magic.bar).show(true));
        feature.put("restore",new Restore().show(true));
        feature.put("saveAsImage",new SaveAsImage().show(false));
        toolbox.setFeature(feature);
        option.toolbox(toolbox);
        //calculable
        option.setCalculable(true);
        //legend
        String legend1 = "蒸发量";
        String legend2 = "降水量";
        String legend3 = "平均温度";
        Legend legend = new Legend();
        legend.data(legend1,legend2,legend3);
        option.legend(legend);
        //grid
//            Grid grid = new Grid();
//            grid.y2(80);
//            option.grid(grid);
        //xAxis
        List<Axis> xAxis = new ArrayList<Axis>();
        CategoryAxis categoryAxis = new CategoryAxis();
        {
            List xAxisValues = new ArrayList();
            for (int i = 1; i <= 12; i++) {
                xAxisValues.add(i + "月");
            }
            categoryAxis.setData(xAxisValues);
        }
        xAxis.add(categoryAxis);
        option.xAxis(xAxis);
        //yAxis
        List<Axis> yAxis = new ArrayList<Axis>();
        {
            ValueAxis valueAxis = new ValueAxis();
            valueAxis.name("水量");
            valueAxis.axisLabel(new AxisLabel().formatter("{value} ml"));
            yAxis.add(valueAxis);
        }
        {
            ValueAxis valueAxis = new ValueAxis();
            valueAxis.name("温度");
            valueAxis.axisLabel(new AxisLabel().formatter("{value} °C"));
            yAxis.add(valueAxis);
        }
        option.yAxis(yAxis);
        //series
        List<Series> series = new ArrayList<Series>();
        {
            Bar bar = new Bar();
            bar.name(legend1).type(SeriesType.bar).yAxisIndex(0);
            List data = new ArrayList();
            double arrays[] = {2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3};
            for (double value : arrays){
                data.add(value);
            }
            bar.setData(data);
            series.add(bar);
        }
        {
            Bar bar = new Bar();
            bar.name(legend2).type(SeriesType.bar).yAxisIndex(0);
            List data = new ArrayList();
            double arrays[] = {2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3};
            for (double value : arrays){
                data.add(value);
            }
            bar.setData(data);
            series.add(bar);
        }
        {
            Line line = new Line();
            line.name(legend3).type(SeriesType.line).yAxisIndex(1);
            List data = new ArrayList();
            double arrays[] = {2.0, 2.2, 3.3, 4.5, 6.3, 10.2, 20.3, 23.4, 23.0, 16.5, 12.0, 6.2};
            for (double value : arrays){
                data.add(value);
            }
            line.setData(data);
            series.add(line);
        }
        option.series(series);
        //
        return option;
    }


    public GsonOption getLineChartOptions() {

        //地址:http://echarts.baidu.com/echarts2/doc/example/line5.html
        GsonOption option = new GsonOption();
        option.legend("高度(km)与气温(°C)变化关系");

        option.toolbox().show(true).feature(Tool.mark, Tool.dataView, new MagicType(Magic.line, Magic.bar), Tool.restore, Tool.saveAsImage);

        option.calculable(true);
        option.tooltip().trigger(Trigger.axis).formatter("Temperature : <br/>{b}km : {c}°C");

        ValueAxis valueAxis = new ValueAxis();
        valueAxis.axisLabel().formatter("{value} °C");
        option.xAxis(valueAxis);

        CategoryAxis categoryAxis = new CategoryAxis();
        categoryAxis.axisLine().onZero(false);
        categoryAxis.axisLabel().formatter("{value} km");
        categoryAxis.boundaryGap(false);
        categoryAxis.data(0, 10, 20, 30, 40, 50, 60, 70, 80);
        option.yAxis(categoryAxis);

        Line line = new Line();
        line.smooth(true).name("高度(km)与气温(°C)变化关系").data(15, -50, -56.5, -46.5, -22.1, -2.5, -27.7, -55.7, -76.5).itemStyle().normal().lineStyle().shadowColor("rgba(0,0,0,0.4)");
        option.series(line);
        return option;
    }
}

封装源码:

TEChartWebView控件源码
public class TEChartWebView extends WebView {

    /** 默认false
     * 在EChart.html和EChart.js中因开发调试多处调用了function toast(msg) 可以设置为true开启调试模式
     */
    private boolean isDebug = false;


    /**
     * 存放在第一时间需要Android调用js的function
     * 因为在第一次见EChart.html及EChart.js还没有加载完成,而Java代码却是在第一时间调用了
     * 所以需要等到html的标签及js加载成功后再调用,在WebViewClient中的onPageFinished方法中
     */
    private List<String> shouldCallJsFunctionArray = new ArrayList<String>();

    public void setDebug(boolean isDebug) {
        this.isDebug = isDebug;
    }

    public boolean isDebug() {

        return isDebug;
    }

    public TEChartWebView(Context context) {
        this(context,null);
    }

    public TEChartWebView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public TEChartWebView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        initWebViewClient();

        init();
    }

    private void init() {
        //
        WebSettings webSettings = getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
        webSettings.setSupportZoom(false);
        webSettings.setDisplayZoomControls(false);
        addJavascriptInterface(new TEChartWebView.WebAppEChartInterface(getContext()), "Android");
        loadUrl("file:///android_asset/echartWeb/EChart/EChart.html");
    }

    private void initWebViewClient () {
        setWebViewClient(new WebViewClient(){
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
            }

            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
                for (String callJs : shouldCallJsFunctionArray) {
                    loadUrl(callJs);
                }
            }

            @Override
            public void onLoadResource(WebView view, String url) {
                super.onLoadResource(view, url);
            }

            @Override
            public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
                super.onReceivedError(view, request, error);
            }
        });
    }

    /**刷新图表
     * java调用js的refreshEChartWithGsonOption方法刷新echart
     * 不能在第一时间就用此方法来显示图表,因为第一时间html的标签还未加载完成,不能获取到标签值
     * 需先设置数据源DataSource,后续视具体情况来手动刷新
     * @param option
     */
    public void refreshEchartsWithOption(GsonOption option) {
        if (dataSource == null) {
            assert false : "ataSource == null";
        }
        String optionString = option.toString();
        String call = "javascript:refreshEchartsWithOption('" + optionString + "')";
        loadUrl(call);
    }


    /**添加图表事件响应监听
     * @param echartActions 事件名称数组
     * @param onAddEchartActionHandlerResponseResultListener 事件点击后的echart返回的事件信息(echart返回的事件信息:http://echarts.baidu.com/api.html#events) 响应监听给开发者
     */
    public void addEchartActionHandler(TEChartConstant.PYEchartAction[] echartActions, OnAddEchartActionHandlerResponseResultListener onAddEchartActionHandlerResponseResultListener) {
        this.onAddEchartActionHandlerResponseResultListener = onAddEchartActionHandlerResponseResultListener;
        //
        for (TEChartConstant.PYEchartAction echartAction : echartActions) {
            String callString = echartAction.actionValue;
            String call = "javascript:addEchartActionHandler('" + callString + "')";
            //loadUrl(call);
            shouldCallJsFunctionArray.add(call);
        }
    }


    /**移除图表事件响应监听
     * @param echartAction 事件名称
     */
    public void removeEchartActionHandler(TEChartConstant.PYEchartAction echartAction) {
        String callString = echartAction.actionValue;
        String call = "javascript:removeEchartActionHandler('" + callString + "')";
        loadUrl(call);
    }


    /**
     *显示Echart自带的默认样式的Loading
     */
    public void myChartShowLoading() {
        String call = "javascript:myChartShowLoading()";
        //loadUrl(call);
        shouldCallJsFunctionArray.add(call);
    }
    /**
     *隐藏Echart自带的默认样式的Loading
     */
    public void myChartHideLoading() {
        String call = "javascript:myChartHideLoading()";
        loadUrl(call);
    }


    ///////////////////////WebAppEChartInterface////////////////////////////////

    /**
     * js 与 Android原生交互接口
     */
    class WebAppEChartInterface {
        Context context;

        public WebAppEChartInterface(Context context) {
            this.context = context;
        }

        @JavascriptInterface
        public void showDebugMessage(String message) {
            if (isDebug) LogUtils.e(message);
        }

        /**
         * 获取图表配置JSON数据
         *
         * @return
         */
        @JavascriptInterface
        public String getChartOptions() {
            if (dataSource != null) {
                GsonOption option = dataSource.markChartOptions();
                LogUtils.d(option.toString());
                return option.toString();
            }
            return null;
        }


        /**添加图表事件响应监听
         * @param params echart返回的事件信息 http://echarts.baidu.com/api.html#events
         */
        @JavascriptInterface
        public void addEchartActionHandlerResponseResult(String params) {
            LogUtils.e(params);
            if (onAddEchartActionHandlerResponseResultListener != null) {
                onAddEchartActionHandlerResponseResultListener.actionHandlerResponseResult(params);
            }
        }


        /**移除图表事件响应监听
         * @param params echart返回的事件信息 http://echarts.baidu.com/api.html#events
         */
        @JavascriptInterface
        public void removeEchartActionHandlerResponseResult(String params) {
            LogUtils.e(params);
        }

    }

    ///////////////////////WebAppEChartInterface////////////////////////////////

    ////////////////////////////数据源 获取图表的JSON配置//////////////////////////////

    private DataSource dataSource;

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
        //
        reload();
    }

    public DataSource getDataSource() {

        return dataSource;
    }

    public interface DataSource {
        GsonOption markChartOptions();
    }
    ////////////////////////////数据源 获取图表的JSON配置//////////////////////////////


    ////////////////////////////添加事件监听echart返回的 事件相关属性(是一个json),将该json返回给开发者使用
    ///////////////////////////echart返回的事件信息:http://echarts.baidu.com/api.html#events

    private OnAddEchartActionHandlerResponseResultListener onAddEchartActionHandlerResponseResultListener;

    public void setOnAddEchartActionHandlerResponseResultListener(OnAddEchartActionHandlerResponseResultListener onAddEchartActionHandlerResponseResultListener) {
        this.onAddEchartActionHandlerResponseResultListener = onAddEchartActionHandlerResponseResultListener;
    }

    public OnAddEchartActionHandlerResponseResultListener getOnAddEchartActionHandlerResponseResultListener() {

        return onAddEchartActionHandlerResponseResultListener;
    }

    public interface OnAddEchartActionHandlerResponseResultListener {
        void actionHandlerResponseResult(String result);
    }

}

时间不是很充裕,只能在零碎时间上来一点一点补充,因此肯定会出现许多不足之处
希望在未来的某一天自己能封装的很完善

项目GitHub地址 https://github.com/tikeyc/TAndroidEChart

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容