├── .gitignore
├── .idea
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── dictionaries
│ └── Administrator.xml
├── encodings.xml
├── gradle.xml
├── inspectionProfiles
│ ├── Project_Default.xml
│ └── profiles_settings.xml
├── misc.xml
└── vcs.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── hunty
│ │ └── widget
│ │ ├── HlApplication.java
│ │ ├── MainActivity.java
│ │ ├── charts
│ │ ├── CandleChartView.java
│ │ ├── CandleParamResult.java
│ │ ├── ChartDataInitUtils.java
│ │ ├── DrawChartUtils.java
│ │ ├── FenshiParamResult.java
│ │ ├── LogUtil.java
│ │ └── RouteLineView.java
│ │ ├── event
│ │ ├── BaseBean.java
│ │ ├── DayKHistoryBean.java
│ │ ├── DayKHistoryEvent.java
│ │ ├── Event.java
│ │ ├── TimeSharingHistoryBean.java
│ │ └── TimeSharingHistoryEvent.java
│ │ └── util
│ │ ├── AbAppConfig.java
│ │ └── ViewUtils.java
│ └── res
│ ├── drawable-xhdpi
│ ├── board_bg.png
│ ├── corsspoint.png
│ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ └── ic_launcher.png
│ ├── layout
│ └── activity_main.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── imgs
├── ScreenShot00027.png
├── ScreenShot00028.png
├── weixin_shouqian.png
└── zhifubao-shouqian.png
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | /.idea
3 | /.gradle
4 | local.properties
5 | .DS_Store
6 | /build
7 | /captures
8 | /debug
9 | /release
10 | .externalNativeBuild
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/dictionaries/Administrator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
19 |
20 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RouteLineProject
2 | 折线图,均线图(日K图),股市行情折线图,带有手指滑动交互;适用于上证指数,欧元汇率,黄金汇率。
3 |
4 | · 这个均值可以后台计算,也可以前台计算。项目中采用的是后台计算,前台展示(如果我记得还清楚的话)。
5 | · 因为数据量比较大,哪怕json解析,目前也是子线程解析。
6 |
7 | 因为最开始的时候,没有想着把这两个控件开源,所以,从设计模式上来说,就没有更多地去考虑通用。这个工作,可以开发者自己
8 | 根据需求,自己去改写。在改写的过程中,如果碰到什么问题,可以给我发邮件,或者issue。我看到的话会回复。
9 |
10 |
11 | ### 折线图(分时图) RouterLineView:
12 |
13 | 折线图,均线图(日K图),股市行情折线图,带有手指滑动交互;适用于上证指数,欧元汇率,黄金汇率。
14 |
15 | 折线图,实时变化图:
16 |
17 | ·提供了初始化的API,和增加点的方法。
18 |
19 | ·需要说明的是,一天的变化的点数,不可能全部描绘到手机屏幕的宽度上。所以,先让后台吧所得到的点,按照一天的总点数,平均
20 | 到几分钟一个点左右。也就是说,后台 会从数据供应商那里拿来的数据,抛弃很多点的信息。这个是可以理解的。
21 |
22 | '''
23 |
24 | RouteLineView routeline = findViewById(R.id.routeline);
25 | //GOLD, SZHENG, EUROPE,提供三种模式。考虑交易交易时间和像素点数目
26 | routeline.setType(RouteLineView.TYPE.SZHENG);
27 | // routeline.setMaxAndMin();
28 | // routeline.addData();
29 |
30 | '''
31 |
32 | 
33 |
34 |
35 |
36 | ### 均线图(日K图) CandleChartView:
37 | 同时带有手指交互功能。
38 |
39 | 
40 |
41 |
42 | --------
43 |
44 | 支付宝打赏
45 | 
46 |
47 | 微信打赏
48 | 
49 |
50 | 欢迎交流学习。
51 | http://blog.csdn.net/u011216417
52 | email me :zhangjianqiu007@126.com
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 33
5 | buildToolsVersion '33.0.0'
6 |
7 |
8 | defaultConfig {
9 |
10 | applicationId "com.hunter.routelineproject"
11 | minSdkVersion 19
12 | targetSdkVersion 33
13 | versionCode 2
14 | versionName "2.0"
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | }
23 |
24 | dependencies {
25 | implementation fileTree(dir: 'libs', include: ['*.jar'])
26 |
27 | implementation 'com.android.support:appcompat-v7:28.0.0'
28 | }
29 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in E:\android/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hunty/widget/HlApplication.java:
--------------------------------------------------------------------------------
1 | package com.hunty.widget;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 |
6 | /**
7 | * Created by zhangJianqiu on 2017/2/26 0026.
8 | */
9 | public class HlApplication extends Application {
10 |
11 | private static Context context;
12 |
13 | public HlApplication() {
14 | context = this;
15 | }
16 |
17 | public static Context getContext() {
18 | return context;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hunty/widget/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.hunty.widget;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.AppCompatActivity;
5 | import android.text.TextUtils;
6 |
7 | import com.hunty.widget.charts.CandleChartView;
8 | import com.hunty.widget.charts.CandleParamResult;
9 | import com.hunty.widget.charts.ChartDataInitUtils;
10 | import com.hunty.widget.charts.FenshiParamResult;
11 | import com.hunty.widget.charts.RouteLineView;
12 | import com.hunty.widget.event.DayKHistoryBean;
13 | import com.hunty.widget.event.DayKHistoryEvent;
14 | import com.hunty.widget.event.TimeSharingHistoryBean;
15 | import com.hunty.widget.event.TimeSharingHistoryEvent;
16 |
17 | import java.text.NumberFormat;
18 | import java.util.ArrayList;
19 |
20 | /**
21 | * main home page
22 | *
23 | * @author Hunter
24 | * @Date 2019年06月25日15:27:15
25 | */
26 | public class MainActivity extends AppCompatActivity implements ChartDataInitUtils.onRouteChartOKPostListener, ChartDataInitUtils.onCandleChartOKPostListener {
27 |
28 | RouteLineView routeline;
29 | CandleChartView chartView;
30 | private NumberFormat nt = NumberFormat.getPercentInstance();
31 |
32 | @Override
33 | protected void onCreate(Bundle savedInstanceState) {
34 | super.onCreate(savedInstanceState);
35 | setContentView(R.layout.activity_main);
36 | routeline = findViewById(R.id.routeline);
37 | chartView = findViewById(R.id.candle);
38 | nt.setMinimumFractionDigits(2);
39 | nt.setMaximumFractionDigits(2);
40 |
41 | ChartDataInitUtils chartDataInitUtils = new ChartDataInitUtils();
42 |
43 | //折线图处理部分
44 | routeline.setType(RouteLineView.TYPE.SZHENG);
45 | // routeline.setMaxAndMin();
46 | // routeline.addData();
47 |
48 | //烛光图部分
49 | chartView.setType(2);
50 |
51 | TimeSharingHistoryEvent routeData = generaterRouteDate();
52 | chartDataInitUtils.initRouteChartData(routeData, this);
53 | DayKHistoryEvent candleData = generaterCandleDate();
54 | chartDataInitUtils.initCandleChartData(candleData, this);
55 | }
56 |
57 | private TimeSharingHistoryEvent generaterRouteDate() {
58 | TimeSharingHistoryEvent routeData = new TimeSharingHistoryEvent(this);
59 | TimeSharingHistoryBean b = new TimeSharingHistoryBean();
60 | ArrayList beans = new ArrayList();
61 | for (int i = 8; i < 9; i++) {//month
62 | for (int j = 11; j < 12; j++) {//day
63 | for (int h = 10; h < 14; h++) {//hours
64 | for (int k = 10; k < 60; k++) {//minutes
65 | TimeSharingHistoryBean.FenShihistoryDatesBean bean = new TimeSharingHistoryBean.FenShihistoryDatesBean();
66 | bean.setTradedate("20190" + i + j);
67 | bean.setTradetime("" + h + k);
68 | bean.setPrice((int) (Math.random() * 1000) + 1000 + "");
69 | bean.setLow("1000");
70 | bean.setHigh("2100");
71 | bean.setClose("1200");
72 | beans.add(bean);
73 | }
74 | }
75 | }
76 | }
77 | b.setList(beans);
78 | routeData.setIsSuccess(true);
79 | routeData.setObject(b);
80 | return routeData;
81 | }
82 |
83 | private DayKHistoryEvent generaterCandleDate() {
84 | DayKHistoryEvent candleData = new DayKHistoryEvent(this);
85 | DayKHistoryBean b = new DayKHistoryBean();
86 | ArrayList beans = new ArrayList<>();
87 |
88 | for (int i = 8; i < 9; i++) {//month
89 | for (int j = 11; j < 12; j++) {//day
90 | for (int h = 10; h < 14; h++) {//hours
91 | for (int k = 10; k < 60; k++) {//minutes
92 | DayKHistoryBean.DayKDatasBean bean = new DayKHistoryBean.DayKDatasBean();
93 | bean.setMa5("1203");
94 | bean.setMa10("1400");
95 | bean.setMa20("1050");
96 | bean.setOpen(900 + j + "");
97 | bean.setLow("1000");
98 | bean.setDate("12090390");
99 | bean.setHigh("1500");
100 | bean.setClose("1200");
101 | beans.add(bean);
102 | }
103 | }
104 | }
105 | }
106 | b.setList(beans);
107 | candleData.setIsSuccess(true);
108 | candleData.setObject(b);
109 | return candleData;
110 | }
111 |
112 | @Override
113 | public void onSuccess(FenshiParamResult data) {
114 | if (null == data) return;
115 | String shangIndex = data.getPrice();
116 | float[][] mRouteData = data.getRouteData();
117 | resetPercent(data.getClose(), data.getPrice());
118 | //最后一个显示配置max min。
119 | if (TextUtils.isEmpty(data.getHigh()) || TextUtils.isEmpty(data.getLow()) || TextUtils.isEmpty(data.getClose()))
120 | return;
121 | routeline.setMaxAndMin(data.getHigh(), data.getLow(), data.getClose());
122 | if (null == mRouteData) return;
123 | routeline.setData(mRouteData);
124 | if (TextUtils.isEmpty(data.getDate()) || TextUtils.isEmpty(data.getTime())) {
125 | return;
126 | }
127 | // tv_fenshi_shijian.setText(StringUtil.formatDate(data.getDate()) + " " + StringUtil.formatTime(data.getTime()));
128 | // tv_fenshi_zhishu.setText(data.getPrice());
129 | //历史数据确定获取不到,一样可以插入数据。。因为页面需要 price值,soNULL判断失效
130 | // if (mAddedData != null && !TextUtils.isEmpty(mAddedData.getaMOUNT())) {
131 | addData();
132 | // }
133 | }
134 |
135 | @Override
136 | public void onSuccess(CandleParamResult result) {
137 | if (null == result || null == result.getmDates()) return;
138 | chartView.setDate(result.getmDates());
139 | if (null == result.getmData() || TextUtils.isEmpty(result.getFirstCandleDate()) || TextUtils.isEmpty(result.getLastcandleDate()))
140 | return;
141 | chartView.setData(result.getmData(), result.getMax(), result.getMin(), formatDate(result.getFirstCandleDate()), formatDate(result.getLastcandleDate()));
142 | }
143 |
144 |
145 | private void resetPercent(String open, String price) {
146 | if (TextUtils.isEmpty(open) || TextUtils.isEmpty(price)) {
147 | return;
148 | }
149 | float closep = Float.parseFloat(open);
150 | float pricef = Float.parseFloat(price);
151 | if (closep < pricef) {
152 | // tv_fenshi_percent.setTextColor(Color.parseColor("#F94747"));
153 | // tv_fenshi_percent.setText("+" + nt.format((pricef - closep) / closep));
154 | } else {
155 | // tv_fenshi_percent.setTextColor(Color.parseColor("#51C678"));
156 | // tv_fenshi_percent.setText("-" + nt.format((closep - pricef) / closep));
157 | }
158 | }
159 |
160 | /**
161 | * mqtt,或者短连接接收过来数据。及时刷新视图。
162 | */
163 | public void onEventMainThread(String base) {
164 | // mAddedData = JSON.parseObject(base.getMsgbody(), MQTimeModel.class);
165 | // if (mRouteData != null) {
166 | addData();
167 | // }
168 | }
169 |
170 | private void addData() {
171 | //添加数据
172 | // if (TextUtils.isEmpty(mAddedData.getpRICE()) || TextUtils.isEmpty(mAddedData.gettRADETIME()) || TextUtils.isEmpty(mAddedData.getdBFDATE()))
173 | // return;
174 | // if (TextUtils.isEmpty(mAddedData.gettRADETIME().substring(0, 2)) || TextUtils.isEmpty(mAddedData.getdBFDATE().substring(0, 2)))
175 | // return;
176 | // mRoutLine.setMaxAndMin(mAddedData.gethIGH(), mAddedData.getlOW(), mAddedData.getcLOSE());
177 | // mRoutLine.addData(mAddedData.getpRICE(), mAddedData.gettRADETIME().substring(0, 2), mAddedData.gettRADETIME().substring(2, 4), mAddedData.getdBFDATE().substring(4, 6), mAddedData.getdBFDATE().substring(6, 8));
178 | //设置文本
179 | // tv_fenshi_shijian.setText(StringUtil.formatDate(mAddedData.gettRADEDATE()) + " " + StringUtil.formatTime(mAddedData.gettRADETIME()));
180 | // tv_fenshi_zhishu.setText(mAddedData.getpRICE());
181 | // resetPercent(mAddedData.getcLOSE(), mAddedData.getpRICE());
182 | }
183 |
184 | /**
185 | * 20160818 -> 08-18
186 | */
187 | public String formatDate(String date) {
188 | return date.substring(4, 6) + "-" + date.substring(6, 8);
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hunty/widget/charts/CandleChartView.java:
--------------------------------------------------------------------------------
1 | package com.hunty.widget.charts;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapFactory;
6 | import android.graphics.Canvas;
7 | import android.graphics.Color;
8 | import android.graphics.DashPathEffect;
9 | import android.graphics.Paint;
10 | import android.graphics.RectF;
11 | import android.util.AttributeSet;
12 | import android.view.MotionEvent;
13 | import android.view.View;
14 |
15 |
16 | import com.hunty.widget.R;
17 | import com.hunty.widget.util.ViewUtils;
18 |
19 | import java.text.DecimalFormat;
20 | import java.util.Calendar;
21 |
22 |
23 | /**
24 | * 烛光图
25 | *
26 | *
27 | * setDate();first
28 | * setData();
29 | *
30 | * @author ZhangJianqiu 2016-05-29周日
31 | */
32 | public class CandleChartView extends View {
33 |
34 | /**
35 | * 整个控件的高度和宽度
36 | */
37 | private float height = 230, width;// width = textSpace+rightwidth+剩下的
38 | /**
39 | * 每个蜡烛的宽度 ,每个蜡烛可以铺开的宽度
40 | **/
41 | private float candlewidth = 6, singlewidth;// dp
42 | /**
43 | * 底部和顶部的初始间隙
44 | **/
45 | private float TOP = 3, low;// dp
46 |
47 | // 常用控件的初始化
48 | private Paint mPaint;
49 | private Calendar mCal = Calendar.getInstance();
50 | private DashPathEffect bgDash = new DashPathEffect(new float[]{10, 10, 10, 10}, 0);
51 | private DashPathEffect crossDash = new DashPathEffect(new float[]{5, 5, 5, 5}, 0);
52 | private DecimalFormat nt = new DecimalFormat("####0.00");
53 |
54 | // 左边的文本
55 | private String[] leftText = new String[]{"1520.08", "1224.42", "1161.00"};
56 | private float[][] leftTextPosition;
57 | // 底部的文本
58 | private String[] bellowIndicator = new String[2];
59 | //左右小黑板
60 | private Bitmap textbox, mCorssDot;
61 | private float boxwidth = 85, xoffset = 5, yoffset = 5;//dp
62 | private RectF dst = new RectF();
63 | private String[] leftIndicatorInbox = new String[]{"日期", "开盘价", "收盘价", "最高", "最低"};
64 | private String[] rightIndicatorInbox = new String[]{"2016-08-05", "0000.00", "0000.00", "0000.00", "0000.00"};
65 | //底部文本的坐标
66 | private float[][] bellowTextPosition = new float[2][2];
67 | /**
68 | * 图片缓存机制
69 | **/
70 | private Bitmap mCacheImg;
71 | private Canvas mCacheCanvas;
72 | /**
73 | * 是否需要重绘 区别手势,默认true
74 | * 设置历史或者大小值改变时置为true
75 | **/
76 | private boolean isNewDrw = true, isTouch = false;
77 | private int touchChartx;//索引
78 |
79 | //背景线条的坐标
80 | private float[] bgLine;
81 |
82 | /**
83 | * 日K 图的数据
84 | *
85 | * [4][i],0代表top,1代表topvalue,2代表bottomvalue,3代表bottom,4代表日期,5代表5日均线,6代表10日均线,7代表20日均线。
86 | * 代表,最高,开盘,收盘,最低,时间(不在做显示使用),*,*,*,
87 | **/
88 | private float[][] mData;
89 | //30个日期
90 | private String[] mDate;
91 | /**
92 | * 保存每个数据的 y 轴坐标点
93 | *
94 | * 表示y和x,
95 | * 0-top,1-open,2-bottom,3-close,
,同时还有,4-ma5,5-ma10,6-ma20,7-x轴。共8个。
96 | * 代表坐标值,前六个是y值,然后一个是x值
97 | **/
98 | private float[][] mDataPosition;
99 | private float max, min;
100 | /**
101 | * 缓存使用
102 | **/
103 | private float candlewidthpercent, cachey;
104 | //图表线图部分的高度
105 | float invalidatey;
106 |
107 | public CandleChartView(Context context, AttributeSet attrs, int defStyleAttr) {
108 | super(context, attrs, defStyleAttr);
109 | init(context);
110 | }
111 |
112 | public CandleChartView(Context context, AttributeSet attrs) {
113 | this(context, attrs, 1);
114 | }
115 |
116 | public CandleChartView(Context context) {
117 | this(context, null);
118 | }
119 |
120 | private void init(Context mContext) {
121 | mPaint = new Paint();
122 | mPaint.setAntiAlias(true);
123 | mPaint.setStrokeCap(Paint.Cap.ROUND);
124 | mPaint.setStrokeJoin(Paint.Join.ROUND);
125 | mPaint.setStyle(Paint.Style.FILL);// 设置具有填充效果
126 | mPaint.setStrokeWidth(1.0f);
127 | //各种数据
128 | height = ViewUtils.dp2px(height);
129 | //图表线图部分的高度
130 | invalidatey = DrawChartUtils.getChartHeight(mPaint, height);//有效到下面的坐标
131 | TOP = ViewUtils.dp2px(TOP);
132 | candlewidth = ViewUtils.dp2px(candlewidth);
133 | boxwidth = ViewUtils.dp2px(boxwidth);
134 |
135 | // 文本框
136 | textbox = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.board_bg);
137 | mCorssDot = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.corsspoint);
138 |
139 | // 底部日期初始化 默认,不设置的情况下,有文本可以显示
140 | bellowIndicator[1] = (mCal.get(Calendar.MONTH) + 1) + "."
141 | + mCal.get(Calendar.DATE);
142 | mCal.add(Calendar.DATE, -30);
143 | bellowIndicator[0] = (mCal.get(Calendar.MONTH) + 1) + "."
144 | + mCal.get(Calendar.DATE);
145 | }
146 |
147 | /**
148 | * 设置烛光图的数据。设置底部x 轴上的文本。
149 | *
150 | * @param values [4][i],0代表top,1代表topvalue,2代表bottomvalue,3代表bottom。
151 | * @param mm 最大值
152 | * @param nn 最小值
153 | */
154 | public void setData(float[][] values, float mm, float nn, String lefttext, String righttext) {
155 | mData = values;
156 | max = mm;
157 | min = nn;
158 | initRightText();
159 | bellowIndicator[0] = lefttext;
160 | bellowIndicator[1] = righttext;
161 | mDataPosition = new float[8][values[0].length];//初始化坐标数组
162 | initData();
163 | if (getVisibility() == View.VISIBLE) {
164 | isNewDrw = true;
165 | postInvalidate();
166 | }
167 | }
168 |
169 | public void setDate(String[] date) {
170 | mDate = date;
171 | }
172 |
173 | /**
174 | * 按照类型的特殊处理
175 | *
176 | * @param type 2 四位小数
177 | */
178 | public void setType(int type) {
179 | if (type == 2) {
180 | nt = new DecimalFormat("#0.0000");
181 | } else {
182 |
183 | }
184 | }
185 |
186 | private void initRightText() {
187 | float cache = (max - min) / 2;
188 | leftText[0] = nt.format(max);
189 | leftText[1] = nt.format(min + cache);
190 | leftText[2] = nt.format(min);
191 | }
192 |
193 | /**
194 | * 数值,转化成纵坐标点
195 | *
196 | * 大量的运算都在这里。只计算y值
197 | */
198 | private void initData() {
199 | low = invalidatey - TOP;//整个的长度,最低点y
200 | float height = low - TOP;
201 | candlewidthpercent = max - min;
202 | if (mData == null) {
203 | LogUtil.ee(this, "the mData is empty,Please call setData to initalise the values first.");
204 | }
205 |
206 | //计算纵坐标点
207 | for (int j = 0; j < mData[0].length; j++) {
208 | mDataPosition[0][j] = low - ((mData[0][j] - min) / candlewidthpercent) * height;
209 | mDataPosition[1][j] = low - ((mData[1][j] - min) / candlewidthpercent) * height;
210 | mDataPosition[2][j] = low - ((mData[2][j] - min) / candlewidthpercent) * height;
211 | mDataPosition[3][j] = low - ((mData[3][j] - min) / candlewidthpercent) * height;
212 | //均线的坐标
213 | if (mData[5][j] != 0) {
214 | mDataPosition[4][j] = low - ((mData[5][j] - min) / candlewidthpercent) * height;
215 | } else {
216 | mDataPosition[4][j] = low - ((mData[5][j - 1] - min) / candlewidthpercent) * height;
217 | }
218 | if (mData[6][j] != 0) {
219 | mDataPosition[5][j] = low - ((mData[6][j] - min) / candlewidthpercent) * height;
220 | } else {
221 | mDataPosition[5][j] = low - ((mData[6][j - 1] - min) / candlewidthpercent) * height;
222 | }
223 | if (mData[7][j] != 0) {
224 | mDataPosition[6][j] = low - ((mData[7][j] - min) / candlewidthpercent) * height;
225 | } else {
226 | mDataPosition[6][j] = low - ((mData[7][j - 1] - min) / candlewidthpercent) * height;
227 | }
228 | }
229 | }
230 |
231 | @Override
232 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
233 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
234 | width = getMeasuredWidth();
235 | height = getMeasuredHeight();
236 | isNewDrw = true;//重新作图
237 | normal();
238 | }
239 |
240 | @Override
241 | protected void onDraw(Canvas canvas) {
242 | if (!isNewDrw) {
243 | // 不是第一次,直接画缓存的
244 | canvas.drawBitmap(mCacheImg, 0, 0, null);
245 | } else {
246 | // 第一次,或者新数据来的时候.画到缓存上
247 | initBitmap();
248 | canvas = mCacheCanvas;
249 | }
250 | // 绘制触摸的竖线
251 | if (isTouch & !isNewDrw) {
252 | //没有数据,则不绘制触摸和文本
253 | if (mData == null || mData[0][0] == 0) {
254 | return;
255 | }
256 | calcEnsureX();
257 | drawCorssLines(canvas);
258 | // 绘制圆点
259 | canvas.drawBitmap(mCorssDot, mDataPosition[7][touchChartx] - 13f, cachey - 13f, mPaint);
260 | // 绘制触摸出来的文本框
261 | drawTextBox(canvas);
262 | }
263 | //图片已经包括的内容
264 | if (!isNewDrw) {
265 | return;
266 | }
267 | // 画背景直线
268 | mPaint.setStrokeWidth(1.0f);
269 | mPaint.setColor(Color.parseColor("#E1C6B1"));
270 | for (int i = 0; i < bgLine.length; i++) {
271 | if (i == 0 || i == 4) {
272 | mPaint.setPathEffect(null);
273 | canvas.drawLine(0, bgLine[i], width, bgLine[i], mPaint);
274 | } else {
275 | mPaint.setPathEffect(bgDash);
276 | canvas.drawLine(0, bgLine[i], width, bgLine[i], mPaint);
277 | }
278 | }
279 | // 画左边的文本
280 | mPaint.setTextSize(DrawChartUtils.ySize);
281 | mPaint.setColor(Color.WHITE);
282 | mPaint.setStyle(Paint.Style.FILL);
283 | for (int i = 0; i < 3; i++) {
284 | canvas.drawText(leftText[i], leftTextPosition[0][i], leftTextPosition[1][i], mPaint);
285 | }
286 | // 画底部文本
287 | mPaint.setTextSize(DrawChartUtils.xSize);
288 | mPaint.setColor(Color.GRAY);
289 | for (int i = 0; i < 2; i++) {
290 | //初始化的是昨天和30前
291 | canvas.drawText(bellowIndicator[i], bellowTextPosition[0][i], bellowTextPosition[1][i], mPaint);
292 | }
293 | //无数据,直接退出
294 | if (mData == null || mDataPosition == null || getVisibility() != View.VISIBLE) {
295 | isNewDrw = false;
296 | postInvalidate();
297 | return;
298 | }
299 | // 开始画蜡烛 candlewidthpercent = candlewidth / singlewidth;
300 | candlewidthpercent = candlewidth / 2;
301 | cachey = singlewidth / 2;
302 | LogUtil.ee("摆放::", " candlewidth:" + candlewidth + " singlewidth:" + singlewidth);
303 | mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
304 | for (int k = 0; k < mData[0].length; k++) {
305 | changeColor(k, mPaint);
306 | //确定x轴中心位置
307 | mDataPosition[7][k] = singlewidth * k + cachey;
308 | //画灯芯
309 | canvas.drawLine(mDataPosition[7][k], mDataPosition[0][k], mDataPosition[7][k], mDataPosition[3][k], mPaint);
310 | //蜡烛的矩形框,style类型空心效果
311 | canvas.drawRect(mDataPosition[7][k] - candlewidthpercent, mDataPosition[1][k], mDataPosition[7][k] + candlewidthpercent, mDataPosition[2][k], mPaint);
312 | if (mDataPosition[1][k] > mDataPosition[2][k]) {
313 | //封闭的小矩形
314 | mPaint.setColor(Color.BLACK);
315 | canvas.drawRect(mDataPosition[7][k] - candlewidthpercent + 1, mDataPosition[1][k] - 1, mDataPosition[7][k] + candlewidthpercent - 1, mDataPosition[2][k] + 1, mPaint);
316 | }
317 | }
318 |
319 | //画5日均线,10日均线,20日均线
320 | mPaint.setStrokeWidth(2.0f);
321 | mPaint.setColor(Color.parseColor("#FCC031"));
322 | for (int j = 1; j < mData[0].length; j++) {
323 | //不画出最高点。三条线相同
324 | if (mDataPosition[4][j - 1] < TOP || mDataPosition[4][j - 1] > low) {
325 | continue;
326 | }
327 | canvas.drawLine(mDataPosition[7][j - 1], mDataPosition[4][j - 1], mDataPosition[7][j], mDataPosition[4][j], mPaint);
328 | }
329 | mPaint.setColor(Color.parseColor("#9A73EC"));
330 | for (int j = 1; j < mData[0].length; j++) {
331 | if (mDataPosition[5][j - 1] < TOP || mDataPosition[5][j - 1] > low) {
332 | continue;
333 | }
334 | canvas.drawLine(mDataPosition[7][j - 1], mDataPosition[5][j - 1], mDataPosition[7][j], mDataPosition[5][j], mPaint);
335 | }
336 | mPaint.setColor(Color.parseColor("#F47431"));
337 | for (int j = 1; j < mData[0].length; j++) {
338 | if (mDataPosition[6][j - 1] < TOP || mDataPosition[6][j - 1] > low) {
339 | continue;
340 | }
341 | canvas.drawLine(mDataPosition[7][j - 1], mDataPosition[6][j - 1], mDataPosition[7][j], mDataPosition[6][j], mPaint);
342 | }
343 |
344 | // 新的一次画图,是画在Bitmap上的。所以刷新。
345 | if (isNewDrw) {
346 | isNewDrw = false;
347 | postInvalidate();
348 | }
349 | }
350 |
351 | //绘制交叉线
352 | private void drawCorssLines(Canvas canvas) {
353 | //竖直线
354 | mPaint.setStrokeWidth(2.0f);
355 | mPaint.setColor(Color.parseColor("#5CAFF4"));
356 | mPaint.setPathEffect(crossDash);
357 | canvas.drawLine(mDataPosition[7][touchChartx], 0, mDataPosition[7][touchChartx], invalidatey, mPaint);
358 | //水平线
359 | cachey = (mDataPosition[1][touchChartx] + mDataPosition[2][touchChartx]) / 2;
360 | canvas.drawLine(0, cachey, width, cachey, mPaint);
361 | }
362 |
363 | private void drawTextBox(Canvas canvas) {
364 | float[][] floats;
365 | // 测量和绘制文本框
366 | // 计算文本的位置
367 | String value = nt.format(mData[2][touchChartx]);
368 | String date = formatdate();
369 | // 绘制框内的文本文本
370 | mPaint.setColor(Color.WHITE);
371 | mPaint.setPathEffect(null);
372 | if (x > (boxwidth + xoffset * 2)) {// 文本框在左边,常态
373 | floats = DrawChartUtils.measureBoxTextAndBox(mPaint, leftIndicatorInbox, rightIndicatorInbox, boxwidth, xoffset, yoffset);
374 | dst.set(xoffset, yoffset, floats[0][0], floats[1][0]);
375 | //绘制滑块,如果文本框在左边,则滑块就在右边
376 | DrawChartUtils.drawBlock(canvas, mPaint, value, cachey, height, width);
377 | DrawChartUtils.drawBellowTime(canvas, mPaint, date, mDataPosition[7][touchChartx], width, height);
378 | } else {// 文本框在右边,过于靠左边时
379 | float temp = width - boxwidth - xoffset * 2;
380 | floats = DrawChartUtils.measureBoxTextAndBox(mPaint, leftIndicatorInbox, rightIndicatorInbox, boxwidth, temp, yoffset);
381 | dst.set(temp, yoffset, floats[0][0], floats[1][0]);
382 | //绘制滑块,如果文本框在右边,则滑块就在左边
383 | DrawChartUtils.drawBlock(canvas, mPaint, value, cachey, height, 0);
384 | DrawChartUtils.drawBellowTime(canvas, mPaint, date, mDataPosition[7][touchChartx], width, height);
385 | }
386 | //文本框
387 | canvas.drawBitmap(textbox, null, dst, null);
388 | //画左边的指示标语
389 | mPaint.setTextSize(DrawChartUtils.boxtextSize);
390 | for (int i = 0; i < leftIndicatorInbox.length; i++) {
391 | canvas.drawText(leftIndicatorInbox[i], floats[0][i + 1], floats[1][i + 1], mPaint);
392 | }
393 | int count = leftIndicatorInbox.length + 1;
394 | canvas.drawText(mDate[touchChartx].substring(0, 4) + "-" + date, floats[0][count], floats[1][count], mPaint);
395 | canvas.drawText(nt.format(mData[1][touchChartx]), floats[0][count + 1], floats[1][count + 1], mPaint);
396 | canvas.drawText(value, floats[0][count + 2], floats[1][count + 2], mPaint);
397 | canvas.drawText(nt.format(mData[0][touchChartx]), floats[0][count + 3], floats[1][count + 3], mPaint);
398 | canvas.drawText(nt.format(mData[3][touchChartx]), floats[0][count + 4], floats[1][count + 4], mPaint);
399 | }
400 |
401 | private String formatdate() {
402 | return mDate[touchChartx].substring(4, 6) + "-" + mDate[touchChartx].substring(6);
403 | }
404 |
405 | private void calcEnsureX() {
406 | for (int i = 0; i < mData[0].length; i++) {
407 | if (mDataPosition[7][i] > x) {
408 | touchChartx = i;
409 | return;
410 | }
411 | }
412 | }
413 |
414 | /**
415 | * 当前触摸坐标
416 | */
417 | static float x, y, srcy;
418 |
419 | @Override
420 | public boolean onTouchEvent(MotionEvent event) {
421 | x = event.getX();
422 | y = event.getY();
423 | switch (event.getAction()) {
424 | case MotionEvent.ACTION_DOWN:
425 | if (y < invalidatey && y > TOP) {
426 | isTouch = true;
427 | srcy = event.getY();
428 | //作图区域点击,则不要父类拦截
429 | this.getParent().requestDisallowInterceptTouchEvent(true);
430 | invalidate();
431 | }
432 | break;
433 | case MotionEvent.ACTION_MOVE:
434 | if (/*x > cachey && */y < invalidatey && y > TOP) {
435 | isTouch = true;
436 | if (Math.abs(srcy - event.getY()) > 50) {
437 | //作图区域拖动,则父类拦截。子类cancel。
438 | this.getParent().requestDisallowInterceptTouchEvent(false);
439 | }
440 | postInvalidate();
441 | } else {
442 | isTouch = false;
443 | }
444 | break;
445 | // 解决事件冲突
446 | default:
447 | isTouch = false;
448 | postInvalidate();
449 | }
450 | return true;
451 | }
452 |
453 | public void changeColor(int k, Paint mPaint) {
454 | // 值大,则坐标小
455 | if (mData[1][k] > mData[2][k]) {//开盘大于收盘..对应坐标左小又大
456 | mPaint.setColor(Color.parseColor("#50c577"));
457 | } else if (mData[1][k] < mData[2][k]) {//收盘大于开盘。位置更换
458 | mPaint.setColor(Color.RED);
459 | } else if (mData[1][k] == mData[2][k]) {//相等,灰色
460 | mPaint.setColor(Color.GRAY);
461 | mPaint.setColor(Color.GRAY);
462 | }
463 | }
464 |
465 | private void initBitmap() {
466 | if (mCacheImg != null || mCacheCanvas != null) {
467 | mCacheCanvas = null;
468 | mCacheImg.recycle();
469 | mCacheImg = null;
470 | }
471 | mCacheImg = Bitmap.createBitmap((int) width, (int) height, Bitmap.Config.ARGB_8888);
472 | mCacheCanvas = new Canvas(mCacheImg);
473 | }
474 |
475 | /**
476 | * 测量完毕,即可获得底纹所有的坐标
477 | * --重新初始化坐标系,和初始化坐标体系
478 | */
479 | private void normal() {
480 | // 计算出底部线的y
481 | bgLine = DrawChartUtils.measureBgLine(mPaint, height);
482 | // 计算左边问本地额坐标
483 | leftTextPosition = DrawChartUtils.measureYText(mPaint, leftText, height, true);
484 | //计算每一个宽度
485 | singlewidth = (width - candlewidth) / 30;//计算每个蜡烛,可以占据的位置 (mData[0].length)
486 | //计算底部日期的坐标
487 | bellowTextPosition = DrawChartUtils.measureXText(mPaint, bellowIndicator, leftText[0], "", height);
488 | candlewidthpercent = candlewidth / singlewidth;
489 | }
490 |
491 | }
492 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hunty/widget/charts/CandleParamResult.java:
--------------------------------------------------------------------------------
1 | package com.hunty.widget.charts;
2 |
3 | /**
4 | * Candle Data handle,then pass to UI thread.
5 | * Created by zhangjianqiu on 16-8-18.
6 | */
7 | public class CandleParamResult {
8 |
9 | String[] mDates;//30`s day.
10 | float[][] mData;
11 | float max;
12 | float min;
13 | String firstCandleDate;//Not first Data.in case of 60`s for web.
14 | String lastcandleDate;
15 |
16 | public String[] getmDates() {
17 | return mDates;
18 | }
19 |
20 | public void setmDates(String[] mDates) {
21 | this.mDates = mDates;
22 | }
23 |
24 | public float[][] getmData() {
25 | return mData;
26 | }
27 |
28 | public void setmData(float[][] mData) {
29 | this.mData = mData;
30 | }
31 |
32 | public float getMax() {
33 | return max;
34 | }
35 |
36 | public void setMax(float max) {
37 | this.max = max;
38 | }
39 |
40 | public float getMin() {
41 | return min;
42 | }
43 |
44 | public void setMin(float min) {
45 | this.min = min;
46 | }
47 |
48 | public String getFirstCandleDate() {
49 | return firstCandleDate;
50 | }
51 |
52 | public void setFirstCandleDate(String firstCandleDate) {
53 | this.firstCandleDate = firstCandleDate;
54 | }
55 |
56 | public String getLastcandleDate() {
57 | return lastcandleDate;
58 | }
59 |
60 | public void setLastcandleDate(String lastcandleDate) {
61 | this.lastcandleDate = lastcandleDate;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hunty/widget/charts/ChartDataInitUtils.java:
--------------------------------------------------------------------------------
1 | package com.hunty.widget.charts;
2 |
3 | import android.os.AsyncTask;
4 | import android.text.TextUtils;
5 |
6 |
7 | import com.hunty.widget.event.DayKHistoryBean;
8 | import com.hunty.widget.event.DayKHistoryEvent;
9 | import com.hunty.widget.event.TimeSharingHistoryBean;
10 | import com.hunty.widget.event.TimeSharingHistoryEvent;
11 |
12 | import java.util.List;
13 |
14 | /**
15 | * ChartData init Task.
16 | * include RouteLine And Candle.
17 | * Created by zhangjianqiu on 16-8-18.
18 | */
19 | public class ChartDataInitUtils {
20 |
21 | private onRouteChartOKPostListener routelistner;
22 | private onCandleChartOKPostListener candlelistner;
23 | /**
24 | * RouteLine Task run.
25 | */
26 | private AsyncTask routeasyncTask = new AsyncTask() {
27 | /**
28 | * 初始化折线图数据
29 | */
30 | @Override
31 | protected FenshiParamResult doInBackground(TimeSharingHistoryEvent... base) {
32 | FenshiParamResult valid = new FenshiParamResult();
33 | float[][] mRouteData;
34 | // TimeSharingHistoryModel data = (TimeSharingHistoryModel) AbJsonUtil.fromJson((String) base[0].getObject(), TimeSharingHistoryModel.class);
35 | TimeSharingHistoryBean data = (TimeSharingHistoryBean) base[0].getObject();
36 | base = null;//event
37 | if (data != null && data.getList().size() > 1) {
38 | // 直接取值,就不需要 初始化一个model了。
39 | List daydata = data.getList();
40 | valid.setHigh(daydata.get(daydata.size() - 1).getHigh());
41 | valid.setLow(daydata.get(daydata.size() - 1).getLow());
42 | valid.setClose(daydata.get(daydata.size() - 1).getClose());
43 | valid.setPrice(daydata.get(daydata.size() - 1).getPrice());
44 | valid.setDate(daydata.get(daydata.size() - 1).getTradedate());
45 | valid.setTime(daydata.get(daydata.size() - 1).getTradetime());
46 | mRouteData = new float[5][daydata.size()];
47 | for (int i = 0; i < daydata.size(); i++) {
48 | mRouteData[0][i] = Float.parseFloat(daydata.get(i).getPrice());//价格
49 | mRouteData[1][i] = Float.parseFloat(daydata.get(i).getTradetime().substring(0, 2));//小时
50 | mRouteData[2][i] = Float.parseFloat(daydata.get(i).getTradetime().substring(2, 4));//分钟
51 | mRouteData[3][i] = Float.parseFloat(daydata.get(i).getTradedate().substring(4, 6));//month
52 | mRouteData[4][i] = Float.parseFloat(daydata.get(i).getTradedate().substring(6, 8));//day
53 | }
54 | data = null;//json
55 | } else {
56 | LogUtil.e("error", "分时数据解析失败");
57 | mRouteData = new float[5][1];
58 | }
59 | valid.setRouteData(mRouteData);
60 | return valid;
61 | }
62 |
63 | @Override
64 | protected void onPostExecute(FenshiParamResult data) {
65 | if (routelistner != null) {
66 | routelistner.onSuccess(data);
67 | }
68 | }
69 | };
70 |
71 | /**
72 | * RouteLine Task run.
73 | */
74 | private AsyncTask candleasycTask = new AsyncTask() {
75 | /**
76 | * 初始化烛光图数据,日K
77 | */
78 | @Override
79 | protected CandleParamResult doInBackground(DayKHistoryEvent... base) {
80 | CandleParamResult candleResult = null;
81 | // DayKInformationModel date = (DayKInformationModel) AbJsonUtil.fromJson((String) base[0].getObject(), DayKInformationModel.class);
82 | DayKHistoryBean date = (DayKHistoryBean) base[0].getObject();
83 | base = null;
84 | if (date != null && date.getList().size() > 0) {
85 | candleResult = new CandleParamResult();
86 | float[][] mCandleData = new float[8][30];
87 | String[] mDate = new String[30];
88 | float max = 0, min = 100000f;
89 | List item = date.getList();
90 | int maxcount = item.size();
91 | int initcount = maxcount - 30;
92 | for (int j = initcount; j < maxcount; j++) {
93 | float high = Float.parseFloat(item.get(j).getHigh());
94 | float low = Float.parseFloat(item.get(j).getLow());
95 | if (high > max) {
96 | max = high;
97 | }
98 | if (low < min) {
99 | min = low;
100 | }
101 | mCandleData[0][j - initcount] = high;
102 | mCandleData[1][j - initcount] = Float.parseFloat(item.get(j).getOpen());
103 | mCandleData[2][j - initcount] = Float.parseFloat(item.get(j).getClose());
104 | mCandleData[3][j - initcount] = low;
105 | mCandleData[4][j - initcount] = Float.parseFloat(item.get(j).getDate());//不在用作显示
106 | mDate[j - initcount] = item.get(j).getDate();
107 | //位空的时候,默认就是 0 。
108 | if (!TextUtils.isEmpty(item.get(j).getMa5())) {
109 | mCandleData[5][j - initcount] = Float.parseFloat(item.get(j).getMa5());
110 | }
111 | if (!TextUtils.isEmpty(item.get(j).getMa5())) {
112 | mCandleData[6][j - initcount] = Float.parseFloat(item.get(j).getMa10());
113 | }
114 | if (!TextUtils.isEmpty(item.get(j).getMa5())) {
115 | mCandleData[7][j - initcount] = Float.parseFloat(item.get(j).getMa20());
116 | }
117 | }
118 | candleResult.setmDates(mDate);
119 | candleResult.setmData(mCandleData);
120 | candleResult.setMax(max);
121 | candleResult.setMin(min);
122 | candleResult.setFirstCandleDate(item.get(initcount).getDate());
123 | candleResult.setLastcandleDate(item.get(item.size() - 1).getDate());
124 | } else {
125 | LogUtil.ee("error", "日K数据解析失败");
126 | }
127 | return candleResult;
128 | }
129 |
130 | @Override
131 | protected void onPostExecute(CandleParamResult data) {
132 | if (data == null) return;
133 | if (candlelistner != null) {
134 | candlelistner.onSuccess(data);
135 | }
136 | }
137 | };
138 |
139 | public void initRouteChartData(TimeSharingHistoryEvent event, onRouteChartOKPostListener listner) {
140 | routelistner = listner;
141 | if (routeasyncTask.getStatus() == AsyncTask.Status.RUNNING) {
142 | return;
143 | }
144 | routeasyncTask.execute(event);
145 | }
146 |
147 | public void initCandleChartData(DayKHistoryEvent event, onCandleChartOKPostListener listner) {
148 | candlelistner = listner;
149 | if (candleasycTask.getStatus() == AsyncTask.Status.RUNNING) {
150 | return;
151 | }
152 | candleasycTask.execute(event);
153 | }
154 |
155 | /**
156 | * Cancel All Task.
157 | */
158 | public void cancelAllTaskAndClean() {
159 | routeasyncTask.cancel(true);
160 | candleasycTask.cancel(true);
161 | routeasyncTask=null;
162 | candleasycTask=null;
163 | }
164 |
165 | public interface onRouteChartOKPostListener {
166 | void onSuccess(FenshiParamResult result);
167 | }
168 |
169 | public interface onCandleChartOKPostListener {
170 | void onSuccess(CandleParamResult result);
171 | }
172 |
173 | }
174 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hunty/widget/charts/DrawChartUtils.java:
--------------------------------------------------------------------------------
1 | package com.hunty.widget.charts;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Color;
5 | import android.graphics.Paint;
6 |
7 | import com.hunty.widget.HlApplication;
8 | import com.hunty.widget.util.ViewUtils;
9 |
10 |
11 | /**
12 | * 折线图
13 | * Created by zhangjianqiu on 2016/8/3 0003.
14 | */
15 | public class DrawChartUtils {
16 |
17 | /**
18 | * x 文本大小
19 | */
20 | public static float xSize = ViewUtils.sp2px(13);// sp
21 | /**
22 | * y 文本大小
23 | */
24 | public static float ySize = ViewUtils.sp2px(13);// sp
25 | /**
26 | * 文本框中的文字大小
27 | */
28 | public static float boxtextSize = ViewUtils.sp2px(10);
29 | /**
30 | * x文本间隙,左侧左右,右侧左右。
31 | */
32 | private static float leftText_paddingLeft = ViewUtils.dp2px(2);
33 | private static float leftText_paddingright = ViewUtils.dp2px(2);
34 | private static float rightText_paddingLeft = leftText_paddingright;
35 | private static float rightText_paddingright = leftText_paddingLeft;
36 | /**
37 | * y文本的上下间隙。所有的间隙。
38 | */
39 | public static float yText_paddingtop = 4;
40 | public static float yText_paddingbottom = 4;
41 | private static float xText_paddingtop = ViewUtils.dip2px(HlApplication.getContext(), 2);
42 | private static float xText_paddingbottom = xText_paddingtop;
43 | /**
44 | * 分时日K,下划线的宽度保存。
45 | */
46 | public static float tabIndicatorbang, x;
47 |
48 | /**
49 | * x 轴文本测量和位置。
50 | * 按照整个屏幕宽度计算。。。。。。注释部分,因为x文本左对齐则不要lefet.。
51 | **/
52 | public static float[][] measureXText(Paint mPaint, String[] xText, String yleftSample, String yrightSample, float height) {
53 | float[][] xposition = new float[2][xText.length];
54 | float left = 0;//getTextWidthAndLength(mPaint, yleftSample, ySize)[0];
55 | float right = getTextWidthAndLength(mPaint, xText[xText.length - 1], ySize)[0];
56 | float width = ViewUtils.getScreenWidth() - left - right - leftText_paddingLeft - leftText_paddingright - rightText_paddingLeft - rightText_paddingright;
57 | float spilitwidth = width / (xText.length - 1);
58 | for (int i = 0; i < xText.length; i++) {
59 | if (i == 0) {
60 | xposition[0][i] = leftText_paddingLeft;//+ leftText_paddingright + left;//第一个文本
61 | } else if (i == (xText.length - 1)) {
62 | xposition[0][i] = ViewUtils.getScreenWidth() - right - rightText_paddingright;//最后一个文本
63 | } else {
64 | xposition[0][i] = xposition[0][0] + i * spilitwidth - getTextWidthAndLength(mPaint, xText[i], xSize)[0] / 2;//中间的文本
65 | }
66 | xposition[1][i] = height - xText_paddingbottom - mPaint.descent();
67 | }
68 | return xposition;
69 | }
70 |
71 | /**
72 | * y 轴文本测量和位置。
73 | */
74 | public static float[][] measureYText(Paint mPaint, String[] yText, float height, boolean isLeft) {
75 | float[][] yposition = new float[2][yText.length];
76 | mPaint.setTextSize(ySize);
77 | yposition[1][0] = yText_paddingtop - mPaint.ascent();
78 | float heightBelow = xText_paddingtop + xText_paddingbottom + getTextWidthAndLength(mPaint, "0", xSize)[1];
79 | mPaint.setTextSize(ySize);
80 | yposition[1][1] = (height - heightBelow) / 2 - mPaint.descent();
81 | yposition[1][2] = height - heightBelow - yText_paddingbottom - mPaint.descent();
82 | if (isLeft) {
83 | yposition[0][0] = leftText_paddingLeft;
84 | yposition[0][1] = leftText_paddingLeft;
85 | yposition[0][2] = leftText_paddingLeft;
86 | } else {
87 | yposition[0][0] = ViewUtils.getScreenWidth() - rightText_paddingright - getTextWidthAndLength(mPaint, yText[0], ySize)[0];
88 | yposition[0][1] = yposition[0][0];
89 | yposition[0][2] = yposition[0][0];
90 | }
91 | return yposition;
92 | }
93 |
94 | /**
95 | * [0,1][0]框的宽高,。。。0是x,1是y。
96 | * 标示的坐标
97 | * 数值的坐标
98 | */
99 | public static float[][] measureBoxTextAndBox(Paint mPaint, String[] leftTagSample, String[] rightValueSample, float boxWidth, float xoffset, float yoffset) {
100 | float[][] position = new float[2][leftTagSample.length + rightValueSample.length + 1];
101 | int cache = leftTagSample.length;//行数
102 | float leftpadding = ViewUtils.dp2px(3);//左侧图文间隙
103 | float rightpadding = ViewUtils.dp2px(4);//右侧图文间隙
104 | float divideheight = ViewUtils.dp2px(5);//行间距
105 | float textHeight = getTextWidthAndLength(mPaint, "0", boxtextSize)[1];//只需要知道高度就行。
106 | for (int i = 0; i < cache; i++) {
107 | //左侧的坐标
108 | position[0][i + 1] = leftpadding + xoffset;//x
109 | position[1][i + 1] = (i + 1) * (divideheight + textHeight) + yoffset;//y
110 | }
111 | for (int j = 0; j < rightValueSample.length; j++) {
112 | //右侧的坐标
113 | float[] cacheposition = getTextWidthAndLength(mPaint, rightValueSample[j], boxtextSize);//右侧文本的长宽
114 | position[0][j + cache + 1] = boxWidth - rightpadding - cacheposition[0] + xoffset;//x
115 | position[1][j + cache + 1] = (j + 1) * (divideheight + textHeight) + yoffset;//y
116 | }
117 | position[0][0] = boxWidth + xoffset;
118 | //长度做索引,-1
119 | position[1][0] = position[1][cache + rightValueSample.length] + divideheight + yoffset;
120 | return position;
121 | }
122 |
123 | /**
124 | * 背景虚线的x坐标
125 | *
126 | * @param mPaint
127 | * @param height
128 | * @return
129 | */
130 | public static float[] measureBgLine(Paint mPaint, float height) {
131 | float[] lines = new float[5];
132 | float heightBelow = xText_paddingtop + xText_paddingbottom + getTextWidthAndLength(mPaint, "0", xSize)[1];
133 | float cache = (height - heightBelow) / (lines.length - 1);
134 | lines[0] = 1;
135 | lines[1] = cache;
136 | lines[2] = cache * 2;
137 | lines[3] = cache * 3;
138 | lines[4] = cache * 4;
139 | return lines;
140 | }
141 |
142 | /**
143 | * float[0] 宽度 float[1] 高度
144 | *
145 | * @param mPaint
146 | * @param text
147 | * @param textSize
148 | * @return
149 | */
150 | public static float[] getTextWidthAndLength(Paint mPaint, String text, float textSize) {
151 | float[] values = new float[2];
152 | mPaint.setTextSize(textSize);
153 | Paint.FontMetrics fm = mPaint.getFontMetrics();
154 | values[0] = mPaint.measureText(text);
155 | values[1] = fm.descent - fm.ascent;
156 | return values;
157 | }
158 |
159 | /**
160 | * 获得图标框的高度。减去底部的高度
161 | *
162 | * @param mPaint
163 | * @param height
164 | * @return
165 | */
166 | public static float getChartHeight(Paint mPaint, float height) {
167 | return height - getTextWidthAndLength(mPaint, "0", xSize)[1] - xText_paddingtop - xText_paddingbottom;
168 | }
169 |
170 | /**
171 | * 获得图标框的宽度。没有右边,则不需要rightSample。
172 | *
173 | * @param mPaint
174 | * @param width
175 | * @param leftSample
176 | * @param rightSample
177 | * @param isHasRight
178 | * @return
179 | */
180 | public static float getChartWidth(Paint mPaint, float width, String leftSample, String rightSample, boolean isHasRight) {
181 | if (isHasRight) {
182 | return width - leftText_paddingLeft - leftText_paddingright - getTextWidthAndLength(mPaint, leftSample, ySize)[0] - rightText_paddingLeft - rightText_paddingright - getTextWidthAndLength(mPaint, rightSample, ySize)[0];
183 | } else {
184 | return width - leftText_paddingLeft - leftText_paddingright - getTextWidthAndLength(mPaint, leftSample, ySize)[0];
185 | }
186 | }
187 |
188 | /**
189 | * 使用从左往右密集排列战略
190 | *
191 | * @param cachehour
192 | * @param cacheminites
193 | * @return
194 | */
195 | private float initXorder(RouteLineView.TYPE type, float cachehour, float cacheminites) {
196 | float time = cachehour * 60 + cacheminites;
197 | if (type == RouteLineView.TYPE.SZHENG) {
198 | if (time >= 780 && time <= 900) {//上证13:00开始
199 | return time - 780 + 120;
200 | } else if (cachehour <= 690 && time >= 570) {
201 | return time - 570;
202 | }
203 | } else if (type == RouteLineView.TYPE.GOLD) {
204 | if (time >= 1250 && time < 1440) {
205 | return time - 1250;
206 | } else if (time >= 540 && time <= 690) {
207 | return time - 540 + 190;
208 | } else if (time >= 810 && time >= 930) {
209 | return time - 810 + 340;
210 | } else if (time >= 0 && time >= 150) {
211 | return time + 460;
212 | }
213 | } else if (type == RouteLineView.TYPE.EUROPE) {
214 | if (time >= 300 && time < 1440) {
215 | return time - 300;
216 | } else if (time <= 270) {
217 | return time + 1140;
218 | }
219 | }
220 | return 0.0f;
221 | }
222 |
223 | //备用,不可删除
224 | //获得最近的 日期序列不为0,并且和当前日期序列少于7的坐标值
225 | private float getNearNoZero(int type, int i, float[][] mData, float[][] mnData) {
226 | int cache = i;
227 | if (type == 1) {
228 | while (true) {
229 | if (mData[4][cache - 1] != 0 && (mData[4][i] - mData[4][cache]) < 7) {
230 | return mnData[1][cache - 1];//x
231 | } else {
232 | cache--;
233 | if (cache == 0) {
234 | return mnData[1][cache];
235 | }
236 | }
237 | }
238 | } else {
239 | while (true) {
240 | if (mData[4][cache - 1] != 0 && (mData[4][i] - mData[4][cache]) < 7) {
241 | return mnData[0][cache - 1];//y
242 | } else {
243 | cache--;
244 | if (cache == 0) {
245 | return mnData[1][cache];
246 | }
247 | }
248 | }
249 | }
250 | }
251 |
252 | //画左边的 offset 0 or width
253 | public static void drawBlock(Canvas canvas, Paint mPaint, String value, float position, float height, float xoffset) {
254 | mPaint.setColor(Color.parseColor("#5CAFF4"));
255 | float textborderpadding = 3;
256 | float[] text = getTextWidthAndLength(mPaint, value, ySize);
257 | float blockheight = textborderpadding * 2 + text[1];
258 | float low = 0, cache = blockheight / 2, blockwidth;
259 | blockwidth = leftText_paddingLeft + leftText_paddingright + text[0];
260 | if (xoffset != 0) {
261 | xoffset = xoffset - blockwidth;
262 | }
263 | if (position < blockheight) {
264 | //上部
265 | canvas.drawRect(xoffset, 0, blockwidth + xoffset, blockheight, mPaint);
266 | mPaint.setColor(Color.WHITE);
267 | canvas.drawText(value, xoffset + leftText_paddingLeft, blockheight - textborderpadding - mPaint.descent(), mPaint);
268 | } else if (position > (low = (getChartHeight(mPaint, height) - cache))) {
269 | //底部
270 | canvas.drawRect(xoffset, low - cache, blockwidth + xoffset, low + cache, mPaint);
271 | mPaint.setColor(Color.WHITE);
272 | canvas.drawText(value, xoffset + leftText_paddingLeft, low + cache - textborderpadding - mPaint.descent(), mPaint);
273 | } else {
274 | //中部
275 | canvas.drawRect(xoffset, position - cache, blockwidth + xoffset, position + cache, mPaint);
276 | mPaint.setColor(Color.WHITE);
277 | canvas.drawText(value, xoffset + leftText_paddingLeft, position + cache - textborderpadding - mPaint.descent(), mPaint);
278 | }
279 | }
280 |
281 |
282 | //画下边
283 | public static void drawBellowTime(Canvas canvas, Paint mPaint, String datetime, float position, float width, float height) {
284 | mPaint.setColor(Color.parseColor("#5CAFF4"));
285 | float textborderpadding = 3;
286 | float[] time = getTextWidthAndLength(mPaint, datetime, xSize);
287 | float cache = leftText_paddingLeft + time[0] / 2;
288 | float top = getChartHeight(mPaint, height);
289 | float below = top + textborderpadding * 2 + time[1];
290 | if (position < cache) {//左侧
291 | canvas.drawRect(0, top, cache * 2, below, mPaint);
292 | mPaint.setColor(Color.WHITE);
293 | canvas.drawText(datetime, leftText_paddingLeft, top + textborderpadding - mPaint.ascent(), mPaint);
294 | } else if ((position + cache) > width) {//右侧
295 | cache *= 2;
296 | canvas.drawRect(width - cache, top, width, below, mPaint);
297 | mPaint.setColor(Color.WHITE);
298 | canvas.drawText(datetime, width - cache + leftText_paddingLeft, top + textborderpadding - mPaint.ascent(), mPaint);
299 | } else {//其他
300 | canvas.drawRect(position - cache, top, position + cache, below, mPaint);
301 | mPaint.setColor(Color.WHITE);
302 | canvas.drawText(datetime, position - cache + leftText_paddingLeft, top + textborderpadding - mPaint.ascent(), mPaint);
303 | }
304 | }
305 |
306 | //分钟的加0操作
307 | public static String formatTime(float x) {
308 | if (x < 10) {
309 | return "0" + (int) x;
310 | } else {
311 | return "" + (int) x;
312 | }
313 | }
314 | }
315 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hunty/widget/charts/FenshiParamResult.java:
--------------------------------------------------------------------------------
1 | package com.hunty.widget.charts;
2 |
3 | /**
4 | * fenshi valid data throw ui thread
5 | *
6 | * Created by zhangjianqiu on 16-8-18.
7 | */
8 | public class FenshiParamResult {
9 |
10 | private String high;//nearly high
11 | private String low;////nearly low
12 | private String close;//nearly close
13 | private String price;//nearly price
14 | private String date;//nearly date
15 | private String time;//nearly time
16 | private float[][] routeData;
17 |
18 | public float[][] getRouteData() {
19 | return routeData;
20 | }
21 |
22 | public void setRouteData(float[][] routeData) {
23 | this.routeData = routeData;
24 | }
25 |
26 | public String getHigh() {
27 | return high;
28 | }
29 |
30 | public void setHigh(String high) {
31 | this.high = high;
32 | }
33 |
34 | public String getLow() {
35 | return low;
36 | }
37 |
38 | public void setLow(String low) {
39 | this.low = low;
40 | }
41 |
42 | public String getClose() {
43 | return close;
44 | }
45 |
46 | public void setClose(String close) {
47 | this.close = close;
48 | }
49 |
50 | public String getPrice() {
51 | return price;
52 | }
53 |
54 | public void setPrice(String price) {
55 | this.price = price;
56 | }
57 |
58 | public String getDate() {
59 | return date;
60 | }
61 |
62 | public void setDate(String date) {
63 | this.date = date;
64 | }
65 |
66 | public String getTime() {
67 | return time;
68 | }
69 |
70 | public void setTime(String time) {
71 | this.time = time;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hunty/widget/charts/LogUtil.java:
--------------------------------------------------------------------------------
1 | package com.hunty.widget.charts;
2 |
3 | import android.util.Log;
4 |
5 | import com.hunty.widget.BuildConfig;
6 |
7 | /**
8 | * 日志工具
9 | */
10 | public class LogUtil {
11 |
12 | private static final long EXPIRED_MILS = 30 * 24 * 60 * 60 * 1000L; // 30天
13 | public static final String PRE_LOG = "-->";
14 | public static final String PRE_EXCEPTION_LOG = "--E->";
15 | public static boolean isDebug = BuildConfig.DEBUG;
16 |
17 | /**
18 | * 写日志到控制台
19 | */
20 | public static void ii(Object tag, String msg) {
21 | if (isDebug) {
22 | if (tag instanceof String) {
23 | android.util.Log.i((String) tag, PRE_LOG + msg);
24 | } else {
25 | android.util.Log.i(tag.getClass().getSimpleName(), PRE_LOG + msg);
26 | }
27 | }
28 | }
29 |
30 | public static void ee(Object tag, String msg) {
31 | if (isDebug) {
32 | if (tag instanceof String) {
33 | android.util.Log.e((String) tag, PRE_EXCEPTION_LOG + msg);
34 | } else {
35 | android.util.Log.e(tag.getClass().getSimpleName(), PRE_EXCEPTION_LOG + msg);
36 | }
37 | }
38 | }
39 |
40 | public static void ee(Object tag, String msg, Throwable tr) {
41 | if (isDebug) {
42 | if (tag instanceof String) {
43 | android.util.Log.e((String) tag, PRE_EXCEPTION_LOG + msg, tr);
44 | } else {
45 | android.util.Log.e(tag.getClass().getSimpleName(), PRE_EXCEPTION_LOG + msg, tr);
46 | }
47 | }
48 |
49 | }
50 |
51 | /**
52 | * 写日志到文件和控制台
53 | */
54 | public static void i(Object tag, String msg) {
55 | if (isDebug) {
56 | if (tag instanceof String) {
57 | Log.i((String) tag, PRE_LOG + msg);
58 | } else {
59 | Log.i(tag.getClass().getSimpleName(), PRE_LOG + msg);
60 | }
61 | }
62 | }
63 |
64 | public static void i(Object tag, String msg, Throwable tr) {
65 | if (isDebug) {
66 | if (tag instanceof String) {
67 | Log.i((String) tag, PRE_LOG + msg, tr);
68 | } else {
69 | Log.i(tag.getClass().getSimpleName(), PRE_LOG + msg, tr);
70 | }
71 | }
72 | }
73 |
74 | public static void e(Object tag, String msg) {
75 | if (isDebug) {
76 | if (tag instanceof String) {
77 | Log.e((String) tag, PRE_EXCEPTION_LOG + msg);
78 | } else {
79 | Log.e(tag.getClass().getSimpleName(), PRE_EXCEPTION_LOG + msg);
80 | }
81 | }
82 | }
83 |
84 | public static void e(Object tag, String msg, Throwable tr) {
85 | if (isDebug) {
86 | if (tag instanceof String) {
87 | Log.e((String) tag, PRE_LOG + msg, tr);
88 | } else {
89 | Log.e(tag.getClass().getSimpleName(), PRE_LOG + msg, tr);
90 | }
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hunty/widget/charts/RouteLineView.java:
--------------------------------------------------------------------------------
1 | package com.hunty.widget.charts;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapFactory;
6 | import android.graphics.Canvas;
7 | import android.graphics.Color;
8 | import android.graphics.DashPathEffect;
9 | import android.graphics.LinearGradient;
10 | import android.graphics.Paint;
11 | import android.graphics.Path;
12 | import android.graphics.RectF;
13 | import android.graphics.Shader;
14 | import android.text.TextUtils;
15 | import android.util.AttributeSet;
16 | import android.view.MotionEvent;
17 | import android.view.View;
18 |
19 | import com.hunty.widget.R;
20 | import com.hunty.widget.util.ViewUtils;
21 |
22 | import java.text.DecimalFormat;
23 | import java.text.NumberFormat;
24 |
25 |
26 | /**
27 | * zhangjianqiu 2016-5-18
28 | *
29 | * perfect in 5-19
30 | * perfect fit in 5-26
31 | * ok in 5-27
32 | *
33 | * setType(TYPE);没有则按照上证的X.
34 | * //setXData(),x轴文本 。没有则按照默认的类型
35 | * setMaxAndMin();先
36 | * setData(float[][] data);绘制折线图。。 一维是任意随机数 二维是从0开始的序号
37 | * 加入图片缓存,减少手指触摸的计算量
38 | * Activity_onPause的时候,执行 recycle();回收静态Bitmap
39 | *
40 | * @author zhangJianQiu
41 | */
42 | public class RouteLineView extends View {
43 |
44 | public enum TYPE {
45 | GOLD, SZHENG, EUROPE
46 | }
47 |
48 | /**
49 | * 每个数据的x轴长度,表示每一分钟的一个点
50 | **/
51 | private float eachUnitPixcels;
52 | private boolean iswilloverwrite = false;
53 |
54 | /**
55 | * 绘制的类型
56 | */
57 | private TYPE type = TYPE.SZHENG;
58 |
59 | // 纵横坐标的x轴y轴数据
60 | /**
61 | * 所有点的 五维数组 ,0维是值 value,1维-小时数,2维-分钟数,3维-比例小数,4维月份,5维日。
62 | */
63 | private float[][] mData;
64 | /**
65 | * 所有的点 一维是y坐标点 ,二维是x的坐标(方便触摸计算,用存储来优化计算)
66 | **/
67 | private float[][] mnData;
68 |
69 | private float width;
70 | private float height = 230;
71 |
72 | private Paint mPaint;
73 | private DashPathEffect bgDash = new DashPathEffect(new float[]{10, 10, 10, 10}, 0);
74 | private DashPathEffect crossDash = new DashPathEffect(new float[]{5, 5, 5, 5}, 0);
75 | private LinearGradient shader;
76 | private NumberFormat nt = NumberFormat.getPercentInstance();//百分比格式化
77 | private DecimalFormat df = new DecimalFormat("####0.00");//小数格式化
78 | /**
79 | * 图片缓存机制,缓存的画布
80 | **/
81 | private Bitmap mCacheImg, mCorssPoint;
82 | private Canvas mCacheCanvas;
83 | /**
84 | * 是否需要重绘 区别手势,默认true
85 | * 设置历史或者大小值改变时置为true
86 | **/
87 | private boolean isNewDrw = true;
88 | // 文本框
89 | private Bitmap textbox;
90 | private RectF dst;
91 | private float boxwidth = 80;// dp
92 | //上部下部图标空隙
93 | private float HTIGHT_TOP = 10f;// y值dp
94 | /**
95 | * 左边空隙
96 | **/
97 | private float xoffset = 10, yoffset = 10;//左边边框的边距。
98 | /**
99 | * 图表的高度(像素)
100 | **/
101 | private float invalidatey;
102 | // 最大最小值
103 | private float max = 1f, min = 100000f;
104 | private float close;
105 | // 备用缓存
106 | private float lastcachex;// 已经画到的x索引
107 | private int lastcachey;// 数据已经有的,长度!!!长度。已经画的电话。
108 | /**
109 | * 纵坐标上,一个百分比文本之间的距离.一共就3个。
110 | **/
111 | private float spilitheight = 0.0f;
112 | //x 上的文本
113 | private String[] xText;
114 | //y 上的文本
115 | private String[] yText_left, yText_right;
116 | //文本框中的文本
117 | private String[] leftIndicatorInbox = new String[]{"时间:", "指数:", "涨跌幅:"};
118 | private String[] rightIndicatorInbox = new String[]{"00:00", "0000.00", "-0.00%"};
119 |
120 | //x轴文本的坐标轴位置点,
121 | private float xposition[][];
122 | //y轴 文本的坐标轴位置点,
123 | private float yposition_left[][], yposition_right[][];
124 | //背景线条
125 | private float[] bglines;
126 | // 触摸的绘制标记
127 | private boolean isTouch = false;
128 | //触摸的x轴坐标,有x 则就有时间点,索引值
129 | private int touchChartx = 0;
130 |
131 | public void setType(TYPE tpe) {
132 | this.type = tpe;
133 | initDataArrayLength();
134 | positionXText();
135 | }
136 |
137 | public void recycle() {
138 | textbox.recycle();
139 | mCacheImg.recycle();
140 | mCorssPoint.recycle();
141 | mCacheImg = null;
142 | }
143 |
144 | public RouteLineView(Context context, AttributeSet attrs, int defStyleAttr) {
145 | super(context, attrs, defStyleAttr);
146 | init(context);
147 | }
148 |
149 | public RouteLineView(Context context, AttributeSet attrs) {
150 | super(context, attrs);
151 | init(context);
152 | }
153 |
154 | public RouteLineView(Context context) {
155 | super(context);
156 | init(context);
157 | }
158 |
159 | private void init(Context context) {
160 | boxwidth = ViewUtils.dp2px(boxwidth);
161 | height = ViewUtils.dp2px(height);
162 |
163 | mPaint = new Paint();
164 | mPaint.setStyle(Paint.Style.FILL);
165 | mPaint.setAntiAlias(true);
166 | mPaint.setStrokeCap(Paint.Cap.ROUND);
167 | mPaint.setStrokeJoin(Paint.Join.ROUND);
168 | nt.setMinimumFractionDigits(2);
169 | nt.setMaximumFractionDigits(2);
170 |
171 | invalidatey = DrawChartUtils.getChartHeight(mPaint, height);
172 | shader = new LinearGradient(0, 0, 0, invalidatey, new int[]{Color.parseColor("#0f5CAFF4"), Color.BLACK}, null, Shader.TileMode.REPEAT);
173 | // 没有数据时的初始显示
174 | yText_right = new String[]{"1.26%", "0.00%", "0.63%",};
175 | yText_left = new String[]{"2890.92", "2887.21", "2877.50"};
176 | // 文本框
177 | textbox = BitmapFactory.decodeResource(context.getResources(), R.drawable.board_bg);
178 | mCorssPoint = BitmapFactory.decodeResource(context.getResources(), R.drawable.corsspoint);
179 |
180 | // 用作画文本框
181 | dst = new RectF();
182 | }
183 |
184 | /**
185 | * 设置历史文本 然后遍历。setData之前要set一次最大最小值
186 | * 一维 值, 二维 小时 095030,三维 分钟
187 | *
188 | * @param data 接口请求的坐标需要的数据
189 | */
190 | public synchronized void setData(float[][] data) {
191 | initData(data);
192 | isNewDrw = true;
193 | postInvalidate();
194 | }
195 |
196 | /**
197 | * 添加.添加之前,set一次最大值最小值。在 set 最大值最小值的时候进行其他数据的计算
198 | *
199 | * @param value 值
200 | * @param hours 时间
201 | */
202 | public void addData(String value, String hours, String minutes, String month, String day) {
203 | float fv = Float.parseFloat(value);
204 | float ft = Float.parseFloat(hours);
205 | float fs = Float.parseFloat(minutes);
206 | float fm = Float.parseFloat(month);
207 | float fd = Float.parseFloat(day);
208 | addData(fv, ft, fs, fm, fd);
209 | }
210 |
211 | /**
212 | * 添加.添加之前,set一次最大值最小值。在 set 最大值最小值的时候进行其他数据的计算
213 | *
214 | * @param value 值
215 | * @param hours 时间
216 | */
217 | public void addData(float value, float hours, float minutes, float month, float day) {
218 | if (type == TYPE.SZHENG && beyoudValueReplace(value, hours, minutes)) {
219 | //上证的替换,替换文本并且重绘。时间点越界,不论250,也废弃
220 | postInvalidate();
221 | return;
222 | }
223 | // 保存时间和值
224 | if (lastcachey == mData[0].length) {
225 | LogUtil.ee("error", ">>>>>DrawError>>>>>>超过250个值。无法储存和绘制");
226 | return;
227 | }
228 | mData[0][lastcachey] = value;
229 | mData[1][lastcachey] = hours;
230 | mData[2][lastcachey] = minutes;
231 | mData[4][lastcachey] = month;
232 | mData[5][lastcachey] = day;
233 | initaddData(false);
234 | //上证的开盘文本
235 | initStartTimeIfSZ();
236 | // 刷新界面
237 | isNewDrw = true;
238 | if (getVisibility() == View.VISIBLE) {
239 | postInvalidate();
240 | }
241 | }
242 |
243 | /**
244 | * 越界数据的替换。。只在上证里。。。并且判断是否越界
245 | */
246 | private boolean beyoudValueReplace(float value, float hours, float minutes) {
247 | if (lastcachey == 250) {
248 | mData[0][lastcachey - 1] = value;
249 | mData[1][lastcachey - 1] = hours;
250 | mData[2][lastcachey - 1] = minutes;
251 | return true;
252 | }
253 | return false;
254 | }
255 |
256 | /**
257 | * 新添加的数据,刷新到视图中。包含重新计算之前的值,和计算新加入的值。
258 | *
259 | * @param isneedCalOthers 是否需要计算其他值
260 | */
261 | private void initaddData(boolean isneedCalOthers) {
262 | if (mData == null && mData[0][0] == 0) return;//无历史数据,直接不添加
263 | //收盘价,距离最高和最低的差距
264 | float value = (Math.abs(close - max) > Math.abs(close - min)) ? Math.abs(close - max) : Math.abs(close - min);
265 | float cacheValue = (invalidatey - HTIGHT_TOP) / 2;
266 |
267 | LogUtil.ee("ADD Data To Chart:", "max:" + max + " min:" + min + " close:" + close);
268 | // y轴数据的初始化.减去最小数。平均分剩余空间
269 | if (isneedCalOthers) {
270 | for (int i = 0; i < lastcachey; i++) {
271 | mData[3][i] = (mData[0][i] - close) / close;//算出比例,保留正负号
272 | mnData[0][i] = ((close - mData[0][i]) * cacheValue) / value + cacheValue + HTIGHT_TOP;//算出的坐标
273 | }
274 | } else {
275 | mData[3][lastcachey] = (mData[0][lastcachey] - close) / close;//比例,计算正确
276 | mnData[0][lastcachey] = ((close - mData[0][lastcachey]) * cacheValue) / value + cacheValue + HTIGHT_TOP;//坐标
277 | lastcachey++;
278 | }
279 | }
280 |
281 | /**
282 | * 设置最大值,最小值,改变整个视图的显示比例和y轴文本。默认情况,必须先有设置一对
283 | * 获取历史数据时,先进行大小比较.
284 | * 每次必须set一次。
285 | * 记住
286 | */
287 | public void setMaxAndMin(String mx, String mn, String closePrice) {
288 | if (TextUtils.isEmpty(mx) || TextUtils.isEmpty(mn)) {
289 | return;
290 | }
291 | float mmax = Float.parseFloat(mx);
292 | float mmin = Float.parseFloat(mn);
293 | float close = Float.parseFloat(closePrice);
294 | setMaxAndMin(mmax, mmin, close);
295 | }
296 |
297 | //setData时的。addData时的。
298 | private void setMaxAndMin(float mmax, float mmin, float closePrice) {
299 | if (mmax < 1 || mmin < 0 || mmax < mmin) {
300 | LogUtil.ee("RouteLine error:", "max and min value is wrong .check fist");
301 | return;
302 | }
303 | float cache2 = (Math.abs(mmax - close) > Math.abs(mmin - close)) ? Math.abs(mmax - close) : Math.abs(mmin - close);//新的差距
304 | float cache1 = (Math.abs(max - close) > Math.abs(min - close)) ? Math.abs(max - close) : Math.abs(min - close);//老的差距
305 | boolean cache3 = (closePrice != close);
306 | close = closePrice;
307 | max = (max < mmax) ? mmax : max;
308 | min = (min > mmin) ? mmin : min;
309 | if (cache3 || cache1 != cache2) {
310 | // 计算文本和文本坐标
311 | measureYText();//用新的,老的会引用0和10000。
312 | initaddData(true);
313 | isNewDrw = true;
314 | postInvalidate();
315 | }
316 | }
317 |
318 | /**
319 | * y 轴文本测量和位置
320 | */
321 | private void measureYText() {
322 | /** 文本数据计算,百分比____每个点代表的百分值 **/
323 | float cacheValue = spilitheight / 2;
324 | //每个点代表的百分数,纵坐标上的
325 | float singlePercent;
326 | if (Math.abs(close - max) > Math.abs(min - close)) {
327 | singlePercent = (Math.abs(close - max) / close) / cacheValue;
328 | } else {
329 | singlePercent = (Math.abs(close - min) / close) / cacheValue;
330 | }
331 | //右边的百分比
332 | yText_right[0] = nt.format(cacheValue * singlePercent);
333 | yText_right[1] = "0.00%";
334 | yText_right[2] = yText_right[0];
335 | //左边的value
336 | //保留4位小数
337 | cacheValue = cacheValue * singlePercent * close;//增长值,全半边百分比占close才是需要的值
338 | if (type == TYPE.EUROPE) {
339 | df.applyPattern("#0.0000");
340 | }
341 | yText_left[0] = df.format(close + cacheValue);
342 | yText_left[1] = df.format(close);
343 | yText_left[2] = df.format(close - cacheValue);
344 | }
345 |
346 |
347 | /**
348 | * 历史数据的计算
349 | */
350 | private synchronized void initData(float[][] freshData) {
351 | if (max == 0 || min == 0)
352 | LogUtil.e("RouteLine", "call setMaxAndMin method before setData method.");
353 |
354 | // y轴数据的初始化.减去最小数。平均分剩余空间
355 | if (mnData == null) LogUtil.e("RouteLine", "mnData null-----------------");
356 |
357 | lastcachey = mData[0].length;//总个数
358 | float value = (Math.abs(close - max) > Math.abs(close - min)) ? Math.abs(close - max) : Math.abs(close - min);
359 | float cacheValue = spilitheight / 2;
360 | for (int i = 0; i < freshData[0].length; i++) {
361 | if (i >= lastcachey) {//不数组越界就可。
362 | break;
363 | }
364 | mnData[0][i] = ((close - freshData[0][i]) * cacheValue) / value + cacheValue + HTIGHT_TOP;//y坐标
365 | mData[0][i] = freshData[0][i];//value
366 | mData[1][i] = freshData[1][i];//hours
367 | mData[2][i] = freshData[2][i];//minutes
368 | mData[3][i] = (mData[0][i] - close) / close;//比例
369 | mData[4][i] = freshData[3][i];//month
370 | mData[5][i] = freshData[4][i];//day
371 | }
372 | lastcachey = (freshData[0].length >= mData[0].length ? mData[0].length : freshData[0].length);//初始化已经画的点数
373 | freshData = null;
374 | //上证时间的话,开盘时间按照
375 | initStartTimeIfSZ();
376 | }
377 |
378 | /**
379 | * 上证时间的话,开盘时间按照。不需要重新测量。
380 | */
381 | private void initStartTimeIfSZ() {
382 | if (type == TYPE.SZHENG && lastcachey > 0) {
383 | LogUtil.e("RouteLine:", "重新设置,上证,左端时间");
384 | xText = new String[]{DrawChartUtils.formatTime(mData[1][0]) + ":" + DrawChartUtils.formatTime(mData[2][0]), "11:30/13:00", "15:00"};
385 | } else if (type == TYPE.GOLD && lastcachey > 0) {
386 | LogUtil.e("RouteLine:", "重新设置,黄金,左端时间");
387 | xText = new String[]{DrawChartUtils.formatTime(mData[1][0]) + ":" + DrawChartUtils.formatTime(mData[2][0]), "15:30"};
388 | }
389 | }
390 |
391 | @Override
392 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
393 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
394 | width = getMeasuredWidth();
395 | height = getMeasuredHeight();
396 | isNewDrw = true;
397 | normal();
398 | }
399 |
400 |
401 | @Override
402 | public void onDraw(Canvas canvas) {
403 | mPaint.setShader(null);
404 | if (!isNewDrw) {
405 | // 不是第一次,直接画缓存的
406 | canvas.drawBitmap(mCacheImg, 0, 0, null);
407 | } else {
408 | // 第一次,或者新数据来的时候.画到缓存上
409 | initBitmap();
410 | // 注释掉,方便 eclipse 调试。
411 | canvas = mCacheCanvas;
412 | LogUtil.ee("attation:", "第一次绘制drawBitmap到缓存");
413 | }
414 |
415 | // 绘制触摸的竖线
416 | if (isTouch & !isNewDrw) {
417 | //没有数据,则不绘制触摸和文本
418 | if (mnData[0][0] == 0) {
419 | return;
420 | }
421 | calcEnsureX();
422 | //绘制交叉点&Line
423 | drawCorss(canvas);
424 | // 绘制圆点
425 | canvas.drawBitmap(mCorssPoint, mnData[1][touchChartx] - 13f, mnData[0][touchChartx] - 13f, mPaint);
426 | // 绘制触摸出来的文本框&ScrollBlock
427 | drawTextBox(canvas);
428 | }
429 |
430 | //图片已经包括的内容
431 | if (!isNewDrw) {
432 | return;
433 | }
434 |
435 | LogUtil.ee("attation:", "绘制各种线条。");
436 | mPaint.setColor(Color.parseColor("#E1C6B1"));
437 | // 绘制背景实线和虚线
438 | mPaint.setStrokeWidth(1.0f);
439 | mPaint.setPathEffect(bgDash);
440 | for (int i = 1; i < 4; i++) {
441 | canvas.drawLine(0, bglines[i], width, bglines[i], mPaint);
442 | }
443 | mPaint.setPathEffect(null);
444 | canvas.drawLine(0, 1, width, 1, mPaint);
445 | canvas.drawLine(0, bglines[4], width, bglines[4], mPaint);
446 |
447 | // x轴文本
448 | mPaint.setTextSize(DrawChartUtils.xSize);
449 | mPaint.setColor(Color.GRAY);
450 | for (int j = 0; j < xText.length; j++) {
451 | canvas.drawText(xText[j], xposition[0][j], xposition[1][j], mPaint);
452 | }
453 |
454 | if (mData != null && mData[0][0] != 0) {
455 | // 绘制折线部分
456 | mnData[1][0] = 1;
457 | Path mPath = new Path();
458 | mPath.moveTo(0, invalidatey);
459 | mPath.lineTo(mnData[1][0], mnData[0][0]);
460 | mPaint.setColor(Color.parseColor("#5CAFF4"));
461 | mPaint.setStrokeWidth(2.0f);
462 | for (int i = 1; i < lastcachey; i++) {
463 | mnData[1][i] = eachUnitPixcels * i;//序号 * 个数 -> x轴坐标
464 | // 防止点重复
465 | if (iswilloverwrite && i != 1 && mnData[1][i] == mnData[1][i - 1]) {
466 | continue;
467 | }
468 | lastcachex = mnData[1][i];
469 | canvas.drawLine(mnData[1][i - 1], mnData[0][i - 1], mnData[1][i], mnData[0][i], mPaint);
470 | mPath.lineTo(mnData[1][i], mnData[0][i]);
471 | }
472 | mPath.lineTo(mnData[1][lastcachey - 1], invalidatey);
473 | mPaint.setShader(shader);
474 | canvas.drawPath(mPath, mPaint);
475 | }
476 |
477 | // y轴文本,y2文本
478 | mPaint.setShader(null);
479 | mPaint.setTextSize(DrawChartUtils.ySize);
480 | mPaint.setColor(Color.RED);
481 | canvas.drawText(yText_left[0], yposition_left[0][0], yposition_left[1][0], mPaint);
482 | canvas.drawText(yText_right[0], yposition_right[0][0], yposition_right[1][0], mPaint);
483 | mPaint.setColor(Color.WHITE);
484 | canvas.drawText(yText_left[1], yposition_left[0][1], yposition_left[1][1], mPaint);
485 | canvas.drawText(yText_right[1], yposition_right[0][1], yposition_right[1][1], mPaint);
486 | mPaint.setColor(Color.parseColor("#50C577"));
487 | canvas.drawText(yText_left[2], yposition_left[0][2], yposition_left[1][2], mPaint);
488 | canvas.drawText(yText_right[2], yposition_right[0][2], yposition_right[1][2], mPaint);
489 |
490 | // 新的一次画图,是画在Bitmap上的。所以刷新。
491 | if (isNewDrw) {
492 | isNewDrw = false;
493 | postInvalidate();
494 | }
495 | }
496 |
497 | private void drawCorss(Canvas canvas) {
498 | //竖直线
499 | mPaint.setColor(Color.parseColor("#5CAFF4"));
500 | mPaint.setStrokeWidth(2.0f);
501 | mPaint.setPathEffect(crossDash);
502 | canvas.drawLine(mnData[1][touchChartx], 0, mnData[1][touchChartx], invalidatey, mPaint);
503 | //水平线
504 | canvas.drawLine(0, mnData[0][touchChartx], width, mnData[0][touchChartx], mPaint);
505 | }
506 |
507 |
508 | private void drawTextBox(Canvas canvas) {
509 | float[][] floats;
510 | // 测量和绘制文本框// 计算文本的位置
511 | if (x > (boxwidth + xoffset * 2)) {// 文本框在左边,常态。左上角
512 | floats = DrawChartUtils.measureBoxTextAndBox(mPaint, leftIndicatorInbox, rightIndicatorInbox, boxwidth, xoffset, yoffset);
513 | dst.set(xoffset, yoffset, floats[0][0], floats[1][0]);
514 | } else {// 文本框在右边,过于靠左边时
515 | float temp = width - boxwidth - xoffset * 2;
516 | floats = DrawChartUtils.measureBoxTextAndBox(mPaint, leftIndicatorInbox, rightIndicatorInbox, boxwidth, temp, yoffset);
517 | dst.set(temp, yoffset, floats[0][0], floats[1][0]);
518 | }
519 |
520 | int cache = rightIndicatorInbox.length;
521 | String date = DrawChartUtils.formatTime(mData[1][touchChartx]) + ":" + DrawChartUtils.formatTime(mData[2][touchChartx]);
522 | String value = df.format(mData[0][touchChartx]);
523 | String percent = nt.format(mData[3][touchChartx]);
524 |
525 | //绘制滑块
526 | DrawChartUtils.drawBlock(canvas, mPaint, value, mnData[0][touchChartx], height, 0);
527 | DrawChartUtils.drawBlock(canvas, mPaint, percent, mnData[0][touchChartx], height, width);
528 | DrawChartUtils.drawBellowTime(canvas, mPaint, DrawChartUtils.formatTime(mData[4][touchChartx]) + "-" + DrawChartUtils.formatTime(mData[5][touchChartx]) + " " + date, mnData[1][touchChartx], width, height);
529 | //文本框
530 | canvas.drawBitmap(textbox, null, dst, null);
531 | // 绘制框内的文本文本
532 | mPaint.setColor(Color.parseColor("#a9a9a9"));
533 | mPaint.setTextSize(DrawChartUtils.boxtextSize);
534 | mPaint.setPathEffect(null);
535 | canvas.drawText(leftIndicatorInbox[0], floats[0][1], floats[1][1], mPaint);
536 | canvas.drawText(date, floats[0][1 + cache], floats[1][1 + cache], mPaint);
537 | canvas.drawText(leftIndicatorInbox[1], floats[0][2], floats[1][2], mPaint);
538 | canvas.drawText(value, floats[0][2 + cache], floats[1][2 + cache], mPaint);
539 | for (int i = 1; i < cache; i++) {
540 | if (mData[3][touchChartx] <= 0) {
541 | mPaint.setColor(Color.parseColor("#50c577"));
542 | } else {
543 | mPaint.setColor(Color.parseColor("#F94747"));
544 | }
545 | if (i != 1) {
546 | canvas.drawText(percent, floats[0][i + 1 + cache], floats[1][i + 1 + cache], mPaint);
547 | canvas.drawText(leftIndicatorInbox[i], floats[0][i + 1], floats[1][i + 1], mPaint);
548 | }
549 |
550 | // if (i == 1) {
551 | //
552 | // } else {
553 | //
554 | // }
555 | }
556 | }
557 |
558 | /**
559 | * 确定触摸的有数据的x 轴坐标
560 | */
561 | private void calcEnsureX() {
562 | // 数组里面都没有坐标值,用得到的x坐标,来类比数组的时间,或者y值,都是可以的
563 | // 因为类比时间需要计算,类比y是直接已经做得的。
564 | for (int i = 0; i < mData[0].length; i++) {
565 | if (mnData[1][i] > x) {
566 | touchChartx = i;
567 | return;
568 | }
569 | }
570 | }
571 |
572 |
573 | /**
574 | * 当前触摸坐标
575 | */
576 | static float x, y, srcy;
577 |
578 | @Override
579 | public boolean onTouchEvent(MotionEvent event) {
580 | int action = event.getAction();
581 | x = event.getX();
582 | y = event.getY();
583 | switch (action) {
584 | case MotionEvent.ACTION_DOWN:
585 | if (x < lastcachex && y < invalidatey) {
586 | isTouch = true;
587 | srcy = event.getY();
588 | //作图区域点击,则不要父类拦截
589 | this.getParent().requestDisallowInterceptTouchEvent(true);
590 | invalidate();
591 | }
592 | break;
593 | case MotionEvent.ACTION_MOVE:
594 | if (x < lastcachex && y < invalidatey) {
595 | isTouch = true;
596 | if (Math.abs(srcy - event.getY()) > 50) {
597 | //作图区域拖动,则父类拦截。子类cancel。
598 | this.getParent().requestDisallowInterceptTouchEvent(false);
599 | }
600 | postInvalidate();
601 | } else {
602 | isTouch = false;
603 | }
604 | break;
605 | // 解决事件冲突
606 | default:
607 | isTouch = false;
608 | postInvalidate();
609 | }
610 | return true;
611 | }
612 |
613 | private void normal() {
614 | //必须要加,会多次调用的。
615 | spilitheight = invalidatey - HTIGHT_TOP * 2;
616 | //X 有初始文本直接测量
617 | positionXText();
618 | //Y 有初始文本直接测量
619 | yposition_left = DrawChartUtils.measureYText(mPaint, yText_left, height, true);
620 | yposition_right = DrawChartUtils.measureYText(mPaint, yText_right, height, false);
621 | //背景线条
622 | bglines = DrawChartUtils.measureBgLine(mPaint, height);
623 | }
624 |
625 | private void initBitmap() {
626 | if (mCacheImg != null || mCacheCanvas != null) {
627 | mCacheCanvas = null;
628 | mCacheImg.recycle();
629 | mCacheImg = null;
630 | }
631 | mCacheImg = Bitmap.createBitmap((int) width, (int) height, Bitmap.Config.ARGB_8888);
632 | mCacheCanvas = new Canvas(mCacheImg);
633 | }
634 |
635 |
636 | /**
637 | * 初始化数组长度 ---> 一个像素一个值
638 | **/
639 | private void initDataArrayLength() {
640 | //黄金大约244个
641 | if (type == TYPE.GOLD) {
642 | mData = new float[6][246];
643 | mnData = new float[2][246];
644 | eachUnitPixcels = width / 246;
645 | //上证大约240个
646 | } else if (type == TYPE.SZHENG) {
647 | mData = new float[6][242];
648 | mnData = new float[2][242];
649 | eachUnitPixcels = width / 242;
650 | } else {
651 | //欧元大约240个
652 | mData = new float[6][242];
653 | mnData = new float[2][242];
654 | eachUnitPixcels = width / 242;
655 | }
656 | iswilloverwrite = (eachUnitPixcels < 1);
657 | }
658 |
659 | private void positionXText() {
660 | // 没有网络获取到时的界面。set->测量
661 | if (type == TYPE.GOLD) {
662 | xText = new String[]{"20:00", "15:30"};
663 | } else if (type == TYPE.SZHENG) {
664 | xText = new String[]{"09:30", "11:30/13:00", "15:00"};
665 | } else {
666 | xText = new String[]{"05:00", "04:30"};
667 | }
668 | xposition = DrawChartUtils.measureXText(mPaint, xText, yText_left[0], yText_right[0], height);//x 底部坐标。
669 | }
670 |
671 | }
672 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hunty/widget/event/BaseBean.java:
--------------------------------------------------------------------------------
1 | package com.hunty.widget.event;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * 作者:fjg on 16/9/8 15:31
7 | * 统一解析bean基类
8 | */
9 | public class BaseBean implements Serializable {
10 |
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hunty/widget/event/DayKHistoryBean.java:
--------------------------------------------------------------------------------
1 | package com.hunty.widget.event;
2 |
3 | import java.util.ArrayList;
4 |
5 | /**
6 | * Created by lenovo23 on 2016/9/12.
7 | */
8 | public class DayKHistoryBean extends BaseBean {
9 | private String resultCode;
10 | private String resultMsg;
11 | private ArrayList list;//数据列表
12 |
13 |
14 | public ArrayList getList() {
15 | return list;
16 | }
17 |
18 | public void setList(ArrayList list) {
19 | this.list = list;
20 | }
21 |
22 | public String getResultCode() {
23 | return resultCode;
24 | }
25 |
26 | public void setResultCode(String resultCode) {
27 | this.resultCode = resultCode;
28 | }
29 |
30 | public String getResultMsg() {
31 | return resultMsg;
32 | }
33 |
34 | public void setResultMsg(String resultMsg) {
35 | this.resultMsg = resultMsg;
36 | }
37 |
38 | public static class DayKDatasBean {
39 |
40 | private String code;//行情代码
41 | private String name;//证券简称
42 | private String close;//开盘价
43 | private String open;//收盘价
44 | private String high;//最高价格
45 | private String low;//最低价格
46 | private String date;//日期
47 | private String time;//时间
48 | //5日均值,10日均值,20日均值,30日均值
49 | private String ma5;
50 | private String ma10;
51 | private String ma20;
52 | private String ma30;
53 |
54 | public String getMa5() {
55 | return ma5;
56 | }
57 |
58 | public void setMa5(String ma5) {
59 | this.ma5 = ma5;
60 | }
61 |
62 | public String getMa10() {
63 | return ma10;
64 | }
65 |
66 | public void setMa10(String ma10) {
67 | this.ma10 = ma10;
68 | }
69 |
70 | public String getMa20() {
71 | return ma20;
72 | }
73 |
74 | public void setMa20(String ma20) {
75 | this.ma20 = ma20;
76 | }
77 |
78 | public String getMa30() {
79 | return ma30;
80 | }
81 |
82 | public void setMa30(String ma30) {
83 | this.ma30 = ma30;
84 | }
85 |
86 | public String getHigh() {
87 | return high;
88 | }
89 |
90 | public void setHigh(String high) {
91 | this.high = high;
92 | }
93 |
94 | public String getCode() {
95 | return code;
96 | }
97 |
98 | public void setCode(String code) {
99 | this.code = code;
100 | }
101 |
102 | public String getName() {
103 | return name;
104 | }
105 |
106 | public void setName(String name) {
107 | this.name = name;
108 | }
109 |
110 | public String getClose() {
111 | return close;
112 | }
113 |
114 | public void setClose(String close) {
115 | this.close = close;
116 | }
117 |
118 | public String getOpen() {
119 | return open;
120 | }
121 |
122 | public void setOpen(String open) {
123 | this.open = open;
124 | }
125 |
126 | public String getLow() {
127 | return low;
128 | }
129 |
130 | public void setLow(String low) {
131 | this.low = low;
132 | }
133 |
134 | public String getDate() {
135 | return date;
136 | }
137 |
138 | public void setDate(String date) {
139 | this.date = date;
140 | }
141 |
142 | public String getTime() {
143 | return time;
144 | }
145 |
146 | public void setTime(String time) {
147 | this.time = time;
148 | }
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hunty/widget/event/DayKHistoryEvent.java:
--------------------------------------------------------------------------------
1 | package com.hunty.widget.event;
2 |
3 | import android.content.Context;
4 |
5 | import java.util.HashMap;
6 | import java.util.Map;
7 |
8 | /**
9 | * Created by zhangjianqiu on 2016/9/12.
10 | * 日K
11 | */
12 | public class DayKHistoryEvent extends Event {
13 |
14 | private Context mContext;
15 |
16 | public DayKHistoryEvent(Context context) {
17 | this.mContext = context;
18 | }
19 |
20 | public void getObservableDayKHistory(String type) {
21 | Map params = new HashMap();
22 | String interfaceHttpUrl = "";
23 |
24 |
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hunty/widget/event/Event.java:
--------------------------------------------------------------------------------
1 | package com.hunty.widget.event;
2 |
3 |
4 | /**
5 | * 网络请求,数据封装
6 | *
7 | */
8 | public class Event {
9 |
10 | public Event(int id) {
11 | setId(id);
12 | }
13 |
14 | public Event() {
15 | }
16 |
17 | /**
18 | * Old Code Style.Log mark.
19 | */
20 | public String TAG = getClass().getSimpleName();
21 | /**
22 | * 普通id
23 | */
24 | private int id = 0;
25 | /**
26 | * 响应数据体
27 | */
28 | private Object object = new Object();
29 | private boolean isSuccess = false;
30 | private boolean isMore = false;//是否是加载更多
31 | private String mGuessType = "";//仅仅在投资风向标的地方使用
32 |
33 | public String getTAG() {
34 | return TAG;
35 | }
36 |
37 | public void setTAG(String TAG) {
38 | this.TAG = TAG;
39 | }
40 |
41 | public int getId() {
42 | return id;
43 | }
44 |
45 | public void setId(int id) {
46 | this.id = id;
47 | }
48 |
49 | public Object getObject() {
50 | return object;
51 | }
52 |
53 | public void setObject(Object object) {
54 | this.object = object;
55 | }
56 |
57 | public boolean isSuccess() {
58 | return isSuccess;
59 | }
60 |
61 | public void setIsSuccess(boolean success) {
62 | isSuccess = success;
63 | }//previous guy did
64 |
65 | public boolean isMore() {
66 | return isMore;
67 | }
68 |
69 | public void setIsMore(boolean more) {
70 | isMore = more;
71 | }//previous guy did
72 |
73 | public String getmGuessType() {
74 | return mGuessType;
75 | }
76 |
77 | public void setmGuessType(String mGuessType) {
78 | this.mGuessType = mGuessType;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hunty/widget/event/TimeSharingHistoryBean.java:
--------------------------------------------------------------------------------
1 | package com.hunty.widget.event;
2 |
3 | import java.util.ArrayList;
4 |
5 | /**
6 | * Created by lenovo23 on 2016/9/12.
7 | */
8 | public class TimeSharingHistoryBean extends BaseBean {
9 |
10 | private String resultCode;
11 | private String resultMsg;
12 | private ArrayList list;
13 |
14 | public String getResultCode() {
15 | return resultCode;
16 | }
17 |
18 | public void setResultCode(String resultCode) {
19 | this.resultCode = resultCode;
20 | }
21 |
22 | public String getResultMsg() {
23 | return resultMsg;
24 | }
25 |
26 | public void setResultMsg(String resultMsg) {
27 | this.resultMsg = resultMsg;
28 | }
29 |
30 | public ArrayList getList() {
31 | return list;
32 | }
33 |
34 | public void setList(ArrayList list) {
35 | this.list = list;
36 | }
37 |
38 | public static class FenShihistoryDatesBean {
39 |
40 | private String code; //行情代码
41 | private String name;// 证券简称
42 | private String close;// 昨日收盘价
43 | private String open;// 今日开盘价
44 | private String amount;//成交金额
45 | private String high;//最高价格
46 | private String low;//最低价格
47 | private String price;//最新价格
48 | private String tradedate;//最新日期
49 | private String tradetime;//最新时间
50 | private String vol;//行情成交量
51 | private String oi;//持仓量
52 | private String settle;//结算价
53 |
54 | public String getCode() {
55 | return code;
56 | }
57 |
58 | public void setCode(String code) {
59 | this.code = code;
60 | }
61 |
62 | public String getSettle() {
63 | return settle;
64 | }
65 |
66 | public void setSettle(String settle) {
67 | this.settle = settle;
68 | }
69 |
70 | public String getOi() {
71 | return oi;
72 | }
73 |
74 | public void setOi(String oi) {
75 | this.oi = oi;
76 | }
77 |
78 | public String getVol() {
79 | return vol;
80 | }
81 |
82 | public void setVol(String vol) {
83 | this.vol = vol;
84 | }
85 |
86 | public String getTradetime() {
87 | return tradetime;
88 | }
89 |
90 | public void setTradetime(String tradetime) {
91 | this.tradetime = tradetime;
92 | }
93 |
94 | public String getTradedate() {
95 | return tradedate;
96 | }
97 |
98 | public void setTradedate(String tradedate) {
99 | this.tradedate = tradedate;
100 | }
101 |
102 | public String getPrice() {
103 | return price;
104 | }
105 |
106 | public void setPrice(String price) {
107 | this.price = price;
108 | }
109 |
110 | public String getLow() {
111 | return low;
112 | }
113 |
114 | public void setLow(String low) {
115 | this.low = low;
116 | }
117 |
118 | public String getHigh() {
119 | return high;
120 | }
121 |
122 | public void setHigh(String high) {
123 | this.high = high;
124 | }
125 |
126 | public String getClose() {
127 | return close;
128 | }
129 |
130 | public void setClose(String close) {
131 | this.close = close;
132 | }
133 |
134 | public String getOpen() {
135 | return open;
136 | }
137 |
138 | public void setOpen(String open) {
139 | this.open = open;
140 | }
141 |
142 | public String getAmount() {
143 | return amount;
144 | }
145 |
146 | public void setAmount(String amount) {
147 | this.amount = amount;
148 | }
149 |
150 | public String getName() {
151 | return name;
152 | }
153 |
154 | public void setName(String name) {
155 | this.name = name;
156 | }
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hunty/widget/event/TimeSharingHistoryEvent.java:
--------------------------------------------------------------------------------
1 | package com.hunty.widget.event;
2 |
3 | import android.content.Context;
4 | import android.text.TextUtils;
5 |
6 |
7 | import java.util.HashMap;
8 | import java.util.Map;
9 |
10 | /**
11 | * EventBus 网路中心
12 | * Created by zhangJianqiu on 2016/9/12.
13 | */
14 | public class TimeSharingHistoryEvent extends Event {
15 |
16 | private Context mContext;
17 |
18 | public TimeSharingHistoryEvent(Context context) {
19 | this.mContext = context;
20 | }
21 |
22 | public void getObservableTimeSharing(String type) {
23 | Map params = new HashMap();
24 | String interfaceHttpUrl = "";
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hunty/widget/util/AbAppConfig.java:
--------------------------------------------------------------------------------
1 | package com.hunty.widget.util;
2 |
3 | /**
4 | * Created by Administrator on 2017/2/26 0026.
5 | */
6 | public class AbAppConfig {
7 | public static final float UI_DENSITY = 0.0f;
8 | public static final int UI_WIDTH = 0;
9 | public static final float UI_HEIGHT = 0;
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hunty/widget/util/ViewUtils.java:
--------------------------------------------------------------------------------
1 | package com.hunty.widget.util;
2 |
3 | import android.content.Context;
4 |
5 | import com.hunty.widget.HlApplication;
6 |
7 |
8 | public class ViewUtils {
9 |
10 | /**
11 | * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
12 | */
13 | public static int dip2px(Context context, float dpValue) {
14 | if (context == null) context = HlApplication.getContext();
15 | final float scale = context.getResources().getDisplayMetrics().density;
16 | return (int) (dpValue * scale + 0.5f);
17 | }
18 |
19 | /**
20 | * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
21 | */
22 | public static int dp2px(float dpValue) {
23 | return dip2px(null, dpValue);
24 | }
25 |
26 | public static float sp2px(float sp) {
27 | final float scale = HlApplication.getContext().getResources().getDisplayMetrics().scaledDensity;
28 | return sp * scale;
29 | }
30 |
31 |
32 | public static int getScreenWidth() {
33 | return HlApplication.getContext().getResources().getDisplayMetrics().widthPixels;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/board_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HDHunter/RouteLineProject/8560bd1d0457dd9323b3bc9e301d673a9955db8b/app/src/main/res/drawable-xhdpi/board_bg.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/corsspoint.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HDHunter/RouteLineProject/8560bd1d0457dd9323b3bc9e301d673a9955db8b/app/src/main/res/drawable-xhdpi/corsspoint.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HDHunter/RouteLineProject/8560bd1d0457dd9323b3bc9e301d673a9955db8b/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HDHunter/RouteLineProject/8560bd1d0457dd9323b3bc9e301d673a9955db8b/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
18 |
22 |
23 |
26 |
27 |
33 |
34 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HDHunter/RouteLineProject/8560bd1d0457dd9323b3bc9e301d673a9955db8b/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | RouteLineProject
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | google()
6 | mavenCentral()
7 | maven { url "https://nexus.yodo1.com/repository/maven-public/" }
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:4.2.2'
11 |
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | google()
20 | mavenCentral()
21 | maven { url "https://nexus.yodo1.com/repository/maven-public/" }
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx4608M -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HDHunter/RouteLineProject/8560bd1d0457dd9323b3bc9e301d673a9955db8b/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun May 07 12:54:47 GMT+08:00 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/imgs/ScreenShot00027.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HDHunter/RouteLineProject/8560bd1d0457dd9323b3bc9e301d673a9955db8b/imgs/ScreenShot00027.png
--------------------------------------------------------------------------------
/imgs/ScreenShot00028.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HDHunter/RouteLineProject/8560bd1d0457dd9323b3bc9e301d673a9955db8b/imgs/ScreenShot00028.png
--------------------------------------------------------------------------------
/imgs/weixin_shouqian.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HDHunter/RouteLineProject/8560bd1d0457dd9323b3bc9e301d673a9955db8b/imgs/weixin_shouqian.png
--------------------------------------------------------------------------------
/imgs/zhifubao-shouqian.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HDHunter/RouteLineProject/8560bd1d0457dd9323b3bc9e301d673a9955db8b/imgs/zhifubao-shouqian.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------