的
@@ -0,0 +1,63 @@
|
||||
#---------以下为通用配置BEGIN------
|
||||
|
||||
# 操作系统忽略文件
|
||||
# OSX
|
||||
*.DS_Store
|
||||
# Windows thumbnail db
|
||||
Thumbs.db
|
||||
|
||||
## AndroidStudio IDE忽略文件
|
||||
# Intellij
|
||||
*.iml
|
||||
.idea/
|
||||
# Android Studio captures folder
|
||||
captures/
|
||||
# Android Studio Navigation editor temp files
|
||||
.navigation/
|
||||
|
||||
## gradle忽略文件
|
||||
# Gradle files
|
||||
.gradle/
|
||||
gradle/
|
||||
gradlew
|
||||
gradlew.bat
|
||||
|
||||
## sdk配置文件
|
||||
# Local configuration file (sdk path, etc)
|
||||
local.properties
|
||||
|
||||
## 编译生成的文件
|
||||
# Generated files
|
||||
bin/
|
||||
gen/
|
||||
out/
|
||||
build/
|
||||
*.dex
|
||||
## *.apk
|
||||
*.ap_
|
||||
*.class
|
||||
|
||||
## 日志文件
|
||||
# Log Files
|
||||
*.log
|
||||
#---------以上为通用配置END--------
|
||||
|
||||
|
||||
#--------- 根据需求个性化配置---------
|
||||
|
||||
# Keystore files
|
||||
# *.jks
|
||||
|
||||
|
||||
## 第三方
|
||||
|
||||
# bugly
|
||||
*.txt
|
||||
|
||||
|
||||
|
||||
# note
|
||||
# .ignore不起作用解决方案
|
||||
# git rm -r --cached .
|
||||
# git add .
|
||||
# git commit -m "update .ignore"
|
||||
@@ -0,0 +1,50 @@
|
||||
language: android
|
||||
jdk: oraclejdk8
|
||||
|
||||
env:
|
||||
global:
|
||||
- ANDROID_API=28
|
||||
- EMULATOR_API=26
|
||||
- ANDROID_BUILD_TOOLS=27.0.3
|
||||
- ADB_INSTALL_TIMEOUT=5 # minutes
|
||||
|
||||
android:
|
||||
components:
|
||||
- tools
|
||||
- platform-tools
|
||||
- build-tools-$ANDROID_BUILD_TOOLS
|
||||
- android-$ANDROID_API
|
||||
- android-$EMULATOR_API
|
||||
- extra-google-m2repository
|
||||
- extra-android-m2repository
|
||||
- sys-img-armeabi-v7a-addon-google_apis-google-$ANDROID_API_LEVEL
|
||||
- sys-img-armeabi-v7a-addon-google_apis-google-$EMULATOR_API_LEVEL
|
||||
|
||||
licenses:
|
||||
- android-sdk-preview-license-.+
|
||||
- android-sdk-license-.+
|
||||
- google-gdk-license-.+
|
||||
|
||||
before_install:
|
||||
- yes | sdkmanager "platforms;android-27"
|
||||
|
||||
|
||||
# Emulator Management: Create, Start and Wait
|
||||
#before_script:
|
||||
# - echo no | android create avd --force -n test -t android-$$ANDROID_API --abi armeabi-v7a
|
||||
# - emulator -avd test -no-skin -no-audio -no-window &
|
||||
# - android-wait-for-emulator
|
||||
# - adb shell input keyevent 82 &
|
||||
|
||||
script:
|
||||
- "./gradlew clean build check -PdisablePreDex --stacktrace"
|
||||
|
||||
before_cache:
|
||||
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
|
||||
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.gradle/caches/
|
||||
- $HOME/.gradle/wrapper/
|
||||
- $HOME/.android/build-cache
|
||||
@@ -0,0 +1,66 @@
|
||||
> ### Notice
|
||||
> *Before you continue, this is the* **ANDROID** *library. If you have an* **iOS** *device, please go here instead*:
|
||||
>
|
||||
> – https://github.com/danielgindi/Charts
|
||||
>
|
||||
> They might tell you to come back here, if they do, listen to them and ignore this notice.
|
||||
|
||||
# How to contribute
|
||||
|
||||
Bug-fixes and features often come from users of the MPAndroidChart library and improve it greatly. We want to keep it as easy as possible to contribute changes that improve the experience for users all around the world. There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things.
|
||||
|
||||
## Creating Issues
|
||||
|
||||
There are two main issue templates, one for bugs and another for feature requests. Please use them! You're issue will be much easier to understand, and bugs easier to fix, if you follow the templates. If your issue doesn't fit into those, just use the generic template.
|
||||
|
||||
Search existing [issues] to see if your bug has already been reported or if a feature request already exists. Don't forget to remove `is:open` so you see all the issues! If you find that one already exists, use reactions to show how much you care!
|
||||
|
||||
## Making Pull Requests
|
||||
|
||||
Careful! If you fail to follow these guidlines, you're pull request may be closed, *even if it's really awesome*.
|
||||
|
||||
0. **Search** open [pull requests] AND existing [issues] to make sure what you want to do isn't already being worked on or already has an open pull request.
|
||||
1. **Fork** the repository
|
||||
1. **Create** a new branch based on `master`, and name it according to your changes
|
||||
1. **Add** your commits, they MUST follow the [Commit Style](#commit-style) below
|
||||
1. **Test** your changes by actually running the example app, or create a new example
|
||||
1. **Create** a pull request, following the auto-generated template
|
||||
1. ???
|
||||
1. Profit :money_with_wings:
|
||||
|
||||
You are encouraged to use [GitHub Desktop] to inspect your code changes before committing them. It can reveal small changes that might have gone unnoticed, and would be requested for removal before merging.
|
||||
|
||||
Check out [#3975](https://github.com/PhilJay/MPAndroidChart/pull/3975) for an example of a good-made-better pull request.
|
||||
|
||||
## Commit Style
|
||||
|
||||
* **Make commits of logical units**
|
||||
Don't load your commits with tons of changes, this makes it hard to follow what is happening. However, if you have done a lot of work, and there are commits and merges all over the place, squash them down into fewer commits.
|
||||
|
||||
* **Conform to the code style**
|
||||
It's easy, just look around!
|
||||
|
||||
* **Write good commit messages**
|
||||
You may prefer [Tim Pope's style], you might like the [commitizen-friendly] way. Regardless of the color you pick, you MUST stay within the lines!
|
||||
```
|
||||
The commit title CANNOT exceed 50 characters
|
||||
|
||||
The body of the message comes after an empty new line, and describes the
|
||||
changes more thoroughly. If the change is obvious and self-explanatory
|
||||
from the title, you can omit the body. You should describe all changes
|
||||
if many were made, or maybe some trickery that only code wizards can
|
||||
understand.
|
||||
|
||||
Be polite and wrap your lines to 72 characters, but if you prefer going
|
||||
to 100 characters then I guess we can't stop you.
|
||||
```
|
||||
|
||||
## Final Notes
|
||||
|
||||
Thanks for reading the contributing file! Have some cake! :cake:
|
||||
|
||||
[issues]: https://github.com/PhilJay/MPAndroidChart/issues
|
||||
[pull requests]: https://github.com/PhilJay/MPAndroidChart/pulls
|
||||
[GitHub Desktop]: https://desktop.github.com/
|
||||
[Tim Pope's style]: https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
|
||||
[commitizen-friendly]: https://github.com/commitizen/cz-cli
|
||||
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,59 @@
|
||||
## FinancialCustomerView
|
||||
* 本项目会对金融交易软件中存在的各种View进行模仿绘制
|
||||
* 提供详细的实现思路
|
||||
* 收集整理相关算法、文档以及专业资料
|
||||
* 开源库不依赖第三方,继承系统View实现
|
||||
* 提供完整Demo
|
||||
* [参考文档](https://github.com/Tophold/FinancialCustomerView/tree/master/%E8%B5%84%E6%96%99%E4%B8%8E%E6%96%87%E6%A1%A3)
|
||||
|
||||
## 号外
|
||||
1. [MPAndroidChartWrapper](https://github.com/scsfwgy/MPAndroidChartWrapper)【开发完善中...】高度封装MPAndroidChart,提供开箱即用的MPAndroidChart。
|
||||
两大原则:1.不修改MPAndroidChart源码,只继承封装原有功能实现扩展。2. 开箱即用。目标:可商用。
|
||||
2. 商用k线图**推荐**使用[MPAndroidChartWrapper](https://github.com/scsfwgy/MPAndroidChartWrapper),让您几行代码实现一个商用级别k线图。
|
||||
|
||||
#### 目录
|
||||
1. ``com.tophold.trade.view.fund.FundView`` 仿蚂蚁金服基金走势图
|
||||
2. ``com.tophold.trade.view.kview.KView`` k线走势图
|
||||
3. ``com.tophold.trade.view.pie.PieChartView`` 饼图
|
||||
4. ``com.tophold.trade.view.seekbar.DoubleThumbSeekBar`` 双Thumb自定义进度条
|
||||
|
||||
#### com.tophold.trade.view.fund.FundView
|
||||
* 仿蚂蚁金服基金走势图,支持长按查看指定数据,可以据此扩展出各种简单的资金走势图。KView的思路来自于此。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
#### com.tophold.trade.view.kview.KView
|
||||
* k线走势图,支持主图+副图+量图
|
||||
* 主图支持缩放、长按十字、滑动等各种手势操作;支持显示最小、最大值;指标支持:ma、boll、ma+boll;图形类别支持分时图、蜡烛图
|
||||
* 副图支持指标:macd、kdj、rsi
|
||||
* 量图支持:量、ma(5,10)
|
||||
*
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
#### com.tophold.trade.view.pie.PieChartView
|
||||
* 饼图,加载动画、特定指示图
|
||||
|
||||

|
||||
|
||||
#### com.tophold.trade.view.seekbar.DoubleThumbSeekBar
|
||||
* 双Thumb自定义进度条,可以高度定制化
|
||||
* 支持单、双thumb
|
||||
* 支持从左、右开始最小值(和滑动方向无关)
|
||||
* 两个thumb可以任意设置开始方向以及起始位置
|
||||
* 支持数据回调
|
||||
* 具体使用参看Demo
|
||||
|
||||

|
||||
|
||||
#### 其它
|
||||
* [天厚投资](https://www.tophold.com/)
|
||||
* [MPAndroidChart](https://github.com/PhilJay/MPAndroidChart)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
# FinancialCustomerView
|
||||
|
||||
## Introduce
|
||||
> This project will simulate the various views in financial transaction software, provide detailed implementation ideas, and collect relevant algorithms, documents and professional materials.
|
||||
|
||||
## Significance
|
||||
> May our developers to say, have very mature third party framework, why return to oneself to realize?
|
||||
|
||||
* Knowing how to write and draw, it is more convenient to extend the third library graphics library.
|
||||
* Understand the principle of implementation, if the third parties can not achieve, you can write one in a leisurely way.
|
||||
* There are many kinds of algorithms and various indicators in financial transactions, but there are few related information on the Internet. I hope can give a little help to financial related developers.
|
||||
* Knowing it, knowing it is so.
|
||||
|
||||
## Demo
|
||||
* impression drawing:[impression drawing](https://github.com/scsfwgy/FinancialCustomerView/blob/master/%E8%B5%84%E6%96%99%E4%B8%8E%E6%96%87%E6%A1%A3/%E6%95%88%E6%9E%9C%E5%9B%BE%E5%92%8C%E8%BF%9B%E5%BA%A6.md)
|
||||
* demo apk:[demo_apk](https://github.com/scsfwgy/FinancialCustomerView/tree/master/apk)
|
||||
|
||||
## Reference material and blogs
|
||||
* reference material and blogs:[reference material and blogs](https://github.com/scsfwgy/FinancialCustomerView/tree/master/%E8%B5%84%E6%96%99%E4%B8%8E%E6%96%87%E6%A1%A3)
|
||||
|
||||
## Schedule
|
||||
* Completed:The FundView has developed in the master branch.
|
||||
* Completed:The TimeSharingView has developed in the master branch.
|
||||
* Completed:The CandleView(including MA、BOLL)has developed in the master branch.
|
||||
* Completed:The code refactoring has completed in the master branch. The code is refactoring in the later period.
|
||||
* being developed:The MinorView is being developed in the feature_minor branch.
|
||||
* plan:Verify the accuracy of the data (proofread data with On-line app).
|
||||
* plan:Test availability using open API in a real environment.
|
||||
* plan:Simulating real use,switching timesharing、5m、15m、30m、1h、1d、1w、1m。
|
||||
|
||||
## Contribution
|
||||
* new branch,PR。
|
||||
|
||||
## Famous third party graphic library
|
||||
* MPAndroidChart:[https://github.com/PhilJay/MPAndroidChart](https://github.com/PhilJay/MPAndroidChart)
|
||||
* AndroidCharts:[https://github.com/HackPlan/AndroidCharts](https://github.com/HackPlan/AndroidCharts)
|
||||
* Android-Charts:[https://github.com/limccn/Android-Charts](https://github.com/limccn/Android-Charts)
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,144 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
/**获取git count HEAD,可以根据该值回退版本*/
|
||||
def getMyVersionCode() {
|
||||
Process process = "git rev-list --count HEAD".execute()
|
||||
process.waitFor()
|
||||
int cccc = process.getText().toInteger()
|
||||
return cccc
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
defaultConfig {
|
||||
applicationId "com.tophold.example"
|
||||
minSdkVersion 17
|
||||
targetSdkVersion 28
|
||||
versionCode getMyVersionCode() as int//查询versioncode即可找到对应git历史
|
||||
versionName "0.0.1"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
|
||||
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
//debug模式下签名的设置,这里的配置主要用于脚本运行。对于采用图形界面构建测不起效。
|
||||
debug {
|
||||
storeFile file(project.debug_storeFile)
|
||||
storePassword project.debug_storePassword
|
||||
keyAlias project.debug_keyAlias
|
||||
keyPassword project.debug_keyPassword
|
||||
v1SigningEnabled true
|
||||
v2SigningEnabled true
|
||||
}
|
||||
|
||||
beta {
|
||||
storeFile file(project.debug_storeFile)
|
||||
storePassword project.debug_storePassword
|
||||
keyAlias project.debug_keyAlias
|
||||
keyPassword project.debug_keyPassword
|
||||
v1SigningEnabled true
|
||||
v2SigningEnabled true
|
||||
}
|
||||
|
||||
release {
|
||||
storeFile file(project.release_storeFile)
|
||||
storePassword project.release_storePassword
|
||||
keyAlias project.release_keyAlias
|
||||
keyPassword project.release_keyPassword
|
||||
v1SigningEnabled true
|
||||
v2SigningEnabled true
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
//平时开发使用
|
||||
debug {
|
||||
// 显示Log
|
||||
buildConfigField "boolean", "LOG_DEBUG", "true"
|
||||
shrinkResources false
|
||||
minifyEnabled false
|
||||
zipAlignEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
//versionName的后缀
|
||||
versionNameSuffix "_debug"
|
||||
//appId后缀,加一个后缀保证各个版本(debug、beta、release可以共存)
|
||||
applicationIdSuffix ".debug"
|
||||
//签名选择
|
||||
signingConfig signingConfigs.debug
|
||||
//动态修改应用的名字和图标
|
||||
manifestPlaceholders = [app_names: "金融View_debug"]
|
||||
debuggable true
|
||||
}
|
||||
|
||||
//内侧使用
|
||||
beta {
|
||||
// 显示Log
|
||||
buildConfigField "boolean", "LOG_DEBUG", "true"
|
||||
shrinkResources false
|
||||
minifyEnabled false
|
||||
zipAlignEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
//versionName的后缀
|
||||
versionNameSuffix "_beta"
|
||||
//appId后缀
|
||||
applicationIdSuffix ".beta"
|
||||
//签名选择
|
||||
signingConfig signingConfigs.beta
|
||||
manifestPlaceholders = [app_names: "金融View_beta"]
|
||||
debuggable true
|
||||
}
|
||||
|
||||
//正式版本
|
||||
release {
|
||||
//不显示log信息
|
||||
buildConfigField "boolean", "LOG_DEBUG", "false"
|
||||
// 移除无用的resource文件
|
||||
shrinkResources true
|
||||
//混淆
|
||||
minifyEnabled true
|
||||
//压缩
|
||||
zipAlignEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
//签名
|
||||
signingConfig signingConfigs.release
|
||||
|
||||
manifestPlaceholders = [app_names: "金融View"]
|
||||
debuggable true
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation 'com.android.support:support-v4:28.0.0'
|
||||
implementation 'com.android.support:recyclerview-v7:28.0.0'
|
||||
implementation 'com.android.support:design:28.0.0'
|
||||
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||
|
||||
implementation project(path: ':financiallib')
|
||||
|
||||
//rx2.0
|
||||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
|
||||
implementation 'io.reactivex.rxjava2:rxjava:2.2.8'
|
||||
//api
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
|
||||
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
|
||||
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'
|
||||
implementation 'com.squareup.okhttp3:okhttp:3.12.0'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:3.11.0'
|
||||
/**https://github.com/CymChad/BaseRecyclerViewAdapterHelper:qucik recycle*/
|
||||
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.49'
|
||||
implementation 'org.greenrobot:eventbus:3.1.1'
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
}
|
||||
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
@@ -0,0 +1,287 @@
|
||||
|
||||
|
||||
|
||||
|
||||
###########################正文####################################
|
||||
##这里是APP默认的混淆配置规则,和第三方没有关系。
|
||||
##这里禁止配置个性化、第三方库的混淆配置。
|
||||
##应用第三方库混淆规则配置请配置在最下方"其它第三方"模块。
|
||||
|
||||
#指定代码的压缩级别
|
||||
-optimizationpasses 5
|
||||
|
||||
#包明不混合大小写
|
||||
-dontusemixedcaseclassnames
|
||||
|
||||
#不去忽略非公共的库类
|
||||
-dontskipnonpubliclibraryclasses
|
||||
|
||||
#优化 不优化输入的类文件
|
||||
-dontoptimize
|
||||
|
||||
#预校验
|
||||
-dontpreverify
|
||||
|
||||
#混淆时是否记录日志
|
||||
-verbose
|
||||
|
||||
# 混淆时所采用的算法
|
||||
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
|
||||
|
||||
#保护注解
|
||||
-keepattributes *Annotation*
|
||||
|
||||
# 保持哪些类不被混淆
|
||||
-keep public class * extends android.app.Fragment
|
||||
-keep public class * extends android.app.Activity
|
||||
-keep public class * extends android.app.Application
|
||||
-keep public class * extends android.app.Service
|
||||
-keep public class * extends android.content.BroadcastReceiver
|
||||
-keep public class * extends android.content.ContentProvider
|
||||
-keep public class * extends android.app.backup.BackupAgentHelper
|
||||
-keep public class * extends android.preference.Preference
|
||||
-keep public class com.android.vending.licensing.ILicensingService
|
||||
|
||||
#如果引用了v4或者v7包
|
||||
-dontwarn android.support.**
|
||||
|
||||
# support design
|
||||
#@link http://stackoverflow.com/a/31028536
|
||||
-dontwarn android.support.design.**
|
||||
-keep class android.support.design.** { *; }
|
||||
-keep interface android.support.design.** { *; }
|
||||
-keep public class android.support.design.R$* { *; }
|
||||
|
||||
|
||||
#忽略警告
|
||||
-ignorewarning
|
||||
|
||||
##记录生成的日志数据,gradle build时在本项目根目录输出##
|
||||
#apk 包内所有 class 的内部结构
|
||||
-dump proguard/class_files.txt
|
||||
#未混淆的类和成员
|
||||
-printseeds proguard/seeds.txt
|
||||
#列出从 apk 中删除的代码
|
||||
-printusage proguard/unused.txt
|
||||
#混淆前后的映射
|
||||
-printmapping proguard/mapping.txt
|
||||
|
||||
#保持 native 方法不被混淆
|
||||
-keepclasseswithmembernames class * {
|
||||
native <methods>;
|
||||
}
|
||||
|
||||
#保持自定义控件类不被混淆
|
||||
-keepclasseswithmembers class * {
|
||||
public <init>(android.content.Context, android.util.AttributeSet);
|
||||
}
|
||||
-keepclassmembers class * extends android.app.Activity {
|
||||
public void *(android.view.View);
|
||||
}
|
||||
|
||||
-keep public class * extends android.view.View {
|
||||
public <init>(android.content.Context);
|
||||
public <init>(android.content.Context, android.util.AttributeSet);
|
||||
public <init>(android.content.Context, android.util.AttributeSet, int);
|
||||
public void set*(...);
|
||||
}
|
||||
|
||||
#保持 Parcelable 不被混淆
|
||||
-keep class * implements android.os.Parcelable {
|
||||
public static final android.os.Parcelable$Creator *;
|
||||
}
|
||||
|
||||
#保持 Serializable 不被混淆
|
||||
-keepnames class * implements java.io.Serializable
|
||||
|
||||
#保持 Serializable 不被混淆并且enum 类也不被混淆
|
||||
-keepclassmembers class * implements java.io.Serializable {
|
||||
static final long serialVersionUID;
|
||||
private static final java.io.ObjectStreamField[] serialPersistentFields;
|
||||
!static !transient <fields>;
|
||||
!private <fields>;
|
||||
!private <methods>;
|
||||
private void writeObject(java.io.ObjectOutputStream);
|
||||
private void readObject(java.io.ObjectInputStream);
|
||||
java.lang.Object writeReplace();
|
||||
java.lang.Object readResolve();
|
||||
}
|
||||
|
||||
#保持枚举 enum 类不被混淆
|
||||
-keepclassmembers enum * {
|
||||
public static **[] values();
|
||||
public static ** valueOf(java.lang.String);
|
||||
}
|
||||
|
||||
-keepclassmembers class * {
|
||||
public void *ButtonClicked(android.view.View);
|
||||
}
|
||||
|
||||
#不混淆资源类
|
||||
-keepclassmembers class **.R$* {
|
||||
public static <fields>;
|
||||
}
|
||||
|
||||
#避免混淆泛型 如果混淆报错建议关掉
|
||||
-keepattributes Signature
|
||||
|
||||
#移除Log类打印各个等级日志的代码,打正式包的时候可以做为禁log使用,这里可以作为禁止log打印的功能使用,另外的一种实现方案是通过BuildConfig.DEBUG的变量来控制
|
||||
#-assumenosideeffects class android.util.Log {
|
||||
# public static *** v(...);
|
||||
# public static *** i(...);
|
||||
# public static *** d(...);
|
||||
# public static *** w(...);
|
||||
# public static *** e(...);
|
||||
#}
|
||||
|
||||
|
||||
|
||||
#################################################必备开发第三方################################
|
||||
# UI相关
|
||||
## https://github.com/JakeWharton/butterknife:butterknife
|
||||
-keep class butterknife.** { *; }
|
||||
-dontwarn butterknife.internal.**
|
||||
-keep class **$$ViewBinder { *; }
|
||||
-keepclasseswithmembernames class * {
|
||||
@butterknife.* <fields>;
|
||||
}
|
||||
-keepclasseswithmembernames class * {
|
||||
@butterknife.* <methods>;
|
||||
}
|
||||
|
||||
## https://github.com/bumptech/glide:glide
|
||||
-keep public class * implements com.bumptech.glide.module.GlideModule
|
||||
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
|
||||
**[] $VALUES;
|
||||
public *;
|
||||
}
|
||||
|
||||
## https://github.com/CymChad/BaseRecyclerViewAdapterHelper:recycle封装
|
||||
-keep class com.chad.library.adapter.** {
|
||||
*;
|
||||
}
|
||||
-keep public class * extends com.chad.library.adapter.base.BaseQuickAdapter
|
||||
-keep public class * extends com.chad.library.adapter.base.BaseViewHolder
|
||||
-keepclassmembers class **$** extends com.chad.library.adapter.base.BaseViewHolder {
|
||||
<init>(...);
|
||||
}
|
||||
|
||||
## https://github.com/gyf-dev/ImmersionBarw:沉浸式*/
|
||||
-keep class com.gyf.barlibrary.* {*;}
|
||||
|
||||
|
||||
# 数据相关
|
||||
## https://github.com/greenrobot/EventBus:EventBus3.0混淆配置
|
||||
-keepattributes *Annotation*
|
||||
-keepclassmembers class ** {
|
||||
@org.greenrobot.eventbus.Subscribe <methods>;
|
||||
}
|
||||
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
|
||||
|
||||
# Only required if you use AsyncExecutor
|
||||
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
|
||||
<init>(java.lang.Throwable);
|
||||
}
|
||||
|
||||
## https://github.com/google/gson:gson
|
||||
-keepattributes Signature
|
||||
# Gson specific classes
|
||||
-keep class sun.misc.Unsafe { *; }
|
||||
# Application classes that will be serialized/deserialized over Gson
|
||||
-keep class com.google.gson.** { *; }
|
||||
-keep class com.google.gson.stream.** { *; }
|
||||
|
||||
## https://github.com/Blankj/AndroidUtilCode:安卓开发常用工具类
|
||||
-keep class com.blankj.utilcode.** { *; }
|
||||
-keepclassmembers class com.blankj.utilcode.** { *; }
|
||||
-dontwarn com.blankj.utilcode.**
|
||||
|
||||
|
||||
# APP运维
|
||||
#bugly
|
||||
-dontwarn com.tencent.bugly.**
|
||||
-keep public class com.tencent.bugly.**{*;}
|
||||
|
||||
# Umeng
|
||||
-keepclassmembers class * {
|
||||
public <init> (org.json.JSONObject);
|
||||
}
|
||||
-keep public class wgyscsf.quickapp.R$*{
|
||||
public static final int *;
|
||||
}
|
||||
-keepclassmembers enum * {
|
||||
public static **[] values();
|
||||
public static ** valueOf(java.lang.String);
|
||||
}
|
||||
|
||||
## UmengPush
|
||||
-dontwarn com.taobao.**
|
||||
-dontwarn anet.channel.**
|
||||
-dontwarn anetwork.channel.**
|
||||
-dontwarn org.android.**
|
||||
-dontwarn org.apache.thrift.**
|
||||
-dontwarn com.xiaomi.**
|
||||
-dontwarn com.huawei.**
|
||||
-keepattributes *Annotation*
|
||||
-keep class com.taobao.** {*;}
|
||||
-keep class org.android.** {*;}
|
||||
-keep class anet.channel.** {*;}
|
||||
-keep class com.umeng.** {*;}
|
||||
-keep class com.xiaomi.** {*;}
|
||||
-keep class com.huawei.** {*;}
|
||||
-keep class org.apache.thrift.** {*;}
|
||||
-keep class com.alibaba.sdk.android.**{*;}
|
||||
-keep class com.ut.**{*;}
|
||||
-keep class com.ta.**{*;}
|
||||
-keep public class **.R$*{
|
||||
public static final int *;
|
||||
}
|
||||
|
||||
#(可选)避免Log打印输出
|
||||
#-assumenosideeffects class android.util.Log {
|
||||
# public static *** v(...);
|
||||
# public static *** d(...);
|
||||
# public static *** i(...);
|
||||
# public static *** w(...);
|
||||
# }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# rx
|
||||
-dontwarn javax.annotation.**
|
||||
-dontwarn javax.inject.**
|
||||
# OkHttp3
|
||||
-dontwarn okhttp3.logging.**
|
||||
-keep class okhttp3.internal.**{*;}
|
||||
-dontwarn okio.**
|
||||
# Retrofit
|
||||
-dontwarn retrofit2.**
|
||||
-keep class retrofit2.** {*;}
|
||||
-keepattributes Signature
|
||||
-keepattributes Exceptions
|
||||
|
||||
# RxJava RxAndroid
|
||||
-dontwarn sun.misc.**
|
||||
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
|
||||
long producerIndex;
|
||||
long consumerIndex;
|
||||
}
|
||||
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
|
||||
rx.internal.util.atomic.LinkedQueueNode producerNode;
|
||||
}
|
||||
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
|
||||
rx.internal.util.atomic.LinkedQueueNode consumerNode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#################################################其它第三方########################
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.tophold.example;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumentation test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() throws Exception {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
||||
|
||||
assertEquals("com.tophold.example", appContext.getPackageName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.tophold.example">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
<application
|
||||
android:name=".MyApplication"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="${app_names}"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:ignore="GoogleAppIndexingWarning">
|
||||
<activity android:name=".MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".demo.fund.FundActivity" />
|
||||
<activity android:name=".demo.kview.beginner.ui.KViewVerticalActivity" />
|
||||
<activity
|
||||
android:name=".demo.kview.beginner.ui.KViewHorizontalActivityActivity"
|
||||
android:screenOrientation="landscape"
|
||||
android:theme="@style/AppTheme_Fullscreen" />
|
||||
<activity android:name=".demo.kview.forex.ui.ForexListActivity" />
|
||||
<activity android:name=".demo.kview.forex.ui.ForexActivity" />
|
||||
<activity android:name=".demo.kview.btc.ui.HuobiListActivity" />
|
||||
<activity android:name=".demo.kview.btc.ui.HuobiActivity" />
|
||||
<activity android:name=".demo.pie.PieChartActivity" />
|
||||
|
||||
<!-- <intent-filter> -->
|
||||
<!-- <action android:name="android.intent.action.MAIN"/> -->
|
||||
|
||||
|
||||
<!-- <category android:name="android.intent.category.LAUNCHER"/> -->
|
||||
<!-- </intent-filter> -->
|
||||
<activity android:name=".demo.seekbar.DoubleThumbSeekBarActivity" />
|
||||
<activity android:name=".demo.kview.KViewActivity"></activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,202 @@
|
||||
[
|
||||
{
|
||||
"actual": "103",
|
||||
"createTime": "Apr 10, 2017 12:04:14 AM",
|
||||
"economicId": 518,
|
||||
"forecast": "102",
|
||||
"historyId": 449366,
|
||||
"previous": "103",
|
||||
"revised": "",
|
||||
"timestamp": 1456213500
|
||||
},
|
||||
{
|
||||
"actual": "102",
|
||||
"createTime": "Apr 10, 2017 12:04:14 AM",
|
||||
"economicId": 518,
|
||||
"forecast": "103",
|
||||
"historyId": 449367,
|
||||
"previous": "103",
|
||||
"revised": "101",
|
||||
"timestamp": 1458805500
|
||||
},
|
||||
{
|
||||
"actual": "105",
|
||||
"createTime": "Apr 10, 2017 12:04:14 AM",
|
||||
"economicId": 518,
|
||||
"forecast": "101",
|
||||
"historyId": 449368,
|
||||
"previous": "102",
|
||||
"revised": "104",
|
||||
"timestamp": 1461221100
|
||||
},
|
||||
{
|
||||
"actual": "104",
|
||||
"createTime": "Apr 10, 2017 12:04:14 AM",
|
||||
"economicId": 518,
|
||||
"forecast": "104",
|
||||
"historyId": 449369,
|
||||
"previous": "105",
|
||||
"revised": "",
|
||||
"timestamp": 1464072300
|
||||
},
|
||||
{
|
||||
"actual": "102",
|
||||
"createTime": "Apr 10, 2017 12:04:14 AM",
|
||||
"economicId": 518,
|
||||
"forecast": "103",
|
||||
"historyId": 449370,
|
||||
"previous": "104",
|
||||
"revised": "",
|
||||
"timestamp": 1466664300
|
||||
},
|
||||
{
|
||||
"actual": "103",
|
||||
"createTime": "Apr 10, 2017 12:04:14 AM",
|
||||
"economicId": 518,
|
||||
"forecast": "101",
|
||||
"historyId": 449371,
|
||||
"previous": "102",
|
||||
"revised": "",
|
||||
"timestamp": 1469083500
|
||||
},
|
||||
{
|
||||
"actual": "101",
|
||||
"createTime": "Apr 10, 2017 12:04:14 AM",
|
||||
"economicId": 518,
|
||||
"forecast": "103",
|
||||
"historyId": 449372,
|
||||
"previous": "103",
|
||||
"revised": "",
|
||||
"timestamp": 1472107500
|
||||
},
|
||||
{
|
||||
"actual": "103",
|
||||
"createTime": "Apr 10, 2017 12:04:14 AM",
|
||||
"economicId": 518,
|
||||
"forecast": "101",
|
||||
"historyId": 449373,
|
||||
"previous": "101",
|
||||
"revised": "",
|
||||
"timestamp": 1474526700
|
||||
},
|
||||
{
|
||||
"actual": "103",
|
||||
"createTime": "Apr 10, 2017 12:04:14 AM",
|
||||
"economicId": 518,
|
||||
"forecast": "103",
|
||||
"historyId": 449374,
|
||||
"previous": "103",
|
||||
"revised": "102",
|
||||
"timestamp": 1477377900
|
||||
},
|
||||
{
|
||||
"actual": "102",
|
||||
"createTime": "Apr 10, 2017 12:04:14 AM",
|
||||
"economicId": 518,
|
||||
"forecast": "102",
|
||||
"historyId": 449375,
|
||||
"previous": "103",
|
||||
"revised": "103",
|
||||
"timestamp": 1479973500
|
||||
},
|
||||
{
|
||||
"actual": "106",
|
||||
"createTime": "Apr 10, 2017 12:04:14 AM",
|
||||
"economicId": 518,
|
||||
"forecast": "103",
|
||||
"historyId": 449376,
|
||||
"previous": "102",
|
||||
"revised": "",
|
||||
"timestamp": 1481874300
|
||||
},
|
||||
{
|
||||
"actual": "106",
|
||||
"createTime": "Apr 10, 2017 12:04:14 AM",
|
||||
"economicId": 518,
|
||||
"forecast": "106",
|
||||
"historyId": 449377,
|
||||
"previous": "106",
|
||||
"revised": "",
|
||||
"timestamp": 1485330300
|
||||
},
|
||||
{
|
||||
"actual": "107",
|
||||
"createTime": "Apr 10, 2017 12:04:14 AM",
|
||||
"economicId": 518,
|
||||
"forecast": "106",
|
||||
"historyId": 449378,
|
||||
"previous": "106",
|
||||
"revised": "",
|
||||
"timestamp": 1487835900
|
||||
},
|
||||
{
|
||||
"actual": "105",
|
||||
"createTime": "Aug 8, 2017 12:35:07 AM",
|
||||
"economicId": 518,
|
||||
"forecast": "107",
|
||||
"historyId": 692633,
|
||||
"previous": "107",
|
||||
"revised": "104",
|
||||
"timestamp": 1490255100
|
||||
},
|
||||
{
|
||||
"actual": "108",
|
||||
"createTime": "Aug 8, 2017 12:35:07 AM",
|
||||
"economicId": 518,
|
||||
"forecast": "104",
|
||||
"historyId": 692634,
|
||||
"previous": "105",
|
||||
"revised": "104",
|
||||
"timestamp": 1493102700
|
||||
},
|
||||
{
|
||||
"actual": "109",
|
||||
"createTime": "Aug 8, 2017 12:35:07 AM",
|
||||
"economicId": 518,
|
||||
"forecast": "108",
|
||||
"historyId": 692635,
|
||||
"previous": "109",
|
||||
"revised": "",
|
||||
"timestamp": 1495521900
|
||||
},
|
||||
{
|
||||
"actual": "109",
|
||||
"createTime": "Aug 8, 2017 12:35:07 AM",
|
||||
"economicId": 518,
|
||||
"forecast": "109",
|
||||
"historyId": 692636,
|
||||
"previous": "109",
|
||||
"revised": "108",
|
||||
"timestamp": 1498113900
|
||||
},
|
||||
{
|
||||
"actual": "109",
|
||||
"createTime": "Aug 8, 2017 12:35:07 AM",
|
||||
"economicId": 518,
|
||||
"forecast": "108",
|
||||
"historyId": 692637,
|
||||
"previous": "109",
|
||||
"revised": "108",
|
||||
"timestamp": 1500965100
|
||||
},
|
||||
{
|
||||
"actual": "111",
|
||||
"createTime": "Aug 24, 2017 6:14:38 PM",
|
||||
"economicId": 518,
|
||||
"forecast": "108",
|
||||
"historyId": 696718,
|
||||
"previous": "108",
|
||||
"revised": "109",
|
||||
"timestamp": 1503557100
|
||||
},
|
||||
{
|
||||
"actual": "110",
|
||||
"createTime": "Oct 9, 2017 9:07:19 AM",
|
||||
"economicId": 518,
|
||||
"forecast": "",
|
||||
"historyId": 698671,
|
||||
"previous": "111",
|
||||
"revised": "",
|
||||
"timestamp": 1506408300
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,100 @@
|
||||
[
|
||||
{
|
||||
"c": "149.1755",
|
||||
"h": "149.1935",
|
||||
"l": "149.1755",
|
||||
"o": "149.1755",
|
||||
"t": "Nov 21, 2017 8:42:00 AM"
|
||||
},
|
||||
{
|
||||
"c": "149.1755",
|
||||
"h": "149.1935",
|
||||
"l": "149.1755",
|
||||
"o": "149.1755",
|
||||
"t": "Nov 21, 2017 8:43:00 AM"
|
||||
},
|
||||
{
|
||||
"c": "149.1755",
|
||||
"h": "149.1935",
|
||||
"l": "149.1755",
|
||||
"o": "149.1755",
|
||||
"t": "Nov 21, 2017 8:44:00 AM"
|
||||
},
|
||||
{
|
||||
"c": "149.1755",
|
||||
"h": "149.1935",
|
||||
"l": "149.1755",
|
||||
"o": "149.1755",
|
||||
"t": "Nov 21, 2017 8:45:00 AM"
|
||||
},
|
||||
{
|
||||
"c": "149.1755",
|
||||
"h": "149.1935",
|
||||
"l": "149.1755",
|
||||
"o": "149.1755",
|
||||
"t": "Nov 21, 2017 8:46:00 AM"
|
||||
},
|
||||
{
|
||||
"c": "149.1755",
|
||||
"h": "149.1935",
|
||||
"l": "149.1755",
|
||||
"o": "149.1755",
|
||||
"t": "Nov 21, 2017 8:47:00 AM"
|
||||
},
|
||||
{
|
||||
"c": "149.1755",
|
||||
"h": "149.1935",
|
||||
"l": "149.1755",
|
||||
"o": "149.1755",
|
||||
"t": "Nov 21, 2017 8:48:00 AM"
|
||||
},
|
||||
{
|
||||
"c": "149.1755",
|
||||
"h": "149.1935",
|
||||
"l": "149.1755",
|
||||
"o": "149.1755",
|
||||
"t": "Nov 21, 2017 8:42:00 AM"
|
||||
},
|
||||
{
|
||||
"c": "149.1755",
|
||||
"h": "149.1935",
|
||||
"l": "149.1755",
|
||||
"o": "149.1755",
|
||||
"t": "Nov 21, 2017 8:43:00 AM"
|
||||
},
|
||||
{
|
||||
"c": "149.1755",
|
||||
"h": "149.1935",
|
||||
"l": "149.1755",
|
||||
"o": "149.1755",
|
||||
"t": "Nov 21, 2017 8:44:00 AM"
|
||||
},
|
||||
{
|
||||
"c": "149.1755",
|
||||
"h": "149.1935",
|
||||
"l": "149.1755",
|
||||
"o": "149.1755",
|
||||
"t": "Nov 21, 2017 8:45:00 AM"
|
||||
},
|
||||
{
|
||||
"c": "149.1755",
|
||||
"h": "149.1935",
|
||||
"l": "149.1755",
|
||||
"o": "149.1755",
|
||||
"t": "Nov 21, 2017 8:46:00 AM"
|
||||
},
|
||||
{
|
||||
"c": "149.1755",
|
||||
"h": "149.1935",
|
||||
"l": "149.1755",
|
||||
"o": "149.1755",
|
||||
"t": "Nov 21, 2017 8:47:00 AM"
|
||||
},
|
||||
{
|
||||
"c": "149.1755",
|
||||
"h": "149.1935",
|
||||
"l": "149.1755",
|
||||
"o": "149.1755",
|
||||
"t": "Nov 21, 2017 8:48:00 AM"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.tophold.example;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.tophold.example.base.BaseActivity;
|
||||
import com.tophold.example.demo.fund.FundActivity;
|
||||
import com.tophold.example.demo.kview.KViewActivity;
|
||||
import com.tophold.example.demo.kview.beginner.ui.KViewHorizontalActivityActivity;
|
||||
import com.tophold.example.demo.kview.beginner.ui.KViewVerticalActivity;
|
||||
import com.tophold.example.demo.kview.btc.ui.HuobiListActivity;
|
||||
import com.tophold.example.demo.kview.forex.ui.ForexListActivity;
|
||||
import com.tophold.example.demo.pie.PieChartActivity;
|
||||
import com.tophold.example.demo.seekbar.DoubleThumbSeekBarActivity;
|
||||
import com.tophold.example.utils.RxUtils;
|
||||
import com.tophold.trade.utils.StringUtils;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.ObservableEmitter;
|
||||
import io.reactivex.ObservableOnSubscribe;
|
||||
import io.reactivex.Scheduler;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
public class MainActivity extends BaseActivity {
|
||||
TextView mTextView;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
mTextView = (TextView) findViewById(R.id.version);
|
||||
mTextView.setText(getVersionStr());
|
||||
}
|
||||
|
||||
public String getVersionStr() {
|
||||
String version = "verisonName:";
|
||||
version += BuildConfig.VERSION_NAME;
|
||||
version += ",versionCode(git head):" + BuildConfig.VERSION_CODE;
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
public void fundView(View view) {
|
||||
go(FundActivity.class);
|
||||
}
|
||||
|
||||
public void kViewDemo(View view) {
|
||||
go(KViewActivity.class);
|
||||
}
|
||||
|
||||
public void onPieTest(View view) {
|
||||
go(PieChartActivity.class);
|
||||
}
|
||||
|
||||
public void onSeekBarTest(View view) {
|
||||
go(DoubleThumbSeekBarActivity.class);
|
||||
}
|
||||
|
||||
|
||||
public void onRx(View view) {
|
||||
Disposable disposable = Observable.create((ObservableOnSubscribe<String>) emitter -> {
|
||||
while (true) {
|
||||
emitter.onNext("a");
|
||||
Thread.sleep(500);
|
||||
emitter.onNext("b");
|
||||
Thread.sleep(2000);
|
||||
emitter.onNext("c");
|
||||
Thread.sleep(9000);
|
||||
emitter.onNext("d");
|
||||
}
|
||||
}).observeOn(Schedulers.io())
|
||||
.compose(RxUtils.rxApiSchedulerHelper())
|
||||
.sample(1000, TimeUnit.MILLISECONDS)
|
||||
.subscribe(s -> Log.d(TAG, "accept: " + s));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.tophold.example;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
import com.tophold.example.demo.kview.btc.api.HuobiWebSocket;
|
||||
import com.tophold.example.demo.kview.forex.api.ForexWebSocket;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/22 21:38
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class MyApplication extends Application {
|
||||
public static Context mAppContext;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
mAppContext = this;
|
||||
ForexWebSocket.getInstance().init();
|
||||
HuobiWebSocket.getInstance().init();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
package com.tophold.example.base;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.ColorRes;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Observer;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
|
||||
import com.tophold.example.demo.kview.forex.api.RetrofitManager;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf
|
||||
* 创建日期 :2017/10/16 16:27
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class BaseActivity extends AppCompatActivity {
|
||||
/**
|
||||
* Activity 跳转
|
||||
*
|
||||
* @param clazz 目标activity
|
||||
* @param bundle 传递参数
|
||||
* @param finish 是否结束当前activity
|
||||
*/
|
||||
public static final int NON_CODE = -1;
|
||||
|
||||
protected Context mContext = null;
|
||||
protected String TAG = null;
|
||||
protected Activity mActivity;
|
||||
/**
|
||||
* 对系统系统的toast进行简单封装,方便使用
|
||||
*/
|
||||
private Toast toast = null;
|
||||
|
||||
private CompositeDisposable compositeDisposable;
|
||||
|
||||
@Override
|
||||
public void setContentView(int view) {
|
||||
super.setContentView(view);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mActivity = this;
|
||||
mContext = this;
|
||||
TAG = this.getClass().getSimpleName();
|
||||
// getBundleExtras
|
||||
Bundle extras = getIntent().getExtras();
|
||||
if (null != extras) {
|
||||
getBundleExtras(extras);
|
||||
}
|
||||
if (isBindEventBusHere()) {
|
||||
EventBus.getDefault().register(mActivity);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isBindEventBusHere() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void getBundleExtras(Bundle extras) {
|
||||
|
||||
}
|
||||
protected Drawable getCompatDrawable(@DrawableRes int drawbaleId) {
|
||||
return ContextCompat.getDrawable(mContext, drawbaleId);
|
||||
}
|
||||
|
||||
protected int getCompatColor(@ColorRes int colorId) {
|
||||
return ContextCompat.getColor(mContext, colorId);
|
||||
}
|
||||
/**
|
||||
* 添加disposable
|
||||
*
|
||||
* @param disposable
|
||||
*/
|
||||
public void unSubscription(Disposable disposable) {
|
||||
if (compositeDisposable == null) {
|
||||
synchronized (CompositeDisposable.class) {
|
||||
if (compositeDisposable == null) {
|
||||
compositeDisposable = new CompositeDisposable();
|
||||
}
|
||||
}
|
||||
}
|
||||
compositeDisposable.add(disposable);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (isBindEventBusHere()) {
|
||||
EventBus.getDefault().unregister(mActivity);
|
||||
}
|
||||
if (compositeDisposable != null) {
|
||||
Log.d(TAG, "base activity dispose");
|
||||
compositeDisposable.clear();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param observable
|
||||
* @param observer
|
||||
*/
|
||||
public void call(Observable observable, Observer observer) {
|
||||
RetrofitManager.call(observable, observer);
|
||||
}
|
||||
/**
|
||||
* startActivity
|
||||
*
|
||||
* @param clazz target Activity
|
||||
*/
|
||||
public void go(Class<? extends Activity> clazz) {
|
||||
_goActivity(clazz, null, NON_CODE, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* startActivity with bundle
|
||||
*
|
||||
* @param clazz target Activity
|
||||
* @param bundle
|
||||
*/
|
||||
public void go(Class<? extends Activity> clazz, Bundle bundle) {
|
||||
_goActivity(clazz, bundle, NON_CODE, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* startActivity then finish this
|
||||
*
|
||||
* @param clazz target Activity
|
||||
*/
|
||||
public void goAndFinish(Class<? extends Activity> clazz) {
|
||||
_goActivity(clazz, null, NON_CODE, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* startActivity with bundle and then finish this
|
||||
*
|
||||
* @param clazz target Activity
|
||||
* @param bundle bundle extra
|
||||
*/
|
||||
public void goAndFinish(Class<? extends Activity> clazz, Bundle bundle) {
|
||||
_goActivity(clazz, bundle, NON_CODE, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* startActivityForResult
|
||||
*
|
||||
* @param clazz
|
||||
* @param requestCode
|
||||
*/
|
||||
protected void goForResult(Class<? extends Activity> clazz, int requestCode) {
|
||||
_goActivity(clazz, null, requestCode, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* startActivityForResult with bundle
|
||||
*
|
||||
* @param clazz
|
||||
* @param bundle
|
||||
* @param requestCode
|
||||
*/
|
||||
protected void goForResult(Class<? extends Activity> clazz, Bundle bundle, int requestCode) {
|
||||
_goActivity(clazz, bundle, requestCode, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* startActivityForResult then finish this
|
||||
*
|
||||
* @param clazz
|
||||
* @param requestCode
|
||||
*/
|
||||
protected void goForResultAndFinish(Class<? extends Activity> clazz, int requestCode) {
|
||||
_goActivity(clazz, null, requestCode, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* startActivityForResult with bundle and then finish this
|
||||
*
|
||||
* @param clazz
|
||||
* @param bundle
|
||||
* @param requestCode
|
||||
*/
|
||||
protected void goForResultAndFinish(Class<? extends Activity> clazz, Bundle bundle, int requestCode) {
|
||||
_goActivity(clazz, bundle, requestCode, true);
|
||||
}
|
||||
|
||||
|
||||
//可以立刻刷新Toast。推荐使用该方式。
|
||||
public void showSingletonToast(String str) {
|
||||
if (toast == null) {
|
||||
toast = Toast.makeText(getApplicationContext(), str, Toast.LENGTH_SHORT);
|
||||
} else {
|
||||
toast.setText(str);
|
||||
}
|
||||
toast.show();
|
||||
}
|
||||
|
||||
public void showToast(String msg) {
|
||||
showToast(msg, Toast.LENGTH_SHORT);
|
||||
}
|
||||
|
||||
public void showToast(String msg, int toastDuration) {
|
||||
if (null != msg && (toastDuration == Toast.LENGTH_SHORT || toastDuration == Toast.LENGTH_LONG)) {
|
||||
Toast.makeText(getApplicationContext(), msg, toastDuration).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void _goActivity(Class<? extends Activity> clazz, Bundle bundle, int requestCode, boolean finish) {
|
||||
if (null == clazz) {
|
||||
throw new IllegalArgumentException("you must pass a target activity where to go.");
|
||||
}
|
||||
Intent intent = new Intent(this, clazz);
|
||||
if (null != bundle) {
|
||||
intent.putExtras(bundle);
|
||||
}
|
||||
if (requestCode > NON_CODE) {
|
||||
startActivityForResult(intent, requestCode);
|
||||
} else {
|
||||
startActivity(intent);
|
||||
}
|
||||
if (finish) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.tophold.example.base;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Observer;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import com.tophold.example.demo.kview.forex.api.RetrofitManager;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/22 14:06
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class BaseFragment extends android.support.v4.app.Fragment {
|
||||
CompositeDisposable disposables;
|
||||
|
||||
protected String TAG;
|
||||
protected Context mContext;
|
||||
protected Activity mActivity;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
TAG = this.getClass().getSimpleName();
|
||||
mContext = this.getActivity();
|
||||
mActivity = getActivity();
|
||||
if (isBindEventBusHere()) {
|
||||
EventBus.getDefault().register(this);
|
||||
}
|
||||
}
|
||||
public boolean isBindEventBusHere() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (isBindEventBusHere()) {
|
||||
EventBus.getDefault().unregister(this);
|
||||
}
|
||||
if (disposables != null) disposables.clear();
|
||||
}
|
||||
|
||||
public void unSubscription(Disposable disposable) {
|
||||
if (disposables == null) {
|
||||
synchronized (CompositeDisposable.class) {
|
||||
if (disposables == null) {
|
||||
disposables = new CompositeDisposable();
|
||||
}
|
||||
}
|
||||
}
|
||||
disposables.add(disposable);
|
||||
}
|
||||
/**
|
||||
* @param observable
|
||||
* @param observer
|
||||
*/
|
||||
public void call(Observable observable, Observer<?> observer) {
|
||||
RetrofitManager.call(observable, observer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.tophold.example.demo.fund;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import com.tophold.example.base.BaseActivity;
|
||||
import com.tophold.example.R;
|
||||
import com.tophold.example.demo.kview.beginner.model.OriginFundMode;
|
||||
import com.tophold.example.demo.kview.beginner.api.FundSimulateNetAPI;
|
||||
import com.tophold.example.utils.GsonUtil;
|
||||
import com.tophold.trade.utils.StringUtils;
|
||||
import com.tophold.trade.view.fund.FundMode;
|
||||
import com.tophold.trade.view.fund.FundView;
|
||||
|
||||
public class FundActivity extends BaseActivity {
|
||||
private FundView mFundView;
|
||||
List<OriginFundMode> mOriginFundModeList;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_fund);
|
||||
initView();
|
||||
initData();
|
||||
loadData();
|
||||
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
mFundView = (FundView) findViewById(R.id.af_fv_fundview);
|
||||
|
||||
/**
|
||||
* 定制,所有的画笔以及其它属性都已经暴露出来,有了更加大的定时灵活性。更多参数可以直接查看源码...
|
||||
*/
|
||||
//常规set、get...
|
||||
mFundView.getBrokenPaint().setColor(getResources().getColor(R.color.colorAccent));//设置折现颜色
|
||||
mFundView.getInnerXPaint().setStrokeWidth(1);//设置内部x轴虚线的宽度,px
|
||||
mFundView.getBrokenPaint().setStrokeWidth(1);
|
||||
//链式调用
|
||||
mFundView
|
||||
.setBasePaddingTop(140)
|
||||
.setBasePaddingLeft(50)
|
||||
.setBasePaddingRight(40)
|
||||
.setBasePaddingBottom(30)
|
||||
.setLoadingText("正在加载,马上就来...");
|
||||
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
mOriginFundModeList = new ArrayList<>();
|
||||
|
||||
}
|
||||
|
||||
private void loadData() {
|
||||
Disposable subscribe = Observable.timer(StringUtils.getRadomNum(500, 3000), TimeUnit.MILLISECONDS)
|
||||
.map(map -> {
|
||||
String originalFundData = FundSimulateNetAPI.getOriginalFundData(mContext);
|
||||
if (originalFundData == null) {
|
||||
Log.e(TAG, "loadData: 从网络获取到的数据为空");
|
||||
return null;
|
||||
}
|
||||
OriginFundMode[] originFunModes;
|
||||
try {
|
||||
originFunModes = GsonUtil.fromJson2Object(originalFundData, OriginFundMode[].class);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
List<OriginFundMode> OriginFundModeList = Arrays.asList(originFunModes);
|
||||
//开始适配图表数据
|
||||
return adapterData(OriginFundModeList);
|
||||
})
|
||||
.subscribeOn(Schedulers.computation())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
mData -> {
|
||||
if (StringUtils.isEmpty(mData)) {
|
||||
Log.d(TAG, "loadData: data is empty!");
|
||||
return;
|
||||
}
|
||||
mFundView.setDataList(mData);
|
||||
}
|
||||
, throwable -> throwable.printStackTrace());
|
||||
|
||||
unSubscription(subscribe);
|
||||
}
|
||||
|
||||
private List<FundMode> adapterData(List<OriginFundMode> originFundModeList) {
|
||||
List<FundMode> fundModeList = new ArrayList<>();//适配后的数据
|
||||
for (OriginFundMode originFundMode : originFundModeList) {
|
||||
FundMode fundMode = new FundMode(originFundMode.timestamp * 1000, originFundMode.actual);
|
||||
fundModeList.add(fundMode);
|
||||
Log.e(TAG, "adapterData: 适配之前:" + originFundMode.actual + "----->>" + fundMode.dataY);
|
||||
}
|
||||
return fundModeList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.tophold.example.demo.kview
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.tophold.example.BuildConfig
|
||||
import com.tophold.example.R
|
||||
import com.tophold.example.base.BaseActivity
|
||||
import com.tophold.example.demo.kview.beginner.ui.KViewHorizontalActivityActivity
|
||||
import com.tophold.example.demo.kview.beginner.ui.KViewVerticalActivity
|
||||
import com.tophold.example.demo.kview.btc.ui.HuobiListActivity
|
||||
import com.tophold.example.demo.kview.forex.ui.ForexListActivity
|
||||
|
||||
class KViewActivity : BaseActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_kview)
|
||||
}
|
||||
|
||||
fun kViewVertical(view: View) {
|
||||
go(KViewVerticalActivity::class.java)
|
||||
}
|
||||
|
||||
fun kViewHorizontal(view: View) {
|
||||
go(KViewHorizontalActivityActivity::class.java)
|
||||
}
|
||||
|
||||
fun kViewEvaluation(view: View) {
|
||||
go(ForexListActivity::class.java)
|
||||
}
|
||||
|
||||
fun btnDemo(view: View) {
|
||||
go(HuobiListActivity::class.java)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.tophold.example.demo.kview.beginner.api;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2017/10/25 15:43
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class FundSimulateNetAPI {
|
||||
/**
|
||||
* 获取去最原始的数据信息
|
||||
*
|
||||
* @return json data
|
||||
*/
|
||||
public static String getOriginalFundData(Context context) {
|
||||
InputStream input = null;
|
||||
try {
|
||||
input = context.getAssets().open("fund.json");
|
||||
String json = convertStreamToString(input);
|
||||
return json;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* input 流转换为字符串
|
||||
*
|
||||
* @param is
|
||||
* @return
|
||||
*/
|
||||
private static String convertStreamToString(java.io.InputStream is) {
|
||||
String s = null;
|
||||
try {
|
||||
Scanner scanner = new Scanner(is, "UTF-8").useDelimiter("\\A");
|
||||
if (scanner.hasNext()) s = scanner.next();
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.tophold.example.demo.kview.beginner.api;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2017/10/25 15:43
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class KViewSimulateNetAPI {
|
||||
/**
|
||||
* 获取去最原始的数据信息
|
||||
*
|
||||
* @return json data
|
||||
*/
|
||||
public static String getOriginalFundData(Context context, int index) {
|
||||
InputStream input = null;
|
||||
try {
|
||||
input = context.getAssets().open("timesharing" + index + ".json");
|
||||
String json = convertStreamToString(input);
|
||||
return json;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* input 流转换为字符串
|
||||
*
|
||||
* @param is
|
||||
* @return
|
||||
*/
|
||||
private static String convertStreamToString(InputStream is) {
|
||||
String s = null;
|
||||
try {
|
||||
Scanner scanner = new Scanner(is, "UTF-8").useDelimiter("\\A");
|
||||
if (scanner.hasNext()) s = scanner.next();
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.tophold.example.demo.kview.beginner.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2017/10/24 15:00
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class OriginFundMode implements Serializable {
|
||||
/**
|
||||
* actual : 103
|
||||
* createTime : Apr 10, 2017 12:04:14 AM
|
||||
* economicId : 518
|
||||
* forecast : 102
|
||||
* historyId : 449366
|
||||
* previous : 103
|
||||
* revised :
|
||||
* timestamp : 1456213500
|
||||
*/
|
||||
|
||||
public String actual;
|
||||
public String createTime;
|
||||
public int economicId;
|
||||
public String forecast;
|
||||
public int historyId;
|
||||
public String previous;
|
||||
public String revised;
|
||||
public long timestamp;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.tophold.example.demo.kview.beginner.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2017/11/21 11:09
|
||||
* 描 述 :原始数据
|
||||
* ============================================================
|
||||
**/
|
||||
public class OriginQuotes implements Serializable {
|
||||
/**
|
||||
* t : 2016-10-25 12:06:00
|
||||
* o : 2357.25
|
||||
* h : 2357.25
|
||||
* l : 2357.25
|
||||
* c : 2357.25
|
||||
*/
|
||||
public String t;
|
||||
public String o;
|
||||
public String h;
|
||||
public String l;
|
||||
public String c;
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
package com.tophold.example.demo.kview.beginner.ui;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.ColorRes;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import com.tophold.example.R;
|
||||
import com.tophold.example.demo.kview.beginner.model.OriginQuotes;
|
||||
import com.tophold.example.demo.kview.beginner.api.KViewSimulateNetAPI;
|
||||
import com.tophold.example.base.BaseActivity;
|
||||
import com.tophold.trade.utils.FormatUtil;
|
||||
import com.tophold.example.utils.GsonUtil;
|
||||
import com.tophold.trade.utils.StringUtils;
|
||||
import com.tophold.trade.utils.TimeUtils;
|
||||
import com.tophold.trade.view.kview.KView;
|
||||
import com.tophold.trade.view.kview.KViewListener;
|
||||
import com.tophold.trade.view.kview.Quotes;
|
||||
|
||||
/**
|
||||
* timesharing0:模拟的是加载更多的数据,注意,会分段取,模拟的是多次加载更多
|
||||
* timesharing1:模拟的是api请求的数据集合,注意:一次加载完毕,模拟的是第一次加载的数据
|
||||
* timesharing2:模拟的是实时**推送**的数据,注意:会分段取,一次取一个。
|
||||
*/
|
||||
public class KViewHorizontalActivityActivity extends BaseActivity {
|
||||
//bind view
|
||||
private LinearLayout mAkvLlContainer;
|
||||
private TextView mAkvTvH;
|
||||
private TextView mAkvTvO;
|
||||
private TextView mAkvTvTime;
|
||||
private TextView mAkvTvL;
|
||||
private TextView mAkvTvC;
|
||||
private TextView mAkvTvP;
|
||||
private KView mAkvKvKview;
|
||||
|
||||
//模拟网络过来的列表数据
|
||||
List<Quotes> mQuotesList;
|
||||
//模拟加载更多的数据
|
||||
List<Quotes> mLoadMoreData;
|
||||
//模拟socket推送过来的单个数据
|
||||
List<Quotes> mPushData;
|
||||
//加载更多,加载到哪儿了。因为真实应用中,也存在加载完毕的情况。这里对应加载到list的最后
|
||||
int index = 0;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_kview_horizontal);
|
||||
initView();
|
||||
initData();
|
||||
loadData();
|
||||
pushData();
|
||||
}
|
||||
|
||||
private void pushData() {
|
||||
Disposable disposable = Observable.interval(StringUtils.getRadomNum(300, 3000), TimeUnit.MILLISECONDS)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
data -> {
|
||||
int size = mPushData.size();
|
||||
if (data < size) {
|
||||
mAkvKvKview.pushKViewData(mPushData.get(data.intValue()), 0);
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
, throwable -> throwable.printStackTrace());
|
||||
|
||||
unSubscription(disposable);
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
mAkvLlContainer = (LinearLayout) findViewById(R.id.akv_ll_container);
|
||||
mAkvTvH = (TextView) findViewById(R.id.akv_tv_h);
|
||||
mAkvTvO = (TextView) findViewById(R.id.akv_tv_o);
|
||||
mAkvTvTime = (TextView) findViewById(R.id.akv_tv_time);
|
||||
mAkvTvL = (TextView) findViewById(R.id.akv_tv_l);
|
||||
mAkvTvC = (TextView) findViewById(R.id.akv_tv_c);
|
||||
mAkvTvP = (TextView) findViewById(R.id.akv_tv_p);
|
||||
mAkvKvKview = (KView) findViewById(R.id.akv_kv_kview);
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
mQuotesList = new ArrayList<>();
|
||||
mLoadMoreData = new ArrayList<>();
|
||||
mPushData = new ArrayList<>();
|
||||
|
||||
//这里先预加载加载更多的数据,然后加载更多的时候分段取出来,模拟加载更多
|
||||
initLoadMoreData();
|
||||
|
||||
//pushData
|
||||
initPushData();
|
||||
|
||||
}
|
||||
|
||||
private void initPushData() {
|
||||
String originalFundData = KViewSimulateNetAPI.getOriginalFundData(mContext, 2);
|
||||
if (originalFundData == null) {
|
||||
Log.e(TAG, "loadData: 从网络获取到的数据为空");
|
||||
return;
|
||||
}
|
||||
List<OriginQuotes> OriginFundModeList;
|
||||
try {
|
||||
OriginFundModeList = GsonUtil.fromJson2Object(originalFundData, new TypeToken<List<OriginQuotes>>() {
|
||||
}.getType());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
//开始适配图表数据
|
||||
mPushData = adapterData(OriginFundModeList);
|
||||
|
||||
}
|
||||
|
||||
private void initLoadMoreData() {
|
||||
String originalFundData = KViewSimulateNetAPI.getOriginalFundData(mContext, 0);
|
||||
if (originalFundData == null) {
|
||||
Log.e(TAG, "loadData: 从网络获取到的数据为空");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
List<OriginQuotes> quotesList = GsonUtil.fromJson2Object(originalFundData,
|
||||
new TypeToken<List<OriginQuotes>>() {
|
||||
}.getType());
|
||||
mLoadMoreData = adapterData(quotesList);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void loadData() {
|
||||
//模拟网络环境加载数据列表
|
||||
Disposable disposable = Observable.timer(StringUtils.getRadomNum(500, 2000),
|
||||
TimeUnit.MILLISECONDS)
|
||||
.doOnNext(data -> {
|
||||
String originalData = KViewSimulateNetAPI.getOriginalFundData(mContext, 2);
|
||||
if (originalData == null) {
|
||||
Log.e(TAG, "loadData: 从网络获取到的数据为空");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
List<OriginQuotes> originQuotes = GsonUtil
|
||||
.fromJson2Object(originalData, new TypeToken<List<OriginQuotes>>() {
|
||||
}.getType());
|
||||
mQuotesList = adapterData(originQuotes);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "loadData: json转换错误");
|
||||
return;
|
||||
}
|
||||
})
|
||||
.subscribeOn(Schedulers.computation())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
data -> mAkvKvKview.setKViewData(mQuotesList, new KViewListener.MasterTouchListener() {
|
||||
@Override
|
||||
public void onLongTouch(Quotes preQuotes, Quotes currentQuotes) {
|
||||
showContanier(preQuotes, currentQuotes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnLongTouch() {
|
||||
mAkvLlContainer.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void needLoadMore() {
|
||||
loadMore();
|
||||
}
|
||||
}),
|
||||
Throwable::printStackTrace
|
||||
);
|
||||
unSubscription(disposable);
|
||||
}
|
||||
|
||||
private void loadMore() {
|
||||
if (mLoadMoreData == null) return;
|
||||
Disposable disposable = Observable.timer(StringUtils.getRadomNum(1000, 5000), TimeUnit.MILLISECONDS)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
data -> {
|
||||
int size = mLoadMoreData.size();
|
||||
int min = size / 20;
|
||||
int max = size / 5;//一次最多加载多少
|
||||
int loadSize = StringUtils.getRadomNum(min, max);
|
||||
if (index == loadSize) {
|
||||
//没有更多数据了
|
||||
mAkvKvKview.loadMoreNoData();
|
||||
}
|
||||
if ((index + loadSize) > mLoadMoreData.size()) {
|
||||
loadSize = mLoadMoreData.size();
|
||||
}
|
||||
List<Quotes> loadList = mLoadMoreData.subList(index, index + loadSize);
|
||||
index = index + loadSize;//重置起始位置
|
||||
mAkvKvKview.loadKViewData(loadList);
|
||||
}
|
||||
, throwable -> throwable.printStackTrace());
|
||||
unSubscription(disposable);
|
||||
|
||||
}
|
||||
|
||||
private List<Quotes> adapterData(List<OriginQuotes> originFundModeList) {
|
||||
List<Quotes> fundModeList = new ArrayList<>();//适配后的数据
|
||||
for (OriginQuotes OriginQuotes : originFundModeList) {
|
||||
Quotes Quotes = new Quotes(OriginQuotes.o, OriginQuotes.h, OriginQuotes.l,
|
||||
OriginQuotes.c, OriginQuotes.t);
|
||||
fundModeList.add(Quotes);
|
||||
}
|
||||
return fundModeList;
|
||||
}
|
||||
|
||||
private void showContanier(Quotes preQuotes, Quotes currentQuotes) {
|
||||
mAkvLlContainer.setVisibility(View.VISIBLE);
|
||||
int digits = 4;
|
||||
boolean isPositive;
|
||||
String precent;
|
||||
double dis = (currentQuotes.c - preQuotes.c) / currentQuotes.c * 100;
|
||||
isPositive = dis >= 0;
|
||||
precent = FormatUtil.formatBySubString(dis, 2);
|
||||
precent += "%";
|
||||
|
||||
//
|
||||
mAkvTvH.setText(FormatUtil.numFormat(currentQuotes.h, digits));
|
||||
mAkvTvO.setText(FormatUtil.numFormat(currentQuotes.o, digits));
|
||||
mAkvTvL.setText(FormatUtil.numFormat(currentQuotes.l, digits));
|
||||
mAkvTvC.setText(FormatUtil.numFormat(currentQuotes.c, digits));
|
||||
mAkvTvP.setText(precent);
|
||||
mAkvTvTime.setText(TimeUtils.millis2String(currentQuotes.t, new SimpleDateFormat("MM-dd HH:mm")));
|
||||
|
||||
if (isPositive) {
|
||||
mAkvTvH.setTextColor(getMyColor(R.color.color_timeSharing_callBackRed));
|
||||
mAkvTvO.setTextColor(getMyColor(R.color.color_timeSharing_callBackRed));
|
||||
mAkvTvL.setTextColor(getMyColor(R.color.color_timeSharing_callBackRed));
|
||||
mAkvTvC.setTextColor(getMyColor(R.color.color_timeSharing_callBackRed));
|
||||
mAkvTvP.setTextColor(getMyColor(R.color.color_timeSharing_callBackRed));
|
||||
} else {
|
||||
mAkvTvH.setTextColor(getMyColor(R.color.color_timeSharing_callBackGreen));
|
||||
mAkvTvO.setTextColor(getMyColor(R.color.color_timeSharing_callBackGreen));
|
||||
mAkvTvL.setTextColor(getMyColor(R.color.color_timeSharing_callBackGreen));
|
||||
mAkvTvC.setTextColor(getMyColor(R.color.color_timeSharing_callBackGreen));
|
||||
mAkvTvP.setTextColor(getMyColor(R.color.color_timeSharing_callBackGreen));
|
||||
}
|
||||
}
|
||||
|
||||
private int getMyColor(@ColorRes int colorId) {
|
||||
return getResources().getColor(colorId);
|
||||
}
|
||||
|
||||
public void showCandle(View view) {
|
||||
boolean showTimSharing = mAkvKvKview.isShowTimSharing();
|
||||
mAkvKvKview.setShowTimSharing(!showTimSharing);
|
||||
if (!showTimSharing) {
|
||||
((Button) view).setText("点击展示蜡烛图");
|
||||
} else {
|
||||
((Button) view).setText("点击展示分时图");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
package com.tophold.example.demo.kview.beginner.ui;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.ColorRes;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import com.tophold.example.base.BaseActivity;
|
||||
import com.tophold.example.R;
|
||||
import com.tophold.example.demo.kview.beginner.api.KViewSimulateNetAPI;
|
||||
import com.tophold.example.demo.kview.beginner.model.OriginQuotes;
|
||||
import com.tophold.trade.utils.FormatUtil;
|
||||
import com.tophold.example.utils.GsonUtil;
|
||||
import com.tophold.trade.utils.StringUtils;
|
||||
import com.tophold.trade.utils.TimeUtils;
|
||||
import com.tophold.trade.view.kview.KView;
|
||||
import com.tophold.trade.view.kview.KViewListener;
|
||||
import com.tophold.trade.view.kview.Quotes;
|
||||
|
||||
/**
|
||||
* timesharing0:模拟的是加载更多的数据,注意,会分段取,模拟的是多次加载更多
|
||||
* timesharing1:模拟的是api请求的数据集合,注意:一次加载完毕,模拟的是第一次加载的数据
|
||||
* timesharing2:模拟的是实时**推送**的数据,注意:会分段取,一次取一个。
|
||||
*/
|
||||
public class KViewVerticalActivity extends BaseActivity {
|
||||
//bind view
|
||||
private LinearLayout mAkvLlContainer;
|
||||
private TextView mAkvTvH;
|
||||
private TextView mAkvTvO;
|
||||
private TextView mAkvTvTime;
|
||||
private TextView mAkvTvL;
|
||||
private TextView mAkvTvC;
|
||||
private TextView mAkvTvP;
|
||||
private KView mAkvKvKview;
|
||||
private Button mAkvBtnShowCandle;
|
||||
private Button mAkvBtnShowMinnor;
|
||||
|
||||
//模拟网络过来的列表数据
|
||||
List<Quotes> mQuotesList;
|
||||
//模拟加载更多的数据
|
||||
List<Quotes> mLoadMoreData;
|
||||
//模拟socket推送过来的单个数据
|
||||
List<Quotes> mPushData;
|
||||
//加载更多,加载到哪儿了。因为真实应用中,也存在加载完毕的情况。这里对应加载到list的最后
|
||||
int index = 0;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_kview_vertical);
|
||||
initView();
|
||||
initData();
|
||||
loadData();
|
||||
pushData();
|
||||
}
|
||||
|
||||
private void pushData() {
|
||||
Disposable disposable = Observable.interval(StringUtils.getRadomNum(300, 3000), TimeUnit.MILLISECONDS)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
data -> {
|
||||
int size = mPushData.size();
|
||||
if (data < size) {
|
||||
mAkvKvKview.pushKViewData(mPushData.get(data.intValue()), 0);
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
, throwable -> throwable.printStackTrace());
|
||||
|
||||
unSubscription(disposable);
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
mAkvLlContainer = (LinearLayout) findViewById(R.id.akv_ll_container);
|
||||
mAkvTvH = (TextView) findViewById(R.id.akv_tv_h);
|
||||
mAkvTvO = (TextView) findViewById(R.id.akv_tv_o);
|
||||
mAkvTvTime = (TextView) findViewById(R.id.akv_tv_time);
|
||||
mAkvTvL = (TextView) findViewById(R.id.akv_tv_l);
|
||||
mAkvTvC = (TextView) findViewById(R.id.akv_tv_c);
|
||||
mAkvTvP = (TextView) findViewById(R.id.akv_tv_p);
|
||||
mAkvKvKview = (KView) findViewById(R.id.akv_kv_kview);
|
||||
mAkvBtnShowCandle = (Button) findViewById(R.id.akv_btn_showCandle);
|
||||
mAkvBtnShowMinnor = (Button) findViewById(R.id.akv_btn_showMinnor);
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
mQuotesList = new ArrayList<>();
|
||||
mLoadMoreData = new ArrayList<>();
|
||||
mPushData = new ArrayList<>();
|
||||
|
||||
//这里先预加载加载更多的数据,然后加载更多的时候分段取出来,模拟加载更多
|
||||
initLoadMoreData();
|
||||
|
||||
//pushData
|
||||
initPushData();
|
||||
|
||||
}
|
||||
|
||||
private void initPushData() {
|
||||
String originalFundData = KViewSimulateNetAPI.getOriginalFundData(mContext, 3);
|
||||
if (originalFundData == null) {
|
||||
Log.e(TAG, "loadData: 从网络获取到的数据为空");
|
||||
return;
|
||||
}
|
||||
List<OriginQuotes> OriginFundModeList;
|
||||
try {
|
||||
OriginFundModeList = GsonUtil.fromJson2Object(originalFundData, new TypeToken<List<OriginQuotes>>() {
|
||||
}.getType());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
//开始适配图表数据
|
||||
mPushData = adapterData(OriginFundModeList);
|
||||
|
||||
}
|
||||
|
||||
private void initLoadMoreData() {
|
||||
String originalFundData = KViewSimulateNetAPI.getOriginalFundData(mContext, 3);
|
||||
if (originalFundData == null) {
|
||||
Log.e(TAG, "loadData: 从网络获取到的数据为空");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
List<OriginQuotes> quotesList = GsonUtil.fromJson2Object(originalFundData,
|
||||
new TypeToken<List<OriginQuotes>>() {
|
||||
}.getType());
|
||||
mLoadMoreData = adapterData(quotesList);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void loadData() {
|
||||
//模拟网络环境加载数据列表
|
||||
Disposable disposable = Observable.timer(StringUtils.getRadomNum(500, 2000),
|
||||
TimeUnit.MILLISECONDS)
|
||||
.doOnNext(data -> {
|
||||
String originalData = KViewSimulateNetAPI.getOriginalFundData(mContext, 3);
|
||||
if (originalData == null) {
|
||||
Log.e(TAG, "loadData: 从网络获取到的数据为空");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
List<OriginQuotes> originQuotes = GsonUtil
|
||||
.fromJson2Object(originalData, new TypeToken<List<OriginQuotes>>() {
|
||||
}.getType());
|
||||
mQuotesList = adapterData(originQuotes);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "loadData: json转换错误");
|
||||
return;
|
||||
}
|
||||
})
|
||||
.subscribeOn(Schedulers.computation())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
data -> {
|
||||
mAkvKvKview.setKViewData(mQuotesList, new KViewListener.MasterTouchListener() {
|
||||
@Override
|
||||
public void onLongTouch(Quotes preQuotes, Quotes currentQuotes) {
|
||||
showContanier(preQuotes, currentQuotes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnLongTouch() {
|
||||
mAkvLlContainer.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void needLoadMore() {
|
||||
loadMore();
|
||||
}
|
||||
});
|
||||
},
|
||||
throwable -> throwable.printStackTrace()
|
||||
);
|
||||
unSubscription(disposable);
|
||||
}
|
||||
|
||||
private void loadMore() {
|
||||
if (mLoadMoreData == null) return;
|
||||
Disposable disposable = Observable.timer(StringUtils.getRadomNum(1000, 5000), TimeUnit.MILLISECONDS)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
data -> {
|
||||
int size = mLoadMoreData.size();
|
||||
int min = size / 20;
|
||||
int max = size / 5;//一次最多加载多少
|
||||
int loadSize = StringUtils.getRadomNum(min, max);
|
||||
if (index == loadSize) {
|
||||
//没有更多数据了
|
||||
mAkvKvKview.loadMoreNoData();
|
||||
}
|
||||
if ((index + loadSize) > mLoadMoreData.size()) {
|
||||
loadSize = mLoadMoreData.size();
|
||||
}
|
||||
List<Quotes> loadList = mLoadMoreData.subList(index, index + loadSize);
|
||||
index = index + loadSize;//重置起始位置
|
||||
mAkvKvKview.loadKViewData(loadList);
|
||||
}
|
||||
, throwable -> throwable.printStackTrace());
|
||||
unSubscription(disposable);
|
||||
|
||||
}
|
||||
|
||||
public void showCandle(View view) {
|
||||
boolean showTimSharing = mAkvKvKview.isShowTimSharing();
|
||||
mAkvKvKview.setShowTimSharing(!showTimSharing);
|
||||
if (!showTimSharing) {
|
||||
mAkvBtnShowCandle.setText("点击展示蜡烛图");
|
||||
} else {
|
||||
mAkvBtnShowCandle.setText("点击展示分时图");
|
||||
}
|
||||
}
|
||||
|
||||
public void showMinor(View view) {
|
||||
boolean showMinor = mAkvKvKview.isShowMinor();
|
||||
mAkvKvKview.setShowMinor(!showMinor);
|
||||
if (!showMinor) {
|
||||
mAkvBtnShowMinnor.setText("点击不显示副图");
|
||||
} else {
|
||||
mAkvBtnShowMinnor.setText("点击显示副图");
|
||||
}
|
||||
}
|
||||
|
||||
private List<Quotes> adapterData(List<OriginQuotes> originFundModeList) {
|
||||
List<Quotes> fundModeList = new ArrayList<>();//适配后的数据
|
||||
for (OriginQuotes OriginQuotes : originFundModeList) {
|
||||
Quotes Quotes = new Quotes(OriginQuotes.o, OriginQuotes.h, OriginQuotes.l,
|
||||
OriginQuotes.c, OriginQuotes.t);
|
||||
fundModeList.add(Quotes);
|
||||
}
|
||||
return fundModeList;
|
||||
}
|
||||
|
||||
private void showContanier(Quotes preQuotes, Quotes currentQuotes) {
|
||||
mAkvLlContainer.setVisibility(View.VISIBLE);
|
||||
int digits = 4;
|
||||
boolean isPositive;
|
||||
String precent;
|
||||
double dis = (currentQuotes.c - preQuotes.c) / currentQuotes.c * 100;
|
||||
isPositive = dis >= 0;
|
||||
precent = FormatUtil.formatBySubString(dis, 2);
|
||||
precent += "%";
|
||||
|
||||
//
|
||||
mAkvTvH.setText(FormatUtil.numFormat(currentQuotes.h, digits));
|
||||
mAkvTvO.setText(FormatUtil.numFormat(currentQuotes.o, digits));
|
||||
mAkvTvL.setText(FormatUtil.numFormat(currentQuotes.l, digits));
|
||||
mAkvTvC.setText(FormatUtil.numFormat(currentQuotes.c, digits));
|
||||
mAkvTvP.setText(precent);
|
||||
mAkvTvTime.setText(TimeUtils.millis2String(currentQuotes.t, new SimpleDateFormat("MM-dd HH:mm")));
|
||||
|
||||
if (isPositive) {
|
||||
mAkvTvH.setTextColor(getMyColor(R.color.color_timeSharing_callBackRed));
|
||||
mAkvTvO.setTextColor(getMyColor(R.color.color_timeSharing_callBackRed));
|
||||
mAkvTvL.setTextColor(getMyColor(R.color.color_timeSharing_callBackRed));
|
||||
mAkvTvC.setTextColor(getMyColor(R.color.color_timeSharing_callBackRed));
|
||||
mAkvTvP.setTextColor(getMyColor(R.color.color_timeSharing_callBackRed));
|
||||
} else {
|
||||
mAkvTvH.setTextColor(getMyColor(R.color.color_timeSharing_callBackGreen));
|
||||
mAkvTvO.setTextColor(getMyColor(R.color.color_timeSharing_callBackGreen));
|
||||
mAkvTvL.setTextColor(getMyColor(R.color.color_timeSharing_callBackGreen));
|
||||
mAkvTvC.setTextColor(getMyColor(R.color.color_timeSharing_callBackGreen));
|
||||
mAkvTvP.setTextColor(getMyColor(R.color.color_timeSharing_callBackGreen));
|
||||
}
|
||||
}
|
||||
|
||||
private int getMyColor(@ColorRes int colorId) {
|
||||
return getResources().getColor(colorId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package com.tophold.example.demo.kview.btc.api;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/28 14:14
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class GZipUtil {
|
||||
// 压缩
|
||||
public static byte[] compress(byte[] data) throws IOException {
|
||||
if (data == null || data.length == 0) {
|
||||
return null;
|
||||
}
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
GZIPOutputStream gzip = new GZIPOutputStream(out);
|
||||
gzip.write(data);
|
||||
gzip.close();
|
||||
return out.toByteArray();//out.toString("ISO-8859-1");
|
||||
}
|
||||
|
||||
public static byte[] compress(String str) throws IOException {
|
||||
if (str == null || str.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
return compress(str.getBytes("utf-8"));
|
||||
}
|
||||
|
||||
// 解压缩
|
||||
public static byte[] uncompress(byte[] data) throws IOException {
|
||||
if (data == null || data.length == 0) {
|
||||
return data;
|
||||
}
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(data);
|
||||
GZIPInputStream gunzip = new GZIPInputStream(in);
|
||||
byte[] buffer = new byte[256];
|
||||
int n;
|
||||
while ((n = gunzip.read(buffer)) >= 0) {
|
||||
out.write(buffer, 0, n);
|
||||
}
|
||||
gunzip.close();
|
||||
in.close();
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
public static String uncompressBytes(byte[] data) throws IOException {
|
||||
byte[] bytes = uncompress(data);
|
||||
return new String(bytes);
|
||||
}
|
||||
|
||||
public static String uncompress(String str) throws IOException {
|
||||
if (str == null || str.length() == 0) {
|
||||
return str;
|
||||
}
|
||||
byte[] data = uncompress(str.getBytes("utf-8")); // ISO-8859-1
|
||||
return new String(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param @param unZipfile
|
||||
* @param @param destFile 指定读取文件,需要从压缩文件中读取文件内容的文件名
|
||||
* @param @return 设定文件
|
||||
* @return String 返回类型
|
||||
* @throws
|
||||
* @Title: unZip
|
||||
* @Description: TODO(这里用一句话描述这个方法的作用)
|
||||
*/
|
||||
public static String unZip(String unZipfile, String destFile) {// unZipfileName需要解压的zip文件名
|
||||
InputStream inputStream;
|
||||
String inData = null;
|
||||
try {
|
||||
// 生成一个zip的文件
|
||||
File f = new File(unZipfile);
|
||||
ZipFile zipFile = new ZipFile(f);
|
||||
|
||||
// 遍历zipFile中所有的实体,并把他们解压出来
|
||||
ZipEntry entry = zipFile.getEntry(destFile);
|
||||
if (!entry.isDirectory()) {
|
||||
// 获取出该压缩实体的输入流
|
||||
inputStream = zipFile.getInputStream(entry);
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
byte[] bys = new byte[4096];
|
||||
for (int p = -1; (p = inputStream.read(bys)) != -1; ) {
|
||||
out.write(bys, 0, p);
|
||||
}
|
||||
inData = out.toString();
|
||||
out.close();
|
||||
inputStream.close();
|
||||
}
|
||||
zipFile.close();
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
return inData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.tophold.example.demo.kview.btc.api;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
/**
|
||||
* 拦截器
|
||||
*
|
||||
* 向请求头里添加公共参数
|
||||
* Created by zhouwei on 16/11/10.
|
||||
*/
|
||||
|
||||
public class HttpCommonInterceptor implements Interceptor {
|
||||
|
||||
private Map<String,String> mHeaderParamsMap = new HashMap<>();
|
||||
public HttpCommonInterceptor() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response intercept(Chain chain) throws IOException {
|
||||
Log.d("HttpCommonInterceptor","add common params");
|
||||
Request oldRequest = chain.request();
|
||||
|
||||
// 添加新的参数,添加到url 中
|
||||
/* HttpUrl.Builder authorizedUrlBuilder = oldRequest.url()
|
||||
.newBuilder()
|
||||
.scheme(oldRequest.url().scheme())
|
||||
.host(oldRequest.url().host());*/
|
||||
|
||||
// 新的请求
|
||||
|
||||
Request.Builder requestBuilder = oldRequest.newBuilder();
|
||||
requestBuilder.method(oldRequest.method(), oldRequest.body());
|
||||
//添加公共参数,添加到header中
|
||||
if(mHeaderParamsMap.size() > 0){
|
||||
for(Map.Entry<String,String> params:mHeaderParamsMap.entrySet()){
|
||||
requestBuilder.header(params.getKey(),params.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
Request newRequest = requestBuilder.build();
|
||||
|
||||
return chain.proceed(newRequest);
|
||||
}
|
||||
|
||||
public static class Builder{
|
||||
HttpCommonInterceptor mHttpCommonInterceptor;
|
||||
|
||||
public Builder(){
|
||||
mHttpCommonInterceptor = new HttpCommonInterceptor();
|
||||
}
|
||||
|
||||
public Builder addHeaderParams(String key, String value){
|
||||
mHttpCommonInterceptor.mHeaderParamsMap.put(key,value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addHeaderParams(String key, int value){
|
||||
return addHeaderParams(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
public Builder addHeaderParams(String key, float value){
|
||||
return addHeaderParams(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
public Builder addHeaderParams(String key, long value){
|
||||
return addHeaderParams(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
public Builder addHeaderParams(String key, double value){
|
||||
return addHeaderParams(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
|
||||
public HttpCommonInterceptor build(){
|
||||
return mHttpCommonInterceptor;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.tophold.example.demo.kview.btc.api;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.QueryMap;
|
||||
import com.tophold.example.demo.kview.btc.model.HuobiData;
|
||||
import com.tophold.example.demo.kview.btc.model.HuobiSymbol;
|
||||
import com.tophold.example.demo.kview.btc.model.HuobiQuote;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/22 11:31
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public interface HuobiService {
|
||||
@GET("/market/history/kline")
|
||||
Observable<HuobiData<List<HuobiQuote>>> chartQuotes(@QueryMap Map<String, Object> params);
|
||||
|
||||
@GET("/v1/common/symbols")
|
||||
Observable<HuobiData<List<HuobiSymbol>>> getSymbolList(@QueryMap Map<String, Object> params);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.tophold.example.demo.kview.btc.api;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/22 21:31
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class HuobiSocketApi {
|
||||
public static final String TAG = HuobiSocketApi.class.getSimpleName();
|
||||
|
||||
public static void ping(long time) {
|
||||
String str = "{\"ping\":" + time + "}";
|
||||
sendService(str);
|
||||
}
|
||||
|
||||
public static void pong(long time) {
|
||||
String str = "{\"pong\":" + time + "}";
|
||||
sendService(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 订阅KLine和取消KLine
|
||||
*
|
||||
* @param id 一个唯一值,建议用时间戳
|
||||
* @param symbol
|
||||
* @param period 周期,不管任何周期,全部转化为时间戳格式
|
||||
* @param sub true:订阅;false:取消订阅
|
||||
*/
|
||||
public static void kLine(long id, String symbol, long period, boolean sub) {
|
||||
String periodByMs = getPeriodByMs(period);
|
||||
if (periodByMs == null) {
|
||||
Log.e(TAG, "subKLine: period 不合法!!!");
|
||||
return;
|
||||
}
|
||||
String kline = "market." + symbol + ".kline." + periodByMs;
|
||||
String json = "{" + (sub ? "\"sub\"" : "\"unsub\"") + ":\"" + kline + "\",\"id\":\"" + id + "\"}";
|
||||
|
||||
sendService(json);
|
||||
|
||||
}
|
||||
|
||||
public static void subKLine(String symbol, long period, boolean sub) {
|
||||
long id = System.currentTimeMillis();
|
||||
kLine(id, symbol, period, sub);
|
||||
}
|
||||
|
||||
private static void sendService(String str) {
|
||||
Log.d(TAG, "sendService: " + str);
|
||||
HuobiWebSocket.getInstance().getWebSocket().send(str);
|
||||
}
|
||||
|
||||
private static String getPeriodByMs(long ms) {
|
||||
long s = ms / 1000;
|
||||
if (s == 1 * 60) return "1min";
|
||||
if (s == 5 * 60) return "5min";
|
||||
if (s == 15 * 60) return "15min";
|
||||
if (s == 30 * 60) return "30min";
|
||||
if (s == 60 * 60) return "60min";
|
||||
if (s == 24 * 60 * 60) return "1day";
|
||||
if (s == 7 * 24 * 60 * 60) return "1week";
|
||||
if (s == 30 * 24 * 60 * 60) return "1mon";
|
||||
if (s == 365 * 24 * 60 * 60) return "1year";
|
||||
Log.d(TAG, "getPeriodByMs: unkonwn ms!!!");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.tophold.example.demo.kview.btc.api;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import com.tophold.example.demo.kview.btc.model.HuobiWsQuote;
|
||||
import com.tophold.example.utils.GsonUtil;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/22 21:26
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class HuobiSocketParser {
|
||||
public static final String TAG = HuobiSocketParser.class.getSimpleName();
|
||||
|
||||
public static void fix2Object(String str) {
|
||||
Log.d(TAG, "fix2Object: " + str);
|
||||
try {
|
||||
formatJson(str);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void formatJson(String str) throws JSONException {
|
||||
JSONObject json = new JSONObject(str);
|
||||
if (json.has("ping")) {
|
||||
long ping = json.getLong("ping");
|
||||
HuobiSocketApi.pong(ping);
|
||||
return;
|
||||
}
|
||||
|
||||
//判断不严谨
|
||||
if (json.has("ch")) {
|
||||
HuobiWsQuote huobiWsQuote = GsonUtil.fromJson2Object(str, HuobiWsQuote.class);
|
||||
if (huobiWsQuote != null) {
|
||||
obj2EventBus(huobiWsQuote);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void obj2EventBus(Object object) {
|
||||
EventBus.getDefault().post(object);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package com.tophold.example.demo.kview.btc.api;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.WebSocket;
|
||||
import okhttp3.WebSocketListener;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
import okio.ByteString;
|
||||
import com.tophold.example.BuildConfig;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/22 21:15
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class HuobiWebSocket {
|
||||
public static final String TAG = HuobiWebSocket.class.getSimpleName();
|
||||
private static final int DEFAULT_TIME_OUT = 20;//超时时间 5s
|
||||
private static final int DEFAULT_READ_TIME_OUT = 20;
|
||||
//temp quotes
|
||||
private static final String BASE_URL = "https://api.huobi.br.com:443/ws";
|
||||
|
||||
Request mRequest;
|
||||
private okhttp3.WebSocket mWebSocket;
|
||||
OkHttpClient client;
|
||||
boolean isConnctted = false;
|
||||
|
||||
public WebSocket getWebSocket() {
|
||||
return mWebSocket;
|
||||
}
|
||||
|
||||
private HuobiWebSocket() {
|
||||
// 创建 OKHttpClient
|
||||
OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
|
||||
builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);//连接超时时间
|
||||
builder.writeTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS);//写操作 超时时间
|
||||
builder.readTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS);//读操作超时时间
|
||||
builder.pingInterval(5000, TimeUnit.MILLISECONDS);
|
||||
builder.retryOnConnectionFailure(true);//失败重试
|
||||
|
||||
//DEBUG模式下 添加日志拦截器
|
||||
if (BuildConfig.DEBUG) {
|
||||
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
|
||||
interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
|
||||
builder.addInterceptor(interceptor);
|
||||
}
|
||||
|
||||
// 添加公共参数拦截器
|
||||
HttpCommonInterceptor commonInterceptor = new HttpCommonInterceptor.Builder()
|
||||
.addHeaderParams("paltform", "android")
|
||||
.addHeaderParams("userToken", "1234343434dfdfd3434")
|
||||
.addHeaderParams("userId", "123445")
|
||||
.build();
|
||||
//builder.addInterceptor(commonInterceptor);
|
||||
|
||||
|
||||
//HuobiWebSocket
|
||||
client = builder.build();
|
||||
}
|
||||
|
||||
public void init() {
|
||||
mRequest = new Request.Builder().url(BASE_URL).build();
|
||||
mWebSocket = client.newWebSocket(mRequest, new WebSocketListener() {
|
||||
@Override
|
||||
public void onOpen(okhttp3.WebSocket webSocket, Response response) {
|
||||
super.onOpen(webSocket, response);
|
||||
isConnctted = true;
|
||||
Log.d(TAG, "onOpen: ");
|
||||
//Toast.makeText(MyApplication.mAppContext, "websocket连接成功...", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(okhttp3.WebSocket webSocket, String text) {
|
||||
super.onMessage(webSocket, text);
|
||||
Log.d(TAG, "onMessage: " + text);
|
||||
HuobiSocketParser.fix2Object(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(WebSocket webSocket, ByteString bytes) {
|
||||
super.onMessage(webSocket, bytes);
|
||||
String s = null;
|
||||
try {
|
||||
s = GZipUtil.uncompressBytes(bytes.toByteArray());
|
||||
HuobiSocketParser.fix2Object(s);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosed(okhttp3.WebSocket webSocket, int code, String reason) {
|
||||
super.onClosed(webSocket, code, reason);
|
||||
isConnctted = false;
|
||||
Log.d(TAG, "onClosed,code: " + code + ",reason:" + reason);
|
||||
//Toast.makeText(MyApplication.mAppContext, "websocket关闭...", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(okhttp3.WebSocket webSocket, Throwable t, @Nullable Response response) {
|
||||
super.onFailure(webSocket, t, response);
|
||||
isConnctted = false;
|
||||
Log.e(TAG, "onFailure: " + (response != null ? response.toString() : "response==null"));
|
||||
t.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static class SingletonHolder {
|
||||
private static final HuobiWebSocket INSTANCE = new HuobiWebSocket();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取RetrofitServiceManager
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static HuobiWebSocket getInstance() {
|
||||
return HuobiWebSocket.SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.tophold.example.demo.kview.btc.api;
|
||||
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Observer;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
import com.tophold.example.BuildConfig;
|
||||
|
||||
|
||||
public class RetrofitManager {
|
||||
private static final int DEFAULT_TIME_OUT = 20;//超时时间 5s
|
||||
private static final int DEFAULT_READ_TIME_OUT = 20;
|
||||
//temp quotes
|
||||
// private static final String BASE_URL = "https://api.huobipro.com";
|
||||
private static final String BASE_URL = "https://api.huobi.br.com";
|
||||
private Retrofit mRetrofit;
|
||||
|
||||
private RetrofitManager() {
|
||||
// 创建 OKHttpClient
|
||||
OkHttpClient.Builder builder = new OkHttpClient.Builder();
|
||||
builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);//连接超时时间
|
||||
builder.writeTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS);//写操作 超时时间
|
||||
builder.readTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS);//读操作超时时间
|
||||
builder.retryOnConnectionFailure(true);//失败重试
|
||||
|
||||
//DEBUG模式下 添加日志拦截器
|
||||
if (BuildConfig.DEBUG) {
|
||||
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
|
||||
interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
|
||||
builder.addInterceptor(interceptor);
|
||||
}
|
||||
|
||||
// 添加公共参数拦截器
|
||||
HttpCommonInterceptor commonInterceptor = new HttpCommonInterceptor.Builder()
|
||||
.addHeaderParams("paltform", "android")
|
||||
.addHeaderParams("userToken", "1234343434dfdfd3434")
|
||||
.addHeaderParams("userId", "123445")
|
||||
.build();
|
||||
//builder.addInterceptor(commonInterceptor);
|
||||
|
||||
|
||||
// 创建Retrofit
|
||||
mRetrofit = new Retrofit.Builder()
|
||||
.baseUrl(BASE_URL)
|
||||
.addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.client(builder.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
private static class SingletonHolder {
|
||||
private static final RetrofitManager INSTANCE = new RetrofitManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取RetrofitServiceManager
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static RetrofitManager getInstance() {
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对应的Service
|
||||
*
|
||||
* @param service Service 的 class
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public <T> T create(Class<T> service) {
|
||||
return mRetrofit.create(service);
|
||||
}
|
||||
|
||||
public static Observable call(Observable<?> observable, Observer observer) {
|
||||
observable.subscribeOn(Schedulers.io())
|
||||
.unsubscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(observer);
|
||||
return observable;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.tophold.example.demo.kview.btc.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/26 13:29
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class HuobiData<T> implements Serializable{
|
||||
public String status;
|
||||
public String ch;
|
||||
public long ts;
|
||||
public T data;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HuobiData{" +
|
||||
"status='" + status + '\'' +
|
||||
", ch='" + ch + '\'' +
|
||||
", ts=" + ts +
|
||||
", data=" + data +
|
||||
'}';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.tophold.example.demo.kview.btc.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/26 13:31
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class HuobiQuote implements Serializable{
|
||||
public long id;
|
||||
public double open;
|
||||
public double close;
|
||||
public double low;
|
||||
public double high;
|
||||
public double amount;
|
||||
public double vol;
|
||||
public double count;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HuobiQuote{" +
|
||||
"id='" + id + '\'' +
|
||||
", open=" + open +
|
||||
", close=" + close +
|
||||
", low=" + low +
|
||||
", high=" + high +
|
||||
", amount=" + amount +
|
||||
", vol=" + vol +
|
||||
", count=" + count +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.tophold.example.demo.kview.btc.model;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/26 13:42
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class HuobiSymbol implements Serializable {
|
||||
@SerializedName("base-currency")
|
||||
public String base_currency;
|
||||
@SerializedName("quote-currency")
|
||||
public String quote_currency;
|
||||
@SerializedName("price-precision")
|
||||
public int price_precision;
|
||||
@SerializedName("amount-precision")
|
||||
public int amount_precision;
|
||||
@SerializedName("symbol-partition")
|
||||
public String symbol_partition;
|
||||
|
||||
public HuobiSymbol(String base_currency, String quote_currency, int price_precision, int amount_precision, String symbol_partition) {
|
||||
this.base_currency = base_currency;
|
||||
this.quote_currency = quote_currency;
|
||||
this.price_precision = price_precision;
|
||||
this.amount_precision = amount_precision;
|
||||
this.symbol_partition = symbol_partition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HuobiSymbol{" +
|
||||
"base_currency='" + base_currency + '\'' +
|
||||
", quote_currency='" + quote_currency + '\'' +
|
||||
", price_precision=" + price_precision +
|
||||
", amount_precision=" + amount_precision +
|
||||
", symbol_partition='" + symbol_partition + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package com.tophold.example.demo.kview.btc.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/26 16:07
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class HuobiTab implements Serializable {
|
||||
public HuobiTab.HuobiType mForexType;
|
||||
public String tabName;
|
||||
|
||||
public HuobiTab(HuobiTab.HuobiType forexType, String tabName) {
|
||||
this.mForexType = forexType;
|
||||
this.tabName = tabName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对应类型的长度
|
||||
*
|
||||
* @return sencond
|
||||
*/
|
||||
public long getTypeLength() {
|
||||
long len = 0;
|
||||
switch (mForexType) {
|
||||
case _timeShring:
|
||||
len = 60;
|
||||
break;
|
||||
case _1m:
|
||||
len = 60;
|
||||
break;
|
||||
case _5m:
|
||||
len = 5 * 60;
|
||||
break;
|
||||
case _15m:
|
||||
len = 15 * 60;
|
||||
break;
|
||||
case _30m:
|
||||
len = 30 * 60;
|
||||
break;
|
||||
case _60m:
|
||||
len = 60 * 60;
|
||||
break;
|
||||
case _1d:
|
||||
len = 24 * 60 * 60;
|
||||
break;
|
||||
case _1w:
|
||||
len = 7 * 24 * 60 * 60;
|
||||
break;
|
||||
case _1mon:
|
||||
len = 30 * 24 * 60 * 60;
|
||||
break;
|
||||
case _1y:
|
||||
len = 365 * 24 * 60 * 60;
|
||||
break;
|
||||
default:
|
||||
len = 60;
|
||||
break;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据mForexType返回接口需要的类型字段
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getType() {
|
||||
String typeMsg = "1min";
|
||||
switch (mForexType) {
|
||||
case _timeShring:
|
||||
typeMsg = "1min";
|
||||
break;
|
||||
case _1m:
|
||||
typeMsg = "1min";
|
||||
break;
|
||||
case _5m:
|
||||
typeMsg = "5min";
|
||||
break;
|
||||
case _15m:
|
||||
typeMsg = "15min";
|
||||
break;
|
||||
case _30m:
|
||||
typeMsg = "30min";
|
||||
break;
|
||||
case _60m:
|
||||
typeMsg = "60min";
|
||||
break;
|
||||
case _1d:
|
||||
typeMsg = "1day";
|
||||
break;
|
||||
case _1w:
|
||||
typeMsg = "1week";
|
||||
break;
|
||||
case _1mon:
|
||||
typeMsg = "1mon";
|
||||
break;
|
||||
case _1y:
|
||||
typeMsg = "1year";
|
||||
break;
|
||||
default:
|
||||
typeMsg = "1min";
|
||||
break;
|
||||
}
|
||||
return typeMsg;
|
||||
}
|
||||
|
||||
public enum HuobiType {
|
||||
_timeShring,
|
||||
_1m,
|
||||
_5m,
|
||||
_15m,
|
||||
_30m,
|
||||
_60m,
|
||||
_1d,
|
||||
_1w,
|
||||
_1mon,
|
||||
_1y
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.tophold.example.demo.kview.btc.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/28 18:39
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class HuobiWsQuote implements Serializable{
|
||||
|
||||
/**
|
||||
* ch : market.eosusdt.kline.1min
|
||||
* ts : 1522233524438
|
||||
* tick : {"id":1522233480,"open":6.317,"close":6.3216,"low":6.3091,"high":6.3216,"amount":2024.6227,"vol":12789.80758224,"count":21}
|
||||
*/
|
||||
|
||||
public String ch;
|
||||
public long ts;
|
||||
public TickBean tick;
|
||||
|
||||
public static class TickBean {
|
||||
/**
|
||||
* id : 1522233480
|
||||
* open : 6.317
|
||||
* close : 6.3216
|
||||
* low : 6.3091
|
||||
* high : 6.3216
|
||||
* amount : 2024.6227
|
||||
* vol : 12789.80758224
|
||||
* count : 21
|
||||
*/
|
||||
|
||||
public int id;
|
||||
public double open;
|
||||
public double close;
|
||||
public double low;
|
||||
public double high;
|
||||
public double amount;
|
||||
public double vol;
|
||||
public int count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
package com.tophold.example.demo.kview.btc.ui;
|
||||
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.ColorRes;
|
||||
import android.support.design.widget.TabLayout;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.tophold.example.base.BaseActivity;
|
||||
import com.tophold.example.utils.NoScrollViewPager;
|
||||
import com.tophold.example.R;
|
||||
import com.tophold.example.demo.kview.btc.model.HuobiSymbol;
|
||||
import com.tophold.example.demo.kview.btc.model.HuobiTab;
|
||||
import com.tophold.trade.utils.FormatUtil;
|
||||
import com.tophold.trade.utils.TimeUtils;
|
||||
import com.tophold.trade.view.kview.Quotes;
|
||||
|
||||
public class HuobiActivity extends BaseActivity {
|
||||
public static final String KEY_FOREX = "KEY_FOREX";
|
||||
public static final String KEY_HORIZONTAL = "KEY_HORIZONTAL";
|
||||
private TabLayout mAfTlTablayout;
|
||||
private NoScrollViewPager mAfVpViewpager;
|
||||
|
||||
private LinearLayout mAkvLlContainer;
|
||||
private TextView mAkvTvH;
|
||||
private TextView mAkvTvO;
|
||||
private TextView mAkvTvTime;
|
||||
private TextView mAkvTvL;
|
||||
private TextView mAkvTvC;
|
||||
private TextView mAkvTvP;
|
||||
private TextView af_tv_symbol;
|
||||
private TextView mAkvTvBlank;
|
||||
|
||||
//是否是横屏
|
||||
boolean mIsHorizontal = false;
|
||||
|
||||
private List<HuobiTab> mForexTabList;
|
||||
private List<Fragment> mKViewFragmentList;
|
||||
|
||||
HuobiSymbol mForex;
|
||||
|
||||
@Override
|
||||
protected void getBundleExtras(Bundle extras) {
|
||||
super.getBundleExtras(extras);
|
||||
mForex = (HuobiSymbol) extras.getSerializable(KEY_FOREX);
|
||||
mIsHorizontal = extras.getBoolean(KEY_HORIZONTAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (mIsHorizontal) {
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);// 隐藏标题
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN);// 设置全屏
|
||||
}
|
||||
setContentView(R.layout.activity_huobi);
|
||||
initView();
|
||||
initData();
|
||||
initAdapter();
|
||||
loadData();
|
||||
initListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
if (mIsHorizontal) {
|
||||
if (getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||
}
|
||||
}
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
mAfTlTablayout = (TabLayout) findViewById(R.id.af_tl_tablayout);
|
||||
mAfVpViewpager = (NoScrollViewPager) findViewById(R.id.af_vp_viewpager);
|
||||
|
||||
mAkvLlContainer = (LinearLayout) findViewById(R.id.akv_ll_container);
|
||||
mAkvTvH = (TextView) findViewById(R.id.akv_tv_h);
|
||||
mAkvTvO = (TextView) findViewById(R.id.akv_tv_o);
|
||||
mAkvTvTime = (TextView) findViewById(R.id.akv_tv_time);
|
||||
mAkvTvL = (TextView) findViewById(R.id.akv_tv_l);
|
||||
mAkvTvC = (TextView) findViewById(R.id.akv_tv_c);
|
||||
mAkvTvP = (TextView) findViewById(R.id.akv_tv_p);
|
||||
mAkvTvBlank = (TextView) findViewById(R.id.af_tv_blank);
|
||||
af_tv_symbol = (TextView) findViewById(R.id.af_tv_symbol);
|
||||
|
||||
if (mIsHorizontal) {
|
||||
af_tv_symbol.setVisibility(View.GONE);
|
||||
mAkvTvBlank.setVisibility(View.GONE);
|
||||
} else {
|
||||
af_tv_symbol.setVisibility(View.VISIBLE);
|
||||
mAkvTvBlank.setVisibility(View.VISIBLE);
|
||||
af_tv_symbol.setText(mForex.base_currency + "/" + mForex.quote_currency);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
mForexTabList = new ArrayList<>();
|
||||
mForexTabList.add(new HuobiTab(HuobiTab.HuobiType._timeShring, "分时"));
|
||||
mForexTabList.add(new HuobiTab(HuobiTab.HuobiType._1m, "1分"));
|
||||
mForexTabList.add(new HuobiTab(HuobiTab.HuobiType._5m, "5分"));
|
||||
mForexTabList.add(new HuobiTab(HuobiTab.HuobiType._15m, "15分"));
|
||||
mForexTabList.add(new HuobiTab(HuobiTab.HuobiType._30m, "30分"));
|
||||
mForexTabList.add(new HuobiTab(HuobiTab.HuobiType._60m, "1小时"));
|
||||
mForexTabList.add(new HuobiTab(HuobiTab.HuobiType._1d, "日K"));
|
||||
mForexTabList.add(new HuobiTab(HuobiTab.HuobiType._1w, "周K"));
|
||||
mForexTabList.add(new HuobiTab(HuobiTab.HuobiType._1mon, "月K"));
|
||||
mForexTabList.add(new HuobiTab(HuobiTab.HuobiType._1y, "年K"));
|
||||
|
||||
mAfTlTablayout.setTabMode(TabLayout.MODE_SCROLLABLE);
|
||||
|
||||
mKViewFragmentList = new ArrayList<>();
|
||||
for (HuobiTab forexTab : mForexTabList) {
|
||||
mKViewFragmentList.add(HuobiFragment.newInstance(forexTab, mForex));
|
||||
}
|
||||
}
|
||||
|
||||
private void initAdapter() {
|
||||
mAfVpViewpager.setAdapter(new HuobiAdapter(getSupportFragmentManager(), mKViewFragmentList, mForexTabList));
|
||||
mAfTlTablayout.setupWithViewPager(mAfVpViewpager);
|
||||
}
|
||||
|
||||
private void loadData() {
|
||||
|
||||
}
|
||||
|
||||
private void initListener() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void hidenContainer() {
|
||||
mAfTlTablayout.setVisibility(View.VISIBLE);
|
||||
mAkvLlContainer.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public void showContanier(Quotes preQuotes, Quotes currentQuotes) {
|
||||
mAfTlTablayout.setVisibility(View.GONE);
|
||||
mAkvLlContainer.setVisibility(View.VISIBLE);
|
||||
int digits = 5;
|
||||
boolean isPositive;
|
||||
String precent;
|
||||
double dis = (currentQuotes.c - preQuotes.c) / currentQuotes.c * 100;
|
||||
isPositive = dis >= 0;
|
||||
precent = FormatUtil.formatBySubString(dis, 2);
|
||||
precent += "%";
|
||||
|
||||
//
|
||||
mAkvTvH.setText(FormatUtil.numFormat(currentQuotes.h, digits));
|
||||
mAkvTvO.setText(FormatUtil.numFormat(currentQuotes.o, digits));
|
||||
mAkvTvL.setText(FormatUtil.numFormat(currentQuotes.l, digits));
|
||||
mAkvTvC.setText(FormatUtil.numFormat(currentQuotes.c, digits));
|
||||
mAkvTvP.setText(precent);
|
||||
mAkvTvTime.setText(TimeUtils.millis2String(currentQuotes.t, new SimpleDateFormat("MM-dd HH:mm")));
|
||||
|
||||
if (isPositive) {
|
||||
mAkvTvH.setTextColor(getMyColor(R.color.color_timeSharing_callBackRed));
|
||||
mAkvTvO.setTextColor(getMyColor(R.color.color_timeSharing_callBackRed));
|
||||
mAkvTvL.setTextColor(getMyColor(R.color.color_timeSharing_callBackRed));
|
||||
mAkvTvC.setTextColor(getMyColor(R.color.color_timeSharing_callBackRed));
|
||||
mAkvTvP.setTextColor(getMyColor(R.color.color_timeSharing_callBackRed));
|
||||
} else {
|
||||
mAkvTvH.setTextColor(getMyColor(R.color.color_timeSharing_callBackGreen));
|
||||
mAkvTvO.setTextColor(getMyColor(R.color.color_timeSharing_callBackGreen));
|
||||
mAkvTvL.setTextColor(getMyColor(R.color.color_timeSharing_callBackGreen));
|
||||
mAkvTvC.setTextColor(getMyColor(R.color.color_timeSharing_callBackGreen));
|
||||
mAkvTvP.setTextColor(getMyColor(R.color.color_timeSharing_callBackGreen));
|
||||
}
|
||||
}
|
||||
|
||||
private int getMyColor(@ColorRes int colorId) {
|
||||
return getResources().getColor(colorId);
|
||||
}
|
||||
|
||||
public void showHorizontal(View view) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putBoolean(KEY_HORIZONTAL, true);
|
||||
bundle.putSerializable(KEY_FOREX, mForex);
|
||||
go(HuobiActivity.class, bundle);
|
||||
}
|
||||
|
||||
public boolean isHorizontal() {
|
||||
return mIsHorizontal;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.tophold.example.demo.kview.btc.ui;
|
||||
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentPagerAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.tophold.example.demo.kview.btc.model.HuobiTab;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/26 13:37
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class HuobiAdapter extends FragmentPagerAdapter {
|
||||
private List<Fragment> mFragmentList;
|
||||
List<HuobiTab> mForexTabList;
|
||||
|
||||
public HuobiAdapter(FragmentManager fm, List<Fragment> fragmentList, List<HuobiTab> mForexTabList) {
|
||||
super(fm);
|
||||
this.mFragmentList = fragmentList;
|
||||
this.mForexTabList = mForexTabList;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
return mFragmentList.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mFragmentList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
return mForexTabList.get(position).tabName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
package com.tophold.example.demo.kview.btc.ui;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.reactivex.Observer;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
|
||||
import com.tophold.example.base.BaseFragment;
|
||||
import com.tophold.example.R;
|
||||
import com.tophold.example.demo.kview.btc.api.HuobiService;
|
||||
import com.tophold.example.demo.kview.btc.api.HuobiSocketApi;
|
||||
import com.tophold.example.demo.kview.btc.api.RetrofitManager;
|
||||
import com.tophold.example.demo.kview.btc.model.HuobiData;
|
||||
import com.tophold.example.demo.kview.btc.model.HuobiQuote;
|
||||
import com.tophold.example.demo.kview.btc.model.HuobiSymbol;
|
||||
import com.tophold.example.demo.kview.btc.model.HuobiTab;
|
||||
import com.tophold.example.demo.kview.btc.model.HuobiWsQuote;
|
||||
import com.tophold.trade.utils.StringUtils;
|
||||
import com.tophold.trade.view.kview.KView;
|
||||
import com.tophold.trade.view.kview.KViewListener;
|
||||
import com.tophold.trade.view.kview.Quotes;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/26 13:36
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class HuobiFragment extends BaseFragment {
|
||||
public static final int DEF_PAGER_SIZE = 1000;
|
||||
private static final String ARG_PARAM1 = "param1";
|
||||
private static final String ARG_PARAM2 = "param2";
|
||||
public static final int DEF_COUNT = 100;
|
||||
private View mRootView;
|
||||
private KView mFkKvKview;
|
||||
HuobiTab mForexTab;
|
||||
HuobiSymbol mForex;
|
||||
|
||||
//net
|
||||
List<Quotes> mQuotesList;
|
||||
|
||||
public HuobiFragment() {
|
||||
|
||||
}
|
||||
|
||||
public static HuobiFragment newInstance(HuobiTab mForexTab, HuobiSymbol forex) {
|
||||
HuobiFragment fragment = new HuobiFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putSerializable(ARG_PARAM1, mForexTab);
|
||||
args.putSerializable(ARG_PARAM2, forex);
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (getArguments() != null) {
|
||||
mForexTab = (HuobiTab) getArguments().getSerializable(ARG_PARAM1);
|
||||
mForex = (HuobiSymbol) getArguments().getSerializable(ARG_PARAM2);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
mRootView = inflater.inflate(R.layout.fragment_huobi, container, false);
|
||||
initView();
|
||||
initData();
|
||||
initAdapter();
|
||||
loadData();
|
||||
initListener();
|
||||
return mRootView;
|
||||
}
|
||||
|
||||
private void loadData() {
|
||||
loadKLineData(null, false);
|
||||
|
||||
subKLineData();
|
||||
}
|
||||
|
||||
private void subKLineData() {
|
||||
HuobiSocketApi.subKLine(mForex.base_currency + mForex.quote_currency, mForexTab.getTypeLength() * 1000, true);
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
mFkKvKview = (KView) mRootView.findViewById(R.id.fk_kv_kview);
|
||||
|
||||
mFkKvKview.setDigit(5);
|
||||
|
||||
if (mForexTab.mForexType == HuobiTab.HuobiType._timeShring) {
|
||||
mFkKvKview.setShowTimSharing(true);
|
||||
} else {
|
||||
mFkKvKview.setShowTimSharing(false);
|
||||
}
|
||||
|
||||
if (((HuobiActivity) getActivity()).isHorizontal()) {
|
||||
mFkKvKview.setShowMinor(true);
|
||||
mFkKvKview.setShowVol(true);
|
||||
} else {
|
||||
mFkKvKview.setShowMinor(false);
|
||||
mFkKvKview.setShowVol(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
mQuotesList = new ArrayList<>();
|
||||
}
|
||||
|
||||
private void initAdapter() {
|
||||
|
||||
}
|
||||
|
||||
private void loadKLineData(String start_time, final boolean isLoadMore) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
String symbol = mForex.base_currency + "" + mForex.quote_currency;
|
||||
map.put("symbol", symbol);
|
||||
map.put("period", mForexTab.getType());
|
||||
map.put("size", DEF_PAGER_SIZE);
|
||||
//if (start_time != null) map.put("st", start_time);
|
||||
call(RetrofitManager.getInstance().create(HuobiService.class).chartQuotes(map), new Observer<HuobiData<List<HuobiQuote>>>() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
unSubscription(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(HuobiData<List<HuobiQuote>> huobiData) {
|
||||
|
||||
String status = huobiData.status;
|
||||
if (!"ok".equals(status)) {
|
||||
Toast.makeText(mContext, "数据获取失败...", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
List<HuobiQuote> data = huobiData.data;
|
||||
if (StringUtils.isEmpty(data)) {
|
||||
Toast.makeText(mContext, "数据为空...", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
adapterData(data);
|
||||
|
||||
drawKView(isLoadMore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void drawKView(boolean isLoadMore) {
|
||||
if (!isLoadMore) {
|
||||
mFkKvKview.setKViewData(mQuotesList, new KViewListener.MasterTouchListener() {
|
||||
@Override
|
||||
public void onLongTouch(Quotes preQuotes, Quotes currentQuotes) {
|
||||
((HuobiActivity) getActivity()).showContanier(preQuotes, currentQuotes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnLongTouch() {
|
||||
((HuobiActivity) getActivity()).hidenContainer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void needLoadMore() {
|
||||
if (StringUtils.isEmpty(mQuotesList)) {
|
||||
mFkKvKview.loadMoreNoData();
|
||||
return;
|
||||
}
|
||||
Quotes quotes = mQuotesList.get(0);
|
||||
String showTime = quotes.getShowTime();
|
||||
//loadKLineData(showTime, true);火币不支持分页
|
||||
}
|
||||
});
|
||||
} else {
|
||||
mFkKvKview.loadKViewData(mQuotesList);
|
||||
}
|
||||
}
|
||||
|
||||
private void adapterData(List<HuobiQuote> huobiQuoteList) {
|
||||
|
||||
Collections.reverse(huobiQuoteList);
|
||||
|
||||
List<Quotes> quotesList = new ArrayList<>();
|
||||
for (HuobiQuote huobiQuote : huobiQuoteList) {
|
||||
Quotes quotes = new Quotes(huobiQuote.open, huobiQuote.high, huobiQuote.low, huobiQuote.close, huobiQuote.id * 1000, huobiQuote.amount);
|
||||
quotesList.add(quotes);
|
||||
}
|
||||
mQuotesList.addAll(0, quotesList);//注意时序问题
|
||||
}
|
||||
|
||||
private void initListener() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBindEventBusHere() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onReviceWsQuotes(HuobiWsQuote huobiWsQuote) {
|
||||
if (huobiWsQuote == null || huobiWsQuote.tick == null) return;
|
||||
//返回的数据真实醉了。。。
|
||||
String ch = huobiWsQuote.ch;
|
||||
String[] split = ch.split("\\.");
|
||||
String symbol = split[1];
|
||||
String lineType = split[3];
|
||||
if (!symbol.equals(mForex.base_currency + mForex.quote_currency)) return;
|
||||
if (!lineType.equals(mForexTab.getType())) return;
|
||||
HuobiWsQuote.TickBean tick = huobiWsQuote.tick;
|
||||
Quotes quotes = new Quotes(tick.open, tick.high, tick.low, tick.close, huobiWsQuote.ts);
|
||||
|
||||
mFkKvKview.pushKViewData(quotes, mForexTab.getTypeLength() * 1000);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
HuobiSocketApi.subKLine(mForex.base_currency + mForex.quote_currency, mForexTab.getTypeLength() * 1000, false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package com.tophold.example.demo.kview.btc.ui;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.chad.library.adapter.base.BaseQuickAdapter;
|
||||
import com.chad.library.adapter.base.BaseViewHolder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.reactivex.Observer;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
|
||||
import com.tophold.example.base.BaseActivity;
|
||||
import com.tophold.example.R;
|
||||
import com.tophold.example.demo.kview.btc.api.HuobiService;
|
||||
import com.tophold.example.demo.kview.btc.api.RetrofitManager;
|
||||
import com.tophold.example.demo.kview.btc.model.HuobiData;
|
||||
import com.tophold.example.demo.kview.btc.model.HuobiSymbol;
|
||||
import com.tophold.trade.utils.StringUtils;
|
||||
|
||||
public class HuobiListActivity extends BaseActivity {
|
||||
|
||||
RecyclerView mAflRlListview;
|
||||
BaseQuickAdapter<HuobiSymbol, BaseViewHolder> mQuickAdapter;
|
||||
List<HuobiSymbol> mForexList;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_huobi_list);
|
||||
initView();
|
||||
initData();
|
||||
initAdapter();
|
||||
loadData();
|
||||
initListener();
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
mAflRlListview = (RecyclerView) findViewById(R.id.afl_rl_listview);
|
||||
Toast.makeText(mContext, "请稍后,在拉取列表...", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
mForexList = new ArrayList<>();
|
||||
}
|
||||
|
||||
private void initAdapter() {
|
||||
mQuickAdapter = new BaseQuickAdapter<HuobiSymbol, BaseViewHolder>(R.layout.item_activity_huobi_list, mForexList) {
|
||||
@Override
|
||||
protected void convert(BaseViewHolder helper, HuobiSymbol item) {
|
||||
helper.setText(R.id.iafl_tv_znName, item.base_currency + "/" + item.quote_currency);
|
||||
helper.setText(R.id.iafl_tv_enName, item.quote_currency);
|
||||
helper.setText(R.id.iafl_tv_part, item.symbol_partition);
|
||||
}
|
||||
};
|
||||
mAflRlListview.setLayoutManager(new LinearLayoutManager(mContext));
|
||||
mAflRlListview.setAdapter(mQuickAdapter);
|
||||
}
|
||||
|
||||
private void loadData() {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
call(RetrofitManager.getInstance().create(HuobiService.class).getSymbolList(map), new Observer<HuobiData<List<HuobiSymbol>>>() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
unSubscription(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(HuobiData<List<HuobiSymbol>> huobiData) {
|
||||
String status = huobiData.status;
|
||||
if (!"ok".equals(status)) {
|
||||
Toast.makeText(mContext, "数据获取失败...", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
List<HuobiSymbol> data = huobiData.data;
|
||||
if (StringUtils.isEmpty(data)) {
|
||||
Toast.makeText(mContext, "数据为空...", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
mForexList.addAll(data);
|
||||
|
||||
//排序操作
|
||||
Collections.sort(mForexList, (o1, o2) -> {
|
||||
if (!o1.symbol_partition.equals(o2.symbol_partition))
|
||||
return -o1.symbol_partition.compareTo(o2.symbol_partition);
|
||||
if (!o1.quote_currency.equals(o2.quote_currency))
|
||||
return -o1.quote_currency.compareTo(o2.quote_currency);
|
||||
return 0;
|
||||
});
|
||||
|
||||
mQuickAdapter.notifyLoadMoreToLoading();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Log.d(TAG, "onComplete: ");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initListener() {
|
||||
mQuickAdapter.setOnItemClickListener((adapter, v, p) -> {
|
||||
HuobiSymbol forex = mForexList.get(p);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putSerializable(HuobiActivity.KEY_FOREX, forex);
|
||||
go(HuobiActivity.class, bundle);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package com.tophold.example.demo.kview.forex;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/22 14:16
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class ForexTab implements Serializable {
|
||||
public ForexType mForexType;
|
||||
public String tabName;
|
||||
|
||||
public ForexTab(ForexType forexType, String tabName) {
|
||||
this.mForexType = forexType;
|
||||
this.tabName = tabName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对应类型的长度
|
||||
*
|
||||
* @return sencond
|
||||
*/
|
||||
public long getTypeLength() {
|
||||
long len = 0;
|
||||
switch (mForexType) {
|
||||
case _timeShring:
|
||||
len = 60;
|
||||
break;
|
||||
case _1m:
|
||||
len = 60;
|
||||
break;
|
||||
case _5m:
|
||||
len = 5 * 60;
|
||||
break;
|
||||
case _15m:
|
||||
len = 15 * 60;
|
||||
break;
|
||||
case _30m:
|
||||
len = 30 * 60;
|
||||
break;
|
||||
case _1h:
|
||||
len = 60 * 60;
|
||||
break;
|
||||
case _4h:
|
||||
len = 4 * 60 * 60;
|
||||
break;
|
||||
case _1d:
|
||||
len = 24 * 60 * 60;
|
||||
break;
|
||||
case _1w:
|
||||
len = 7 * 24 * 60 * 60;
|
||||
break;
|
||||
case _1mon:
|
||||
len = 30 * 24 * 60 * 60;
|
||||
break;
|
||||
default:
|
||||
len = 60;
|
||||
break;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据mForexType返回接口需要的类型字段
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getType() {
|
||||
String typeMsg = "1m";
|
||||
switch (mForexType) {
|
||||
case _timeShring:
|
||||
typeMsg = "1m";
|
||||
break;
|
||||
case _1m:
|
||||
typeMsg = "1m";
|
||||
break;
|
||||
case _5m:
|
||||
typeMsg = "5m";
|
||||
break;
|
||||
case _15m:
|
||||
typeMsg = "15m";
|
||||
break;
|
||||
case _30m:
|
||||
typeMsg = "30m";
|
||||
break;
|
||||
case _1h:
|
||||
typeMsg = "1h";
|
||||
break;
|
||||
case _4h:
|
||||
typeMsg = "4h";
|
||||
break;
|
||||
case _1d:
|
||||
typeMsg = "1d";
|
||||
break;
|
||||
case _1w:
|
||||
typeMsg = "1w";
|
||||
break;
|
||||
case _1mon:
|
||||
typeMsg = "1mon";
|
||||
break;
|
||||
default:
|
||||
typeMsg = "1m";
|
||||
break;
|
||||
}
|
||||
return typeMsg;
|
||||
}
|
||||
|
||||
public enum ForexType {
|
||||
_timeShring,
|
||||
_1m,
|
||||
_5m,
|
||||
_15m,
|
||||
_30m,
|
||||
_1h,
|
||||
_4h,
|
||||
_1d,
|
||||
_1w,
|
||||
_1mon
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.tophold.example.demo.kview.forex.api;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.WebSocketListener;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
import com.tophold.example.BuildConfig;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/22 21:15
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class ForexWebSocket {
|
||||
public static final String TAG = ForexWebSocket.class.getSimpleName();
|
||||
private static final int DEFAULT_TIME_OUT = 5;//超时时间 5s
|
||||
private static final int DEFAULT_READ_TIME_OUT = 10;
|
||||
//temp quotes
|
||||
private static final String BASE_URL = "http://***:8990/websocket";
|
||||
private static final String TOKEN="eyJ0eXAiOiJKV1QiLCJhbGc***Y2NvdW50SWQiOiJFVVI2MTQxLjAwMSIsImlhdCI6MTUyMjgxOTE0NiwiZXhwIjoxNTIzNDIzOTQ2fQ.je5e76RSNh07ZYtu3_yOA8BsBl_wH0_tkqxlgX5hhww";
|
||||
|
||||
Request mRequest;
|
||||
okhttp3.WebSocket mWebSocket;
|
||||
OkHttpClient client;
|
||||
boolean isConnctted = false;
|
||||
|
||||
private ForexWebSocket() {
|
||||
// 创建 OKHttpClient
|
||||
OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
|
||||
builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);//连接超时时间
|
||||
builder.writeTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS);//写操作 超时时间
|
||||
builder.readTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS);//读操作超时时间
|
||||
builder.retryOnConnectionFailure(true);//失败重试
|
||||
|
||||
//DEBUG模式下 添加日志拦截器
|
||||
if (BuildConfig.DEBUG) {
|
||||
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
|
||||
interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
|
||||
builder.addInterceptor(interceptor);
|
||||
}
|
||||
|
||||
// 添加公共参数拦截器
|
||||
HttpCommonInterceptor commonInterceptor = new HttpCommonInterceptor.Builder()
|
||||
.addHeaderParams("paltform", "android")
|
||||
.addHeaderParams("userToken", "1234343434dfdfd3434")
|
||||
.addHeaderParams("userId", "123445")
|
||||
.build();
|
||||
builder.addInterceptor(commonInterceptor);
|
||||
|
||||
|
||||
//HuobiWebSocket
|
||||
client = builder.build();
|
||||
}
|
||||
|
||||
public void init() {
|
||||
mRequest = new Request.Builder().header("Sec-WebSocket-Protocol", TOKEN).url(BASE_URL).build();
|
||||
mWebSocket = client.newWebSocket(mRequest, new WebSocketListener() {
|
||||
@Override
|
||||
public void onOpen(okhttp3.WebSocket webSocket, Response response) {
|
||||
super.onOpen(webSocket, response);
|
||||
isConnctted = true;
|
||||
Log.d(TAG, "onOpen: ");
|
||||
//Toast.makeText(MyApplication.mAppContext, "websocket连接成功...", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(okhttp3.WebSocket webSocket, String text) {
|
||||
super.onMessage(webSocket, text);
|
||||
WebSocketParser.fix2Object(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosed(okhttp3.WebSocket webSocket, int code, String reason) {
|
||||
super.onClosed(webSocket, code, reason);
|
||||
isConnctted = false;
|
||||
Log.d(TAG, "onClosed,code: " + code + ",reason:" + reason);
|
||||
//Toast.makeText(MyApplication.mAppContext, "websocket关闭...", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(okhttp3.WebSocket webSocket, Throwable t, @Nullable Response response) {
|
||||
super.onFailure(webSocket, t, response);
|
||||
isConnctted = false;
|
||||
//Toast.makeText(MyApplication.mAppContext, "websocket异常:" + response.toString(), Toast.LENGTH_SHORT).show();
|
||||
Log.e(TAG, "onFailure: " + (response != null ? response.toString() : "response==null"));
|
||||
t.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static class SingletonHolder {
|
||||
private static final ForexWebSocket INSTANCE = new ForexWebSocket();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取RetrofitServiceManager
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static ForexWebSocket getInstance() {
|
||||
return ForexWebSocket.SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.tophold.example.demo.kview.forex.api;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
/**
|
||||
* 拦截器
|
||||
*
|
||||
* 向请求头里添加公共参数
|
||||
* Created by zhouwei on 16/11/10.
|
||||
*/
|
||||
|
||||
public class HttpCommonInterceptor implements Interceptor {
|
||||
|
||||
private Map<String,String> mHeaderParamsMap = new HashMap<>();
|
||||
public HttpCommonInterceptor() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response intercept(Chain chain) throws IOException {
|
||||
Log.d("HttpCommonInterceptor","add common params");
|
||||
Request oldRequest = chain.request();
|
||||
|
||||
// 添加新的参数,添加到url 中
|
||||
/* HttpUrl.Builder authorizedUrlBuilder = oldRequest.url()
|
||||
.newBuilder()
|
||||
.scheme(oldRequest.url().scheme())
|
||||
.host(oldRequest.url().host());*/
|
||||
|
||||
// 新的请求
|
||||
|
||||
Request.Builder requestBuilder = oldRequest.newBuilder();
|
||||
requestBuilder.method(oldRequest.method(), oldRequest.body());
|
||||
//添加公共参数,添加到header中
|
||||
if(mHeaderParamsMap.size() > 0){
|
||||
for(Map.Entry<String,String> params:mHeaderParamsMap.entrySet()){
|
||||
requestBuilder.header(params.getKey(),params.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
Request newRequest = requestBuilder.build();
|
||||
|
||||
return chain.proceed(newRequest);
|
||||
}
|
||||
|
||||
public static class Builder{
|
||||
HttpCommonInterceptor mHttpCommonInterceptor;
|
||||
|
||||
public Builder(){
|
||||
mHttpCommonInterceptor = new HttpCommonInterceptor();
|
||||
}
|
||||
|
||||
public Builder addHeaderParams(String key, String value){
|
||||
mHttpCommonInterceptor.mHeaderParamsMap.put(key,value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addHeaderParams(String key, int value){
|
||||
return addHeaderParams(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
public Builder addHeaderParams(String key, float value){
|
||||
return addHeaderParams(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
public Builder addHeaderParams(String key, long value){
|
||||
return addHeaderParams(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
public Builder addHeaderParams(String key, double value){
|
||||
return addHeaderParams(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
|
||||
public HttpCommonInterceptor build(){
|
||||
return mHttpCommonInterceptor;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.tophold.example.demo.kview.forex.api;
|
||||
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Observer;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
import com.tophold.example.BuildConfig;
|
||||
|
||||
|
||||
public class RetrofitManager {
|
||||
private static final int DEFAULT_TIME_OUT = 5;//超时时间 5s
|
||||
private static final int DEFAULT_READ_TIME_OUT = 10;
|
||||
//temp quotes
|
||||
private static final String BASE_URL = "http://***:8700/";
|
||||
private Retrofit mRetrofit;
|
||||
|
||||
private RetrofitManager() {
|
||||
// 创建 OKHttpClient
|
||||
OkHttpClient.Builder builder = new OkHttpClient.Builder();
|
||||
builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);//连接超时时间
|
||||
builder.writeTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS);//写操作 超时时间
|
||||
builder.readTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS);//读操作超时时间
|
||||
builder.retryOnConnectionFailure(true);//失败重试
|
||||
|
||||
//DEBUG模式下 添加日志拦截器
|
||||
if (BuildConfig.DEBUG) {
|
||||
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
|
||||
interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
|
||||
builder.addInterceptor(interceptor);
|
||||
}
|
||||
|
||||
// 添加公共参数拦截器
|
||||
HttpCommonInterceptor commonInterceptor = new HttpCommonInterceptor.Builder()
|
||||
.addHeaderParams("paltform", "android")
|
||||
.addHeaderParams("userToken", "1234343434dfdfd3434")
|
||||
.addHeaderParams("userId", "123445")
|
||||
.build();
|
||||
builder.addInterceptor(commonInterceptor);
|
||||
|
||||
|
||||
// 创建Retrofit
|
||||
mRetrofit = new Retrofit.Builder()
|
||||
.baseUrl(BASE_URL)
|
||||
.addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.client(builder.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
private static class SingletonHolder {
|
||||
private static final RetrofitManager INSTANCE = new RetrofitManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取RetrofitServiceManager
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static RetrofitManager getInstance() {
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对应的Service
|
||||
*
|
||||
* @param service Service 的 class
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public <T> T create(Class<T> service) {
|
||||
return mRetrofit.create(service);
|
||||
}
|
||||
|
||||
public static Observable call(Observable<?> observable, Observer observer) {
|
||||
observable.subscribeOn(Schedulers.io())
|
||||
.unsubscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(observer);
|
||||
return observable;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.tophold.example.demo.kview.forex.api;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/22 21:31
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class WebSocketApi {
|
||||
public static final String TAG = WebSocketApi.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* 订阅价格和取消订阅
|
||||
*
|
||||
* @param isSub true:订阅,false:取消订阅
|
||||
*/
|
||||
public static void subPrice(String symbol, boolean isSub) {
|
||||
String str = "35=V|55=" + symbol + "|263=" + (isSub ? 1 : 2);
|
||||
Log.d(TAG, "subPrice: " + str);
|
||||
if (ForexWebSocket.getInstance().isConnctted) {
|
||||
ForexWebSocket.getInstance().mWebSocket.send(str);
|
||||
} else {
|
||||
Log.e(TAG, "subPrice: websocket未连接");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.tophold.example.demo.kview.forex.api;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.tophold.example.demo.kview.forex.model.WsPrice;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/22 21:26
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class WebSocketParser {
|
||||
public static final String TAG = WebSocketParser.class.getSimpleName();
|
||||
|
||||
public static void fix2Object(String str) {
|
||||
try {
|
||||
if (str == null || str.length() == 0) return;
|
||||
Log.d(TAG, "fix2Object: " + str);
|
||||
String[] arrs = str.split("\\|");
|
||||
Map<String, String> map = new HashMap<>();
|
||||
for (String arr : arrs) {
|
||||
String[] items = arr.split("=");
|
||||
map.put(items[0], items[1]);
|
||||
}
|
||||
//maping
|
||||
map2Obj(map);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void map2Obj(Map<String, String> map) {
|
||||
|
||||
String type = map.get("35");
|
||||
if (type == null) {
|
||||
Log.e(TAG, "map2Obj: type == null");
|
||||
return;
|
||||
}
|
||||
if (type.equals("V")) {
|
||||
map2WsPrice(map);
|
||||
}
|
||||
}
|
||||
|
||||
private static void map2WsPrice(Map<String, String> map) {
|
||||
WsPrice wsPrice = new WsPrice();
|
||||
wsPrice.productName = map.get("55");
|
||||
wsPrice.lastUpdateTime = Long.parseLong(map.get("20068"));
|
||||
wsPrice.bidPrice = Double.parseDouble(map.get("132"));
|
||||
wsPrice.askPrice = Double.parseDouble(map.get("133"));
|
||||
|
||||
EventBus.getDefault().post(wsPrice);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.tophold.example.demo.kview.forex.api;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.Path;
|
||||
import retrofit2.http.QueryMap;
|
||||
import com.tophold.example.demo.kview.forex.model.XcfdQuotes;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/22 11:31
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public interface XcfdService {
|
||||
@GET("/kline/{productCode}/{type}")
|
||||
Observable<List<XcfdQuotes>> chartQuotes(@Path("productCode") String productCode, @Path("type") String type, @QueryMap Map<String, Object> params);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.tophold.example.demo.kview.forex.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/22 13:03
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class Forex implements Serializable{
|
||||
public String id;
|
||||
public String enName;
|
||||
public String cnName;
|
||||
|
||||
public Forex(String id, String enName, String cnName) {
|
||||
this.id=id;
|
||||
this.enName=enName;
|
||||
this.cnName=cnName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Forex{" +
|
||||
"id='" + id + '\'' +
|
||||
", enName='" + enName + '\'' +
|
||||
", cnName='" + cnName + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.tophold.example.demo.kview.forex.model;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2017/12/26 11:38
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class WsPrice {
|
||||
|
||||
//TAG:55,COMMENT:产品
|
||||
@SerializedName("55")
|
||||
public String productName;
|
||||
//TAG:20068,COMMENT:系统最后价格时间
|
||||
@SerializedName("20068")
|
||||
public long lastUpdateTime;
|
||||
//TAG:132,COMMENT:--->对应老系统的卖价
|
||||
@SerializedName("132")
|
||||
public double bidPrice;
|
||||
//TAG:133,COMMENT:--->对应老系统的买价
|
||||
@SerializedName("133")
|
||||
public double askPrice;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WsPrice{" +
|
||||
", productName='" + productName + '\'' +
|
||||
", bidPrice='" + bidPrice + '\'' +
|
||||
", askPrice='" + askPrice + '\'' +
|
||||
"现价:" + ((bidPrice + askPrice) / 2) +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.tophold.example.demo.kview.forex.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/22 11:52
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class XcfdQuotes implements Serializable{
|
||||
public String t; //201802080610
|
||||
public String o;
|
||||
public String h;
|
||||
public String l;
|
||||
public String c;
|
||||
|
||||
public long s;//数据开始时间
|
||||
public long e;//结束时间
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Quotes{" +
|
||||
"t=" + t +
|
||||
", o='" + o + '\'' +
|
||||
", h='" + h + '\'' +
|
||||
", l='" + l + '\'' +
|
||||
", c='" + c + '\'' +
|
||||
", s=" + s +
|
||||
", e=" + e +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
package com.tophold.example.demo.kview.forex.ui;
|
||||
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.ColorRes;
|
||||
import android.support.design.widget.TabLayout;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.tophold.example.R;
|
||||
import com.tophold.example.demo.kview.forex.api.WebSocketApi;
|
||||
import com.tophold.example.demo.kview.forex.model.Forex;
|
||||
import com.tophold.example.base.BaseActivity;
|
||||
import com.tophold.example.utils.NoScrollViewPager;
|
||||
import com.tophold.trade.utils.FormatUtil;
|
||||
import com.tophold.trade.utils.TimeUtils;
|
||||
import com.tophold.example.demo.kview.forex.ForexTab;
|
||||
import com.tophold.trade.view.kview.Quotes;
|
||||
|
||||
public class ForexActivity extends BaseActivity {
|
||||
public static final String KEY_FOREX = "KEY_FOREX";
|
||||
public static final String KEY_HORIZONTAL = "KEY_HORIZONTAL";
|
||||
private TabLayout mAfTlTablayout;
|
||||
private NoScrollViewPager mAfVpViewpager;
|
||||
|
||||
private LinearLayout mAkvLlContainer;
|
||||
private TextView mAkvTvH;
|
||||
private TextView mAkvTvO;
|
||||
private TextView mAkvTvTime;
|
||||
private TextView mAkvTvL;
|
||||
private TextView mAkvTvC;
|
||||
private TextView mAkvTvP;
|
||||
private TextView af_tv_symbol;
|
||||
private TextView mAkvTvBlank;
|
||||
|
||||
//是否是横屏
|
||||
boolean mIsHorizontal = false;
|
||||
|
||||
private List<ForexTab> mForexTabList;
|
||||
private List<Fragment> mKViewFragmentList;
|
||||
|
||||
Forex mForex;
|
||||
|
||||
@Override
|
||||
protected void getBundleExtras(Bundle extras) {
|
||||
super.getBundleExtras(extras);
|
||||
mForex = (Forex) extras.getSerializable(KEY_FOREX);
|
||||
mIsHorizontal = extras.getBoolean(KEY_HORIZONTAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (mIsHorizontal) {
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);// 隐藏标题
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN);// 设置全屏
|
||||
}
|
||||
setContentView(R.layout.activity_forex);
|
||||
initView();
|
||||
initData();
|
||||
initAdapter();
|
||||
loadData();
|
||||
initListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
if (mIsHorizontal) {
|
||||
if (getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||
}
|
||||
}
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
mAfTlTablayout = (TabLayout) findViewById(R.id.af_tl_tablayout);
|
||||
mAfVpViewpager = (NoScrollViewPager) findViewById(R.id.af_vp_viewpager);
|
||||
|
||||
mAkvLlContainer = (LinearLayout) findViewById(R.id.akv_ll_container);
|
||||
mAkvTvH = (TextView) findViewById(R.id.akv_tv_h);
|
||||
mAkvTvO = (TextView) findViewById(R.id.akv_tv_o);
|
||||
mAkvTvTime = (TextView) findViewById(R.id.akv_tv_time);
|
||||
mAkvTvL = (TextView) findViewById(R.id.akv_tv_l);
|
||||
mAkvTvC = (TextView) findViewById(R.id.akv_tv_c);
|
||||
mAkvTvP = (TextView) findViewById(R.id.akv_tv_p);
|
||||
mAkvTvBlank = (TextView) findViewById(R.id.af_tv_blank);
|
||||
af_tv_symbol = (TextView) findViewById(R.id.af_tv_symbol);
|
||||
|
||||
if (mIsHorizontal) {
|
||||
af_tv_symbol.setVisibility(View.GONE);
|
||||
mAkvTvBlank.setVisibility(View.GONE);
|
||||
} else {
|
||||
af_tv_symbol.setVisibility(View.VISIBLE);
|
||||
mAkvTvBlank.setVisibility(View.VISIBLE);
|
||||
af_tv_symbol.setText(mForex.cnName + "(" + mForex.enName + ")");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
mForexTabList = new ArrayList<>();
|
||||
mForexTabList.add(new ForexTab(ForexTab.ForexType._timeShring, "分时"));
|
||||
mForexTabList.add(new ForexTab(ForexTab.ForexType._1m, "1分"));
|
||||
mForexTabList.add(new ForexTab(ForexTab.ForexType._5m, "5分"));
|
||||
mForexTabList.add(new ForexTab(ForexTab.ForexType._15m, "15分"));
|
||||
mForexTabList.add(new ForexTab(ForexTab.ForexType._30m, "30分"));
|
||||
mForexTabList.add(new ForexTab(ForexTab.ForexType._1h, "1时"));
|
||||
mForexTabList.add(new ForexTab(ForexTab.ForexType._4h, "4时"));
|
||||
mForexTabList.add(new ForexTab(ForexTab.ForexType._1d, "日K"));
|
||||
mForexTabList.add(new ForexTab(ForexTab.ForexType._1w, "周K"));
|
||||
mForexTabList.add(new ForexTab(ForexTab.ForexType._1mon, "月"));
|
||||
|
||||
mAfTlTablayout.setTabMode(TabLayout.MODE_SCROLLABLE);
|
||||
|
||||
mKViewFragmentList = new ArrayList<>();
|
||||
for (ForexTab forexTab : mForexTabList) {
|
||||
mKViewFragmentList.add(KViewFragment.newInstance(forexTab, mForex));
|
||||
}
|
||||
|
||||
//加载实时价格数据
|
||||
WebSocketApi.subPrice(mForex.enName, true);
|
||||
}
|
||||
|
||||
private void initAdapter() {
|
||||
mAfVpViewpager.setAdapter(new KViewAdapter(getSupportFragmentManager(), mKViewFragmentList, mForexTabList));
|
||||
mAfTlTablayout.setupWithViewPager(mAfVpViewpager);
|
||||
}
|
||||
|
||||
private void loadData() {
|
||||
|
||||
}
|
||||
|
||||
private void initListener() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void hidenContainer() {
|
||||
mAfTlTablayout.setVisibility(View.VISIBLE);
|
||||
mAkvLlContainer.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public void showContanier(Quotes preQuotes, Quotes currentQuotes) {
|
||||
mAfTlTablayout.setVisibility(View.GONE);
|
||||
mAkvLlContainer.setVisibility(View.VISIBLE);
|
||||
int digits = 5;
|
||||
boolean isPositive;
|
||||
String precent;
|
||||
double dis = (currentQuotes.c - preQuotes.c) / currentQuotes.c * 100;
|
||||
isPositive = dis >= 0;
|
||||
precent = FormatUtil.formatBySubString(dis, 2);
|
||||
precent += "%";
|
||||
|
||||
//
|
||||
mAkvTvH.setText(FormatUtil.numFormat(currentQuotes.h, digits));
|
||||
mAkvTvO.setText(FormatUtil.numFormat(currentQuotes.o, digits));
|
||||
mAkvTvL.setText(FormatUtil.numFormat(currentQuotes.l, digits));
|
||||
mAkvTvC.setText(FormatUtil.numFormat(currentQuotes.c, digits));
|
||||
mAkvTvP.setText(precent);
|
||||
mAkvTvTime.setText(TimeUtils.millis2String(currentQuotes.t, new SimpleDateFormat("MM-dd HH:mm")));
|
||||
|
||||
if (isPositive) {
|
||||
mAkvTvH.setTextColor(getMyColor(R.color.color_timeSharing_callBackRed));
|
||||
mAkvTvO.setTextColor(getMyColor(R.color.color_timeSharing_callBackRed));
|
||||
mAkvTvL.setTextColor(getMyColor(R.color.color_timeSharing_callBackRed));
|
||||
mAkvTvC.setTextColor(getMyColor(R.color.color_timeSharing_callBackRed));
|
||||
mAkvTvP.setTextColor(getMyColor(R.color.color_timeSharing_callBackRed));
|
||||
} else {
|
||||
mAkvTvH.setTextColor(getMyColor(R.color.color_timeSharing_callBackGreen));
|
||||
mAkvTvO.setTextColor(getMyColor(R.color.color_timeSharing_callBackGreen));
|
||||
mAkvTvL.setTextColor(getMyColor(R.color.color_timeSharing_callBackGreen));
|
||||
mAkvTvC.setTextColor(getMyColor(R.color.color_timeSharing_callBackGreen));
|
||||
mAkvTvP.setTextColor(getMyColor(R.color.color_timeSharing_callBackGreen));
|
||||
}
|
||||
}
|
||||
|
||||
private int getMyColor(@ColorRes int colorId) {
|
||||
return getResources().getColor(colorId);
|
||||
}
|
||||
|
||||
public void showHorizontal(View view) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putBoolean(KEY_HORIZONTAL, true);
|
||||
bundle.putSerializable(KEY_FOREX, mForex);
|
||||
go(ForexActivity.class, bundle);
|
||||
}
|
||||
|
||||
public boolean isHorizontal() {
|
||||
return mIsHorizontal;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
WebSocketApi.subPrice(mForex.enName, false);//取消订阅
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.tophold.example.demo.kview.forex.ui;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
|
||||
import com.chad.library.adapter.base.BaseQuickAdapter;
|
||||
import com.chad.library.adapter.base.BaseViewHolder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.tophold.example.R;
|
||||
import com.tophold.example.demo.kview.forex.model.Forex;
|
||||
import com.tophold.example.base.BaseActivity;
|
||||
|
||||
public class ForexListActivity extends BaseActivity {
|
||||
RecyclerView mAflRlListview;
|
||||
BaseQuickAdapter<Forex, BaseViewHolder> mQuickAdapter;
|
||||
List<Forex> mForexList;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_forex_list);
|
||||
initView();
|
||||
initData();
|
||||
initAdapter();
|
||||
loadData();
|
||||
initListener();
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
mAflRlListview = (RecyclerView) findViewById(R.id.afl_rl_listview);
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
mForexList = new ArrayList<>();
|
||||
mForexList.add(new Forex("1", "EURUSD", "欧元/美元"));
|
||||
mForexList.add(new Forex("2", "USDJPY", "美元/日元"));
|
||||
mForexList.add(new Forex("3", "AUDUSD", "澳元/美元"));
|
||||
mForexList.add(new Forex("4", "GBPUSD", "英镑/美元"));
|
||||
mForexList.add(new Forex("5", "USDCHF", "美元/瑞郎"));
|
||||
mForexList.add(new Forex("6", "USDSGD", "美元/新加坡元"));
|
||||
mForexList.add(new Forex("7", "USDCAD", "美元/加元"));
|
||||
mForexList.add(new Forex("8", "EURJPY", "欧元/日元"));
|
||||
mForexList.add(new Forex("9", "EURGBP", "欧元/英镑"));
|
||||
mForexList.add(new Forex("10", "NZDUSD", "纽元/美元"));
|
||||
mForexList.add(new Forex("11", "GBPJYP", "英镑/日元"));
|
||||
mForexList.add(new Forex("12", "USDMXN", "美元/墨西哥比索"));
|
||||
mForexList.add(new Forex("13", "GOLD", "黄金"));
|
||||
mForexList.add(new Forex("14", "SILVER", "白银"));
|
||||
}
|
||||
|
||||
private void initAdapter() {
|
||||
mQuickAdapter = new BaseQuickAdapter<Forex, BaseViewHolder>(R.layout.item_activity_forex_list, mForexList) {
|
||||
@Override
|
||||
protected void convert(BaseViewHolder helper, Forex item) {
|
||||
helper.setText(R.id.iafl_tv_enName, item.enName);
|
||||
helper.setText(R.id.iafl_tv_znName, item.cnName);
|
||||
}
|
||||
};
|
||||
mAflRlListview.setLayoutManager(new LinearLayoutManager(mContext));
|
||||
mAflRlListview.setAdapter(mQuickAdapter);
|
||||
}
|
||||
|
||||
private void loadData() {
|
||||
|
||||
}
|
||||
|
||||
private void initListener() {
|
||||
mQuickAdapter.setOnItemClickListener((adapter, v, p) -> {
|
||||
Forex forex = mForexList.get(p);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putSerializable(ForexActivity.KEY_FOREX, forex);
|
||||
go(ForexActivity.class, bundle);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.tophold.example.demo.kview.forex.ui;
|
||||
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentPagerAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.tophold.example.demo.kview.forex.ForexTab;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/22 14:38
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class KViewAdapter extends FragmentPagerAdapter {
|
||||
private List<Fragment> mFragmentList;
|
||||
List<ForexTab> mForexTabList;
|
||||
|
||||
public KViewAdapter(FragmentManager fm, List<Fragment> fragmentList, List<ForexTab> mForexTabList) {
|
||||
super(fm);
|
||||
this.mFragmentList = fragmentList;
|
||||
this.mForexTabList = mForexTabList;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
return mFragmentList.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mFragmentList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
return mForexTabList.get(position).tabName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
package com.tophold.example.demo.kview.forex.ui;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.reactivex.Observer;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
|
||||
import com.tophold.example.base.BaseFragment;
|
||||
import com.tophold.example.R;
|
||||
import com.tophold.example.demo.kview.forex.api.RetrofitManager;
|
||||
import com.tophold.example.demo.kview.forex.api.XcfdService;
|
||||
import com.tophold.example.demo.kview.forex.model.Forex;
|
||||
import com.tophold.example.demo.kview.forex.model.WsPrice;
|
||||
import com.tophold.example.demo.kview.forex.model.XcfdQuotes;
|
||||
import com.tophold.trade.utils.StringUtils;
|
||||
import com.tophold.example.demo.kview.forex.ForexTab;
|
||||
import com.tophold.trade.view.kview.KView;
|
||||
import com.tophold.trade.view.kview.KViewListener;
|
||||
import com.tophold.trade.view.kview.Quotes;
|
||||
|
||||
public class KViewFragment extends BaseFragment {
|
||||
private static final String ARG_PARAM1 = "param1";
|
||||
private static final String ARG_PARAM2 = "param2";
|
||||
public static final int DEF_COUNT = 100;
|
||||
private View mRootView;
|
||||
private KView mFkKvKview;
|
||||
ForexTab mForexTab;
|
||||
Forex mForex;
|
||||
|
||||
//net
|
||||
List<Quotes> mQuotesList;
|
||||
|
||||
public KViewFragment() {
|
||||
|
||||
}
|
||||
|
||||
public static KViewFragment newInstance(ForexTab mForexTab, Forex forex) {
|
||||
KViewFragment fragment = new KViewFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putSerializable(ARG_PARAM1, mForexTab);
|
||||
args.putSerializable(ARG_PARAM2, forex);
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (getArguments() != null) {
|
||||
mForexTab = (ForexTab) getArguments().getSerializable(ARG_PARAM1);
|
||||
mForex = (Forex) getArguments().getSerializable(ARG_PARAM2);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
mRootView = inflater.inflate(R.layout.fragment_kview, container, false);
|
||||
initView();
|
||||
initData();
|
||||
initAdapter();
|
||||
loadData(null, false);
|
||||
initListener();
|
||||
return mRootView;
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
mFkKvKview = (KView) mRootView.findViewById(R.id.fk_kv_kview);
|
||||
|
||||
mFkKvKview.setDigit(5);
|
||||
|
||||
if (mForexTab.mForexType == ForexTab.ForexType._timeShring) {
|
||||
mFkKvKview.setShowTimSharing(true);
|
||||
} else {
|
||||
mFkKvKview.setShowTimSharing(false);
|
||||
}
|
||||
|
||||
if (((ForexActivity) getActivity()).isHorizontal()) {
|
||||
mFkKvKview.setShowMinor(true);
|
||||
} else {
|
||||
mFkKvKview.setShowMinor(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
mQuotesList = new ArrayList<>();
|
||||
}
|
||||
|
||||
private void initAdapter() {
|
||||
|
||||
}
|
||||
|
||||
private void loadData(String start_time, final boolean isLoadMore) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("count", DEF_COUNT);
|
||||
if (start_time != null) map.put("st", start_time);
|
||||
call(RetrofitManager.getInstance().create(XcfdService.class).chartQuotes(mForex.enName, mForexTab.getType(), map), new Observer<List<XcfdQuotes>>() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(List<XcfdQuotes> xcfdQuotesList) {
|
||||
if (StringUtils.isEmpty(xcfdQuotesList)) {
|
||||
Log.d(TAG, "onNext: 数据为空");
|
||||
return;
|
||||
}
|
||||
adapterData(xcfdQuotesList);
|
||||
|
||||
drawKView(isLoadMore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
e.printStackTrace();
|
||||
Toast.makeText(mContext, "" + e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void drawKView(boolean isLoadMore) {
|
||||
if (!isLoadMore) {
|
||||
mFkKvKview.setKViewData(mQuotesList, new KViewListener.MasterTouchListener() {
|
||||
@Override
|
||||
public void onLongTouch(Quotes preQuotes, Quotes currentQuotes) {
|
||||
((ForexActivity) getActivity()).showContanier(preQuotes, currentQuotes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnLongTouch() {
|
||||
((ForexActivity) getActivity()).hidenContainer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void needLoadMore() {
|
||||
if (StringUtils.isEmpty(mQuotesList)) {
|
||||
mFkKvKview.loadMoreNoData();
|
||||
return;
|
||||
}
|
||||
Quotes quotes = mQuotesList.get(0);
|
||||
String showTime = quotes.getShowTime();
|
||||
loadData(showTime, true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
mFkKvKview.loadKViewData(mQuotesList);
|
||||
}
|
||||
}
|
||||
|
||||
private void adapterData(List<XcfdQuotes> xcfdQuotesList) {
|
||||
List<Quotes> quotesList = new ArrayList<>();
|
||||
for (XcfdQuotes xcfdQuotes : xcfdQuotesList) {
|
||||
Quotes quotes = new Quotes(xcfdQuotes.o, xcfdQuotes.h, xcfdQuotes.l, xcfdQuotes.c, xcfdQuotes.s, xcfdQuotes.e);
|
||||
quotesList.add(quotes);
|
||||
}
|
||||
|
||||
mQuotesList.addAll(0, quotesList);//注意时序问题
|
||||
}
|
||||
|
||||
private void initListener() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBindEventBusHere() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onRevicePrice(WsPrice wsPrice) {
|
||||
if (wsPrice == null || !wsPrice.productName.equals(mForex.enName)) return;
|
||||
double currPrice = (wsPrice.askPrice + wsPrice.bidPrice) / 2.0;//均价
|
||||
String currPriceStr = String.valueOf(currPrice);
|
||||
|
||||
Quotes quotes = new Quotes(currPriceStr, currPriceStr, currPriceStr, currPriceStr, wsPrice.lastUpdateTime, wsPrice.lastUpdateTime);
|
||||
|
||||
mFkKvKview.pushKViewData(quotes, mForexTab.getTypeLength() * 1000);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.tophold.example.demo.pie
|
||||
|
||||
import android.os.Bundle
|
||||
import android.support.annotation.ColorInt
|
||||
import android.support.v4.content.ContextCompat
|
||||
import com.tophold.example.base.BaseActivity
|
||||
import com.tophold.example.R
|
||||
import com.tophold.trade.view.pie.PieEntrys
|
||||
import kotlinx.android.synthetic.main.activity_pie_chart.*
|
||||
|
||||
class PieChartActivity : BaseActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_pie_chart)
|
||||
|
||||
initPieChart()
|
||||
|
||||
loadPieChart()
|
||||
}
|
||||
|
||||
private fun loadPieChart() {
|
||||
val pieEntrysList: MutableList<PieEntrys> = ArrayList()
|
||||
pieEntrysList.add(PieEntrys(10f, "80%", getColorId(R.color.trade_analyze_pie_1), false, "澳元/美元"))
|
||||
pieEntrysList.add(PieEntrys(50f, "胜率 86.96%", getColorId(R.color.trade_analyze_pie_2), true, "英镑/美元"))
|
||||
pieEntrysList.add(PieEntrys(1f, "60.71%", getColorId(R.color.trade_analyze_pie_3), false, "黄金"))
|
||||
pieEntrysList.add(PieEntrys(1f, "76.47%", getColorId(R.color.trade_analyze_pie_4), false, "欧元/美元"))
|
||||
|
||||
hatab_tapc_chart.pieEntryList = pieEntrysList
|
||||
}
|
||||
|
||||
private fun initPieChart() {
|
||||
hatab_tapc_chart.basePaddingTop = 40f
|
||||
hatab_tapc_chart.basePaddingBottom = 40f
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
private fun getColorId(colorId: Int): Int {
|
||||
return ContextCompat.getColor(mContext,colorId)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
package com.tophold.example.demo.seekbar
|
||||
|
||||
import android.os.Bundle
|
||||
import android.support.annotation.NonNull
|
||||
import com.tophold.example.base.BaseActivity
|
||||
import com.tophold.example.R
|
||||
import kotlinx.android.synthetic.main.activity_double_thumb_seek_bar.*
|
||||
import com.tophold.trade.utils.RenderUtils.dp2px
|
||||
import com.tophold.trade.view.seekbar.DoubleTumb
|
||||
|
||||
|
||||
class DoubleThumbSeekBarActivity : BaseActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_double_thumb_seek_bar)
|
||||
renderView1()
|
||||
}
|
||||
|
||||
private fun renderView1() {
|
||||
/**
|
||||
* def
|
||||
*/
|
||||
am_dtsv_seek0.init(loadTpSeekBar())
|
||||
|
||||
/**
|
||||
* 加载单个thumb,从左边开始且最小值从最左边开始
|
||||
*/
|
||||
am_dtsv_seek1.init(loadTpSeekBar(
|
||||
false, -44.0, 66.0, true, 4,
|
||||
true, false, 0.2, greenA = false))
|
||||
/**
|
||||
* 单个thumb,从右边开始且从左边开始最小值
|
||||
*/
|
||||
am_dtsv_seek2.init(loadTpSeekBar(
|
||||
false, -44.0, 66.0, true, 4,
|
||||
false, true, 0.2, greenA = true))
|
||||
/**
|
||||
* 双thumb同向,最小值从左边开始
|
||||
*/
|
||||
am_dtsv_seek3.init(loadTpSeekBar(
|
||||
true, -44.0, 66.0, true, 4,
|
||||
true, true, 0.2, false,
|
||||
true, true, 0.33, false))
|
||||
/**
|
||||
* 双thumb同向,最小值从右边开始
|
||||
*/
|
||||
am_dtsv_seek4.init(loadTpSeekBar(
|
||||
true, -44.0, 66.0, false, 4,
|
||||
false, true, 0.2, true,
|
||||
false, true, 0.33, true))
|
||||
|
||||
/**
|
||||
* 交叉方式显示
|
||||
*/
|
||||
am_dtsv_seek5.init(loadTpSeekBar(
|
||||
true, -44.0, 66.0, false, 4,
|
||||
true, true, 0.2, false,
|
||||
false, true, 0.33, true))
|
||||
}
|
||||
|
||||
/**
|
||||
* @param doubleThumb 是否启动双thumb
|
||||
* @param min 最小值
|
||||
* @param max 最大值
|
||||
* @param minFromLeft 最小值是否从左边开始(注意和从哪边开始滑动无关)
|
||||
* @param digit 格式化的小数位数
|
||||
*
|
||||
* @param fromLeftA 是否从左边开始滑动
|
||||
* @param showTipsA 是否实时展示当前值
|
||||
* @param progressA 默认进度(0~1)
|
||||
* @param greenA thumbA的背景色
|
||||
*
|
||||
* @param fromLeftB 是否从左边开始滑动
|
||||
* @param showTipsB 是否实时展示当前值
|
||||
* @param progressB 默认进度(0~1)
|
||||
* @param greenB thumbA的背景色
|
||||
*
|
||||
*/
|
||||
@NonNull
|
||||
fun loadTpSeekBar(doubleThumb: Boolean = false, min: Double = 0.0, max: Double = 100.0, minFromLeft: Boolean = true, digit: Int = 2,
|
||||
fromLeftA: Boolean = true, showTipsA: Boolean = true, progressA: Double = 0.0, greenA: Boolean = false,
|
||||
fromLeftB: Boolean = true, showTipsB: Boolean = true, progressB: Double = 0.0, greenB: Boolean = false): DoubleTumb {
|
||||
|
||||
val thumbAForeground = if (!greenA) {
|
||||
getCompatColor(R.color.dtsb_thumb1Color)
|
||||
} else {
|
||||
getCompatColor(R.color.dtsb_thumb2Color)
|
||||
|
||||
}
|
||||
|
||||
val thumbADrawable = if (!greenA) {
|
||||
getCompatDrawable(R.drawable.layer_seekbar_thumb_red)
|
||||
} else {
|
||||
getCompatDrawable(R.drawable.layer_seekbar_thumb_green)
|
||||
}
|
||||
|
||||
val thumbA = DoubleTumb.Thumb(thumbAForeground)
|
||||
thumbA.progress = progressA//默认位置,百分比值(0~1)
|
||||
thumbA.mFromLeft = fromLeftA//是否从左边开始滑动
|
||||
thumbA.mShowTips = showTipsA
|
||||
thumbA.setmThumb(thumbADrawable)
|
||||
thumbA.setmThumbWidth(dp2px(mContext, 20f))
|
||||
thumbA.setmThumbHight(dp2px(mContext, 25f))
|
||||
|
||||
var thumbB: DoubleTumb.Thumb? = null
|
||||
//复杂模式显示两个thumb
|
||||
if (doubleThumb) {
|
||||
val thumbBForeground = if (!greenB) {
|
||||
getCompatColor(R.color.dtsb_thumb11Color)
|
||||
} else {
|
||||
getCompatColor(R.color.dtsb_thumb22Color)
|
||||
|
||||
}
|
||||
val thumbBDrawable = if (!greenB) {
|
||||
getCompatDrawable(R.drawable.layer_seekbar_thumb_red)
|
||||
} else {
|
||||
getCompatDrawable(R.drawable.layer_seekbar_thumb_green)
|
||||
}
|
||||
thumbB = DoubleTumb.Thumb(thumbBForeground)
|
||||
thumbB.progress = progressB
|
||||
thumbB.mFromLeft = fromLeftB
|
||||
thumbB.mShowTips = showTipsB
|
||||
thumbB.setmThumb(thumbBDrawable)
|
||||
thumbB.setmThumbWidth(dp2px(mContext, 20f))
|
||||
thumbB.setmThumbHight(dp2px(mContext, 25f))
|
||||
}
|
||||
|
||||
val doubleTumb = DoubleTumb(min, max,
|
||||
dp2px(mContext, 4f).toFloat(),
|
||||
getCompatColor(R.color.dtsb_bgColor),
|
||||
thumbA,
|
||||
thumbB)
|
||||
//注意这里!!!
|
||||
doubleTumb.mMinLeft = minFromLeft
|
||||
doubleTumb.mDigit = digit
|
||||
//根据总高度取设置
|
||||
doubleTumb.mLineTop = dp2px(mContext, 40f)
|
||||
doubleTumb.mLineBottom = dp2px(mContext, 10f)
|
||||
doubleTumb.mLineLeft = dp2px(mContext, 8f)
|
||||
doubleTumb.mLineRight = dp2px(mContext, 8f)
|
||||
|
||||
return doubleTumb
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.tophold.example.utils;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <p>GSON工具类</p>
|
||||
*
|
||||
* @author
|
||||
* @version $Id: GsonUtil.java
|
||||
*/
|
||||
public class GsonUtil {
|
||||
|
||||
private static Gson gson = null;
|
||||
private static Gson prettyGson = null;
|
||||
|
||||
static {
|
||||
gson = new GsonBuilder()
|
||||
.setDateFormat("yyyy-MM-dd HH:mm:ss").create();
|
||||
prettyGson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss")
|
||||
.setPrettyPrinting()
|
||||
.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* 小写下划线的格式解析JSON字符串到对象
|
||||
* <p>例如 is_success->isSuccess</p>
|
||||
*
|
||||
* @param json
|
||||
* @param classOfT
|
||||
* @return
|
||||
*/
|
||||
public static <T> T fromJsonUnderScoreStyle(String json, Class<T> classOfT) {
|
||||
return gson.fromJson(json, classOfT);
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON字符串转为Map<String,String>
|
||||
*
|
||||
* @param json
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public static <T> T fronJson2Map(String json) {
|
||||
return gson.fromJson(json, new TypeToken<Map<String, String>>() {
|
||||
}.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* 小写下划线的格式将对象转换成JSON字符串
|
||||
*
|
||||
* @param src
|
||||
* @return
|
||||
*/
|
||||
public static String toJson(Object src) {
|
||||
return gson.toJson(src);
|
||||
}
|
||||
|
||||
public static String toPrettyString(Object src) {
|
||||
return prettyGson.toJson(src);
|
||||
}
|
||||
|
||||
public static <T> T fromJson2Object(String src, Class<T> t) {
|
||||
return gson.fromJson(src, t);
|
||||
}
|
||||
|
||||
public static <T> T fromJson2Object(String src, Type typeOfT) {
|
||||
return gson.fromJson(src, typeOfT);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.tophold.example.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* 作 者 : wgyscsf@163.com
|
||||
* 创建日期 :2018/03/22 14:55
|
||||
* 描 述 :
|
||||
* ============================================================
|
||||
**/
|
||||
public class NoScrollViewPager extends ViewPager {
|
||||
public NoScrollViewPager(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public NoScrollViewPager(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent arg0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent arg0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.tophold.example.utils;
|
||||
|
||||
import io.reactivex.FlowableTransformer;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.ObservableTransformer;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Created by chao.qu at 2017/10/20
|
||||
*
|
||||
* @author quchao
|
||||
*/
|
||||
|
||||
public class RxUtils {
|
||||
|
||||
/**
|
||||
* 统一线程处理
|
||||
*
|
||||
* @param <T> 指定的泛型类型
|
||||
* @return FlowableTransformer
|
||||
*/
|
||||
public static <T> FlowableTransformer<T, T> rxFlSchedulerHelper() {
|
||||
return flowable -> flowable.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread());
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一线程处理
|
||||
*
|
||||
* @param <T> 指定的泛型类型
|
||||
* @return ObservableTransformer
|
||||
*/
|
||||
public static <T> ObservableTransformer<T, T> rxSchedulerHelper() {
|
||||
return observable -> observable.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread());
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一线程处理
|
||||
*
|
||||
* @param <T> 指定的泛型类型
|
||||
* @return ObservableTransformer
|
||||
*/
|
||||
public static <T> ObservableTransformer<T, T> rxApiSchedulerHelper() {
|
||||
return observable -> observable.subscribeOn(Schedulers.io())
|
||||
.unsubscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread());
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到 Observable
|
||||
*
|
||||
* @param <T> 指定的泛型类型
|
||||
* @return Observable
|
||||
*/
|
||||
private static <T> Observable<T> createData(final T t) {
|
||||
return Observable.create(emitter -> {
|
||||
try {
|
||||
emitter.onNext(t);
|
||||
emitter.onComplete();
|
||||
} catch (Exception e) {
|
||||
emitter.onError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
@@ -0,0 +1,11 @@
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item>
|
||||
<shape>
|
||||
<size
|
||||
android:height="20dp"
|
||||
android:width="18dp"/>
|
||||
<solid android:color="@android:color/transparent" />
|
||||
</shape>
|
||||
</item>
|
||||
<item android:drawable="@drawable/ico_sl"/>
|
||||
</layer-list>
|
||||
@@ -0,0 +1,11 @@
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item>
|
||||
<shape>
|
||||
<size
|
||||
android:height="20dp"
|
||||
android:width="18dp"/>
|
||||
<solid android:color="@android:color/transparent" />
|
||||
</shape>
|
||||
</item>
|
||||
<item android:drawable="@drawable/ico_tp"/>
|
||||
</layer-list>
|
||||
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.tophold.trade.view.seekbar.DoubleThumbSeekBar
|
||||
android:id="@+id/am_dtsv_seek0"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="54dp"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginRight="4dp"
|
||||
android:background="#fff" />
|
||||
|
||||
<com.tophold.trade.view.seekbar.DoubleThumbSeekBar
|
||||
android:id="@+id/am_dtsv_seek1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="54dp"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginRight="4dp"
|
||||
android:background="#fff" />
|
||||
|
||||
|
||||
<com.tophold.trade.view.seekbar.DoubleThumbSeekBar
|
||||
android:id="@+id/am_dtsv_seek2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="54dp"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginRight="4dp"
|
||||
android:background="#fff" />
|
||||
|
||||
<com.tophold.trade.view.seekbar.DoubleThumbSeekBar
|
||||
android:id="@+id/am_dtsv_seek3"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="54dp"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginRight="4dp"
|
||||
android:background="#fff" />
|
||||
|
||||
<com.tophold.trade.view.seekbar.DoubleThumbSeekBar
|
||||
android:id="@+id/am_dtsv_seek4"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="54dp"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginRight="4dp"
|
||||
android:background="#fff" />
|
||||
|
||||
<com.tophold.trade.view.seekbar.DoubleThumbSeekBar
|
||||
android:id="@+id/am_dtsv_seek5"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="54dp"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginRight="4dp"
|
||||
android:background="#fff" />
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<android.support.design.widget.TabLayout
|
||||
android:id="@+id/af_tl_tablayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
app:tabIndicatorColor="@color/color_tb_indicator"
|
||||
app:tabSelectedTextColor="@color/color_tb_selectedTxt"
|
||||
app:tabTextColor="@color/color_tb_Txt"
|
||||
/>
|
||||
|
||||
<!--按下的指标显示-->
|
||||
<LinearLayout
|
||||
android:id="@+id/akv_ll_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:background="#e7e3e3"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="4dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="高:"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_h"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#f00"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="开:"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_o"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#f00"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="低:"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_l"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#f00"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="收:"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_c"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#f00"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="幅:"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_p"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#f00"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0.5dp"
|
||||
android:background="#8f8d8d"/>
|
||||
|
||||
<com.tophold.example.utils.NoScrollViewPager
|
||||
android:id="@+id/af_vp_viewpager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="300dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/af_tv_symbol"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:text="欧元/美元(USDCAD)"
|
||||
android:gravity="center"
|
||||
android:background="#a7a4a4"/>
|
||||
<TextView
|
||||
android:id="@+id/af_tv_blank"
|
||||
android:onClick="showHorizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="4dp"
|
||||
android:background="#cccccc"
|
||||
android:gravity="center"
|
||||
android:text="业务模块(单击这里进入横屏)"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/afl_rl_listview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:background="#000"
|
||||
|
||||
>
|
||||
<com.tophold.trade.view.fund.FundView
|
||||
android:id="@+id/af_fv_fundview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="300dp"
|
||||
android:background="#fff"/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,205 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<android.support.design.widget.TabLayout
|
||||
android:id="@+id/af_tl_tablayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
app:tabIndicatorColor="@color/color_tb_indicator"
|
||||
app:tabSelectedTextColor="@color/color_tb_selectedTxt"
|
||||
app:tabTextColor="@color/color_tb_Txt"
|
||||
/>
|
||||
|
||||
<!--按下的指标显示-->
|
||||
<LinearLayout
|
||||
android:id="@+id/akv_ll_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:background="#e7e3e3"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="4dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="高:"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_h"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#f00"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="开:"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_o"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#f00"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="低:"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_l"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#f00"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="收:"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_c"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#f00"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="幅:"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_p"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#f00"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0.5dp"
|
||||
android:background="#8f8d8d"/>
|
||||
|
||||
<com.tophold.example.utils.NoScrollViewPager
|
||||
android:id="@+id/af_vp_viewpager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="300dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/af_tv_symbol"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:text="欧元/美元(USDCAD)"
|
||||
android:gravity="center"
|
||||
android:background="#a7a4a4"/>
|
||||
<TextView
|
||||
android:id="@+id/af_tv_blank"
|
||||
android:onClick="showHorizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="4dp"
|
||||
android:background="#cccccc"
|
||||
android:gravity="center"
|
||||
android:text="业务模块(单击这里进入横屏)"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="#d9cfcf">
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/afl_rl_listview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:onClick="kViewVertical"
|
||||
android:text="K线图竖屏(本地数据)" />
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:onClick="kViewHorizontal"
|
||||
android:text="K线图横屏(本地数据)" />
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:onClick="kViewEvaluation"
|
||||
android:text="外汇Demo(可能因为API限制显示不了)"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:onClick="btnDemo"
|
||||
android:text="数字货币demo(火币API)"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,172 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!--按下的指标显示-->
|
||||
<LinearLayout
|
||||
android:id="@+id/akv_ll_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#e7e3e3"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="4dp"
|
||||
android:visibility="invisible">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="高:"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_h"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#f00"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="开:"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_o"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#f00"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="低:"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_l"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#f00"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="收:"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_c"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#f00"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="幅:"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_p"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#f00"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<com.tophold.trade.view.kview.KView
|
||||
android:id="@+id/akv_kv_kview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<Button
|
||||
android:onClick="showCandle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="30dp"
|
||||
android:text="点击展示蜡烛图"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,192 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!--按下的指标显示-->
|
||||
<LinearLayout
|
||||
android:id="@+id/akv_ll_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:background="#e7e3e3"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="4dp"
|
||||
android:visibility="invisible">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="25dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="高:"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_h"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#f00"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="开:"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_o"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#f00"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="25dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="低:"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_l"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#f00"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="收:"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_c"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#f00"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="幅:"
|
||||
android:textColor="#000"
|
||||
android:textSize="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/akv_tv_p"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/string_placeHold"
|
||||
android:textColor="#f00"
|
||||
android:textSize="12dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<com.tophold.trade.view.kview.KView
|
||||
android:id="@+id/akv_kv_kview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="300dp"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="45dp"
|
||||
android:layout_marginTop="100dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/akv_btn_showCandle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="45dp"
|
||||
android:layout_weight="1"
|
||||
android:onClick="showCandle"
|
||||
android:text="点击展示蜡烛图"/>
|
||||
|
||||
<View
|
||||
android:layout_width="10dp"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/akv_btn_showMinnor"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="45dp"
|
||||
android:layout_weight="1"
|
||||
android:onClick="showMinor"
|
||||
android:text="点击不显示副图"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/version"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="top"
|
||||
android:gravity="center"
|
||||
android:padding="16dp"
|
||||
android:text="verisonName:1.4,versionCode(git head):"/>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="100dp"
|
||||
android:onClick="fundView"
|
||||
android:text="去看自定义基金View Demo"
|
||||
android:textAllCaps="false"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:textAllCaps="false"
|
||||
android:onClick="kViewDemo"
|
||||
android:text="去看KView Demo"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:onClick="onPieTest"
|
||||
android:text="去看PieChart饼图 Demo"
|
||||
android:textAllCaps="false"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:onClick="onSeekBarTest"
|
||||
android:text="去看DoubleThumbSeekBar Demo"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:onClick="onRx"
|
||||
android:text="去看Rx"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#dedbdb"
|
||||
android:gravity="center">
|
||||
|
||||
|
||||
<com.tophold.trade.view.pie.PieChartView
|
||||
android:id="@+id/hatab_tapc_chart"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="215dp"
|
||||
android:background="#fff"/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,9 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.tophold.trade.view.kview.KView
|
||||
android:id="@+id/fk_kv_kview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
</FrameLayout>
|
||||
@@ -0,0 +1,9 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.tophold.trade.view.kview.KView
|
||||
android:id="@+id/fk_kv_kview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
</FrameLayout>
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="45dp"
|
||||
android:background="#d9cfcf">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/iafl_tv_znName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="黄金"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/iafl_tv_enName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/iafl_tv_znName"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="GOLD"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:background="#ffffff"/>
|
||||
</RelativeLayout>
|
||||
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="45dp"
|
||||
android:background="#fff">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/iafl_tv_znName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:gravity="center_vertical"
|
||||
android:textSize="18sp"
|
||||
android:text="黄金"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/iafl_tv_enName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/iafl_tv_znName"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:textSize="10sp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="GOLD"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/iafl_tv_part"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_marginRight="10dp"
|
||||
android:text="主区"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:background="#8b8989"/>
|
||||
</RelativeLayout>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 14 KiB |