├── .gitignore
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ └── ibm.json
│ ├── java
│ └── com
│ │ └── github
│ │ └── tifezh
│ │ └── kchart
│ │ ├── DataHelper.java
│ │ ├── DataRequest.java
│ │ ├── ExampleActivity.java
│ │ ├── LoadMoreActivity.java
│ │ ├── MainActivity.java
│ │ ├── MinuteChartActivity.java
│ │ └── chart
│ │ ├── KChartAdapter.java
│ │ ├── KLineEntity.java
│ │ └── MinuteLineEntity.java
│ └── res
│ ├── color
│ └── tab_light_text_color_selector.xml
│ ├── layout
│ ├── activity_example.xml
│ ├── activity_example_light.xml
│ ├── activity_main.xml
│ └── activity_minute_chart.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxxhdpi
│ └── 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
├── img
├── demo.gif
├── menu.png
├── style1.png
└── style2.png
├── kchartlib
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── github
│ │ └── tifezh
│ │ └── kchartlib
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── github
│ │ │ └── tifezh
│ │ │ └── kchartlib
│ │ │ ├── chart
│ │ │ ├── BaseKChartAdapter.java
│ │ │ ├── BaseKChartView.java
│ │ │ ├── KChartTabView.java
│ │ │ ├── KChartView.java
│ │ │ ├── MinuteChartView.java
│ │ │ ├── ScrollAndScaleView.java
│ │ │ ├── TabView.java
│ │ │ ├── base
│ │ │ │ ├── IAdapter.java
│ │ │ │ ├── IChartDraw.java
│ │ │ │ ├── IDateTimeFormatter.java
│ │ │ │ └── IValueFormatter.java
│ │ │ ├── draw
│ │ │ │ ├── BOLLDraw.java
│ │ │ │ ├── KDJDraw.java
│ │ │ │ ├── MACDDraw.java
│ │ │ │ ├── MainDraw.java
│ │ │ │ ├── RSIDraw.java
│ │ │ │ └── VolumeDraw.java
│ │ │ ├── entity
│ │ │ │ ├── IBOLL.java
│ │ │ │ ├── ICandle.java
│ │ │ │ ├── IKDJ.java
│ │ │ │ ├── IKLine.java
│ │ │ │ ├── IMACD.java
│ │ │ │ ├── IMinuteLine.java
│ │ │ │ ├── IRSI.java
│ │ │ │ └── IVolume.java
│ │ │ └── formatter
│ │ │ │ ├── BigValueFormatter.java
│ │ │ │ ├── DateFormatter.java
│ │ │ │ ├── TimeFormatter.java
│ │ │ │ └── ValueFormatter.java
│ │ │ └── utils
│ │ │ ├── DateUtil.java
│ │ │ └── ViewUtil.java
│ └── res
│ │ ├── color
│ │ └── tab_text_color_selector.xml
│ │ ├── layout
│ │ ├── item_tab.xml
│ │ └── layout_tab.xml
│ │ └── values
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── github
│ └── tifezh
│ └── kchartlib
│ └── ExampleUnitTest.java
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the ART/Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Gradle files
17 | .gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | # Android Studio captures folder
33 | captures/
34 |
35 | # Intellij
36 | *.iml
37 | .idea/workspace.xml
38 |
39 | # Keystore files
40 | *.jks
41 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # KChartView
2 | KChart for Android ;股票k线图
3 |
4 | 效果预览
5 | -------
6 | * 支持macd,kdj,rsi,boll多种指标切换,支持横竖屏切换,支持长按,缩放,滑动,fling事件等。
7 |
8 |
9 |
10 |
11 | * 支持自定义样式
12 |
13 |
14 |
15 |
16 |
17 | #### 配置及使用
18 |
19 | ##### xml简单配置
20 | ```xml
21 |
25 |
26 | ```
27 |
28 |
29 | ##### xml中配置示例
30 |
31 | ```xml
32 |
69 |
70 | ```
71 |
72 | ##### 数据实体继承IKLine类 获取各个指标的值
73 |
74 | ```java
75 | public class KLineEntity implements KLine {
76 |
77 | public String getDatetime() {
78 | return Date;
79 | }
80 |
81 | public float getOpenPrice() {
82 | return Open;
83 | }
84 |
85 | public float getHighPrice() {
86 | return High;
87 | }
88 |
89 | public float getLowPrice() {
90 | return Low;
91 | }
92 |
93 | public float getClosePrice() {
94 | return Close;
95 | }
96 |
97 | public float getMA5Price() {
98 | return MA5Price;
99 | }
100 |
101 | public float getMA10Price() {
102 | return MA10Price;
103 | }
104 |
105 | public float getMA20Price() {
106 | return MA20Price;
107 | }
108 |
109 | public float getDea() {
110 | return dea;
111 | }
112 |
113 | public float getDif() {
114 | return dif;
115 | }
116 |
117 | public float getMacd() {
118 | return macd;
119 | }
120 |
121 | public float getK() {
122 | return k;
123 | }
124 |
125 | public float getD() {
126 | return d;
127 | }
128 |
129 | public float getJ() {
130 | return j;
131 | }
132 |
133 | public float getRsi1() {
134 | return rsi1;
135 | }
136 |
137 | public float getRsi2() {
138 | return rsi2;
139 | }
140 |
141 | public float getRsi3() {
142 | return rsi3;
143 | }
144 |
145 | public float getUp() {
146 | return up;
147 | }
148 |
149 | public float getMb() {
150 | return mb;
151 | }
152 |
153 | public float getDn() {
154 | return dn;
155 | }
156 |
157 | public String Date;
158 | public float Open;
159 | public float High;
160 | public float Low;
161 | public float Close;
162 | public float Volume;
163 | public float MA5Price;
164 | public float MA10Price;
165 | public float MA20Price;
166 | public float dea;
167 | public float dif;
168 | public float macd;
169 | public float k;
170 | public float d;
171 | public float j;
172 | public float rsi1;
173 | public float rsi2;
174 | public float rsi3;
175 | public float up;
176 | public float mb;
177 | public float dn;
178 | }
179 | ```
180 |
181 | ##### 定义数据适配器
182 |
183 | ```java
184 | public class KChartAdapter extends BaseKChartAdapter {
185 | private List datas = new ArrayList<>();
186 | public KChartAdapter() {
187 | }
188 |
189 | @Override
190 | public int getCount() {
191 | return datas.size();
192 | }
193 |
194 | @Override
195 | public Object getItem(int position) {
196 | return datas.get(position);
197 | }
198 |
199 | @Override
200 | public Date getDate(int position) {
201 | try {
202 | String s = datas.get(position).Date;
203 | String[] split = s.split("/");
204 | Date date = new Date();
205 | date.setYear(Integer.parseInt(split[0]) - 1900);
206 | date.setMonth(Integer.parseInt(split[1]) - 1);
207 | date.setDate(Integer.parseInt(split[2]));
208 | return date;
209 | } catch (Exception e) {
210 | e.printStackTrace();
211 | }
212 | return null;
213 | }
214 |
215 | /**
216 | * 向头部添加数据
217 | */
218 | public void addHeaderData(List data) {
219 | if (data != null && !data.isEmpty()) {
220 | datas.addAll(data);
221 | notifyDataSetChanged();
222 | }
223 | }
224 |
225 | /**
226 | * 向尾部添加数据
227 | */
228 | public void addFooterData(List data) {
229 | if (data != null && !data.isEmpty()) {
230 | datas.addAll(0, data);
231 | notifyDataSetChanged();
232 | }
233 | }
234 |
235 | /**
236 | * 改变某个点的值
237 | * @param position 索引值
238 | */
239 | public void changeItem(int position,KLineEntity data)
240 | {
241 | datas.set(position,data);
242 | notifyDataSetChanged();
243 | }
244 | }
245 | ```
246 | ##### 加载数据
247 |
248 | ```java
249 | mKChartView.showLoading();
250 | new Thread(new Runnable() {
251 | @Override
252 | public void run() {
253 | final List data = DataRequest.getALL(ExampleActivity.this);
254 | runOnUiThread(new Runnable() {
255 | @Override
256 | public void run() {
257 | //追加数据
258 | mAdapter.addFooterData(data);
259 | //开始动画
260 | mKChartView.startAnimation();
261 | //刷新完成
262 | mKChartView.refreshEnd();
263 | }
264 | });
265 | }
266 | }).start();
267 | ```
268 | ##### 更多使用方法请下载demo查看
269 |
270 | #### 扩展性
271 |
272 | ##### 添加其他指数 以添加kdj指标为例
273 | * 定义kdj中的值
274 | ```java
275 | public interface IKDJ {
276 |
277 | /**
278 | * K值
279 | */
280 | float getK();
281 |
282 | /**
283 | * D值
284 | */
285 | float getD();
286 |
287 | /**
288 | * J值
289 | */
290 | float getJ();
291 |
292 | }
293 | ```
294 | * 实现IChartDraw接口
295 | ```java
296 | public class KDJDraw implements IChartDraw {
297 |
298 | private Paint mKPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
299 | private Paint mDPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
300 | private Paint mJPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
301 |
302 | public KDJDraw(BaseKChartView view) {
303 | }
304 |
305 | @Override
306 | public void drawTranslated(@Nullable IKDJ lastPoint, @NonNull IKDJ curPoint, float lastX, float curX, @NonNull Canvas canvas, @NonNull BaseKChartView view, int position) {
307 | view.drawChildLine(canvas, mKPaint, lastX, lastPoint.getK(), curX, curPoint.getK());
308 | view.drawChildLine(canvas, mDPaint, lastX, lastPoint.getD(), curX, curPoint.getD());
309 | view.drawChildLine(canvas, mJPaint, lastX, lastPoint.getJ(), curX, curPoint.getJ());
310 | }
311 |
312 | @Override
313 | public void drawText(@NonNull Canvas canvas, @NonNull BaseKChartView view, int position, float x, float y) {
314 | String text = "";
315 | IKDJ point = (IKDJ) view.getItem(position);
316 | text = "K:" + view.formatValue(point.getK()) + " ";
317 | canvas.drawText(text, x, y, mKPaint);
318 | x += mKPaint.measureText(text);
319 | text = "D:" + view.formatValue(point.getD()) + " ";
320 | canvas.drawText(text, x, y, mDPaint);
321 | x += mDPaint.measureText(text);
322 | text = "J:" + view.formatValue(point.getJ()) + " ";
323 | canvas.drawText(text, x, y, mJPaint);
324 | }
325 |
326 | @Override
327 | public float getMaxValue(IKDJ point) {
328 | return Math.max(point.getK(), Math.max(point.getD(), point.getJ()));
329 | }
330 |
331 | @Override
332 | public float getMinValue(IKDJ point) {
333 | return Math.min(point.getK(), Math.min(point.getD(), point.getJ()));
334 | }
335 |
336 | /**
337 | * 设置K颜色
338 | */
339 | public void setKColor(int color) {
340 | mKPaint.setColor(color);
341 | }
342 |
343 | /**
344 | * 设置D颜色
345 | */
346 | public void setDColor(int color) {
347 | mDPaint.setColor(color);
348 | }
349 |
350 | /**
351 | * 设置J颜色
352 | */
353 | public void setJColor(int color) {
354 | mJPaint.setColor(color);
355 | }
356 |
357 | /**
358 | * 设置曲线宽度
359 | */
360 | public void setLineWidth(float width)
361 | {
362 | mKPaint.setStrokeWidth(width);
363 | mDPaint.setStrokeWidth(width);
364 | mJPaint.setStrokeWidth(width);
365 | }
366 |
367 | /**
368 | * 设置文字大小
369 | */
370 | public void setTextSize(float textSize)
371 | {
372 | mKPaint.setTextSize(textSize);
373 | mDPaint.setTextSize(textSize);
374 | mJPaint.setTextSize(textSize);
375 | }
376 | }
377 | ```
378 | * 添加kdj指标
379 | ```java
380 | mKChartView.addChildDraw("KDJ", mKDJDraw);
381 | ```
382 | ##### 自定义画线,画柱体 以macd为例
383 | * 重写 drawTranslated(在此方法中绘画的会滑动和缩放) 方法 ,如下所示:
384 | ```java
385 | @Override
386 | public void drawTranslated(@Nullable IMACD lastPoint, @NonNull IMACD curPoint, float lastX, float curX, @NonNull Canvas canvas, @NonNull BaseKChartView view, int position) {
387 | drawMACD(canvas, view, curX, curPoint.getMacd());
388 | view.drawChildLine(canvas, mDIFPaint, lastX, lastPoint.getDea(), curX, curPoint.getDea());
389 | view.drawChildLine(canvas, mDEAPaint, lastX, lastPoint.getDif(), curX, curPoint.getDif());
390 | }
391 | /**
392 | * 画macd
393 | * @param canvas
394 | * @param x
395 | * @param macd
396 | */
397 | private void drawMACD(Canvas canvas, BaseKChartView view, float x, float macd) {
398 | float macdy = view.getChildY(macd);
399 | float r = mMACDWidth / 2;
400 | float zeroy=view.getChildY(0);
401 | if (macd > 0) {
402 | canvas.drawRect(x - r, macdy, x + r, zeroy, mRedPaint);
403 | } else {
404 | canvas.drawRect(x - r, zeroy, x + r, macdy, mGreenPaint);
405 | }
406 | }
407 | ```
408 |
409 | License
410 | -------
411 |
412 | Copyright 2018 tifezh
413 |
414 | Licensed under the Apache License, Version 2.0 (the "License");
415 | you may not use this file except in compliance with the License.
416 | You may obtain a copy of the License at
417 |
418 | http://www.apache.org/licenses/LICENSE-2.0
419 |
420 | Unless required by applicable law or agreed to in writing, software
421 | distributed under the License is distributed on an "AS IS" BASIS,
422 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
423 | See the License for the specific language governing permissions and
424 | limitations under the License.
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 27
5 | buildToolsVersion "27.0.1"
6 | defaultConfig {
7 | applicationId "com.github.tifezh.kchart"
8 | minSdkVersion 15
9 | targetSdkVersion 27
10 | versionCode 1
11 | versionName "1.0"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | sourceSets { main { assets.srcDirs = ['src/main/assets', 'src/main/assets/'] } }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | implementation 'com.android.support:appcompat-v7:27.0.1'
25 | implementation project(path: ':kchartlib')
26 | implementation 'com.jakewharton:butterknife:8.8.1'
27 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
28 | implementation 'com.google.code.gson:gson:2.8.0'
29 | }
30 |
--------------------------------------------------------------------------------
/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 D:\Sdk/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 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
26 |
27 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/tifezh/kchart/DataHelper.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchart;
2 |
3 | import com.github.tifezh.kchart.chart.KLineEntity;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * 数据辅助类 计算macd rsi等
9 | * Created by tifezh on 2016/11/26.
10 | */
11 |
12 | public class DataHelper {
13 |
14 | /**
15 | * 计算RSI
16 | *
17 | * @param datas
18 | */
19 | static void calculateRSI(List datas) {
20 | float rsi1 = 0;
21 | float rsi2 = 0;
22 | float rsi3 = 0;
23 | float rsi1ABSEma = 0;
24 | float rsi2ABSEma = 0;
25 | float rsi3ABSEma = 0;
26 | float rsi1MaxEma = 0;
27 | float rsi2MaxEma = 0;
28 | float rsi3MaxEma = 0;
29 | for (int i = 0; i < datas.size(); i++) {
30 | KLineEntity point = datas.get(i);
31 | final float closePrice = point.getClosePrice();
32 | if (i == 0) {
33 | rsi1 = 0;
34 | rsi2 = 0;
35 | rsi3 = 0;
36 | rsi1ABSEma = 0;
37 | rsi2ABSEma = 0;
38 | rsi3ABSEma = 0;
39 | rsi1MaxEma = 0;
40 | rsi2MaxEma = 0;
41 | rsi3MaxEma = 0;
42 | } else {
43 | float Rmax = Math.max(0, closePrice - datas.get(i - 1).getClosePrice());
44 | float RAbs = Math.abs(closePrice - datas.get(i - 1).getClosePrice());
45 | rsi1MaxEma = (Rmax + (6f - 1) * rsi1MaxEma) / 6f;
46 | rsi1ABSEma = (RAbs + (6f - 1) * rsi1ABSEma) / 6f;
47 |
48 | rsi2MaxEma = (Rmax + (12f - 1) * rsi2MaxEma) / 12f;
49 | rsi2ABSEma = (RAbs + (12f - 1) * rsi2ABSEma) / 12f;
50 |
51 | rsi3MaxEma = (Rmax + (24f - 1) * rsi3MaxEma) / 24f;
52 | rsi3ABSEma = (RAbs + (24f - 1) * rsi3ABSEma) / 24f;
53 |
54 | rsi1 = (rsi1MaxEma / rsi1ABSEma) * 100;
55 | rsi2 = (rsi2MaxEma / rsi2ABSEma) * 100;
56 | rsi3 = (rsi3MaxEma / rsi3ABSEma) * 100;
57 | }
58 | point.rsi1 = rsi1;
59 | point.rsi2 = rsi2;
60 | point.rsi3 = rsi3;
61 | }
62 | }
63 |
64 | /**
65 | * 计算kdj
66 | *
67 | * @param datas
68 | */
69 | static void calculateKDJ(List datas) {
70 | float k = 0;
71 | float d = 0;
72 |
73 | for (int i = 0; i < datas.size(); i++) {
74 | KLineEntity point = datas.get(i);
75 | final float closePrice = point.getClosePrice();
76 | int startIndex = i - 8;
77 | if (startIndex < 0) {
78 | startIndex = 0;
79 | }
80 | float max9 = Float.MIN_VALUE;
81 | float min9 = Float.MAX_VALUE;
82 | for (int index = startIndex; index <= i; index++) {
83 | max9 = Math.max(max9, datas.get(index).getHighPrice());
84 | min9 = Math.min(min9, datas.get(index).getLowPrice());
85 |
86 | }
87 | float rsv = 100f * (closePrice - min9) / (max9 - min9);
88 | if (i == 0) {
89 | k = rsv;
90 | d = rsv;
91 | } else {
92 | k = (rsv + 2f * k) / 3f;
93 | d = (k + 2f * d) / 3f;
94 | }
95 | point.k = k;
96 | point.d = d;
97 | point.j = 3f * k - 2 * d;
98 | }
99 |
100 | }
101 |
102 | /**
103 | * 计算macd
104 | *
105 | * @param datas
106 | */
107 | static void calculateMACD(List datas) {
108 | float ema12 = 0;
109 | float ema26 = 0;
110 | float dif = 0;
111 | float dea = 0;
112 | float macd = 0;
113 |
114 | for (int i = 0; i < datas.size(); i++) {
115 | KLineEntity point = datas.get(i);
116 | final float closePrice = point.getClosePrice();
117 | if (i == 0) {
118 | ema12 = closePrice;
119 | ema26 = closePrice;
120 | } else {
121 | // EMA(12) = 前一日EMA(12) X 11/13 + 今日收盘价 X 2/13
122 | // EMA(26) = 前一日EMA(26) X 25/27 + 今日收盘价 X 2/27
123 | ema12 = ema12 * 11f / 13f + closePrice * 2f / 13f;
124 | ema26 = ema26 * 25f / 27f + closePrice * 2f / 27f;
125 | }
126 | // DIF = EMA(12) - EMA(26) 。
127 | // 今日DEA = (前一日DEA X 8/10 + 今日DIF X 2/10)
128 | // 用(DIF-DEA)*2即为MACD柱状图。
129 | dif = ema12 - ema26;
130 | dea = dea * 8f / 10f + dif * 2f / 10f;
131 | macd = (dif - dea) * 2f;
132 | point.dif = dif;
133 | point.dea = dea;
134 | point.macd = macd;
135 | }
136 |
137 | }
138 |
139 | /**
140 | * 计算 BOLL 需要在计算ma之后进行
141 | *
142 | * @param datas
143 | */
144 | static void calculateBOLL(List datas) {
145 | for (int i = 0; i < datas.size(); i++) {
146 | KLineEntity point = datas.get(i);
147 | final float closePrice = point.getClosePrice();
148 | if (i == 0) {
149 | point.mb = closePrice;
150 | point.up = Float.NaN;
151 | point.dn = Float.NaN;
152 | } else {
153 | int n = 20;
154 | if (i < 20) {
155 | n = i + 1;
156 | }
157 | float md = 0;
158 | for (int j = i - n + 1; j <= i; j++) {
159 | float c = datas.get(j).getClosePrice();
160 | float m = point.getMA20Price();
161 | float value = c - m;
162 | md += value * value;
163 | }
164 | md = md / (n - 1);
165 | md = (float) Math.sqrt(md);
166 | point.mb = point.getMA20Price();
167 | point.up = point.mb + 2f * md;
168 | point.dn = point.mb - 2f * md;
169 | }
170 | }
171 |
172 | }
173 |
174 | /**
175 | * 计算ma
176 | *
177 | * @param datas
178 | */
179 | static void calculateMA(List datas) {
180 | float ma5 = 0;
181 | float ma10 = 0;
182 | float ma20 = 0;
183 |
184 | for (int i = 0; i < datas.size(); i++) {
185 | KLineEntity point = datas.get(i);
186 | final float closePrice = point.getClosePrice();
187 |
188 | ma5 += closePrice;
189 | ma10 += closePrice;
190 | ma20 += closePrice;
191 | if (i >= 5) {
192 | ma5 -= datas.get(i - 5).getClosePrice();
193 | point.MA5Price = ma5 / 5f;
194 | } else {
195 | point.MA5Price = ma5 / (i + 1f);
196 | }
197 | if (i >= 10) {
198 | ma10 -= datas.get(i - 10).getClosePrice();
199 | point.MA10Price = ma10 / 10f;
200 | } else {
201 | point.MA10Price = ma10 / (i + 1f);
202 | }
203 | if (i >= 20) {
204 | ma20 -= datas.get(i - 20).getClosePrice();
205 | point.MA20Price = ma20 / 20f;
206 | } else {
207 | point.MA20Price = ma20 / (i + 1f);
208 | }
209 | }
210 | }
211 |
212 | /**
213 | * 计算MA BOLL RSI KDJ MACD
214 | *
215 | * @param datas
216 | */
217 | static void calculate(List datas) {
218 | calculateMA(datas);
219 | calculateMACD(datas);
220 | calculateBOLL(datas);
221 | calculateRSI(datas);
222 | calculateKDJ(datas);
223 | calculateVolumeMA(datas);
224 | }
225 |
226 | private static void calculateVolumeMA(List entries) {
227 | float volumeMa5 = 0;
228 | float volumeMa10 = 0;
229 |
230 | for (int i = 0; i < entries.size(); i++) {
231 | KLineEntity entry = entries.get(i);
232 |
233 | volumeMa5 += entry.getVolume();
234 | volumeMa10 += entry.getVolume();
235 |
236 | if (i >= 5) {
237 |
238 | volumeMa5 -= entries.get(i - 5).getVolume();
239 | entry.MA5Volume = (volumeMa5 / 5f);
240 | } else {
241 |
242 | entry.MA5Volume = (volumeMa5 / (i + 1f));
243 | }
244 |
245 | if (i >= 10) {
246 | volumeMa10 -= entries.get(i - 10).getVolume();
247 | entry.MA10Volume = (volumeMa10 / 5f);
248 | } else {
249 | entry.MA10Volume = (volumeMa10 / (i + 1f));
250 | }
251 | }
252 | }
253 | }
254 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/tifezh/kchart/DataRequest.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchart;
2 |
3 | import android.content.Context;
4 | import android.support.annotation.NonNull;
5 | import android.support.annotation.Nullable;
6 |
7 | import com.github.tifezh.kchart.chart.KLineEntity;
8 | import com.github.tifezh.kchart.chart.MinuteLineEntity;
9 | import com.google.gson.Gson;
10 | import com.google.gson.reflect.TypeToken;
11 |
12 | import java.io.InputStream;
13 | import java.util.ArrayList;
14 | import java.util.Date;
15 | import java.util.List;
16 | import java.util.Random;
17 |
18 | /**
19 | * 模拟网络请求
20 | * Created by tifezh on 2017/7/3.
21 | */
22 |
23 | public class DataRequest {
24 | private static List datas = null;
25 | private static Random random = new Random();
26 |
27 | public static String getStringFromAssert(Context context, String fileName) {
28 | try {
29 | InputStream in = context.getResources().getAssets().open(fileName);
30 | int length = in.available();
31 | byte[] buffer = new byte[length];
32 | in.read(buffer);
33 | return new String(buffer, 0, buffer.length, "UTF-8");
34 | } catch (Exception e) {
35 | e.printStackTrace();
36 | }
37 | return "";
38 | }
39 |
40 | public static List getALL(Context context) {
41 | if (datas == null) {
42 | final List data = new Gson().fromJson(getStringFromAssert(context, "ibm.json"), new TypeToken>() {}.getType());
43 | DataHelper.calculate(data);
44 | datas = data;
45 | }
46 | return datas;
47 | }
48 |
49 | /**
50 | * 分页查询
51 | *
52 | * @param context
53 | * @param offset 开始的索引
54 | * @param size 每次查询的条数
55 | */
56 | public static List getData(Context context, int offset, int size) {
57 | List all = getALL(context);
58 | List data = new ArrayList<>();
59 | int start = Math.max(0, all.size() - 1 - offset - size);
60 | int stop = Math.min(all.size(), all.size() - offset);
61 | for (int i = start; i < stop; i++) {
62 | data.add(all.get(i));
63 | }
64 | return data;
65 | }
66 |
67 | /**
68 | * 随机生成分时数据
69 | */
70 | public static List
71 | getMinuteData(@NonNull Date startTime,
72 | @NonNull Date endTime,
73 | @Nullable Date firstEndTime,
74 | @Nullable Date secondStartTime) {
75 | List list = new ArrayList<>();
76 | long startDate=startTime.getTime();
77 | if(firstEndTime==null&&secondStartTime==null) {
78 | while (startDate <= endTime.getTime()) {
79 | MinuteLineEntity data = new MinuteLineEntity();
80 | data.time = new Date(startDate);
81 | startDate += 60000;
82 | list.add(data);
83 | }
84 | }
85 | else {
86 | while (startDate <= firstEndTime.getTime()) {
87 | MinuteLineEntity data = new MinuteLineEntity();
88 | data.time = new Date(startDate);
89 | startDate += 60000;
90 | list.add(data);
91 | }
92 | startDate=secondStartTime.getTime();
93 | while (startDate <= endTime.getTime()) {
94 | MinuteLineEntity data = new MinuteLineEntity();
95 | data.time = new Date(startDate);
96 | startDate += 60000;
97 | list.add(data);
98 | }
99 | }
100 | randomLine(list);
101 | randomVolume(list);
102 | float sum = 0;
103 | for (int i = 0; i < list.size(); i++) {
104 | MinuteLineEntity data = list.get(i);
105 | sum += data.price;
106 | data.avg = 1f * sum / (i + 1);
107 | }
108 | return list;
109 | }
110 |
111 | private static void randomVolume(List list){
112 | for(MinuteLineEntity data:list){
113 | data.volume= (int) (Math.random()*Math.random()*Math.random()*Math.random()*10000000);
114 | }
115 | }
116 |
117 | /**
118 | * 生成随机曲线
119 | */
120 | private static void randomLine(List list) {
121 | float STEP_MAX = 0.9f;
122 | float STEP_CHANGE = 1f;
123 | float HEIGHT_MAX = 200;
124 |
125 | float height = (float) (Math.random() * HEIGHT_MAX);
126 | float slope = (float) ((Math.random() * STEP_MAX) * 2 - STEP_MAX);
127 |
128 | for (int x = 0; x < list.size(); x++) {
129 | height += slope;
130 | slope += (Math.random() * STEP_CHANGE) * 2 - STEP_CHANGE;
131 |
132 | if (slope > STEP_MAX) {
133 | slope = STEP_MAX;
134 | }
135 | if (slope < -STEP_MAX) {
136 | slope = -STEP_MAX;
137 | }
138 |
139 | if (height > HEIGHT_MAX) {
140 | height = HEIGHT_MAX;
141 | slope *= -1;
142 | }
143 | if (height < 0) {
144 | height = 0;
145 | slope *= -1;
146 | }
147 |
148 | list.get(x).price = height + 1000;
149 | }
150 | }
151 | }
152 |
153 |
154 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/tifezh/kchart/ExampleActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchart;
2 |
3 | import android.content.res.Configuration;
4 | import android.os.Build;
5 | import android.os.Bundle;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.util.Log;
8 | import android.view.View;
9 | import android.view.Window;
10 | import android.view.WindowManager;
11 | import android.widget.LinearLayout;
12 | import android.widget.RelativeLayout;
13 | import android.widget.TextView;
14 |
15 | import com.github.tifezh.kchart.chart.KChartAdapter;
16 | import com.github.tifezh.kchart.chart.KLineEntity;
17 | import com.github.tifezh.kchartlib.chart.BaseKChartView;
18 | import com.github.tifezh.kchartlib.chart.KChartView;
19 | import com.github.tifezh.kchartlib.chart.formatter.DateFormatter;
20 |
21 | import java.util.List;
22 |
23 | import butterknife.BindView;
24 | import butterknife.ButterKnife;
25 |
26 | public class ExampleActivity extends AppCompatActivity {
27 |
28 |
29 | @BindView(R.id.title_view)
30 | RelativeLayout mTitleView;
31 | @BindView(R.id.tv_price)
32 | TextView mTvPrice;
33 | @BindView(R.id.tv_percent)
34 | TextView mTvPercent;
35 | @BindView(R.id.ll_status)
36 | LinearLayout mLlStatus;
37 | @BindView(R.id.kchart_view)
38 | KChartView mKChartView;
39 | private KChartAdapter mAdapter;
40 |
41 | @Override
42 | protected void onCreate(Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 | int type = getIntent().getIntExtra("type", 0);
45 | if (type == 0) {
46 | setContentView(R.layout.activity_example);
47 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
48 | Window window = getWindow();
49 | window.setFlags(
50 | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
51 | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
52 | }
53 | } else {
54 | setContentView(R.layout.activity_example_light);
55 | }
56 | ButterKnife.bind(this);
57 | initView();
58 | initData();
59 | }
60 |
61 | private void initView() {
62 | mAdapter = new KChartAdapter();
63 | mKChartView.setAdapter(mAdapter);
64 | mKChartView.setDateTimeFormatter(new DateFormatter());
65 | mKChartView.setGridRows(4);
66 | mKChartView.setGridColumns(4);
67 | mKChartView.setOnSelectedChangedListener(new BaseKChartView.OnSelectedChangedListener() {
68 | @Override
69 | public void onSelectedChanged(BaseKChartView view, Object point, int index) {
70 | KLineEntity data = (KLineEntity) point;
71 | Log.i("onSelectedChanged", "index:" + index + " closePrice:" + data.getClosePrice());
72 | }
73 | });
74 | }
75 |
76 | private void initData() {
77 | mKChartView.showLoading();
78 | new Thread(new Runnable() {
79 | @Override
80 | public void run() {
81 | final List data = DataRequest.getALL(ExampleActivity.this);
82 | runOnUiThread(new Runnable() {
83 | @Override
84 | public void run() {
85 | mAdapter.addFooterData(data);
86 | mKChartView.startAnimation();
87 | mKChartView.refreshEnd();
88 | }
89 | });
90 | }
91 | }).start();
92 | }
93 |
94 | @Override
95 | public void onConfigurationChanged(Configuration newConfig) {
96 | super.onConfigurationChanged(newConfig);
97 | if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
98 | mLlStatus.setVisibility(View.GONE);
99 | mKChartView.setGridRows(3);
100 | mKChartView.setGridColumns(8);
101 | } else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
102 | mLlStatus.setVisibility(View.VISIBLE);
103 | mKChartView.setGridRows(4);
104 | mKChartView.setGridColumns(4);
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/tifezh/kchart/LoadMoreActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchart;
2 |
3 | import android.content.res.Configuration;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.util.Log;
7 | import android.view.View;
8 | import android.widget.LinearLayout;
9 | import android.widget.RelativeLayout;
10 | import android.widget.TextView;
11 |
12 | import com.github.tifezh.kchart.chart.KChartAdapter;
13 | import com.github.tifezh.kchart.chart.KLineEntity;
14 | import com.github.tifezh.kchartlib.chart.BaseKChartView;
15 | import com.github.tifezh.kchartlib.chart.KChartView;
16 | import com.github.tifezh.kchartlib.chart.formatter.DateFormatter;
17 |
18 | import java.util.List;
19 |
20 | import butterknife.BindView;
21 | import butterknife.ButterKnife;
22 |
23 | /**
24 | * Created by tifezh on 2017/7/3.
25 | */
26 |
27 | public class LoadMoreActivity extends AppCompatActivity implements KChartView.KChartRefreshListener {
28 |
29 | @BindView(R.id.title_view)
30 | RelativeLayout mTitleView;
31 | @BindView(R.id.tv_price)
32 | TextView mTvPrice;
33 | @BindView(R.id.tv_percent)
34 | TextView mTvPercent;
35 | @BindView(R.id.ll_status)
36 | LinearLayout mLlStatus;
37 | @BindView(R.id.kchart_view)
38 | KChartView mKChartView;
39 | private KChartAdapter mAdapter;
40 |
41 | @Override
42 | protected void onCreate(Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 | setContentView(R.layout.activity_example_light);
45 | ButterKnife.bind(this);
46 | initView();
47 | initData();
48 | }
49 |
50 | private void initView() {
51 | mAdapter = new KChartAdapter();
52 | mKChartView.setAdapter(mAdapter);
53 | mKChartView.setDateTimeFormatter(new DateFormatter());
54 | mKChartView.setGridRows(4);
55 | mKChartView.setGridColumns(4);
56 | mKChartView.setOnSelectedChangedListener(new BaseKChartView.OnSelectedChangedListener() {
57 | @Override
58 | public void onSelectedChanged(BaseKChartView view, Object point, int index) {
59 | KLineEntity data = (KLineEntity) point;
60 | Log.i("onSelectedChanged", "index:" + index + " closePrice:" + data.getClosePrice());
61 | }
62 | });
63 | }
64 |
65 | private void initData() {
66 | mKChartView.showLoading();
67 | mKChartView.setRefreshListener(this);
68 | onLoadMoreBegin(mKChartView);
69 | }
70 |
71 | @Override
72 | public void onConfigurationChanged(Configuration newConfig) {
73 | super.onConfigurationChanged(newConfig);
74 | if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
75 | mLlStatus.setVisibility(View.GONE);
76 | mKChartView.setGridRows(3);
77 | mKChartView.setGridColumns(8);
78 | } else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
79 | mLlStatus.setVisibility(View.VISIBLE);
80 | mKChartView.setGridRows(4);
81 | mKChartView.setGridColumns(4);
82 | }
83 | }
84 |
85 | @Override
86 | public void onLoadMoreBegin(KChartView chart) {
87 | new Thread(new Runnable() {
88 | @Override
89 | public void run() {
90 | final List data = DataRequest.getData(LoadMoreActivity.this, mAdapter.getCount(), 500);
91 | try {
92 | Thread.sleep(1000);
93 | } catch (InterruptedException e) {
94 | e.printStackTrace();
95 | }
96 | if (!data.isEmpty()) {
97 | Log.i("onLoadMoreBegin", "start:" + data.get(0).getDatetime() + " stop:" + data.get(data.size() - 1).getDatetime());
98 | }
99 | runOnUiThread(new Runnable() {
100 | @Override
101 | public void run() {
102 | //第一次加载时开始动画
103 | if (mAdapter.getCount() == 0) {
104 | mKChartView.startAnimation();
105 | }
106 | mAdapter.addFooterData(data);
107 | //加载完成,还有更多数据
108 | if (data.size() > 0) {
109 | mKChartView.refreshComplete();
110 | }
111 | //加载完成,没有更多数据
112 | else {
113 | mKChartView.refreshEnd();
114 | }
115 | }
116 | });
117 | }
118 | }).start();
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/tifezh/kchart/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchart;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.view.View;
8 |
9 | /**
10 | * Created by tifezh on 2017/6/30.
11 | */
12 |
13 | public class MainActivity extends AppCompatActivity implements View.OnClickListener{
14 | @Override
15 | protected void onCreate(@Nullable Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 | setContentView(R.layout.activity_main);
18 | }
19 |
20 | @Override
21 | public void onClick(View v) {
22 | Intent intent=new Intent();
23 | switch (v.getId())
24 | {
25 | case R.id.btn_style1:
26 | intent.setClass(this,ExampleActivity.class);
27 | intent.putExtra("type",0);
28 | break;
29 | case R.id.btn_style2:
30 | intent.setClass(this,ExampleActivity.class);
31 | intent.putExtra("type",1);
32 | break;
33 | case R.id.btn_loadmore:
34 | intent.setClass(this,LoadMoreActivity.class);
35 | break;
36 | case R.id.btn_minute:
37 | intent.setClass(this,MinuteChartActivity.class);
38 | break;
39 | }
40 | startActivity(intent);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/tifezh/kchart/MinuteChartActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchart;
2 |
3 | import android.os.Build;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.view.Window;
8 | import android.view.WindowManager;
9 |
10 | import com.github.tifezh.kchart.chart.MinuteLineEntity;
11 | import com.github.tifezh.kchartlib.chart.MinuteChartView;
12 | import com.github.tifezh.kchartlib.utils.DateUtil;
13 |
14 | import java.text.ParseException;
15 | import java.util.Date;
16 | import java.util.List;
17 |
18 |
19 | import butterknife.BindView;
20 | import butterknife.ButterKnife;
21 |
22 | /**
23 | * Created by tifezh on 2017/7/20.
24 | */
25 |
26 | public class MinuteChartActivity extends AppCompatActivity {
27 |
28 |
29 | @BindView(R.id.minuteChartView)
30 | MinuteChartView mMinuteChartView;
31 |
32 | @Override
33 | public void onCreate(@Nullable Bundle savedInstanceState) {
34 | super.onCreate(savedInstanceState);
35 | setContentView(R.layout.activity_minute_chart);
36 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
37 | Window window = getWindow();
38 | window.setFlags(
39 | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
40 | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
41 | }
42 | ButterKnife.bind(this);
43 | initView();
44 | initData();
45 | }
46 |
47 | private void initView() {
48 | }
49 |
50 | private void initData() {
51 | try {
52 | //整体开始时间
53 | Date startTime = DateUtil.shortTimeFormat.parse("09:30");
54 | //整体的结束时间
55 | Date endTime = DateUtil.shortTimeFormat.parse("15:00");
56 | //休息开始时间
57 | Date firstEndTime = DateUtil.shortTimeFormat.parse("11:30");
58 | //休息结束时间
59 | Date secondStartTime = DateUtil.shortTimeFormat.parse("13:00");
60 | //获取随机生成的数据
61 | List minuteData =
62 | DataRequest.getMinuteData(startTime,
63 | endTime,
64 | firstEndTime,
65 | secondStartTime);
66 | mMinuteChartView.initData(minuteData,
67 | startTime,
68 | endTime,
69 | firstEndTime,
70 | secondStartTime,
71 | (float) (minuteData.get(0).price - 0.5 + Math.random()));
72 | } catch (ParseException e) {
73 | e.printStackTrace();
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/tifezh/kchart/chart/KChartAdapter.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchart.chart;
2 |
3 | import com.github.tifezh.kchartlib.chart.BaseKChartAdapter;
4 |
5 | import java.util.ArrayList;
6 | import java.util.Date;
7 | import java.util.List;
8 |
9 | /**
10 | * 数据适配器
11 | * Created by tifezh on 2016/6/18.
12 | */
13 |
14 | public class KChartAdapter extends BaseKChartAdapter {
15 |
16 | private List datas = new ArrayList<>();
17 |
18 | public KChartAdapter() {
19 |
20 | }
21 |
22 | @Override
23 | public int getCount() {
24 | return datas.size();
25 | }
26 |
27 | @Override
28 | public Object getItem(int position) {
29 | return datas.get(position);
30 | }
31 |
32 | @Override
33 | public Date getDate(int position) {
34 | try {
35 | String s = datas.get(position).Date;
36 | String[] split = s.split("/");
37 | Date date = new Date();
38 | date.setYear(Integer.parseInt(split[0]) - 1900);
39 | date.setMonth(Integer.parseInt(split[1]) - 1);
40 | date.setDate(Integer.parseInt(split[2]));
41 | return date;
42 | } catch (Exception e) {
43 | e.printStackTrace();
44 | }
45 | return null;
46 | }
47 |
48 | /**
49 | * 向头部添加数据
50 | */
51 | public void addHeaderData(List data) {
52 | if (data != null && !data.isEmpty()) {
53 | datas.addAll(data);
54 | notifyDataSetChanged();
55 | }
56 | }
57 |
58 | /**
59 | * 向尾部添加数据
60 | */
61 | public void addFooterData(List data) {
62 | if (data != null && !data.isEmpty()) {
63 | datas.addAll(0, data);
64 | notifyDataSetChanged();
65 | }
66 | }
67 |
68 | /**
69 | * 改变某个点的值
70 | * @param position 索引值
71 | */
72 | public void changeItem(int position,KLineEntity data)
73 | {
74 | datas.set(position,data);
75 | notifyDataSetChanged();
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/tifezh/kchart/chart/KLineEntity.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchart.chart;
2 |
3 | import com.github.tifezh.kchartlib.chart.entity.IKLine;
4 |
5 |
6 | /**
7 | * K线实体
8 | * Created by tifezh on 2016/5/16.
9 | */
10 |
11 | public class KLineEntity implements IKLine {
12 |
13 | public String getDatetime() {
14 | return Date;
15 | }
16 |
17 | @Override
18 | public float getOpenPrice() {
19 | return Open;
20 | }
21 |
22 | @Override
23 | public float getHighPrice() {
24 | return High;
25 | }
26 |
27 | @Override
28 | public float getLowPrice() {
29 | return Low;
30 | }
31 |
32 | @Override
33 | public float getClosePrice() {
34 | return Close;
35 | }
36 |
37 | @Override
38 | public float getMA5Price() {
39 | return MA5Price;
40 | }
41 |
42 | @Override
43 | public float getMA10Price() {
44 | return MA10Price;
45 | }
46 |
47 | @Override
48 | public float getMA20Price() {
49 | return MA20Price;
50 | }
51 |
52 | @Override
53 | public float getDea() {
54 | return dea;
55 | }
56 |
57 | @Override
58 | public float getDif() {
59 | return dif;
60 | }
61 |
62 | @Override
63 | public float getMacd() {
64 | return macd;
65 | }
66 |
67 | @Override
68 | public float getK() {
69 | return k;
70 | }
71 |
72 | @Override
73 | public float getD() {
74 | return d;
75 | }
76 |
77 | @Override
78 | public float getJ() {
79 | return j;
80 | }
81 |
82 | @Override
83 | public float getRsi1() {
84 | return rsi1;
85 | }
86 |
87 | @Override
88 | public float getRsi2() {
89 | return rsi2;
90 | }
91 |
92 | @Override
93 | public float getRsi3() {
94 | return rsi3;
95 | }
96 |
97 | @Override
98 | public float getUp() {
99 | return up;
100 | }
101 |
102 | @Override
103 | public float getMb() {
104 | return mb;
105 | }
106 |
107 | @Override
108 | public float getDn() {
109 | return dn;
110 | }
111 |
112 | @Override
113 | public float getVolume() {
114 | return Volume;
115 | }
116 |
117 | @Override
118 | public float getMA5Volume() {
119 | return MA5Volume;
120 | }
121 |
122 | @Override
123 | public float getMA10Volume() {
124 | return MA10Volume;
125 | }
126 |
127 | public String Date;
128 | public float Open;
129 | public float High;
130 | public float Low;
131 | public float Close;
132 | public float Volume;
133 |
134 | public float MA5Price;
135 |
136 | public float MA10Price;
137 |
138 | public float MA20Price;
139 |
140 | public float dea;
141 |
142 | public float dif;
143 |
144 | public float macd;
145 |
146 | public float k;
147 |
148 | public float d;
149 |
150 | public float j;
151 |
152 | public float rsi1;
153 |
154 | public float rsi2;
155 |
156 | public float rsi3;
157 |
158 | public float up;
159 |
160 | public float mb;
161 |
162 | public float dn;
163 |
164 | public float MA5Volume;
165 |
166 | public float MA10Volume;
167 |
168 |
169 |
170 |
171 | }
172 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/tifezh/kchart/chart/MinuteLineEntity.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchart.chart;
2 |
3 | import com.github.tifezh.kchartlib.chart.entity.IMinuteLine;
4 |
5 | import java.util.Date;
6 |
7 | /**
8 | * 分时图实体
9 | * Created by tifezh on 2017/7/20.
10 | */
11 |
12 | public class MinuteLineEntity implements IMinuteLine {
13 | /**
14 | * time : 09:30
15 | * price : 3.53
16 | * avg : 3.5206
17 | * vol : 9251
18 | */
19 |
20 | public Date time;
21 | public float price;
22 | public float avg;
23 | public float volume;
24 |
25 | @Override
26 | public float getAvgPrice() {
27 | return avg;
28 | }
29 |
30 | @Override
31 | public float getPrice() {
32 | return price;
33 | }
34 |
35 | @Override
36 | public Date getDate() {
37 | return time;
38 | }
39 |
40 | @Override
41 | public float getVolume() {
42 | return volume;
43 | }
44 |
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/app/src/main/res/color/tab_light_text_color_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_example.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
13 |
14 |
22 |
23 |
24 |
28 |
29 |
37 |
38 |
44 |
45 |
53 |
54 |
64 |
65 |
66 |
72 |
73 |
79 |
80 |
87 |
88 |
89 |
90 |
96 |
97 |
103 |
104 |
111 |
112 |
113 |
114 |
115 |
119 |
120 |
125 |
126 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_example_light.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
13 |
14 |
22 |
23 |
24 |
28 |
29 |
37 |
38 |
44 |
45 |
53 |
54 |
64 |
65 |
66 |
72 |
73 |
79 |
80 |
87 |
88 |
89 |
90 |
96 |
97 |
103 |
104 |
111 |
112 |
113 |
114 |
115 |
119 |
120 |
158 |
159 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
24 |
25 |
32 |
33 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_minute_chart.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
13 |
14 |
22 |
23 |
24 |
28 |
29 |
37 |
38 |
44 |
45 |
53 |
54 |
64 |
65 |
66 |
72 |
73 |
79 |
80 |
87 |
88 |
89 |
90 |
96 |
97 |
103 |
104 |
111 |
112 |
113 |
114 |
115 |
119 |
120 |
125 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tifezh/KChartView/9e8cc232ed59e6c34818749c96cdad38d40ea5e2/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tifezh/KChartView/9e8cc232ed59e6c34818749c96cdad38d40ea5e2/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tifezh/KChartView/9e8cc232ed59e6c34818749c96cdad38d40ea5e2/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tifezh/KChartView/9e8cc232ed59e6c34818749c96cdad38d40ea5e2/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tifezh/KChartView/9e8cc232ed59e6c34818749c96cdad38d40ea5e2/app/src/main/res/mipmap-xxxhdpi/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 | @color/chart_background
4 | @color/chart_background
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 | 10sp
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | KChartViewDemo
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 | jcenter()
6 | google()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.0.1'
10 |
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | jcenter()
19 | google()
20 | }
21 | }
22 |
23 | task clean(type: Delete) {
24 | delete rootProject.buildDir
25 | }
26 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tifezh/KChartView/9e8cc232ed59e6c34818749c96cdad38d40ea5e2/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Mar 26 14:33:00 CST 2018
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-4.1-all.zip
7 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/img/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tifezh/KChartView/9e8cc232ed59e6c34818749c96cdad38d40ea5e2/img/demo.gif
--------------------------------------------------------------------------------
/img/menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tifezh/KChartView/9e8cc232ed59e6c34818749c96cdad38d40ea5e2/img/menu.png
--------------------------------------------------------------------------------
/img/style1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tifezh/KChartView/9e8cc232ed59e6c34818749c96cdad38d40ea5e2/img/style1.png
--------------------------------------------------------------------------------
/img/style2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tifezh/KChartView/9e8cc232ed59e6c34818749c96cdad38d40ea5e2/img/style2.png
--------------------------------------------------------------------------------
/kchartlib/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/kchartlib/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 27
5 | buildToolsVersion "27.0.1"
6 |
7 | defaultConfig {
8 | minSdkVersion 15
9 | targetSdkVersion 27
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 |
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | }
23 |
24 | dependencies {
25 | compile fileTree(include: ['*.jar'], dir: 'libs')
26 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
27 | exclude group: 'com.android.support', module: 'support-annotations'
28 | })
29 | provided 'com.android.support:appcompat-v7:27.0.1'
30 | testCompile 'junit:junit:4.12'
31 | }
32 |
--------------------------------------------------------------------------------
/kchartlib/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 D:\Sdk/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 |
--------------------------------------------------------------------------------
/kchartlib/src/androidTest/java/com/github/tifezh/kchartlib/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.assertEquals;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.github.tifezh.kchartlib.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/kchartlib/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/BaseKChartAdapter.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart;
2 |
3 | import android.database.DataSetObservable;
4 | import android.database.DataSetObserver;
5 |
6 | import com.github.tifezh.kchartlib.chart.base.IAdapter;
7 |
8 | /**
9 | * k线图的数据适配器
10 | * Created by tifezh on 2016/6/9.
11 | */
12 |
13 | public abstract class BaseKChartAdapter implements IAdapter {
14 |
15 | private final DataSetObservable mDataSetObservable = new DataSetObservable();
16 |
17 | public void notifyDataSetChanged() {
18 | if (getCount() > 0) {
19 | mDataSetObservable.notifyChanged();
20 | } else {
21 | mDataSetObservable.notifyInvalidated();
22 | }
23 | }
24 |
25 |
26 | @Override
27 | public void registerDataSetObserver(DataSetObserver observer) {
28 | mDataSetObservable.registerObserver(observer);
29 | }
30 |
31 | @Override
32 | public void unregisterDataSetObserver(DataSetObserver observer) {
33 | mDataSetObservable.unregisterObserver(observer);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/KChartTabView.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.pm.ActivityInfo;
6 | import android.content.res.ColorStateList;
7 | import android.content.res.Configuration;
8 | import android.util.AttributeSet;
9 | import android.view.LayoutInflater;
10 | import android.view.MotionEvent;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.LinearLayout;
14 | import android.widget.RelativeLayout;
15 | import android.widget.TextView;
16 |
17 | import com.github.tifezh.kchartlib.R;
18 | import com.github.tifezh.kchartlib.utils.ViewUtil;
19 |
20 |
21 | /**
22 | * K线图中间位置的TabBar
23 | * Created by tifezh on 2016/5/17.
24 | */
25 | public class KChartTabView extends RelativeLayout implements View.OnClickListener {
26 |
27 | LinearLayout mLlContainer;
28 | TextView mTvFullScreen;
29 | private TabSelectListener mTabSelectListener = null;
30 | //当前选择的index
31 | private int mSelectedIndex = 0;
32 | private ColorStateList mColorStateList;
33 | private int mIndicatorColor;
34 |
35 | public KChartTabView(Context context) {
36 | super(context);
37 | init();
38 | }
39 |
40 | public KChartTabView(Context context, AttributeSet attrs) {
41 | super(context, attrs);
42 | init();
43 | }
44 |
45 | public KChartTabView(Context context, AttributeSet attrs, int defStyleAttr) {
46 | super(context, attrs, defStyleAttr);
47 | init();
48 | }
49 |
50 | private void init() {
51 | View view = LayoutInflater.from(getContext()).inflate(R.layout.layout_tab, null, false);
52 | LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtil.Dp2Px(getContext(), 30));
53 | view.setLayoutParams(layoutParams);
54 | addView(view);
55 | mLlContainer = (LinearLayout) findViewById(R.id.ll_container);
56 | mTvFullScreen = (TextView) findViewById(R.id.tv_fullScreen);
57 | mTvFullScreen.setOnClickListener(new OnClickListener() {
58 | @Override
59 | public void onClick(View v) {
60 | Activity activity = (Activity) getContext();
61 | boolean isVertical = (getContext().getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT);
62 | if (isVertical) {
63 | activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
64 |
65 | } else {
66 | activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
67 | }
68 | }
69 | });
70 | mTvFullScreen.setSelected(true);
71 | if(mColorStateList!=null)
72 | {
73 | mTvFullScreen.setTextColor(mColorStateList);
74 | }
75 | }
76 |
77 | @Override
78 | public void onClick(View v) {
79 | if (mSelectedIndex >= 0 && mSelectedIndex < mLlContainer.getChildCount()) {
80 | mLlContainer.getChildAt(mSelectedIndex).setSelected(false);
81 | }
82 | mSelectedIndex = mLlContainer.indexOfChild(v);
83 | v.setSelected(true);
84 | mTabSelectListener.onTabSelected(mSelectedIndex);
85 | }
86 |
87 | public interface TabSelectListener {
88 | /**
89 | * 选择tab的位置序号
90 | *
91 | * @param position
92 | */
93 | void onTabSelected(int position);
94 | }
95 |
96 | @Override
97 | public boolean dispatchTouchEvent(MotionEvent ev) {
98 | getParent().requestDisallowInterceptTouchEvent(true);
99 | return super.dispatchTouchEvent(ev);
100 | }
101 |
102 | /**
103 | * 添加选项卡
104 | *
105 | * @param text 选项卡文字
106 | */
107 | public void addTab(String text) {
108 | TabView tabView=new TabView(getContext());
109 | tabView.setOnClickListener(this);
110 | tabView.setText(text);
111 | tabView.setTextColor(mColorStateList);
112 | tabView.setIndicatorColor(mIndicatorColor);
113 | mLlContainer.addView(tabView);
114 | //第一个默认选中
115 | if (mLlContainer.getChildCount() == 1) {
116 | tabView.setSelected(true);
117 | mSelectedIndex = 0;
118 | onTabSelected(mSelectedIndex);
119 | }
120 | }
121 |
122 | /**
123 | * 设置选项卡监听
124 | *
125 | * @param listener TabSelectListener
126 | */
127 | public void setOnTabSelectListener(TabSelectListener listener) {
128 | this.mTabSelectListener = listener;
129 | //默认选中上一个位置
130 | if (mLlContainer.getChildCount() > 0 && mTabSelectListener != null) {
131 | mTabSelectListener.onTabSelected(mSelectedIndex);
132 | }
133 | }
134 |
135 | private void onTabSelected(int position) {
136 | if (mTabSelectListener != null) {
137 | mTabSelectListener.onTabSelected(position);
138 | }
139 | }
140 |
141 | public void setTextColor(ColorStateList color)
142 | {
143 | mColorStateList=color;
144 | for(int i=0;i mPoints = new ArrayList<>();
61 | private Date mFirstStartTime;
62 | private Date mFirstEndTime;
63 | private Date mSecondStartTime;
64 | private Date mSecondEndTime;
65 | private long mTotalTime;
66 | private float mPointWidth;
67 |
68 | private IValueFormatter mVolumeFormatter;
69 |
70 | public MinuteChartView(Context context) {
71 | super(context);
72 | init();
73 | }
74 |
75 | public MinuteChartView(Context context, AttributeSet attrs) {
76 | super(context, attrs);
77 | init();
78 | }
79 |
80 | public MinuteChartView(Context context, AttributeSet attrs, int defStyleAttr) {
81 | super(context, attrs, defStyleAttr);
82 | init();
83 | }
84 |
85 | private void init() {
86 | mDetector = new GestureDetectorCompat(getContext(), this);
87 | mTopPadding = dp2px(mTopPadding);
88 | mBottomPadding = dp2px(mBottomPadding);
89 | mTextSize = sp2px(mTextSize);
90 | mVolumeHeight=dp2px(mVolumeHeight);
91 | mGridPaint.setColor(Color.parseColor("#353941"));
92 | mGridPaint.setStrokeWidth(dp2px(1));
93 | mTextPaint.setColor(Color.parseColor("#B1B2B6"));
94 | mTextPaint.setTextSize(mTextSize);
95 | mTextPaint.setStrokeWidth(dp2px(0.5f));
96 | mAvgPaint.setColor(Color.parseColor("#90A901"));
97 | mAvgPaint.setStrokeWidth(dp2px(0.5f));
98 | mAvgPaint.setTextSize(mTextSize);
99 | mPricePaint.setColor(Color.parseColor("#FF6600"));
100 | mPricePaint.setStrokeWidth(dp2px(0.5f));
101 | mPricePaint.setTextSize(mTextSize);
102 | mVolumePaintGreen.setColor(ContextCompat.getColor(getContext(), R.color.chart_green));
103 | mVolumePaintRed.setColor(ContextCompat.getColor(getContext(),R.color.chart_red));
104 | mBackgroundColor =Color.parseColor("#202326");
105 | mBackgroundPaint.setColor(mBackgroundColor);
106 |
107 | mVolumeFormatter=new BigValueFormatter();
108 | }
109 |
110 | @Override
111 | public boolean onTouchEvent(MotionEvent event) {
112 | this.mDetector.onTouchEvent(event);
113 | switch (event.getAction() & MotionEvent.ACTION_MASK) {
114 | case MotionEvent.ACTION_DOWN:
115 | break;
116 | case MotionEvent.ACTION_MOVE:
117 | //一个点的时候滑动
118 | if (event.getPointerCount() == 1) {
119 | //长按之后移动
120 | if (isLongPress) {
121 | calculateSelectedX(event.getX());
122 | invalidate();
123 | }
124 | }
125 | break;
126 | case MotionEvent.ACTION_UP:
127 | isLongPress = false;
128 | invalidate();
129 | break;
130 | case MotionEvent.ACTION_CANCEL:
131 | isLongPress = false;
132 | invalidate();
133 | break;
134 | }
135 | return true;
136 | }
137 |
138 | private void calculateSelectedX(float x) {
139 | selectedIndex = (int) (x * 1f / getX(mPoints.size() - 1) * (mPoints.size() - 1) + 0.5f);
140 | if (selectedIndex < 0) {
141 | selectedIndex = 0;
142 | }
143 | if (selectedIndex > mPoints.size() - 1) {
144 | selectedIndex = mPoints.size() - 1;
145 | }
146 | }
147 |
148 | /**
149 | * 根据索引获取x的值
150 | */
151 | private float getX(int position)
152 | {
153 | Date date=mPoints.get(position).getDate();
154 | if(mSecondStartTime!=null&&date.getTime()>=mSecondStartTime.getTime())
155 | {
156 | return 1f* (date.getTime()-mSecondStartTime.getTime()+60000+
157 | mFirstEndTime.getTime()-mFirstStartTime.getTime()) /mTotalTime* (mWidth-mPointWidth)+mPointWidth/2f;
158 | }
159 | else {
160 | return 1f*(date.getTime()-mFirstStartTime.getTime())/mTotalTime* (mWidth-mPointWidth)+mPointWidth/2f;
161 | }
162 | }
163 |
164 | /**
165 | * 获取最大能有多少个点
166 | */
167 | private long getMaxPointCount(){
168 | return mTotalTime/ONE_MINUTE;
169 | }
170 |
171 |
172 | @Override
173 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
174 | super.onSizeChanged(w, h, oldw, oldh);
175 | int height = h - mTopPadding - mBottomPadding;
176 | this.mHeight = height-mVolumeHeight;
177 | this.mWidth = w;
178 | notifyChanged();
179 | }
180 |
181 | /**
182 | * @param data 数据源
183 | * @param startTime 显示的开始时间
184 | * @param endTime 显示的结束时间
185 | * @param yesClosePrice 昨日开盘价
186 | */
187 | public void initData(Collection extends IMinuteLine> data,
188 | Date startTime,
189 | Date endTime,
190 | float yesClosePrice) {
191 | initData(data,startTime,endTime,null,null,yesClosePrice);
192 | }
193 |
194 | /**
195 | * @param data 数据源
196 | * @param startTime 显示的开始时间
197 | * @param endTime 显示的结束时间
198 | * @param firstEndTime 休息开始时间 可空
199 | * @param secondStartTime 休息结束时间 可空
200 | * @param yesClosePrice 昨收价
201 | */
202 | public void initData(Collection extends IMinuteLine> data,
203 | @NonNull Date startTime,
204 | @NonNull Date endTime,
205 | @Nullable Date firstEndTime,
206 | @Nullable Date secondStartTime,
207 | float yesClosePrice){
208 | this.mFirstStartTime = startTime;
209 | this.mSecondEndTime = endTime;
210 | if(mFirstStartTime.getTime()>=mSecondEndTime.getTime()) throw new IllegalStateException("开始时间不能大于结束时间");
211 | mTotalTime=mSecondEndTime.getTime()-mFirstStartTime.getTime();
212 | if(firstEndTime!=null&&secondStartTime!=null) {
213 | this.mFirstEndTime = firstEndTime;
214 | this.mSecondStartTime = secondStartTime;
215 | if(!(mFirstStartTime.getTime() offsetValueMin ? offsetValueMax : offsetValueMin) * 1.2f;
248 | //坐标轴高度以开始的点对称
249 | mValueMax = mValueStart + offset;
250 | mValueMin = mValueStart - offset;
251 | //y轴的缩放值
252 | mScaleY = mHeight / (mValueMax - mValueMin);
253 | //判断最大值和最小值是否一致
254 | if(mValueMax == mValueMin){
255 | //当最大值和最小值都相等的时候 分别增大最大值和 减小最小值
256 | mValueMax += Math.abs(mValueMax*0.05f);
257 | mValueMin -= Math.abs(mValueMax*0.05f);
258 | if (mValueMax == 0) {
259 | mValueMax = 1;
260 | }
261 | }
262 |
263 | if(mVolumeMax == 0){
264 | mVolumeMax=1;
265 | }
266 |
267 | mVolumeMax*=1.1f;
268 | //成交量的缩放值
269 | mVolumeScaleY = mVolumeHeight / mVolumeMax;
270 | mPointWidth=(float) mWidth/getMaxPointCount();
271 | mVolumePaintRed.setStrokeWidth(mPointWidth*0.8f);
272 | mVolumePaintGreen.setStrokeWidth(mPointWidth*0.8f);
273 | invalidate();
274 | }
275 |
276 | @Override
277 | protected void onDraw(Canvas canvas) {
278 | super.onDraw(canvas);
279 | canvas.drawColor(mBackgroundColor);
280 | if (mWidth == 0 || mHeight == 0 || mPoints == null || mPoints.size() == 0) {
281 | return;
282 | }
283 | drawGird(canvas);
284 | if (mPoints.size() > 0) {
285 | IMinuteLine lastPoint = mPoints.get(0);
286 | float lastX=getX(0);
287 | for (int i = 0; i < mPoints.size(); i++) {
288 | IMinuteLine curPoint=mPoints.get(i);
289 | float curX=getX(i);
290 | canvas.drawLine(lastX, getY(lastPoint.getPrice()), curX, getY(curPoint.getPrice()), mPricePaint);
291 | canvas.drawLine(lastX, getY(lastPoint.getAvgPrice()),curX, getY(curPoint.getAvgPrice()), mAvgPaint);
292 | //成交量
293 | Paint volumePaint=((i==0&&curPoint.getPrice()<=mValueStart)||curPoint.getPrice()<=lastPoint.getPrice())?mVolumePaintGreen:mVolumePaintRed;
294 | canvas.drawLine(curX,getVolumeY(0),curX,getVolumeY(curPoint.getVolume()),volumePaint);
295 | lastPoint = curPoint;
296 | lastX=curX;
297 | }
298 | }
299 | drawText(canvas);
300 | //画指示线
301 | if (isLongPress) {
302 | IMinuteLine point = mPoints.get(selectedIndex);
303 | float x=getX(selectedIndex);
304 | canvas.drawLine(x, 0, x, mHeight+mVolumeHeight, mTextPaint);
305 | canvas.drawLine(0, getY(point.getPrice()), mWidth, getY(point.getPrice()), mTextPaint);
306 | //画指示线的时间
307 | String text = DateUtil.shortTimeFormat.format(point.getDate());
308 | x = x - mTextPaint.measureText(text) / 2;
309 | if (x < 0) {
310 | x = 0;
311 | }
312 | if (x > mWidth - mTextPaint.measureText(text)) {
313 | x = mWidth - mTextPaint.measureText(text);
314 | }
315 | Paint.FontMetrics fm = mTextPaint.getFontMetrics();
316 | float textHeight = fm.descent - fm.ascent;
317 | float baseLine = (textHeight - fm.bottom - fm.top) / 2;
318 | //下方时间
319 | canvas.drawRect(x,mHeight+mVolumeHeight-baseLine+textHeight,x+mTextPaint.measureText(text),mVolumeHeight+mHeight+baseLine,mBackgroundPaint);
320 | canvas.drawText(text, x, mHeight+mVolumeHeight+baseLine, mTextPaint);
321 |
322 | float r = textHeight / 2;
323 | float y=getY(point.getPrice());
324 | //左方值
325 | text=floatToString(point.getPrice());
326 | canvas.drawRect(0, y - r, mTextPaint.measureText(text), y + r, mBackgroundPaint);
327 | canvas.drawText(text, 0, fixTextY(y), mTextPaint);
328 | //右方值
329 | text=floatToString((point.getPrice() - mValueStart)*100f / mValueStart)+"%";
330 | canvas.drawRect(mWidth-mTextPaint.measureText(text), y - r,mWidth, y + r, mBackgroundPaint);
331 | canvas.drawText(text, mWidth-mTextPaint.measureText(text), fixTextY(y), mTextPaint);
332 | }
333 | drawValue(canvas, isLongPress ? selectedIndex : mPoints.size() - 1);
334 | }
335 |
336 | /**
337 | * 画值
338 | */
339 | private void drawValue(Canvas canvas, int index) {
340 | Paint.FontMetrics fm = mTextPaint.getFontMetrics();
341 | float textHeight = fm.descent - fm.ascent;
342 | float baseLine = (textHeight - fm.bottom - fm.top) / 2;
343 | if (index >= 0 && index < mPoints.size()) {
344 | float y = baseLine-textHeight;
345 | IMinuteLine point = mPoints.get(index);
346 | String text = "成交价:" + floatToString(point.getPrice()) + " ";
347 | float x = 0;
348 | canvas.drawText(text, x, y, mPricePaint);
349 | x += mPricePaint.measureText(text);
350 | text = "均价:" + floatToString(point.getAvgPrice()) + " ";
351 | canvas.drawText(text, x, y, mAvgPaint);
352 | //成交量
353 | text="VOL:"+mVolumeFormatter.format(point.getVolume());
354 | canvas.drawText(text,mWidth-mTextPaint.measureText(text),mHeight+baseLine,mTextPaint);
355 | }
356 | }
357 |
358 | /**
359 | * 修正y值
360 | */
361 | private float getY(float value) {
362 | return (mValueMax - value) * mScaleY;
363 | }
364 |
365 | private float getVolumeY(float value){
366 | return (mVolumeMax -value) * mVolumeScaleY + mHeight;
367 | }
368 |
369 | private void drawGird(Canvas canvas) {
370 | //先画出坐标轴
371 | canvas.translate(0, mTopPadding);
372 | canvas.scale(1, 1);
373 | //横向的grid
374 | float rowSpace = mHeight / mGridRows;
375 |
376 | for (int i = 0; i <= mGridRows; i++) {
377 | canvas.drawLine(0, rowSpace * i, mWidth, rowSpace * i, mGridPaint);
378 | }
379 | canvas.drawLine(0, rowSpace * mGridRows /2, mWidth, rowSpace * mGridRows /2, mGridPaint);
380 |
381 | canvas.drawLine(0, mHeight+mVolumeHeight, mWidth, mHeight+mVolumeHeight, mGridPaint);
382 | //纵向的grid
383 | float columnSpace = mWidth / GridColumns;
384 | for (int i = 0; i <= GridColumns; i++) {
385 | canvas.drawLine(columnSpace * i, 0, columnSpace * i, mHeight+mVolumeHeight, mGridPaint);
386 | }
387 |
388 | }
389 | /**
390 | * 解决text居中的问题
391 | */
392 | public float fixTextY(float y) {
393 | Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
394 | return (y + (fontMetrics.descent - fontMetrics.ascent) / 2 - fontMetrics.descent);
395 | }
396 |
397 | private void drawText(Canvas canvas) {
398 | Paint.FontMetrics fm = mTextPaint.getFontMetrics();
399 | float textHeight = fm.descent - fm.ascent;
400 | float baseLine = (textHeight - fm.bottom - fm.top) / 2;
401 | //画左边的值
402 | canvas.drawText(floatToString(mValueMax), 0, baseLine, mTextPaint);
403 | canvas.drawText(floatToString(mValueMin), 0, mHeight, mTextPaint);
404 | float rowValue = (mValueMax - mValueMin) / mGridRows;
405 | float rowSpace = mHeight / mGridRows;
406 | for (int i = 0; i <= mGridRows; i++) {
407 | String text = floatToString(rowValue * (mGridRows - i) + mValueMin);
408 | if (i >= 1 && i < mGridRows) {
409 | canvas.drawText(text, 0, fixTextY(rowSpace * i), mTextPaint);
410 | }
411 | }
412 | String text = floatToString((mValueMax - mValueStart)*100f / mValueStart)+"%";
413 | canvas.drawText(text, mWidth - mTextPaint.measureText(text), baseLine, mTextPaint);
414 | text = floatToString((mValueMin - mValueStart)*100f / mValueStart)+"%";
415 | canvas.drawText(text, mWidth - mTextPaint.measureText(text), mHeight, mTextPaint);
416 | for (int i = 0; i <= mGridRows; i++) {
417 | text = floatToString((rowValue * (mGridRows - i) + mValueMin - mValueStart)*100f / mValueStart)+"%";
418 | if (i >= 1 && i < mGridRows) {
419 | canvas.drawText(text, mWidth - mTextPaint.measureText(text), fixTextY(rowSpace * i), mTextPaint);
420 | }
421 | }
422 | //画时间
423 | float y = mHeight+ mVolumeHeight +baseLine;
424 | canvas.drawText(DateUtil.shortTimeFormat.format(mFirstStartTime), 0, y, mTextPaint);
425 | canvas.drawText(DateUtil.shortTimeFormat.format(mSecondEndTime),
426 | mWidth - mTextPaint.measureText(DateUtil.shortTimeFormat.format(mSecondEndTime)), y, mTextPaint);
427 | //成交量
428 | canvas.drawText(mVolumeFormatter.format(mVolumeMax),0,mHeight+baseLine,mTextPaint);
429 | }
430 |
431 | public int dp2px(float dp) {
432 | final float scale = getContext().getResources().getDisplayMetrics().density;
433 | return (int) (dp * scale + 0.5f);
434 | }
435 |
436 | public int sp2px(float spValue) {
437 | final float fontScale = getContext().getResources().getDisplayMetrics().scaledDensity;
438 | return (int) (spValue * fontScale + 0.5f);
439 | }
440 |
441 | /**
442 | * 保留2位小数
443 | */
444 | public String floatToString(float value) {
445 | String s = String.format("%.2f", value);
446 | char end = s.charAt(s.length() - 1);
447 | while (s.contains(".") && (end == '0' || end == '.')) {
448 | s = s.substring(0, s.length() - 1);
449 | end = s.charAt(s.length() - 1);
450 | }
451 | return s;
452 | }
453 |
454 | @Override
455 | public boolean onDown(MotionEvent e) {
456 | return false;
457 | }
458 |
459 | @Override
460 | public void onShowPress(MotionEvent e) {
461 |
462 | }
463 |
464 | @Override
465 | public boolean onSingleTapUp(MotionEvent e) {
466 | return false;
467 | }
468 |
469 | @Override
470 | public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
471 | return false;
472 | }
473 |
474 | @Override
475 | public void onLongPress(MotionEvent e) {
476 | isLongPress = true;
477 | calculateSelectedX(e.getX());
478 | invalidate();
479 | }
480 |
481 | @Override
482 | public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
483 | return false;
484 | }
485 |
486 | /**
487 | * 设置开始的值 对称轴线
488 | */
489 | public void setValueStart(float valueStart) {
490 | this.mValueStart = valueStart;
491 | }
492 |
493 | /**
494 | * 修改某个点的值
495 | * @param position 索引值
496 | */
497 | public void changePoint(int position,IMinuteLine point)
498 | {
499 | mPoints.set(position,point);
500 | notifyChanged();
501 | }
502 |
503 | /**
504 | * 获取点的个数
505 | */
506 | private int getItemSize()
507 | {
508 | return mPoints.size();
509 | }
510 |
511 | /**
512 | * 刷新最后一个点
513 | */
514 | public void refreshLastPoint(IMinuteLine point) {
515 | changePoint(getItemSize()-1,point);
516 | }
517 |
518 | /**
519 | * 添加一个点
520 | */
521 | public void addPoint(IMinuteLine point) {
522 | mPoints.add(point);
523 | notifyChanged();
524 | }
525 |
526 | /**
527 | * 根据索引获取点
528 | */
529 | public IMinuteLine getItem(int position)
530 | {
531 | return mPoints.get(position);
532 | }
533 |
534 | /**
535 | * 设置成交量格式化器
536 | * @param volumeFormatter {@link IValueFormatter} 成交量格式化器
537 | */
538 | public void setVolumeFormatter(IValueFormatter volumeFormatter) {
539 | mVolumeFormatter = volumeFormatter;
540 | }
541 | }
542 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/ScrollAndScaleView.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart;
2 |
3 | import android.content.Context;
4 | import android.support.v4.view.GestureDetectorCompat;
5 | import android.util.AttributeSet;
6 | import android.view.GestureDetector;
7 | import android.view.MotionEvent;
8 | import android.view.ScaleGestureDetector;
9 | import android.widget.OverScroller;
10 | import android.widget.RelativeLayout;
11 |
12 | /**
13 | * 可以滑动和放大的view
14 | * Created by tian on 2016/5/3.
15 | */
16 | public abstract class ScrollAndScaleView extends RelativeLayout implements
17 | GestureDetector.OnGestureListener,
18 | ScaleGestureDetector.OnScaleGestureListener {
19 | protected int mScrollX = 0;
20 | protected GestureDetectorCompat mDetector;
21 | protected ScaleGestureDetector mScaleDetector;
22 |
23 | protected boolean isLongPress = false;
24 |
25 | private OverScroller mScroller;
26 |
27 | protected boolean touch = false;
28 |
29 | protected float mScaleX = 1;
30 |
31 | protected float mScaleXMax = 2f;
32 |
33 | protected float mScaleXMin = 0.5f;
34 |
35 | private boolean mMultipleTouch=false;
36 |
37 | private boolean mScrollEnable=true;
38 |
39 | private boolean mScaleEnable=true;
40 |
41 | public ScrollAndScaleView(Context context) {
42 | super(context);
43 | init();
44 | }
45 |
46 | public ScrollAndScaleView(Context context, AttributeSet attrs) {
47 | super(context, attrs);
48 | init();
49 | }
50 |
51 | public ScrollAndScaleView(Context context, AttributeSet attrs, int defStyleAttr) {
52 | super(context, attrs, defStyleAttr);
53 | init();
54 | }
55 |
56 | private void init() {
57 | setWillNotDraw(false);
58 | mDetector = new GestureDetectorCompat(getContext(), this);
59 | mScaleDetector = new ScaleGestureDetector(getContext(), this);
60 | mScroller = new OverScroller(getContext());
61 | }
62 |
63 | @Override
64 | public boolean onDown(MotionEvent e) {
65 | return false;
66 | }
67 |
68 | @Override
69 | public void onShowPress(MotionEvent e) {
70 |
71 | }
72 |
73 | @Override
74 | public boolean onSingleTapUp(MotionEvent e) {
75 | return false;
76 | }
77 |
78 | @Override
79 | public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
80 | if (!isLongPress&&!isMultipleTouch()) {
81 | scrollBy(Math.round(distanceX), 0);
82 | return true;
83 | }
84 | return false;
85 | }
86 |
87 | @Override
88 | public void onLongPress(MotionEvent e) {
89 | isLongPress = true;
90 | }
91 |
92 | @Override
93 | public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
94 | if (!isTouch()&&isScrollEnable()) {
95 | mScroller.fling(mScrollX, 0
96 | , Math.round(velocityX / mScaleX), 0,
97 | Integer.MIN_VALUE, Integer.MAX_VALUE,
98 | 0, 0);
99 | }
100 | return true;
101 | }
102 |
103 | @Override
104 | public void computeScroll() {
105 | if (mScroller.computeScrollOffset()) {
106 | if (!isTouch()) {
107 | scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
108 | } else {
109 | mScroller.forceFinished(true);
110 | }
111 | }
112 | }
113 |
114 | @Override
115 | public void scrollBy(int x, int y) {
116 | scrollTo(mScrollX - Math.round(x / mScaleX), 0);
117 | }
118 |
119 | @Override
120 | public void scrollTo(int x, int y) {
121 | if(!isScrollEnable())
122 | {
123 | mScroller.forceFinished(true);
124 | return;
125 | }
126 | int oldX = mScrollX;
127 | mScrollX = x;
128 | if (mScrollX < getMinScrollX()) {
129 | mScrollX = getMinScrollX();
130 | onRightSide();
131 | mScroller.forceFinished(true);
132 | } else if (mScrollX > getMaxScrollX()) {
133 | mScrollX = getMaxScrollX();
134 | onLeftSide();
135 | mScroller.forceFinished(true);
136 | }
137 | onScrollChanged(mScrollX, 0, oldX, 0);
138 | invalidate();
139 | }
140 |
141 | @Override
142 | public boolean onScale(ScaleGestureDetector detector) {
143 | if(!isScaleEnable())
144 | {
145 | return false;
146 | }
147 | float oldScale=mScaleX;
148 | mScaleX *= detector.getScaleFactor();
149 | if (mScaleX < mScaleXMin) {
150 | mScaleX = mScaleXMin;
151 | } else if (mScaleX > mScaleXMax) {
152 | mScaleX = mScaleXMax;
153 | } else {
154 | onScaleChanged(mScaleX,oldScale);
155 | }
156 | return true;
157 | }
158 |
159 | protected void onScaleChanged(float scale,float oldScale)
160 | {
161 | invalidate();
162 | }
163 |
164 | @Override
165 | public boolean onScaleBegin(ScaleGestureDetector detector) {
166 | return true;
167 | }
168 |
169 | @Override
170 | public void onScaleEnd(ScaleGestureDetector detector) {
171 |
172 | }
173 |
174 | @Override
175 | public boolean onTouchEvent(MotionEvent event) {
176 | switch (event.getAction() & MotionEvent.ACTION_MASK) {
177 | case MotionEvent.ACTION_DOWN:
178 | touch = true;
179 | break;
180 | case MotionEvent.ACTION_MOVE:
181 | if (event.getPointerCount() == 1) {
182 | //长按之后移动
183 | if (isLongPress) {
184 | onLongPress(event);
185 | }
186 | }
187 | break;
188 | case MotionEvent.ACTION_POINTER_UP:
189 | invalidate();
190 | break;
191 | case MotionEvent.ACTION_UP:
192 | isLongPress = false;
193 | touch = false;
194 | invalidate();
195 | break;
196 | case MotionEvent.ACTION_CANCEL:
197 | isLongPress = false;
198 | touch = false;
199 | invalidate();
200 | break;
201 | }
202 | mMultipleTouch=event.getPointerCount()>1;
203 | this.mDetector.onTouchEvent(event);
204 | this.mScaleDetector.onTouchEvent(event);
205 | return true;
206 | }
207 |
208 |
209 | /**
210 | * 滑到了最左边
211 | */
212 | abstract public void onLeftSide();
213 |
214 | /**
215 | * 滑到了最右边
216 | */
217 | abstract public void onRightSide();
218 |
219 | /**
220 | * 是否在触摸中
221 | *
222 | * @return
223 | */
224 | public boolean isTouch() {
225 | return touch;
226 | }
227 |
228 | /**
229 | * 获取位移的最小值
230 | *
231 | * @return
232 | */
233 | public abstract int getMinScrollX();
234 |
235 | /**
236 | * 获取位移的最大值
237 | *
238 | * @return
239 | */
240 | public abstract int getMaxScrollX();
241 |
242 | /**
243 | * 设置ScrollX
244 | *
245 | * @param scrollX
246 | */
247 | public void setScrollX(int scrollX) {
248 | this.mScrollX = scrollX;
249 | scrollTo(scrollX, 0);
250 | }
251 |
252 | /**
253 | * 是否是多指触控
254 | * @return
255 | */
256 | public boolean isMultipleTouch() {
257 | return mMultipleTouch;
258 | }
259 |
260 | protected void checkAndFixScrollX() {
261 | if (mScrollX < getMinScrollX()) {
262 | mScrollX = getMinScrollX();
263 | mScroller.forceFinished(true);
264 | } else if (mScrollX > getMaxScrollX()) {
265 | mScrollX = getMaxScrollX();
266 | mScroller.forceFinished(true);
267 | }
268 | }
269 |
270 | public float getScaleXMax() {
271 | return mScaleXMax;
272 | }
273 |
274 | public float getScaleXMin() {
275 | return mScaleXMin;
276 | }
277 |
278 | public boolean isScrollEnable() {
279 | return mScrollEnable;
280 | }
281 |
282 | public boolean isScaleEnable() {
283 | return mScaleEnable;
284 | }
285 |
286 | /**
287 | * 设置缩放的最大值
288 | */
289 | public void setScaleXMax(float scaleXMax) {
290 | mScaleXMax = scaleXMax;
291 | }
292 |
293 | /**
294 | * 设置缩放的最小值
295 | */
296 | public void setScaleXMin(float scaleXMin) {
297 | mScaleXMin = scaleXMin;
298 | }
299 |
300 | /**
301 | * 设置是否可以滑动
302 | */
303 | public void setScrollEnable(boolean scrollEnable) {
304 | mScrollEnable = scrollEnable;
305 | }
306 |
307 | /**
308 | * 设置是否可以缩放
309 | */
310 | public void setScaleEnable(boolean scaleEnable) {
311 | mScaleEnable = scaleEnable;
312 | }
313 |
314 | @Override
315 | public float getScaleX() {
316 | return mScaleX;
317 | }
318 | }
319 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/TabView.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart;
2 |
3 | import android.content.Context;
4 | import android.content.res.ColorStateList;
5 | import android.util.AttributeSet;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.widget.RelativeLayout;
9 | import android.widget.TextView;
10 |
11 | import com.github.tifezh.kchartlib.R;
12 |
13 | /**
14 | * Created by tifezh on 2017/6/30.
15 | */
16 |
17 | public class TabView extends RelativeLayout{
18 |
19 | private TextView mTextView;
20 | private View mIndicator;
21 |
22 | public TabView(Context context) {
23 | this(context,null);
24 | }
25 |
26 | public TabView(Context context, AttributeSet attrs) {
27 | this(context, attrs,0);
28 | }
29 |
30 | public TabView(Context context, AttributeSet attrs, int defStyleAttr) {
31 | super(context, attrs, defStyleAttr);
32 | addView(LayoutInflater.from(getContext()).inflate(R.layout.item_tab, null));
33 | mTextView= (TextView) findViewById(R.id.tab_text);
34 | mIndicator=findViewById(R.id.indicator);
35 | }
36 |
37 | public void setTextColor(ColorStateList color)
38 | {
39 | if(color!=null) {
40 | mTextView.setTextColor(color);
41 | }
42 | }
43 |
44 | public void setText(String text)
45 | {
46 | mTextView.setText(text);
47 | }
48 |
49 | public void setIndicatorColor(int color)
50 | {
51 | mIndicator.setBackgroundColor(color);
52 | }
53 |
54 | @Override
55 | public void setSelected(boolean selected) {
56 | super.setSelected(selected);
57 | mIndicator.setVisibility(selected?VISIBLE:INVISIBLE);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/base/IAdapter.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart.base;
2 |
3 | import android.database.DataSetObserver;
4 |
5 | import java.util.Date;
6 |
7 |
8 | /**
9 | * 数据适配器
10 | * Created by tifezh on 2016/6/14.
11 | */
12 |
13 | public interface IAdapter {
14 | /**
15 | * 获取点的数目
16 | *
17 | * @return
18 | */
19 | int getCount();
20 |
21 | /**
22 | * 通过序号获取item
23 | *
24 | * @param position 对应的序号
25 | * @return 数据实体
26 | */
27 | Object getItem(int position);
28 |
29 | /**
30 | * 通过序号获取时间
31 | *
32 | * @param position
33 | * @return
34 | */
35 | Date getDate(int position);
36 |
37 | /**
38 | * 注册一个数据观察者
39 | *
40 | * @param observer 数据观察者
41 | */
42 | void registerDataSetObserver(DataSetObserver observer);
43 |
44 | /**
45 | * 移除一个数据观察者
46 | *
47 | * @param observer 数据观察者
48 | */
49 | void unregisterDataSetObserver(DataSetObserver observer);
50 |
51 | /**
52 | * 当数据发生变化时调用
53 | */
54 | void notifyDataSetChanged();
55 | }
56 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/base/IChartDraw.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart.base;
2 |
3 | import android.graphics.Canvas;
4 | import android.support.annotation.NonNull;
5 | import android.support.annotation.Nullable;
6 |
7 | import com.github.tifezh.kchartlib.chart.BaseKChartView;
8 |
9 |
10 | /**
11 | * 画图的基类 根据实体来画图形
12 | * Created by tifezh on 2016/6/14.
13 | */
14 |
15 | public interface IChartDraw {
16 | /**
17 | * 需要滑动 物体draw方法
18 | *
19 | * @param canvas canvas
20 | * @param view k线图View
21 | * @param position 当前点的位置
22 | * @param lastPoint 上一个点
23 | * @param curPoint 当前点
24 | * @param lastX 上一个点的x坐标
25 | * @param curX 当前点的X坐标
26 | */
27 | void drawTranslated(@Nullable T lastPoint, @NonNull T curPoint, float lastX, float curX, @NonNull Canvas canvas, @NonNull BaseKChartView view, int position);
28 |
29 | /**
30 | * @param canvas
31 | * @param view
32 | * @param position 该点的位置
33 | * @param x x的起始坐标
34 | * @param y y的起始坐标
35 | */
36 | void drawText(@NonNull Canvas canvas, @NonNull BaseKChartView view, int position, float x, float y);
37 |
38 | /**
39 | * 获取当前实体中最大的值
40 | *
41 | * @param point
42 | * @return
43 | */
44 | float getMaxValue(T point);
45 |
46 | /**
47 | * 获取当前实体中最小的值
48 | *
49 | * @param point
50 | * @return
51 | */
52 | float getMinValue(T point);
53 |
54 | /**
55 | * 获取value格式化器
56 | */
57 | IValueFormatter getValueFormatter();
58 | }
59 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/base/IDateTimeFormatter.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart.base;
2 |
3 | import java.util.Date;
4 |
5 | /**
6 | * 时间格式化接口
7 | * Created by tifezh on 2016/6/21.
8 | */
9 |
10 | public interface IDateTimeFormatter {
11 | String format(Date date);
12 | }
13 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/base/IValueFormatter.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart.base;
2 |
3 | /**
4 | * Value格式化接口
5 | * Created by tifezh on 2016/6/21.
6 | */
7 |
8 | public interface IValueFormatter {
9 | /**
10 | * 格式化value
11 | *
12 | * @param value 传入的value值
13 | * @return 返回字符串
14 | */
15 | String format(float value);
16 | }
17 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/draw/BOLLDraw.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart.draw;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Paint;
5 | import android.support.annotation.NonNull;
6 | import android.support.annotation.Nullable;
7 |
8 | import com.github.tifezh.kchartlib.chart.BaseKChartView;
9 | import com.github.tifezh.kchartlib.chart.entity.IBOLL;
10 | import com.github.tifezh.kchartlib.chart.base.IChartDraw;
11 | import com.github.tifezh.kchartlib.chart.base.IValueFormatter;
12 | import com.github.tifezh.kchartlib.chart.formatter.ValueFormatter;
13 |
14 | /**
15 | * BOLL实现类
16 | * Created by tifezh on 2016/6/19.
17 | */
18 |
19 | public class BOLLDraw implements IChartDraw {
20 |
21 | private Paint mUpPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
22 | private Paint mMbPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
23 | private Paint mDnPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
24 |
25 | public BOLLDraw(BaseKChartView view) {
26 |
27 | }
28 |
29 | @Override
30 | public void drawTranslated(@Nullable IBOLL lastPoint, @NonNull IBOLL curPoint, float lastX, float curX, @NonNull Canvas canvas, @NonNull BaseKChartView view, int position) {
31 | view.drawChildLine(canvas, mUpPaint, lastX, lastPoint.getUp(), curX, curPoint.getUp());
32 | view.drawChildLine(canvas, mMbPaint, lastX, lastPoint.getMb(), curX, curPoint.getMb());
33 | view.drawChildLine(canvas, mDnPaint, lastX, lastPoint.getDn(), curX, curPoint.getDn());
34 | }
35 |
36 | @Override
37 | public void drawText(@NonNull Canvas canvas, @NonNull BaseKChartView view, int position, float x, float y) {
38 | String text = "";
39 | IBOLL point = (IBOLL) view.getItem(position);
40 | text = "UP:" + view.formatValue(point.getUp()) + " ";
41 | canvas.drawText(text, x, y, mUpPaint);
42 | x += mUpPaint.measureText(text);
43 | text = "MB:" + view.formatValue(point.getMb()) + " ";
44 | canvas.drawText(text, x, y, mMbPaint);
45 | x += mMbPaint.measureText(text);
46 | text = "DN:" + view.formatValue(point.getDn()) + " ";
47 | canvas.drawText(text, x, y, mDnPaint);
48 | }
49 |
50 | @Override
51 | public float getMaxValue(IBOLL point) {
52 | if (Float.isNaN(point.getUp())) {
53 | return point.getMb();
54 | }
55 | return point.getUp();
56 | }
57 |
58 | @Override
59 | public float getMinValue(IBOLL point) {
60 | if (Float.isNaN(point.getDn())) {
61 | return point.getMb();
62 | }
63 | return point.getDn();
64 | }
65 |
66 | @Override
67 | public IValueFormatter getValueFormatter() {
68 | return new ValueFormatter();
69 | }
70 |
71 | /**
72 | * 设置up颜色
73 | */
74 | public void setUpColor(int color) {
75 | mUpPaint.setColor(color);
76 | }
77 |
78 | /**
79 | * 设置mb颜色
80 | * @param color
81 | */
82 | public void setMbColor(int color) {
83 | mMbPaint.setColor(color);
84 | }
85 |
86 | /**
87 | * 设置dn颜色
88 | */
89 | public void setDnColor(int color) {
90 | mDnPaint.setColor(color);
91 | }
92 |
93 | /**
94 | * 设置曲线宽度
95 | */
96 | public void setLineWidth(float width)
97 | {
98 | mUpPaint.setStrokeWidth(width);
99 | mMbPaint.setStrokeWidth(width);
100 | mDnPaint.setStrokeWidth(width);
101 | }
102 |
103 | /**
104 | * 设置文字大小
105 | */
106 | public void setTextSize(float textSize)
107 | {
108 | mUpPaint.setTextSize(textSize);
109 | mMbPaint.setTextSize(textSize);
110 | mDnPaint.setTextSize(textSize);
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/draw/KDJDraw.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart.draw;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Paint;
5 | import android.support.annotation.NonNull;
6 | import android.support.annotation.Nullable;
7 |
8 | import com.github.tifezh.kchartlib.chart.BaseKChartView;
9 | import com.github.tifezh.kchartlib.chart.entity.IKDJ;
10 | import com.github.tifezh.kchartlib.chart.base.IChartDraw;
11 | import com.github.tifezh.kchartlib.chart.base.IValueFormatter;
12 | import com.github.tifezh.kchartlib.chart.formatter.ValueFormatter;
13 |
14 | /**
15 | * KDJ实现类
16 | * Created by tifezh on 2016/6/19.
17 | */
18 |
19 | public class KDJDraw implements IChartDraw {
20 |
21 | private Paint mKPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
22 | private Paint mDPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
23 | private Paint mJPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
24 |
25 | public KDJDraw(BaseKChartView view) {
26 | }
27 |
28 | @Override
29 | public void drawTranslated(@Nullable IKDJ lastPoint, @NonNull IKDJ curPoint, float lastX, float curX, @NonNull Canvas canvas, @NonNull BaseKChartView view, int position) {
30 | view.drawChildLine(canvas, mKPaint, lastX, lastPoint.getK(), curX, curPoint.getK());
31 | view.drawChildLine(canvas, mDPaint, lastX, lastPoint.getD(), curX, curPoint.getD());
32 | view.drawChildLine(canvas, mJPaint, lastX, lastPoint.getJ(), curX, curPoint.getJ());
33 | }
34 |
35 | @Override
36 | public void drawText(@NonNull Canvas canvas, @NonNull BaseKChartView view, int position, float x, float y) {
37 | String text = "";
38 | IKDJ point = (IKDJ) view.getItem(position);
39 | text = "K:" + view.formatValue(point.getK()) + " ";
40 | canvas.drawText(text, x, y, mKPaint);
41 | x += mKPaint.measureText(text);
42 | text = "D:" + view.formatValue(point.getD()) + " ";
43 | canvas.drawText(text, x, y, mDPaint);
44 | x += mDPaint.measureText(text);
45 | text = "J:" + view.formatValue(point.getJ()) + " ";
46 | canvas.drawText(text, x, y, mJPaint);
47 | }
48 |
49 | @Override
50 | public float getMaxValue(IKDJ point) {
51 | return Math.max(point.getK(), Math.max(point.getD(), point.getJ()));
52 | }
53 |
54 | @Override
55 | public float getMinValue(IKDJ point) {
56 | return Math.min(point.getK(), Math.min(point.getD(), point.getJ()));
57 | }
58 |
59 | @Override
60 | public IValueFormatter getValueFormatter() {
61 | return new ValueFormatter();
62 | }
63 |
64 | /**
65 | * 设置K颜色
66 | */
67 | public void setKColor(int color) {
68 | mKPaint.setColor(color);
69 | }
70 |
71 | /**
72 | * 设置D颜色
73 | */
74 | public void setDColor(int color) {
75 | mDPaint.setColor(color);
76 | }
77 |
78 | /**
79 | * 设置J颜色
80 | */
81 | public void setJColor(int color) {
82 | mJPaint.setColor(color);
83 | }
84 |
85 | /**
86 | * 设置曲线宽度
87 | */
88 | public void setLineWidth(float width)
89 | {
90 | mKPaint.setStrokeWidth(width);
91 | mDPaint.setStrokeWidth(width);
92 | mJPaint.setStrokeWidth(width);
93 | }
94 |
95 | /**
96 | * 设置文字大小
97 | */
98 | public void setTextSize(float textSize)
99 | {
100 | mKPaint.setTextSize(textSize);
101 | mDPaint.setTextSize(textSize);
102 | mJPaint.setTextSize(textSize);
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/draw/MACDDraw.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart.draw;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Paint;
6 | import android.support.annotation.NonNull;
7 | import android.support.annotation.Nullable;
8 | import android.support.v4.content.ContextCompat;
9 |
10 | import com.github.tifezh.kchartlib.R;
11 | import com.github.tifezh.kchartlib.chart.BaseKChartView;
12 | import com.github.tifezh.kchartlib.chart.entity.IMACD;
13 | import com.github.tifezh.kchartlib.chart.base.IChartDraw;
14 | import com.github.tifezh.kchartlib.chart.base.IValueFormatter;
15 | import com.github.tifezh.kchartlib.chart.formatter.ValueFormatter;
16 |
17 | /**
18 | * macd实现类
19 | * Created by tifezh on 2016/6/19.
20 | */
21 |
22 | public class MACDDraw implements IChartDraw {
23 |
24 | private Paint mRedPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
25 | private Paint mGreenPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
26 | private Paint mDIFPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
27 | private Paint mDEAPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
28 | private Paint mMACDPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
29 | /**macd 中柱子的宽度*/
30 | private float mMACDWidth = 0;
31 |
32 | public MACDDraw(BaseKChartView view) {
33 | Context context=view.getContext();
34 | mRedPaint.setColor(ContextCompat.getColor(context,R.color.chart_red));
35 | mGreenPaint.setColor(ContextCompat.getColor(context,R.color.chart_green));
36 | }
37 |
38 | @Override
39 | public void drawTranslated(@Nullable IMACD lastPoint, @NonNull IMACD curPoint, float lastX, float curX, @NonNull Canvas canvas, @NonNull BaseKChartView view, int position) {
40 | drawMACD(canvas, view, curX, curPoint.getMacd());
41 | view.drawChildLine(canvas, mDIFPaint, lastX, lastPoint.getDea(), curX, curPoint.getDea());
42 | view.drawChildLine(canvas, mDEAPaint, lastX, lastPoint.getDif(), curX, curPoint.getDif());
43 | }
44 |
45 | @Override
46 | public void drawText(@NonNull Canvas canvas, @NonNull BaseKChartView view, int position, float x, float y) {
47 | String text = "";
48 | IMACD point = (IMACD) view.getItem(position);
49 | text = "DIF:" + view.formatValue(point.getDif()) + " ";
50 | canvas.drawText(text, x, y, mDEAPaint);
51 | x += mDIFPaint.measureText(text);
52 | text = "DEA:" + view.formatValue(point.getDea()) + " ";
53 | canvas.drawText(text, x, y, mDIFPaint);
54 | x += mDEAPaint.measureText(text);
55 | text = "MACD:" + view.formatValue(point.getMacd()) + " ";
56 | canvas.drawText(text, x, y, mMACDPaint);
57 | }
58 |
59 | @Override
60 | public float getMaxValue(IMACD point) {
61 | return Math.max(point.getMacd(), Math.max(point.getDea(), point.getDif()));
62 | }
63 |
64 | @Override
65 | public float getMinValue(IMACD point) {
66 | return Math.min(point.getMacd(), Math.min(point.getDea(), point.getDif()));
67 | }
68 |
69 | @Override
70 | public IValueFormatter getValueFormatter() {
71 | return new ValueFormatter();
72 | }
73 |
74 | /**
75 | * 画macd
76 | * @param canvas
77 | * @param x
78 | * @param macd
79 | */
80 | private void drawMACD(Canvas canvas, BaseKChartView view, float x, float macd) {
81 | float macdy = view.getChildY(macd);
82 | float r = mMACDWidth / 2;
83 | float zeroy = view.getChildY(0);
84 | if (macd > 0) {
85 | // left top right bottom
86 | canvas.drawRect(x - r, macdy, x + r, zeroy, mRedPaint);
87 | } else {
88 | canvas.drawRect(x - r, zeroy, x + r, macdy, mGreenPaint);
89 | }
90 | }
91 |
92 | /**
93 | * 设置DIF颜色
94 | */
95 | public void setDIFColor(int color) {
96 | this.mDIFPaint.setColor(color);
97 | }
98 |
99 | /**
100 | * 设置DEA颜色
101 | */
102 | public void setDEAColor(int color) {
103 | this.mDEAPaint.setColor(color);
104 | }
105 |
106 | /**
107 | * 设置MACD颜色
108 | */
109 | public void setMACDColor(int color) {
110 | this.mMACDPaint.setColor(color);
111 | }
112 |
113 | /**
114 | * 设置MACD的宽度
115 | * @param MACDWidth
116 | */
117 | public void setMACDWidth(float MACDWidth) {
118 | mMACDWidth = MACDWidth;
119 | }
120 |
121 | /**
122 | * 设置曲线宽度
123 | */
124 | public void setLineWidth(float width)
125 | {
126 | mDEAPaint.setStrokeWidth(width);
127 | mDIFPaint.setStrokeWidth(width);
128 | mMACDPaint.setStrokeWidth(width);
129 | }
130 |
131 | /**
132 | * 设置文字大小
133 | */
134 | public void setTextSize(float textSize)
135 | {
136 | mDEAPaint.setTextSize(textSize);
137 | mDIFPaint.setTextSize(textSize);
138 | mMACDPaint.setTextSize(textSize);
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/draw/MainDraw.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart.draw;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Paint;
6 | import android.graphics.RectF;
7 | import android.support.annotation.NonNull;
8 | import android.support.annotation.Nullable;
9 | import android.support.v4.content.ContextCompat;
10 |
11 | import com.github.tifezh.kchartlib.R;
12 | import com.github.tifezh.kchartlib.chart.BaseKChartView;
13 | import com.github.tifezh.kchartlib.chart.entity.ICandle;
14 | import com.github.tifezh.kchartlib.chart.entity.IKLine;
15 | import com.github.tifezh.kchartlib.chart.base.IChartDraw;
16 | import com.github.tifezh.kchartlib.chart.base.IValueFormatter;
17 | import com.github.tifezh.kchartlib.chart.formatter.ValueFormatter;
18 | import com.github.tifezh.kchartlib.utils.ViewUtil;
19 |
20 | import java.util.ArrayList;
21 | import java.util.List;
22 |
23 | /**
24 | * 主图的实现类
25 | * Created by tifezh on 2016/6/14.
26 | */
27 |
28 | public class MainDraw implements IChartDraw{
29 |
30 | private float mCandleWidth = 0;
31 | private float mCandleLineWidth = 0;
32 | private Paint mRedPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
33 | private Paint mGreenPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
34 | private Paint ma5Paint = new Paint(Paint.ANTI_ALIAS_FLAG);
35 | private Paint ma10Paint = new Paint(Paint.ANTI_ALIAS_FLAG);
36 | private Paint ma20Paint = new Paint(Paint.ANTI_ALIAS_FLAG);
37 |
38 | private Paint mSelectorTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
39 | private Paint mSelectorBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
40 | private Context mContext;
41 |
42 | private boolean mCandleSolid=true;
43 |
44 | public MainDraw(BaseKChartView view) {
45 | Context context=view.getContext();
46 | mContext=context;
47 | mRedPaint.setColor(ContextCompat.getColor(context,R.color.chart_red));
48 | mGreenPaint.setColor(ContextCompat.getColor(context,R.color.chart_green));
49 | }
50 |
51 | @Override
52 | public void drawTranslated(@Nullable ICandle lastPoint, @NonNull ICandle curPoint, float lastX, float curX, @NonNull Canvas canvas, @NonNull BaseKChartView view, int position) {
53 | drawCandle(view, canvas, curX, curPoint.getHighPrice(), curPoint.getLowPrice(), curPoint.getOpenPrice(), curPoint.getClosePrice());
54 | //画ma5
55 | if (lastPoint.getMA5Price() != 0) {
56 | view.drawMainLine(canvas, ma5Paint, lastX, lastPoint.getMA5Price(), curX, curPoint.getMA5Price());
57 | }
58 | //画ma10
59 | if (lastPoint.getMA10Price() != 0) {
60 | view.drawMainLine(canvas, ma10Paint, lastX, lastPoint.getMA10Price(), curX, curPoint.getMA10Price());
61 | }
62 | //画ma20
63 | if (lastPoint.getMA20Price() != 0) {
64 | view.drawMainLine(canvas, ma20Paint, lastX, lastPoint.getMA20Price(), curX, curPoint.getMA20Price());
65 | }
66 | }
67 |
68 | @Override
69 | public void drawText(@NonNull Canvas canvas, @NonNull BaseKChartView view, int position, float x, float y) {
70 | ICandle point = (IKLine) view.getItem(position);
71 | String text = "MA5:" + view.formatValue(point.getMA5Price()) + " ";
72 | canvas.drawText(text, x, y, ma5Paint);
73 | x += ma5Paint.measureText(text);
74 | text = "MA10:" + view.formatValue(point.getMA10Price()) + " ";
75 | canvas.drawText(text, x, y, ma10Paint);
76 | x += ma10Paint.measureText(text);
77 | text = "MA20:" + view.formatValue(point.getMA20Price()) + " ";
78 | canvas.drawText(text, x, y, ma20Paint);
79 | if (view.isLongPress()) {
80 | drawSelector(view, canvas);
81 | }
82 | }
83 |
84 | @Override
85 | public float getMaxValue(ICandle point) {
86 | return Math.max(point.getHighPrice(), point.getMA20Price());
87 | }
88 |
89 | @Override
90 | public float getMinValue(ICandle point) {
91 | return Math.min(point.getMA20Price(), point.getLowPrice());
92 | }
93 |
94 | @Override
95 | public IValueFormatter getValueFormatter() {
96 | return new ValueFormatter();
97 | }
98 |
99 | /**
100 | * 画Candle
101 | * @param canvas
102 | * @param x x轴坐标
103 | * @param high 最高价
104 | * @param low 最低价
105 | * @param open 开盘价
106 | * @param close 收盘价
107 | */
108 | private void drawCandle(BaseKChartView view, Canvas canvas, float x, float high, float low, float open, float close) {
109 | high = view.getMainY(high);
110 | low = view.getMainY(low);
111 | open = view.getMainY(open);
112 | close = view.getMainY(close);
113 | float r = mCandleWidth / 2;
114 | float lineR = mCandleLineWidth / 2;
115 | if (open > close) {
116 | //实心
117 | if(mCandleSolid) {
118 | canvas.drawRect(x - r, close, x + r, open, mRedPaint);
119 | canvas.drawRect(x - lineR, high, x + lineR, low, mRedPaint);
120 | }
121 | else {
122 | mRedPaint.setStrokeWidth(mCandleLineWidth);
123 | canvas.drawLine(x, high, x, close, mRedPaint);
124 | canvas.drawLine(x, open, x, low, mRedPaint);
125 | canvas.drawLine(x - r + lineR, open, x - r + lineR, close, mRedPaint);
126 | canvas.drawLine(x + r - lineR, open, x + r - lineR, close, mRedPaint);
127 | mRedPaint.setStrokeWidth(mCandleLineWidth * view.getScaleX());
128 | canvas.drawLine(x - r, open, x + r, open, mRedPaint);
129 | canvas.drawLine(x - r, close, x + r, close, mRedPaint);
130 | }
131 |
132 | } else if (open < close) {
133 | canvas.drawRect(x - r, open, x + r, close, mGreenPaint);
134 | canvas.drawRect(x - lineR, high, x + lineR, low, mGreenPaint);
135 | } else {
136 | canvas.drawRect(x - r, open, x + r, close + 1, mRedPaint);
137 | canvas.drawRect(x - lineR, high, x + lineR, low, mRedPaint);
138 | }
139 | }
140 |
141 | /**
142 | * draw选择器
143 | * @param view
144 | * @param canvas
145 | */
146 | private void drawSelector(BaseKChartView view, Canvas canvas) {
147 | Paint.FontMetrics metrics = mSelectorTextPaint.getFontMetrics();
148 | float textHeight = metrics.descent - metrics.ascent;
149 |
150 | int index = view.getSelectedIndex();
151 | float padding = ViewUtil.Dp2Px(mContext, 5);
152 | float margin = ViewUtil.Dp2Px(mContext, 5);
153 | float width = 0;
154 | float left;
155 | float top = margin+view.getTopPadding();
156 | float height = padding * 8 + textHeight * 5;
157 |
158 | ICandle point = (ICandle) view.getItem(index);
159 | List strings = new ArrayList<>();
160 | strings.add(view.formatDateTime(view.getAdapter().getDate(index)));
161 | strings.add("高:" + point.getHighPrice());
162 | strings.add("低:" + point.getLowPrice());
163 | strings.add("开:" + point.getOpenPrice());
164 | strings.add("收:" + point.getClosePrice());
165 |
166 | for (String s : strings) {
167 | width = Math.max(width, mSelectorTextPaint.measureText(s));
168 | }
169 | width += padding * 2;
170 |
171 | float x = view.translateXtoX(view.getX(index));
172 | if (x > view.getChartWidth() / 2) {
173 | left = margin;
174 | } else {
175 | left = view.getChartWidth() - width - margin;
176 | }
177 |
178 | RectF r = new RectF(left, top, left + width, top + height);
179 | canvas.drawRoundRect(r, padding, padding, mSelectorBackgroundPaint);
180 | float y = top + padding * 2 + (textHeight - metrics.bottom - metrics.top) / 2;
181 |
182 | for (String s : strings) {
183 | canvas.drawText(s, left + padding, y, mSelectorTextPaint);
184 | y += textHeight + padding;
185 | }
186 |
187 | }
188 |
189 | /**
190 | * 设置蜡烛宽度
191 | * @param candleWidth
192 | */
193 | public void setCandleWidth(float candleWidth) {
194 | mCandleWidth = candleWidth;
195 | }
196 |
197 | /**
198 | * 设置蜡烛线宽度
199 | * @param candleLineWidth
200 | */
201 | public void setCandleLineWidth(float candleLineWidth) {
202 | mCandleLineWidth = candleLineWidth;
203 | }
204 |
205 | /**
206 | * 设置ma5颜色
207 | * @param color
208 | */
209 | public void setMa5Color(int color) {
210 | this.ma5Paint.setColor(color);
211 | }
212 |
213 | /**
214 | * 设置ma10颜色
215 | * @param color
216 | */
217 | public void setMa10Color(int color) {
218 | this.ma10Paint.setColor(color);
219 | }
220 |
221 | /**
222 | * 设置ma20颜色
223 | * @param color
224 | */
225 | public void setMa20Color(int color) {
226 | this.ma20Paint.setColor(color);
227 | }
228 |
229 | /**
230 | * 设置选择器文字颜色
231 | * @param color
232 | */
233 | public void setSelectorTextColor(int color) {
234 | mSelectorTextPaint.setColor(color);
235 | }
236 |
237 | /**
238 | * 设置选择器文字大小
239 | * @param textSize
240 | */
241 | public void setSelectorTextSize(float textSize){
242 | mSelectorTextPaint.setTextSize(textSize);
243 | }
244 |
245 | /**
246 | * 设置选择器背景
247 | * @param color
248 | */
249 | public void setSelectorBackgroundColor(int color) {
250 | mSelectorBackgroundPaint.setColor(color);
251 | }
252 |
253 | /**
254 | * 设置曲线宽度
255 | */
256 | public void setLineWidth(float width)
257 | {
258 | ma20Paint.setStrokeWidth(width);
259 | ma10Paint.setStrokeWidth(width);
260 | ma5Paint.setStrokeWidth(width);
261 | }
262 |
263 | /**
264 | * 设置文字大小
265 | */
266 | public void setTextSize(float textSize)
267 | {
268 | ma20Paint.setTextSize(textSize);
269 | ma10Paint.setTextSize(textSize);
270 | ma5Paint.setTextSize(textSize);
271 | }
272 |
273 | /**
274 | * 蜡烛是否实心
275 | */
276 | public void setCandleSolid(boolean candleSolid) {
277 | mCandleSolid = candleSolid;
278 | }
279 | }
280 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/draw/RSIDraw.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart.draw;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Paint;
5 | import android.support.annotation.NonNull;
6 | import android.support.annotation.Nullable;
7 |
8 | import com.github.tifezh.kchartlib.chart.BaseKChartView;
9 | import com.github.tifezh.kchartlib.chart.entity.IRSI;
10 | import com.github.tifezh.kchartlib.chart.base.IChartDraw;
11 | import com.github.tifezh.kchartlib.chart.base.IValueFormatter;
12 | import com.github.tifezh.kchartlib.chart.formatter.ValueFormatter;
13 |
14 | /**
15 | * RSI实现类
16 | * Created by tifezh on 2016/6/19.
17 | */
18 |
19 | public class RSIDraw implements IChartDraw {
20 |
21 | private Paint mRSI1Paint = new Paint(Paint.ANTI_ALIAS_FLAG);
22 | private Paint mRSI2Paint = new Paint(Paint.ANTI_ALIAS_FLAG);
23 | private Paint mRSI3Paint = new Paint(Paint.ANTI_ALIAS_FLAG);
24 |
25 | public RSIDraw(BaseKChartView view) {
26 |
27 | }
28 |
29 | @Override
30 | public void drawTranslated(@Nullable IRSI lastPoint, @NonNull IRSI curPoint, float lastX, float curX, @NonNull Canvas canvas, @NonNull BaseKChartView view, int position) {
31 | view.drawChildLine(canvas, mRSI1Paint, lastX, lastPoint.getRsi1(), curX, curPoint.getRsi1());
32 | view.drawChildLine(canvas, mRSI2Paint, lastX, lastPoint.getRsi2(), curX, curPoint.getRsi2());
33 | view.drawChildLine(canvas, mRSI3Paint, lastX, lastPoint.getRsi3(), curX, curPoint.getRsi3());
34 | }
35 |
36 | @Override
37 | public void drawText(@NonNull Canvas canvas, @NonNull BaseKChartView view, int position, float x, float y) {
38 | String text = "";
39 | IRSI point = (IRSI) view.getItem(position);
40 | text = "RSI1:" + view.formatValue(point.getRsi1()) + " ";
41 | canvas.drawText(text, x, y, mRSI1Paint);
42 | x += mRSI1Paint.measureText(text);
43 | text = "RSI2:" + view.formatValue(point.getRsi2()) + " ";
44 | canvas.drawText(text, x, y, mRSI2Paint);
45 | x += mRSI2Paint.measureText(text);
46 | text = "RSI3:" + view.formatValue(point.getRsi3()) + " ";
47 | canvas.drawText(text, x, y, mRSI3Paint);
48 | }
49 |
50 | @Override
51 | public float getMaxValue(IRSI point) {
52 | return Math.max(point.getRsi1(), Math.max(point.getRsi2(), point.getRsi3()));
53 | }
54 |
55 | @Override
56 | public float getMinValue(IRSI point) {
57 | return Math.min(point.getRsi1(), Math.min(point.getRsi2(), point.getRsi3()));
58 | }
59 |
60 | @Override
61 | public IValueFormatter getValueFormatter() {
62 | return new ValueFormatter();
63 | }
64 |
65 | public void setRSI1Color(int color) {
66 | mRSI1Paint.setColor(color);
67 | }
68 |
69 | public void setRSI2Color(int color) {
70 | mRSI2Paint.setColor(color);
71 | }
72 |
73 | public void setRSI3Color(int color) {
74 | mRSI3Paint.setColor(color);
75 | }
76 |
77 | /**
78 | * 设置曲线宽度
79 | */
80 | public void setLineWidth(float width)
81 | {
82 | mRSI1Paint.setStrokeWidth(width);
83 | mRSI2Paint.setStrokeWidth(width);
84 | mRSI3Paint.setStrokeWidth(width);
85 | }
86 |
87 | /**
88 | * 设置文字大小
89 | */
90 | public void setTextSize(float textSize)
91 | {
92 | mRSI2Paint.setTextSize(textSize);
93 | mRSI3Paint.setTextSize(textSize);
94 | mRSI1Paint.setTextSize(textSize);
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/draw/VolumeDraw.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart.draw;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Paint;
6 | import android.support.annotation.NonNull;
7 | import android.support.annotation.Nullable;
8 | import android.support.v4.content.ContextCompat;
9 |
10 | import com.github.tifezh.kchartlib.R;
11 | import com.github.tifezh.kchartlib.chart.BaseKChartView;
12 | import com.github.tifezh.kchartlib.chart.entity.IVolume;
13 | import com.github.tifezh.kchartlib.chart.base.IChartDraw;
14 | import com.github.tifezh.kchartlib.chart.base.IValueFormatter;
15 | import com.github.tifezh.kchartlib.chart.formatter.BigValueFormatter;
16 | import com.github.tifezh.kchartlib.utils.ViewUtil;
17 |
18 | /**
19 | * Created by hjm on 2017/11/14 17:49.
20 | */
21 |
22 | public class VolumeDraw implements IChartDraw {
23 |
24 | private Paint mRedPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
25 | private Paint mGreenPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
26 | private Paint ma5Paint = new Paint(Paint.ANTI_ALIAS_FLAG);
27 | private Paint ma10Paint = new Paint(Paint.ANTI_ALIAS_FLAG);
28 | private int pillarWidth = 0;
29 |
30 | public VolumeDraw(BaseKChartView view) {
31 | Context context = view.getContext();
32 | mRedPaint.setColor(ContextCompat.getColor(context, R.color.chart_red));
33 | mGreenPaint.setColor(ContextCompat.getColor(context, R.color.chart_green));
34 | pillarWidth = ViewUtil.Dp2Px(context, 4);
35 | }
36 |
37 | @Override
38 | public void drawTranslated(
39 | @Nullable IVolume lastPoint, @NonNull IVolume curPoint, float lastX, float curX,
40 | @NonNull Canvas canvas, @NonNull BaseKChartView view, int position) {
41 |
42 | drawHistogram(canvas, curPoint, lastPoint, curX, view, position);
43 | view.drawChildLine(canvas, ma5Paint, lastX, lastPoint.getMA5Volume(), curX, curPoint.getMA5Volume());
44 | view.drawChildLine(canvas, ma10Paint, lastX, lastPoint.getMA10Volume(), curX, curPoint.getMA10Volume());
45 | }
46 |
47 | private void drawHistogram(
48 | Canvas canvas, IVolume curPoint, IVolume lastPoint, float curX,
49 | BaseKChartView view, int position) {
50 |
51 | float r = pillarWidth / 2;
52 | float top = view.getChildY(curPoint.getVolume());
53 | int bottom = view.getChildRect().bottom;
54 | if (curPoint.getClosePrice() >= curPoint.getOpenPrice()) {//涨
55 | canvas.drawRect(curX - r, top, curX + r, bottom, mRedPaint);
56 | } else {
57 | canvas.drawRect(curX - r, top, curX + r, bottom, mGreenPaint);
58 | }
59 |
60 | }
61 |
62 | @Override
63 | public void drawText(
64 | @NonNull Canvas canvas, @NonNull BaseKChartView view, int position, float x, float y) {
65 | IVolume point = (IVolume) view.getItem(position);
66 | String text = "VOL:" + getValueFormatter().format(point.getVolume()) + " ";
67 | canvas.drawText(text, x, y, view.getTextPaint());
68 | x += view.getTextPaint().measureText(text);
69 | text = "MA5:" + getValueFormatter().format(point.getMA5Volume()) + " ";
70 | canvas.drawText(text, x, y, ma5Paint);
71 | x += ma5Paint.measureText(text);
72 | text = "MA10:" + getValueFormatter().format(point.getMA10Volume()) + " ";
73 | canvas.drawText(text, x, y, ma10Paint);
74 | }
75 |
76 | @Override
77 | public float getMaxValue(IVolume point) {
78 | return Math.max(point.getVolume(), Math.max(point.getMA5Volume(), point.getMA10Volume()));
79 | }
80 |
81 | @Override
82 | public float getMinValue(IVolume point) {
83 | return Math.min(point.getVolume(), Math.min(point.getMA5Volume(), point.getMA10Volume()));
84 | }
85 |
86 | @Override
87 | public IValueFormatter getValueFormatter() {
88 | return new BigValueFormatter();
89 | }
90 |
91 | /**
92 | * 设置 MA5 线的颜色
93 | *
94 | * @param color
95 | */
96 | public void setMa5Color(int color) {
97 | this.ma5Paint.setColor(color);
98 | }
99 |
100 | /**
101 | * 设置 MA10 线的颜色
102 | *
103 | * @param color
104 | */
105 | public void setMa10Color(int color) {
106 | this.ma10Paint.setColor(color);
107 | }
108 |
109 | public void setLineWidth(float width) {
110 | this.ma5Paint.setStrokeWidth(width);
111 | this.ma10Paint.setStrokeWidth(width);
112 | }
113 |
114 | /**
115 | * 设置文字大小
116 | *
117 | * @param textSize
118 | */
119 | public void setTextSize(float textSize) {
120 | this.ma5Paint.setTextSize(textSize);
121 | this.ma10Paint.setTextSize(textSize);
122 | }
123 |
124 | }
125 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/entity/IBOLL.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart.entity;
2 |
3 | /**
4 | * 布林线指标接口
5 | * @see 相关说明
6 | * Created by tifezh on 2016/6/10.
7 | */
8 |
9 | public interface IBOLL {
10 |
11 | /**
12 | * 上轨线
13 | */
14 | float getUp();
15 |
16 | /**
17 | * 中轨线
18 | */
19 | float getMb();
20 |
21 | /**
22 | * 下轨线
23 | */
24 | float getDn();
25 | }
26 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/entity/ICandle.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart.entity;
2 |
3 | /**
4 | * 蜡烛图实体接口
5 | * Created by tifezh on 2016/6/9.
6 | */
7 |
8 | public interface ICandle {
9 |
10 | /**
11 | * 开盘价
12 | */
13 | float getOpenPrice();
14 |
15 | /**
16 | * 最高价
17 | */
18 | float getHighPrice();
19 |
20 | /**
21 | * 最低价
22 | */
23 | float getLowPrice();
24 |
25 | /**
26 | * 收盘价
27 | */
28 | float getClosePrice();
29 |
30 | /**
31 | * 五(月,日,时,分,5分等)均价
32 | */
33 | float getMA5Price();
34 |
35 | /**
36 | * 十(月,日,时,分,5分等)均价
37 | */
38 | float getMA10Price();
39 |
40 | /**
41 | * 二十(月,日,时,分,5分等)均价
42 | */
43 | float getMA20Price();
44 | }
45 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/entity/IKDJ.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart.entity;
2 |
3 | /**
4 | * KDJ指标(随机指标)接口
5 | * @see 相关说明
6 | * Created by tifezh on 2016/6/10.
7 | */
8 | public interface IKDJ {
9 |
10 | /**
11 | * K值
12 | */
13 | float getK();
14 |
15 | /**
16 | * D值
17 | */
18 | float getD();
19 |
20 | /**
21 | * J值
22 | */
23 | float getJ();
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/entity/IKLine.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart.entity;
2 |
3 | /**
4 | * k线实体接口
5 | * Created by tifezh on 2016/6/9.
6 | */
7 |
8 | public interface IKLine extends ICandle, IBOLL, IMACD, IKDJ, IRSI,IVolume {
9 | }
10 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/entity/IMACD.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart.entity;
2 |
3 | /**
4 | * MACD指标(指数平滑移动平均线)接口
5 | * @see 相关说明
6 | * Created by tifezh on 2016/6/10.
7 | */
8 |
9 | public interface IMACD {
10 |
11 |
12 | /**
13 | * DEA值
14 | */
15 | float getDea();
16 |
17 | /**
18 | * DIF值
19 | */
20 | float getDif();
21 |
22 | /**
23 | * MACD值
24 | */
25 | float getMacd();
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/entity/IMinuteLine.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart.entity;
2 |
3 | import java.util.Date;
4 |
5 | /**
6 | * 分时图实体接口
7 | * Created by tifezh on 2017/7/19.
8 | */
9 |
10 | public interface IMinuteLine {
11 |
12 | /**
13 | * @return 获取均价
14 | */
15 | float getAvgPrice();
16 |
17 | /**
18 | * @return 获取成交价
19 | */
20 | float getPrice();
21 |
22 | /**
23 | * 该指标对应的时间
24 | */
25 | Date getDate();
26 |
27 | /**
28 | * 成交量
29 | */
30 | float getVolume();
31 | }
32 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/entity/IRSI.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart.entity;
2 |
3 | /**
4 | * RSI指标接口
5 | * @see 相关说明
6 | * Created by tifezh on 2016/6/10.
7 | */
8 |
9 | public interface IRSI {
10 |
11 | /**
12 | * RSI1值
13 | */
14 | float getRsi1();
15 | /**
16 | * RSI2值
17 | */
18 | float getRsi2();
19 | /**
20 | * RSI3值
21 | */
22 | float getRsi3();
23 | }
24 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/entity/IVolume.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart.entity;
2 |
3 | /**
4 | * 成交量接口
5 | * Created by hjm on 2017/11/14 17:46.
6 | */
7 |
8 | public interface IVolume {
9 |
10 | /**
11 | * 开盘价
12 | */
13 | float getOpenPrice();
14 |
15 | /**
16 | * 收盘价
17 | */
18 | float getClosePrice();
19 |
20 | /**
21 | * 成交量
22 | */
23 | float getVolume();
24 |
25 | /**
26 | * 五(月,日,时,分,5分等)均量
27 | */
28 | float getMA5Volume();
29 |
30 | /**
31 | * 十(月,日,时,分,5分等)均量
32 | */
33 | float getMA10Volume();
34 | }
35 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/formatter/BigValueFormatter.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart.formatter;
2 |
3 | import com.github.tifezh.kchartlib.chart.base.IValueFormatter;
4 |
5 | import java.util.Locale;
6 |
7 | /**
8 | * 对较大数据进行格式化
9 | * Created by tifezh on 2017/12/13.
10 | */
11 |
12 | public class BigValueFormatter implements IValueFormatter{
13 |
14 | //必须是排好序的
15 | private int[] values={10000,1000000,100000000};
16 | private String[] units={"万","百万","亿"};
17 |
18 | @Override
19 | public String format(float value) {
20 | String unit="";
21 | int i=values.length-1;
22 | while (i>=0)
23 | {
24 | if(value>values[i]) {
25 | value /= values[i];
26 | unit = units[i];
27 | break;
28 | }
29 | i--;
30 | }
31 | return String.format(Locale.getDefault(),"%.2f", value)+unit;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/formatter/DateFormatter.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart.formatter;
2 |
3 | import com.github.tifezh.kchartlib.chart.base.IDateTimeFormatter;
4 | import com.github.tifezh.kchartlib.utils.DateUtil;
5 |
6 | import java.util.Date;
7 |
8 | /**
9 | * 时间格式化器
10 | * Created by tifezh on 2016/6/21.
11 | */
12 |
13 | public class DateFormatter implements IDateTimeFormatter {
14 | @Override
15 | public String format(Date date) {
16 | if (date != null) {
17 | return DateUtil.DateFormat.format(date);
18 | } else {
19 | return "";
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/formatter/TimeFormatter.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart.formatter;
2 |
3 | import com.github.tifezh.kchartlib.chart.base.IDateTimeFormatter;
4 | import com.github.tifezh.kchartlib.utils.DateUtil;
5 |
6 | import java.util.Date;
7 |
8 | /**
9 | * 时间格式化器
10 | * Created by tifezh on 2016/6/21.
11 | */
12 |
13 | public class TimeFormatter implements IDateTimeFormatter {
14 | @Override
15 | public String format(Date date) {
16 | if (date == null) {
17 | return "";
18 | }
19 | return DateUtil.shortTimeFormat.format(date);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/chart/formatter/ValueFormatter.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.chart.formatter;
2 |
3 | import com.github.tifezh.kchartlib.chart.base.IValueFormatter;
4 |
5 | /**
6 | * Value格式化类
7 | * Created by tifezh on 2016/6/21.
8 | */
9 |
10 | public class ValueFormatter implements IValueFormatter {
11 | @Override
12 | public String format(float value) {
13 | return String.format("%.2f", value);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/utils/DateUtil.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.utils;
2 |
3 | import java.text.SimpleDateFormat;
4 |
5 | /**
6 | * 时间工具类
7 | * Created by tifezh on 2016/4/27.
8 | */
9 | public class DateUtil {
10 | public static SimpleDateFormat longTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
11 | public static SimpleDateFormat shortTimeFormat = new SimpleDateFormat("HH:mm");
12 | public static SimpleDateFormat DateFormat = new SimpleDateFormat("yyyy/MM/dd");
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/kchartlib/src/main/java/com/github/tifezh/kchartlib/utils/ViewUtil.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib.utils;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * Created by tian on 2016/4/11.
7 | */
8 | public class ViewUtil {
9 | static public int Dp2Px(Context context, float dp) {
10 | final float scale = context.getResources().getDisplayMetrics().density;
11 | return (int) (dp * scale + 0.5f);
12 | }
13 |
14 | static public int Px2Dp(Context context, float px) {
15 | final float scale = context.getResources().getDisplayMetrics().density;
16 | return (int) (px / scale + 0.5f);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/kchartlib/src/main/res/color/tab_text_color_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/kchartlib/src/main/res/layout/item_tab.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
15 |
16 |
22 |
23 |
--------------------------------------------------------------------------------
/kchartlib/src/main/res/layout/layout_tab.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
16 |
17 |
21 |
22 |
31 |
32 |
--------------------------------------------------------------------------------
/kchartlib/src/main/res/values/attrs.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 |
--------------------------------------------------------------------------------
/kchartlib/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 | #DF3536
8 | #35DF7E
9 |
10 | #18CCF6
11 | #FE5EDF
12 | #E7A520
13 | #fff
14 |
15 | #202326
16 | #353941
17 | #B1B2B6
18 | #c830343C
19 | #30343C
20 | #FF6601
21 |
22 |
--------------------------------------------------------------------------------
/kchartlib/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 10sp
3 | 12sp
4 | 1dp
5 | 4dp
6 | 0.5dp
7 | 1dp
8 | 6dp
9 | 15dp
10 | 15dp
11 |
--------------------------------------------------------------------------------
/kchartlib/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | KChartLib
3 |
4 |
--------------------------------------------------------------------------------
/kchartlib/src/test/java/com/github/tifezh/kchartlib/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.github.tifezh.kchartlib;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.assertEquals;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':kchartlib'
2 |
--------------------------------------------------------------------------------