的
This commit is contained in:
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,32 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 27
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 27
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
implementation 'com.android.support:appcompat-v7:27.1.1'
|
||||
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'
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.github.fujianlian.klinechart;
|
||||
|
||||
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.*;
|
||||
|
||||
/**
|
||||
* Instrumented 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() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
||||
|
||||
assertEquals("com.github.fujianlian.klinechart.test", appContext.getPackageName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.github.fujianlian.klinechart" />
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.github.fujianlian.klinechart;
|
||||
|
||||
import android.database.DataSetObservable;
|
||||
import android.database.DataSetObserver;
|
||||
|
||||
import com.github.fujianlian.klinechart.base.IAdapter;
|
||||
|
||||
/**
|
||||
* k线图的数据适配器
|
||||
* Created by tifezh on 2016/6/9.
|
||||
*/
|
||||
|
||||
public abstract class BaseKLineChartAdapter implements IAdapter {
|
||||
|
||||
private final DataSetObservable mDataSetObservable = new DataSetObservable();
|
||||
|
||||
@Override
|
||||
public void notifyDataSetChanged() {
|
||||
if (getCount() > 0) {
|
||||
mDataSetObservable.notifyChanged();
|
||||
} else {
|
||||
mDataSetObservable.notifyInvalidated();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void registerDataSetObserver(DataSetObserver observer) {
|
||||
mDataSetObservable.registerObserver(observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterDataSetObserver(DataSetObserver observer) {
|
||||
mDataSetObservable.unregisterObserver(observer);
|
||||
}
|
||||
}
|
||||
+1314
File diff suppressed because it is too large
Load Diff
+302
@@ -0,0 +1,302 @@
|
||||
package com.github.fujianlian.klinechart;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 数据辅助类 计算macd rsi等
|
||||
* Created by tifezh on 2016/11/26.
|
||||
*/
|
||||
public class DataHelper {
|
||||
|
||||
/**
|
||||
* 计算RSI
|
||||
*
|
||||
* @param dataList
|
||||
*/
|
||||
static void calculateRSI(List<KLineEntity> dataList) {
|
||||
Float rsi;
|
||||
float rsiABSEma = 0;
|
||||
float rsiMaxEma = 0;
|
||||
for (int i = 0; i < dataList.size(); i++) {
|
||||
KLineEntity point = dataList.get(i);
|
||||
final float closePrice = point.getClosePrice();
|
||||
if (i == 0) {
|
||||
rsi = 0f;
|
||||
rsiABSEma = 0;
|
||||
rsiMaxEma = 0;
|
||||
} else {
|
||||
float Rmax = Math.max(0, closePrice - dataList.get(i - 1).getClosePrice());
|
||||
float RAbs = Math.abs(closePrice - dataList.get(i - 1).getClosePrice());
|
||||
|
||||
rsiMaxEma = (Rmax + (14f - 1) * rsiMaxEma) / 14f;
|
||||
rsiABSEma = (RAbs + (14f - 1) * rsiABSEma) / 14f;
|
||||
rsi = (rsiMaxEma / rsiABSEma) * 100;
|
||||
}
|
||||
if (i < 13) {
|
||||
rsi = 0f;
|
||||
}
|
||||
if (rsi.isNaN())
|
||||
rsi = 0f;
|
||||
point.rsi = rsi;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算kdj
|
||||
*
|
||||
* @param dataList
|
||||
*/
|
||||
static void calculateKDJ(List<KLineEntity> dataList) {
|
||||
float k = 0;
|
||||
float d = 0;
|
||||
for (int i = 0; i < dataList.size(); i++) {
|
||||
KLineEntity point = dataList.get(i);
|
||||
final float closePrice = point.getClosePrice();
|
||||
int startIndex = i - 13;
|
||||
if (startIndex < 0) {
|
||||
startIndex = 0;
|
||||
}
|
||||
float max14 = Float.MIN_VALUE;
|
||||
float min14 = Float.MAX_VALUE;
|
||||
for (int index = startIndex; index <= i; index++) {
|
||||
max14 = Math.max(max14, dataList.get(index).getHighPrice());
|
||||
min14 = Math.min(min14, dataList.get(index).getLowPrice());
|
||||
}
|
||||
Float rsv = 100f * (closePrice - min14) / (max14 - min14);
|
||||
if (rsv.isNaN()) {
|
||||
rsv = 0f;
|
||||
}
|
||||
if (i == 0) {
|
||||
k = 50;
|
||||
d = 50;
|
||||
} else {
|
||||
k = (rsv + 2f * k) / 3f;
|
||||
d = (k + 2f * d) / 3f;
|
||||
}
|
||||
if (i < 13) {
|
||||
point.k = 0;
|
||||
point.d = 0;
|
||||
point.j = 0;
|
||||
} else if (i == 13 || i == 14) {
|
||||
point.k = k;
|
||||
point.d = 0;
|
||||
point.j = 0;
|
||||
} else {
|
||||
point.k = k;
|
||||
point.d = d;
|
||||
point.j = 3f * k - 2 * d;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算wr
|
||||
*
|
||||
* @param dataList
|
||||
*/
|
||||
static void calculateWR(List<KLineEntity> dataList) {
|
||||
Float r;
|
||||
for (int i = 0; i < dataList.size(); i++) {
|
||||
KLineEntity point = dataList.get(i);
|
||||
int startIndex = i - 14;
|
||||
if (startIndex < 0) {
|
||||
startIndex = 0;
|
||||
}
|
||||
float max14 = Float.MIN_VALUE;
|
||||
float min14 = Float.MAX_VALUE;
|
||||
for (int index = startIndex; index <= i; index++) {
|
||||
max14 = Math.max(max14, dataList.get(index).getHighPrice());
|
||||
min14 = Math.min(min14, dataList.get(index).getLowPrice());
|
||||
}
|
||||
if (i < 13) {
|
||||
point.r = -10;
|
||||
} else {
|
||||
r = -100 * (max14 - dataList.get(i).getClosePrice()) / (max14 - min14);
|
||||
if (r.isNaN()) {
|
||||
point.r = 0;
|
||||
} else {
|
||||
point.r = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算macd
|
||||
*
|
||||
* @param dataList
|
||||
*/
|
||||
static void calculateMACD(List<KLineEntity> dataList) {
|
||||
float ema12 = 0;
|
||||
float ema26 = 0;
|
||||
float dif = 0;
|
||||
float dea = 0;
|
||||
float macd = 0;
|
||||
|
||||
for (int i = 0; i < dataList.size(); i++) {
|
||||
KLineEntity point = dataList.get(i);
|
||||
final float closePrice = point.getClosePrice();
|
||||
if (i == 0) {
|
||||
ema12 = closePrice;
|
||||
ema26 = closePrice;
|
||||
} else {
|
||||
// EMA(12) = 前一日EMA(12) X 11/13 + 今日收盘价 X 2/13
|
||||
ema12 = ema12 * 11f / 13f + closePrice * 2f / 13f;
|
||||
// EMA(26) = 前一日EMA(26) X 25/27 + 今日收盘价 X 2/27
|
||||
ema26 = ema26 * 25f / 27f + closePrice * 2f / 27f;
|
||||
}
|
||||
// DIF = EMA(12) - EMA(26) 。
|
||||
// 今日DEA = (前一日DEA X 8/10 + 今日DIF X 2/10)
|
||||
// 用(DIF-DEA)*2即为MACD柱状图。
|
||||
dif = ema12 - ema26;
|
||||
dea = dea * 8f / 10f + dif * 2f / 10f;
|
||||
macd = (dif - dea) * 2f;
|
||||
point.dif = dif;
|
||||
point.dea = dea;
|
||||
point.macd = macd;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算 BOLL 需要在计算ma之后进行
|
||||
*
|
||||
* @param dataList
|
||||
*/
|
||||
static void calculateBOLL(List<KLineEntity> dataList) {
|
||||
for (int i = 0; i < dataList.size(); i++) {
|
||||
KLineEntity point = dataList.get(i);
|
||||
if (i < 19) {
|
||||
point.mb = 0;
|
||||
point.up = 0;
|
||||
point.dn = 0;
|
||||
} else {
|
||||
int n = 20;
|
||||
float md = 0;
|
||||
for (int j = i - n + 1; j <= i; j++) {
|
||||
float c = dataList.get(j).getClosePrice();
|
||||
float m = point.getMA20Price();
|
||||
float value = c - m;
|
||||
md += value * value;
|
||||
}
|
||||
md = md / (n - 1);
|
||||
md = (float) Math.sqrt(md);
|
||||
point.mb = point.getMA20Price();
|
||||
point.up = point.mb + 2f * md;
|
||||
point.dn = point.mb - 2f * md;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算ma
|
||||
*
|
||||
* @param dataList
|
||||
*/
|
||||
static void calculateMA(List<KLineEntity> dataList) {
|
||||
float ma5 = 0;
|
||||
float ma10 = 0;
|
||||
float ma20 = 0;
|
||||
float ma30 = 0;
|
||||
float ma60 = 0;
|
||||
|
||||
for (int i = 0; i < dataList.size(); i++) {
|
||||
KLineEntity point = dataList.get(i);
|
||||
final float closePrice = point.getClosePrice();
|
||||
|
||||
ma5 += closePrice;
|
||||
ma10 += closePrice;
|
||||
ma20 += closePrice;
|
||||
ma30 += closePrice;
|
||||
ma60 += closePrice;
|
||||
if (i == 4) {
|
||||
point.MA5Price = ma5 / 5f;
|
||||
} else if (i >= 5) {
|
||||
ma5 -= dataList.get(i - 5).getClosePrice();
|
||||
point.MA5Price = ma5 / 5f;
|
||||
} else {
|
||||
point.MA5Price = 0f;
|
||||
}
|
||||
if (i == 9) {
|
||||
point.MA10Price = ma10 / 10f;
|
||||
} else if (i >= 10) {
|
||||
ma10 -= dataList.get(i - 10).getClosePrice();
|
||||
point.MA10Price = ma10 / 10f;
|
||||
} else {
|
||||
point.MA10Price = 0f;
|
||||
}
|
||||
if (i == 19) {
|
||||
point.MA20Price = ma20 / 20f;
|
||||
} else if (i >= 20) {
|
||||
ma20 -= dataList.get(i - 20).getClosePrice();
|
||||
point.MA20Price = ma20 / 20f;
|
||||
} else {
|
||||
point.MA20Price = 0f;
|
||||
}
|
||||
if (i == 29) {
|
||||
point.MA30Price = ma30 / 30f;
|
||||
} else if (i >= 30) {
|
||||
ma30 -= dataList.get(i - 30).getClosePrice();
|
||||
point.MA30Price = ma30 / 30f;
|
||||
} else {
|
||||
point.MA30Price = 0f;
|
||||
}
|
||||
if (i == 59) {
|
||||
point.MA60Price = ma60 / 60f;
|
||||
} else if (i >= 60) {
|
||||
ma60 -= dataList.get(i - 60).getClosePrice();
|
||||
point.MA60Price = ma60 / 60f;
|
||||
} else {
|
||||
point.MA60Price = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算MA BOLL RSI KDJ MACD
|
||||
*
|
||||
* @param dataList
|
||||
*/
|
||||
public static void calculate(List<KLineEntity> dataList) {
|
||||
calculateMA(dataList);
|
||||
calculateMACD(dataList);
|
||||
calculateBOLL(dataList);
|
||||
calculateRSI(dataList);
|
||||
calculateKDJ(dataList);
|
||||
calculateWR(dataList);
|
||||
calculateVolumeMA(dataList);
|
||||
}
|
||||
|
||||
private static void calculateVolumeMA(List<KLineEntity> entries) {
|
||||
float volumeMa5 = 0;
|
||||
float volumeMa10 = 0;
|
||||
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
KLineEntity entry = entries.get(i);
|
||||
|
||||
volumeMa5 += entry.getVolume();
|
||||
volumeMa10 += entry.getVolume();
|
||||
|
||||
if (i == 4) {
|
||||
entry.MA5Volume = (volumeMa5 / 5f);
|
||||
} else if (i > 4) {
|
||||
volumeMa5 -= entries.get(i - 5).getVolume();
|
||||
entry.MA5Volume = volumeMa5 / 5f;
|
||||
} else {
|
||||
entry.MA5Volume = 0f;
|
||||
}
|
||||
|
||||
if (i == 9) {
|
||||
entry.MA10Volume = volumeMa10 / 10f;
|
||||
} else if (i > 9) {
|
||||
volumeMa10 -= entries.get(i - 10).getVolume();
|
||||
entry.MA10Volume = volumeMa10 / 10f;
|
||||
} else {
|
||||
entry.MA10Volume = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
package com.github.fujianlian.klinechart;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 数据适配器
|
||||
* Created by tifezh on 2016/6/18.
|
||||
*/
|
||||
public class KLineChartAdapter extends BaseKLineChartAdapter {
|
||||
|
||||
private List<KLineEntity> datas = new ArrayList<>();
|
||||
|
||||
public KLineChartAdapter() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return datas.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return datas.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDate(int position) {
|
||||
return datas.get(position).Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* 向头部添加数据
|
||||
*/
|
||||
public void addHeaderData(List<KLineEntity> data) {
|
||||
if (data != null && !data.isEmpty()) {
|
||||
datas.clear();
|
||||
datas.addAll(data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 向尾部添加数据
|
||||
*/
|
||||
public void addFooterData(List<KLineEntity> data) {
|
||||
if (data != null && !data.isEmpty()) {
|
||||
datas.clear();
|
||||
datas.addAll(0, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 改变某个点的值
|
||||
*
|
||||
* @param position 索引值
|
||||
*/
|
||||
public void changeItem(int position, KLineEntity data) {
|
||||
datas.set(position, data);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据清除
|
||||
*/
|
||||
public void clearData() {
|
||||
datas.clear();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
+466
@@ -0,0 +1,466 @@
|
||||
package com.github.fujianlian.klinechart;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.support.annotation.ColorRes;
|
||||
import android.support.annotation.DimenRes;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import com.github.fujianlian.klinechart.draw.KDJDraw;
|
||||
import com.github.fujianlian.klinechart.draw.MACDDraw;
|
||||
import com.github.fujianlian.klinechart.draw.MainDraw;
|
||||
import com.github.fujianlian.klinechart.draw.RSIDraw;
|
||||
import com.github.fujianlian.klinechart.draw.VolumeDraw;
|
||||
import com.github.fujianlian.klinechart.draw.WRDraw;
|
||||
|
||||
/**
|
||||
* k线图
|
||||
* Created by tian on 2016/5/20.
|
||||
*/
|
||||
public class KLineChartView extends BaseKLineChartView {
|
||||
|
||||
ProgressBar mProgressBar;
|
||||
private boolean isRefreshing = false;
|
||||
private boolean isLoadMoreEnd = false;
|
||||
private boolean mLastScrollEnable;
|
||||
private boolean mLastScaleEnable;
|
||||
|
||||
private KChartRefreshListener mRefreshListener;
|
||||
|
||||
private MACDDraw mMACDDraw;
|
||||
private RSIDraw mRSIDraw;
|
||||
private MainDraw mMainDraw;
|
||||
private KDJDraw mKDJDraw;
|
||||
private WRDraw mWRDraw;
|
||||
private VolumeDraw mVolumeDraw;
|
||||
|
||||
|
||||
public KLineChartView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public KLineChartView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public KLineChartView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
initView();
|
||||
initAttrs(attrs);
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
mProgressBar = new ProgressBar(getContext());
|
||||
LayoutParams layoutParams = new LayoutParams(dp2px(50), dp2px(50));
|
||||
layoutParams.addRule(CENTER_IN_PARENT);
|
||||
addView(mProgressBar, layoutParams);
|
||||
mProgressBar.setVisibility(GONE);
|
||||
mVolumeDraw = new VolumeDraw(this);
|
||||
mMACDDraw = new MACDDraw(this);
|
||||
mWRDraw = new WRDraw(this);
|
||||
mKDJDraw = new KDJDraw(this);
|
||||
mRSIDraw = new RSIDraw(this);
|
||||
mMainDraw = new MainDraw(this);
|
||||
addChildDraw(mMACDDraw);
|
||||
addChildDraw(mKDJDraw);
|
||||
addChildDraw(mRSIDraw);
|
||||
addChildDraw(mWRDraw);
|
||||
setVolDraw(mVolumeDraw);
|
||||
setMainDraw(mMainDraw);
|
||||
}
|
||||
|
||||
private void initAttrs(AttributeSet attrs) {
|
||||
TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.KLineChartView);
|
||||
if (array != null) {
|
||||
try {
|
||||
//public
|
||||
setPointWidth(array.getDimension(R.styleable.KLineChartView_kc_point_width, getDimension(R.dimen.chart_point_width)));
|
||||
setTextSize(array.getDimension(R.styleable.KLineChartView_kc_text_size, getDimension(R.dimen.chart_text_size)));
|
||||
setTextColor(array.getColor(R.styleable.KLineChartView_kc_text_color, getColor(R.color.chart_text)));
|
||||
setMTextSize(array.getDimension(R.styleable.KLineChartView_kc_text_size, getDimension(R.dimen.chart_text_size)));
|
||||
setMTextColor(array.getColor(R.styleable.KLineChartView_kc_text_color, getColor(R.color.chart_white)));
|
||||
setLineWidth(array.getDimension(R.styleable.KLineChartView_kc_line_width, getDimension(R.dimen.chart_line_width)));
|
||||
setBackgroundColor(array.getColor(R.styleable.KLineChartView_kc_background_color, getColor(R.color.chart_bac)));
|
||||
setSelectPointColor(array.getColor(R.styleable.KLineChartView_kc_background_color, getColor(R.color.chart_point_bac)));
|
||||
|
||||
setSelectedXLineColor(Color.WHITE);
|
||||
setSelectedXLineWidth(getDimension(R.dimen.chart_line_width));
|
||||
|
||||
setSelectedYLineColor(Color.parseColor("#8040424D"));
|
||||
setSelectedYLineWidth(getDimension(R.dimen.chart_point_width));
|
||||
|
||||
setGridLineWidth(array.getDimension(R.styleable.KLineChartView_kc_grid_line_width, getDimension(R.dimen.chart_grid_line_width)));
|
||||
setGridLineColor(array.getColor(R.styleable.KLineChartView_kc_grid_line_color, getColor(R.color.chart_grid_line)));
|
||||
//macd
|
||||
setMACDWidth(array.getDimension(R.styleable.KLineChartView_kc_macd_width, getDimension(R.dimen.chart_candle_width)));
|
||||
setDIFColor(array.getColor(R.styleable.KLineChartView_kc_dif_color, getColor(R.color.chart_ma5)));
|
||||
setDEAColor(array.getColor(R.styleable.KLineChartView_kc_dea_color, getColor(R.color.chart_ma10)));
|
||||
setMACDColor(array.getColor(R.styleable.KLineChartView_kc_macd_color, getColor(R.color.chart_ma30)));
|
||||
//kdj
|
||||
setKColor(array.getColor(R.styleable.KLineChartView_kc_dif_color, getColor(R.color.chart_ma5)));
|
||||
setDColor(array.getColor(R.styleable.KLineChartView_kc_dea_color, getColor(R.color.chart_ma10)));
|
||||
setJColor(array.getColor(R.styleable.KLineChartView_kc_macd_color, getColor(R.color.chart_ma30)));
|
||||
//wr
|
||||
setRColor(array.getColor(R.styleable.KLineChartView_kc_dif_color, getColor(R.color.chart_ma5)));
|
||||
//rsi
|
||||
setRSI1Color(array.getColor(R.styleable.KLineChartView_kc_dif_color, getColor(R.color.chart_ma5)));
|
||||
setRSI2Color(array.getColor(R.styleable.KLineChartView_kc_dea_color, getColor(R.color.chart_ma10)));
|
||||
setRSI3Color(array.getColor(R.styleable.KLineChartView_kc_macd_color, getColor(R.color.chart_ma30)));
|
||||
//main
|
||||
setMa5Color(array.getColor(R.styleable.KLineChartView_kc_dif_color, getColor(R.color.chart_ma5)));
|
||||
setMa10Color(array.getColor(R.styleable.KLineChartView_kc_dea_color, getColor(R.color.chart_ma10)));
|
||||
setMa30Color(array.getColor(R.styleable.KLineChartView_kc_macd_color, getColor(R.color.chart_ma30)));
|
||||
setCandleWidth(array.getDimension(R.styleable.KLineChartView_kc_candle_width, getDimension(R.dimen.chart_candle_width)));
|
||||
setCandleLineWidth(array.getDimension(R.styleable.KLineChartView_kc_candle_line_width, getDimension(R.dimen.chart_candle_line_width)));
|
||||
setSelectorBackgroundColor(array.getColor(R.styleable.KLineChartView_kc_selector_background_color, getColor(R.color.chart_selector)));
|
||||
setSelectorTextSize(array.getDimension(R.styleable.KLineChartView_kc_selector_text_size, getDimension(R.dimen.chart_selector_text_size)));
|
||||
setCandleSolid(array.getBoolean(R.styleable.KLineChartView_kc_candle_solid, true));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
array.recycle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float getDimension(@DimenRes int resId) {
|
||||
return getResources().getDimension(resId);
|
||||
}
|
||||
|
||||
private int getColor(@ColorRes int resId) {
|
||||
return ContextCompat.getColor(getContext(), resId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLeftSide() {
|
||||
showLoading();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRightSide() {
|
||||
}
|
||||
|
||||
public void showLoading() {
|
||||
if (!isLoadMoreEnd && !isRefreshing) {
|
||||
isRefreshing = true;
|
||||
if (mProgressBar != null) {
|
||||
mProgressBar.setVisibility(View.VISIBLE);
|
||||
}
|
||||
if (mRefreshListener != null) {
|
||||
mRefreshListener.onLoadMoreBegin(this);
|
||||
}
|
||||
mLastScaleEnable = isScaleEnable();
|
||||
mLastScrollEnable = isScrollEnable();
|
||||
super.setScrollEnable(false);
|
||||
super.setScaleEnable(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void justShowLoading() {
|
||||
if (!isRefreshing) {
|
||||
isLongPress = false;
|
||||
isRefreshing = true;
|
||||
if (mProgressBar != null) {
|
||||
mProgressBar.setVisibility(View.VISIBLE);
|
||||
}
|
||||
if (mRefreshListener != null) {
|
||||
mRefreshListener.onLoadMoreBegin(this);
|
||||
}
|
||||
mLastScaleEnable = isScaleEnable();
|
||||
mLastScrollEnable = isScrollEnable();
|
||||
super.setScrollEnable(false);
|
||||
super.setScaleEnable(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void hideLoading() {
|
||||
if (mProgressBar != null) {
|
||||
mProgressBar.setVisibility(View.GONE);
|
||||
}
|
||||
super.setScrollEnable(mLastScrollEnable);
|
||||
super.setScaleEnable(mLastScaleEnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏选择器内容
|
||||
*/
|
||||
public void hideSelectData() {
|
||||
isLongPress = false;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新完成
|
||||
*/
|
||||
public void refreshComplete() {
|
||||
isRefreshing = false;
|
||||
hideLoading();
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新完成,没有数据
|
||||
*/
|
||||
public void refreshEnd() {
|
||||
isLoadMoreEnd = true;
|
||||
isRefreshing = false;
|
||||
hideLoading();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置加载更多
|
||||
*/
|
||||
public void resetLoadMoreEnd() {
|
||||
isLoadMoreEnd = false;
|
||||
}
|
||||
|
||||
public void setLoadMoreEnd() {
|
||||
isLoadMoreEnd = true;
|
||||
}
|
||||
|
||||
public interface KChartRefreshListener {
|
||||
/**
|
||||
* 加载更多
|
||||
*
|
||||
* @param chart
|
||||
*/
|
||||
void onLoadMoreBegin(KLineChartView chart);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScaleEnable(boolean scaleEnable) {
|
||||
if (isRefreshing) {
|
||||
throw new IllegalStateException("请勿在刷新状态设置属性");
|
||||
}
|
||||
super.setScaleEnable(scaleEnable);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScrollEnable(boolean scrollEnable) {
|
||||
if (isRefreshing) {
|
||||
throw new IllegalStateException("请勿在刷新状态设置属性");
|
||||
}
|
||||
super.setScrollEnable(scrollEnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置DIF颜色
|
||||
*/
|
||||
public void setDIFColor(int color) {
|
||||
mMACDDraw.setDIFColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置DEA颜色
|
||||
*/
|
||||
public void setDEAColor(int color) {
|
||||
mMACDDraw.setDEAColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置MACD颜色
|
||||
*/
|
||||
public void setMACDColor(int color) {
|
||||
mMACDDraw.setMACDColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置MACD的宽度
|
||||
*
|
||||
* @param MACDWidth
|
||||
*/
|
||||
public void setMACDWidth(float MACDWidth) {
|
||||
mMACDDraw.setMACDWidth(MACDWidth);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置K颜色
|
||||
*/
|
||||
public void setKColor(int color) {
|
||||
mKDJDraw.setKColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置D颜色
|
||||
*/
|
||||
public void setDColor(int color) {
|
||||
mKDJDraw.setDColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置J颜色
|
||||
*/
|
||||
public void setJColor(int color) {
|
||||
mKDJDraw.setJColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置R颜色
|
||||
*/
|
||||
public void setRColor(int color) {
|
||||
mWRDraw.setRColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置ma5颜色
|
||||
*
|
||||
* @param color
|
||||
*/
|
||||
public void setMa5Color(int color) {
|
||||
mMainDraw.setMa5Color(color);
|
||||
mVolumeDraw.setMa5Color(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置ma10颜色
|
||||
*
|
||||
* @param color
|
||||
*/
|
||||
public void setMa10Color(int color) {
|
||||
mMainDraw.setMa10Color(color);
|
||||
mVolumeDraw.setMa10Color(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置ma20颜色
|
||||
*
|
||||
* @param color
|
||||
*/
|
||||
public void setMa30Color(int color) {
|
||||
mMainDraw.setMa30Color(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置选择器文字大小
|
||||
*
|
||||
* @param textSize
|
||||
*/
|
||||
public void setSelectorTextSize(float textSize) {
|
||||
mMainDraw.setSelectorTextSize(textSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置选择器背景
|
||||
*
|
||||
* @param color
|
||||
*/
|
||||
public void setSelectorBackgroundColor(int color) {
|
||||
mMainDraw.setSelectorBackgroundColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置蜡烛宽度
|
||||
*
|
||||
* @param candleWidth
|
||||
*/
|
||||
public void setCandleWidth(float candleWidth) {
|
||||
mMainDraw.setCandleWidth(candleWidth);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置蜡烛线宽度
|
||||
*
|
||||
* @param candleLineWidth
|
||||
*/
|
||||
public void setCandleLineWidth(float candleLineWidth) {
|
||||
mMainDraw.setCandleLineWidth(candleLineWidth);
|
||||
}
|
||||
|
||||
/**
|
||||
* 蜡烛是否空心
|
||||
*/
|
||||
public void setCandleSolid(boolean candleSolid) {
|
||||
mMainDraw.setCandleSolid(candleSolid);
|
||||
}
|
||||
|
||||
public void setRSI1Color(int color) {
|
||||
mRSIDraw.setRSI1Color(color);
|
||||
}
|
||||
|
||||
public void setRSI2Color(int color) {
|
||||
mRSIDraw.setRSI2Color(color);
|
||||
}
|
||||
|
||||
public void setRSI3Color(int color) {
|
||||
mRSIDraw.setRSI3Color(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTextSize(float textSize) {
|
||||
super.setTextSize(textSize);
|
||||
mMainDraw.setTextSize(textSize);
|
||||
mRSIDraw.setTextSize(textSize);
|
||||
mMACDDraw.setTextSize(textSize);
|
||||
mKDJDraw.setTextSize(textSize);
|
||||
mWRDraw.setTextSize(textSize);
|
||||
mVolumeDraw.setTextSize(textSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLineWidth(float lineWidth) {
|
||||
super.setLineWidth(lineWidth);
|
||||
mMainDraw.setLineWidth(lineWidth);
|
||||
mRSIDraw.setLineWidth(lineWidth);
|
||||
mMACDDraw.setLineWidth(lineWidth);
|
||||
mKDJDraw.setLineWidth(lineWidth);
|
||||
mWRDraw.setLineWidth(lineWidth);
|
||||
mVolumeDraw.setLineWidth(lineWidth);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTextColor(int color) {
|
||||
super.setTextColor(color);
|
||||
mMainDraw.setSelectorTextColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置刷新监听
|
||||
*/
|
||||
public void setRefreshListener(KChartRefreshListener refreshListener) {
|
||||
mRefreshListener = refreshListener;
|
||||
}
|
||||
|
||||
public void setMainDrawLine(boolean isLine) {
|
||||
mMainDraw.setLine(isLine);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
private int startX;
|
||||
private int startY;
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
switch (ev.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
startX = (int) ev.getX();
|
||||
startY = (int) ev.getY();
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
int dX = (int) (ev.getX() - startX);
|
||||
int dY = (int) (ev.getY() - startX);
|
||||
if (Math.abs(dX) > Math.abs(dY)) {
|
||||
//左右滑动
|
||||
return true;
|
||||
} else {
|
||||
//上下滑动
|
||||
return false;
|
||||
}
|
||||
case MotionEvent.ACTION_UP:
|
||||
break;
|
||||
default:
|
||||
}
|
||||
return super.onInterceptTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLongPress(MotionEvent e) {
|
||||
if (!isRefreshing) {
|
||||
super.onLongPress(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
package com.github.fujianlian.klinechart;
|
||||
|
||||
import com.github.fujianlian.klinechart.entity.IKLine;
|
||||
|
||||
/**
|
||||
* K线实体
|
||||
* Created by tifezh on 2016/5/16.
|
||||
*/
|
||||
public class KLineEntity implements IKLine {
|
||||
|
||||
public String getDate() {
|
||||
return Date;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getOpenPrice() {
|
||||
return Open;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHighPrice() {
|
||||
return High;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getLowPrice() {
|
||||
return Low;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getClosePrice() {
|
||||
return Close;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMA5Price() {
|
||||
return MA5Price;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMA10Price() {
|
||||
return MA10Price;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMA20Price() {
|
||||
return MA20Price;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMA30Price() {
|
||||
return MA30Price;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMA60Price() {
|
||||
return MA60Price;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getDea() {
|
||||
return dea;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getDif() {
|
||||
return dif;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMacd() {
|
||||
return macd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getK() {
|
||||
return k;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getD() {
|
||||
return d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getJ() {
|
||||
return j;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getR() {
|
||||
return r;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getRsi() {
|
||||
return rsi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getUp() {
|
||||
return up;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMb() {
|
||||
return mb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getDn() {
|
||||
return dn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getVolume() {
|
||||
return Volume;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMA5Volume() {
|
||||
return MA5Volume;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMA10Volume() {
|
||||
return MA10Volume;
|
||||
}
|
||||
|
||||
public String Date;
|
||||
public float Open;
|
||||
public float High;
|
||||
public float Low;
|
||||
public float Close;
|
||||
public float Volume;
|
||||
|
||||
public float MA5Price;
|
||||
|
||||
public float MA10Price;
|
||||
|
||||
public float MA20Price;
|
||||
|
||||
public float MA30Price;
|
||||
|
||||
public float MA60Price;
|
||||
|
||||
public float dea;
|
||||
|
||||
public float dif;
|
||||
|
||||
public float macd;
|
||||
|
||||
public float k;
|
||||
|
||||
public float d;
|
||||
|
||||
public float j;
|
||||
|
||||
public float r;
|
||||
|
||||
public float rsi;
|
||||
|
||||
public float up;
|
||||
|
||||
public float mb;
|
||||
|
||||
public float dn;
|
||||
|
||||
public float MA5Volume;
|
||||
|
||||
public float MA10Volume;
|
||||
|
||||
|
||||
}
|
||||
+327
@@ -0,0 +1,327 @@
|
||||
package com.github.fujianlian.klinechart;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v4.view.GestureDetectorCompat;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ScaleGestureDetector;
|
||||
import android.widget.OverScroller;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
/**
|
||||
* 可以滑动和放大的view
|
||||
* Created by tian on 2016/5/3.
|
||||
*/
|
||||
public abstract class ScrollAndScaleView extends RelativeLayout implements
|
||||
GestureDetector.OnGestureListener,
|
||||
ScaleGestureDetector.OnScaleGestureListener {
|
||||
protected int mScrollX = 0;
|
||||
protected GestureDetectorCompat mDetector;
|
||||
protected ScaleGestureDetector mScaleDetector;
|
||||
|
||||
protected boolean isLongPress = false;
|
||||
|
||||
private OverScroller mScroller;
|
||||
|
||||
protected boolean touch = false;
|
||||
|
||||
protected float mScaleX = 1;
|
||||
|
||||
protected float mScaleXMax = 2f;
|
||||
|
||||
protected float mScaleXMin = 0.5f;
|
||||
|
||||
private boolean mMultipleTouch = false;
|
||||
|
||||
private boolean mScrollEnable = true;
|
||||
|
||||
private boolean mScaleEnable = true;
|
||||
|
||||
public ScrollAndScaleView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public ScrollAndScaleView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public ScrollAndScaleView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setWillNotDraw(false);
|
||||
mDetector = new GestureDetectorCompat(getContext(), this);
|
||||
mScaleDetector = new ScaleGestureDetector(getContext(), this);
|
||||
mScroller = new OverScroller(getContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDown(MotionEvent e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShowPress(MotionEvent e) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSingleTapUp(MotionEvent e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
||||
if (!isLongPress && !isMultipleTouch()) {
|
||||
scrollBy(Math.round(distanceX), 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLongPress(MotionEvent e) {
|
||||
isLongPress = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
||||
if (!isTouch() && isScrollEnable()) {
|
||||
mScroller.fling(mScrollX, 0
|
||||
, Math.round(velocityX / mScaleX), 0,
|
||||
Integer.MIN_VALUE, Integer.MAX_VALUE,
|
||||
0, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void computeScroll() {
|
||||
if (mScroller.computeScrollOffset()) {
|
||||
if (!isTouch()) {
|
||||
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
|
||||
} else {
|
||||
mScroller.forceFinished(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scrollBy(int x, int y) {
|
||||
scrollTo(mScrollX - Math.round(x / mScaleX), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scrollTo(int x, int y) {
|
||||
if (!isScrollEnable()) {
|
||||
mScroller.forceFinished(true);
|
||||
return;
|
||||
}
|
||||
int oldX = mScrollX;
|
||||
mScrollX = x;
|
||||
if (mScrollX < getMinScrollX()) {
|
||||
mScrollX = getMinScrollX();
|
||||
onRightSide();
|
||||
mScroller.forceFinished(true);
|
||||
} else if (mScrollX > getMaxScrollX()) {
|
||||
mScrollX = getMaxScrollX();
|
||||
onLeftSide();
|
||||
mScroller.forceFinished(true);
|
||||
}
|
||||
onScrollChanged(mScrollX, 0, oldX, 0);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onScale(ScaleGestureDetector detector) {
|
||||
if (!isScaleEnable()) {
|
||||
return false;
|
||||
}
|
||||
float oldScale = mScaleX;
|
||||
mScaleX *= detector.getScaleFactor();
|
||||
if (mScaleX < mScaleXMin) {
|
||||
mScaleX = mScaleXMin;
|
||||
} else if (mScaleX > mScaleXMax) {
|
||||
mScaleX = mScaleXMax;
|
||||
} else {
|
||||
onScaleChanged(mScaleX, oldScale);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void onScaleChanged(float scale, float oldScale) {
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onScaleBegin(ScaleGestureDetector detector) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScaleEnd(ScaleGestureDetector detector) {
|
||||
|
||||
}
|
||||
|
||||
float x;
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
// 按压手指超过1个
|
||||
if (event.getPointerCount() > 1) {
|
||||
isLongPress = false;
|
||||
}
|
||||
switch (event.getAction() & MotionEvent.ACTION_MASK) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
touch = true;
|
||||
x = event.getX();
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
//长按之后移动
|
||||
if (isLongPress) {
|
||||
onLongPress(event);
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
invalidate();
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (x == event.getX()) {
|
||||
if (isLongPress) {
|
||||
isLongPress = false;
|
||||
}
|
||||
}
|
||||
touch = false;
|
||||
invalidate();
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
isLongPress = false;
|
||||
touch = false;
|
||||
invalidate();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
mMultipleTouch = event.getPointerCount() > 1;
|
||||
this.mDetector.onTouchEvent(event);
|
||||
this.mScaleDetector.onTouchEvent(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 滑到了最左边
|
||||
*/
|
||||
abstract public void onLeftSide();
|
||||
|
||||
/**
|
||||
* 滑到了最右边
|
||||
*/
|
||||
abstract public void onRightSide();
|
||||
|
||||
/**
|
||||
* 是否在触摸中
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isTouch() {
|
||||
return touch;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取位移的最小值
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public abstract int getMinScrollX();
|
||||
|
||||
/**
|
||||
* 获取位移的最大值
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public abstract int getMaxScrollX();
|
||||
|
||||
/**
|
||||
* 设置ScrollX
|
||||
*
|
||||
* @param scrollX
|
||||
*/
|
||||
public void setScrollX(int scrollX) {
|
||||
this.mScrollX = scrollX;
|
||||
scrollTo(scrollX, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是多指触控
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isMultipleTouch() {
|
||||
return mMultipleTouch;
|
||||
}
|
||||
|
||||
protected void checkAndFixScrollX() {
|
||||
if (mScrollX < getMinScrollX()) {
|
||||
mScrollX = getMinScrollX();
|
||||
mScroller.forceFinished(true);
|
||||
} else if (mScrollX > getMaxScrollX()) {
|
||||
mScrollX = getMaxScrollX();
|
||||
mScroller.forceFinished(true);
|
||||
}
|
||||
}
|
||||
|
||||
public float getScaleXMax() {
|
||||
return mScaleXMax;
|
||||
}
|
||||
|
||||
public float getScaleXMin() {
|
||||
return mScaleXMin;
|
||||
}
|
||||
|
||||
public boolean isScrollEnable() {
|
||||
return mScrollEnable;
|
||||
}
|
||||
|
||||
public boolean isScaleEnable() {
|
||||
return mScaleEnable;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置缩放的最大值
|
||||
*/
|
||||
public void setScaleXMax(float scaleXMax) {
|
||||
mScaleXMax = scaleXMax;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置缩放的最小值
|
||||
*/
|
||||
public void setScaleXMin(float scaleXMin) {
|
||||
mScaleXMin = scaleXMin;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否可以滑动
|
||||
*/
|
||||
public void setScrollEnable(boolean scrollEnable) {
|
||||
mScrollEnable = scrollEnable;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否可以缩放
|
||||
*/
|
||||
public void setScaleEnable(boolean scaleEnable) {
|
||||
mScaleEnable = scaleEnable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getScaleX() {
|
||||
return mScaleX;
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package com.github.fujianlian.klinechart.base;
|
||||
|
||||
import android.database.DataSetObserver;
|
||||
|
||||
/**
|
||||
* 数据适配器
|
||||
* Created by tifezh on 2016/6/14.
|
||||
*/
|
||||
|
||||
public interface IAdapter {
|
||||
/**
|
||||
* 获取点的数目
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
int getCount();
|
||||
|
||||
/**
|
||||
* 通过序号获取item
|
||||
*
|
||||
* @param position 对应的序号
|
||||
* @return 数据实体
|
||||
*/
|
||||
Object getItem(int position);
|
||||
|
||||
/**
|
||||
* 通过序号获取时间
|
||||
*
|
||||
* @param position
|
||||
* @return
|
||||
*/
|
||||
String getDate(int position);
|
||||
|
||||
/**
|
||||
* 注册一个数据观察者
|
||||
*
|
||||
* @param observer 数据观察者
|
||||
*/
|
||||
void registerDataSetObserver(DataSetObserver observer);
|
||||
|
||||
/**
|
||||
* 移除一个数据观察者
|
||||
*
|
||||
* @param observer 数据观察者
|
||||
*/
|
||||
void unregisterDataSetObserver(DataSetObserver observer);
|
||||
|
||||
/**
|
||||
* 当数据发生变化时调用
|
||||
*/
|
||||
void notifyDataSetChanged();
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package com.github.fujianlian.klinechart.base;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.github.fujianlian.klinechart.BaseKLineChartView;
|
||||
|
||||
|
||||
/**
|
||||
* 画图的基类 根据实体来画图形
|
||||
* Created by tifezh on 2016/6/14.
|
||||
*/
|
||||
public interface IChartDraw<T> {
|
||||
|
||||
/**
|
||||
* 需要滑动 物体draw方法
|
||||
*
|
||||
* @param canvas canvas
|
||||
* @param view k线图View
|
||||
* @param position 当前点的位置
|
||||
* @param lastPoint 上一个点
|
||||
* @param curPoint 当前点
|
||||
* @param lastX 上一个点的x坐标
|
||||
* @param curX 当前点的X坐标
|
||||
*/
|
||||
void drawTranslated(@Nullable T lastPoint, @NonNull T curPoint, float lastX, float curX, @NonNull Canvas canvas, @NonNull BaseKLineChartView view, int position);
|
||||
|
||||
/**
|
||||
* @param canvas
|
||||
* @param view
|
||||
* @param position 该点的位置
|
||||
* @param x x的起始坐标
|
||||
* @param y y的起始坐标
|
||||
*/
|
||||
void drawText(@NonNull Canvas canvas, @NonNull BaseKLineChartView view, int position, float x, float y);
|
||||
|
||||
/**
|
||||
* 获取当前实体中最大的值
|
||||
*
|
||||
* @param point
|
||||
* @return
|
||||
*/
|
||||
float getMaxValue(T point);
|
||||
|
||||
/**
|
||||
* 获取当前实体中最小的值
|
||||
*
|
||||
* @param point
|
||||
* @return
|
||||
*/
|
||||
float getMinValue(T point);
|
||||
|
||||
/**
|
||||
* 获取value格式化器
|
||||
*/
|
||||
IValueFormatter getValueFormatter();
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.github.fujianlian.klinechart.base;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 时间格式化接口
|
||||
* Created by tifezh on 2016/6/21.
|
||||
*/
|
||||
|
||||
public interface IDateTimeFormatter {
|
||||
String format(Date date);
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.github.fujianlian.klinechart.base;
|
||||
|
||||
/**
|
||||
* Value格式化接口
|
||||
* Created by tifezh on 2016/6/21.
|
||||
*/
|
||||
|
||||
public interface IValueFormatter {
|
||||
/**
|
||||
* 格式化value
|
||||
*
|
||||
* @param value 传入的value值
|
||||
* @return 返回字符串
|
||||
*/
|
||||
String format(float value);
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
package com.github.fujianlian.klinechart.draw;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.github.fujianlian.klinechart.BaseKLineChartView;
|
||||
import com.github.fujianlian.klinechart.base.IChartDraw;
|
||||
import com.github.fujianlian.klinechart.base.IValueFormatter;
|
||||
import com.github.fujianlian.klinechart.entity.IKDJ;
|
||||
import com.github.fujianlian.klinechart.formatter.ValueFormatter;
|
||||
|
||||
/**
|
||||
* KDJ实现类
|
||||
* Created by tifezh on 2016/6/19.
|
||||
*/
|
||||
|
||||
public class KDJDraw implements IChartDraw<IKDJ> {
|
||||
|
||||
private Paint mKPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint mDPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint mJPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
|
||||
public KDJDraw(BaseKLineChartView view) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawTranslated(@Nullable IKDJ lastPoint, @NonNull IKDJ curPoint, float lastX, float curX, @NonNull Canvas canvas, @NonNull BaseKLineChartView view, int position) {
|
||||
if (lastPoint.getK() != 0) {
|
||||
view.drawChildLine(canvas, mKPaint, lastX, lastPoint.getK(), curX, curPoint.getK());
|
||||
}
|
||||
if (lastPoint.getD() != 0) {
|
||||
view.drawChildLine(canvas, mDPaint, lastX, lastPoint.getD(), curX, curPoint.getD());
|
||||
}
|
||||
if (lastPoint.getJ() != 0) {
|
||||
view.drawChildLine(canvas, mJPaint, lastX, lastPoint.getJ(), curX, curPoint.getJ());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawText(@NonNull Canvas canvas, @NonNull BaseKLineChartView view, int position, float x, float y) {
|
||||
IKDJ point = (IKDJ) view.getItem(position);
|
||||
if (point.getK() != 0) {
|
||||
String text = "KDJ(14,1,3) ";
|
||||
canvas.drawText(text, x, y, view.getTextPaint());
|
||||
x += view.getTextPaint().measureText(text);
|
||||
text = "K:" + view.formatValue(point.getK()) + " ";
|
||||
canvas.drawText(text, x, y, mKPaint);
|
||||
x += mKPaint.measureText(text);
|
||||
if (point.getD() != 0) {
|
||||
text = "D:" + view.formatValue(point.getD()) + " ";
|
||||
canvas.drawText(text, x, y, mDPaint);
|
||||
x += mDPaint.measureText(text);
|
||||
text = "J:" + view.formatValue(point.getJ()) + " ";
|
||||
canvas.drawText(text, x, y, mJPaint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMaxValue(IKDJ point) {
|
||||
return Math.max(point.getK(), Math.max(point.getD(), point.getJ()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMinValue(IKDJ point) {
|
||||
return Math.min(point.getK(), Math.min(point.getD(), point.getJ()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IValueFormatter getValueFormatter() {
|
||||
return new ValueFormatter();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置K颜色
|
||||
*/
|
||||
public void setKColor(int color) {
|
||||
mKPaint.setColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置D颜色
|
||||
*/
|
||||
public void setDColor(int color) {
|
||||
mDPaint.setColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置J颜色
|
||||
*/
|
||||
public void setJColor(int color) {
|
||||
mJPaint.setColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置曲线宽度
|
||||
*/
|
||||
public void setLineWidth(float width) {
|
||||
mKPaint.setStrokeWidth(width);
|
||||
mDPaint.setStrokeWidth(width);
|
||||
mJPaint.setStrokeWidth(width);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置文字大小
|
||||
*/
|
||||
public void setTextSize(float textSize) {
|
||||
mKPaint.setTextSize(textSize);
|
||||
mDPaint.setTextSize(textSize);
|
||||
mJPaint.setTextSize(textSize);
|
||||
}
|
||||
}
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
package com.github.fujianlian.klinechart.draw;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
|
||||
import com.github.fujianlian.klinechart.R;
|
||||
import com.github.fujianlian.klinechart.BaseKLineChartView;
|
||||
import com.github.fujianlian.klinechart.base.IChartDraw;
|
||||
import com.github.fujianlian.klinechart.base.IValueFormatter;
|
||||
import com.github.fujianlian.klinechart.entity.IMACD;
|
||||
import com.github.fujianlian.klinechart.formatter.ValueFormatter;
|
||||
|
||||
/**
|
||||
* macd实现类
|
||||
* Created by tifezh on 2016/6/19.
|
||||
*/
|
||||
|
||||
public class MACDDraw implements IChartDraw<IMACD> {
|
||||
|
||||
private Paint mRedPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint mGreenPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint mDIFPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint mDEAPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint mMACDPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
/**
|
||||
* macd 中柱子的宽度
|
||||
*/
|
||||
private float mMACDWidth = 0;
|
||||
|
||||
public MACDDraw(BaseKLineChartView view) {
|
||||
Context context = view.getContext();
|
||||
mRedPaint.setColor(ContextCompat.getColor(context, R.color.chart_red));
|
||||
mGreenPaint.setColor(ContextCompat.getColor(context, R.color.chart_green));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawTranslated(@Nullable IMACD lastPoint, @NonNull IMACD curPoint, float lastX, float curX, @NonNull Canvas canvas, @NonNull BaseKLineChartView view, int position) {
|
||||
drawMACD(canvas, view, curX, curPoint.getMacd());
|
||||
view.drawChildLine(canvas, mDIFPaint, lastX, lastPoint.getDea(), curX, curPoint.getDea());
|
||||
view.drawChildLine(canvas, mDEAPaint, lastX, lastPoint.getDif(), curX, curPoint.getDif());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawText(@NonNull Canvas canvas, @NonNull BaseKLineChartView view, int position, float x, float y) {
|
||||
IMACD point = (IMACD) view.getItem(position);
|
||||
String text = "MACD(12,26,9) ";
|
||||
canvas.drawText(text, x, y, view.getTextPaint());
|
||||
x += view.getTextPaint().measureText(text);
|
||||
text = "MACD:" + view.formatValue(point.getMacd()) + " ";
|
||||
canvas.drawText(text, x, y, mMACDPaint);
|
||||
x += mMACDPaint.measureText(text);
|
||||
text = "DIF:" + view.formatValue(point.getDif()) + " ";
|
||||
canvas.drawText(text, x, y, mDEAPaint);
|
||||
x += mDIFPaint.measureText(text);
|
||||
text = "DEA:" + view.formatValue(point.getDea());
|
||||
canvas.drawText(text, x, y, mDIFPaint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMaxValue(IMACD point) {
|
||||
return Math.max(point.getMacd(), Math.max(point.getDea(), point.getDif()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMinValue(IMACD point) {
|
||||
return Math.min(point.getMacd(), Math.min(point.getDea(), point.getDif()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IValueFormatter getValueFormatter() {
|
||||
return new ValueFormatter();
|
||||
}
|
||||
|
||||
/**
|
||||
* 画macd
|
||||
*
|
||||
* @param canvas
|
||||
* @param x
|
||||
* @param macd
|
||||
*/
|
||||
private void drawMACD(Canvas canvas, BaseKLineChartView view, float x, float macd) {
|
||||
float macdy = view.getChildY(macd);
|
||||
float r = mMACDWidth / 2;
|
||||
float zeroy = view.getChildY(0);
|
||||
if (macd > 0) {
|
||||
// left top right bottom
|
||||
canvas.drawRect(x - r, macdy, x + r, zeroy, mRedPaint);
|
||||
} else {
|
||||
canvas.drawRect(x - r, zeroy, x + r, macdy, mGreenPaint);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置DIF颜色
|
||||
*/
|
||||
public void setDIFColor(int color) {
|
||||
this.mDIFPaint.setColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置DEA颜色
|
||||
*/
|
||||
public void setDEAColor(int color) {
|
||||
this.mDEAPaint.setColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置MACD颜色
|
||||
*/
|
||||
public void setMACDColor(int color) {
|
||||
this.mMACDPaint.setColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置MACD的宽度
|
||||
*
|
||||
* @param MACDWidth
|
||||
*/
|
||||
public void setMACDWidth(float MACDWidth) {
|
||||
mMACDWidth = MACDWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置曲线宽度
|
||||
*/
|
||||
public void setLineWidth(float width) {
|
||||
mDEAPaint.setStrokeWidth(width);
|
||||
mDIFPaint.setStrokeWidth(width);
|
||||
mMACDPaint.setStrokeWidth(width);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置文字大小
|
||||
*/
|
||||
public void setTextSize(float textSize) {
|
||||
mDEAPaint.setTextSize(textSize);
|
||||
mDIFPaint.setTextSize(textSize);
|
||||
mMACDPaint.setTextSize(textSize);
|
||||
}
|
||||
}
|
||||
+410
@@ -0,0 +1,410 @@
|
||||
package com.github.fujianlian.klinechart.draw;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
|
||||
import com.github.fujianlian.klinechart.R;
|
||||
import com.github.fujianlian.klinechart.BaseKLineChartView;
|
||||
import com.github.fujianlian.klinechart.KLineChartView;
|
||||
import com.github.fujianlian.klinechart.base.IChartDraw;
|
||||
import com.github.fujianlian.klinechart.base.IValueFormatter;
|
||||
import com.github.fujianlian.klinechart.entity.ICandle;
|
||||
import com.github.fujianlian.klinechart.entity.IKLine;
|
||||
import com.github.fujianlian.klinechart.formatter.ValueFormatter;
|
||||
import com.github.fujianlian.klinechart.utils.ViewUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 主图的实现类
|
||||
* Created by tifezh on 2016/6/14.
|
||||
*/
|
||||
public class MainDraw implements IChartDraw<ICandle> {
|
||||
|
||||
private float mCandleWidth = 0;
|
||||
private float mCandleLineWidth = 0;
|
||||
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint mRedPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint mGreenPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint ma5Paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint ma10Paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint ma30Paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
|
||||
private Paint mSelectorTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint mSelectorBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Context mContext;
|
||||
|
||||
private boolean mCandleSolid = true;
|
||||
// 是否分时
|
||||
private boolean isLine = false;
|
||||
private Status status = Status.MA;
|
||||
private KLineChartView kChartView;
|
||||
|
||||
public MainDraw(BaseKLineChartView view) {
|
||||
Context context = view.getContext();
|
||||
kChartView = (KLineChartView) view;
|
||||
mContext = context;
|
||||
mRedPaint.setColor(ContextCompat.getColor(context, R.color.chart_red));
|
||||
mGreenPaint.setColor(ContextCompat.getColor(context, R.color.chart_green));
|
||||
mLinePaint.setColor(ContextCompat.getColor(context, R.color.chart_line));
|
||||
paint.setColor(ContextCompat.getColor(context, R.color.chart_line_background));
|
||||
}
|
||||
|
||||
public void setStatus(Status status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawTranslated(@Nullable ICandle lastPoint, @NonNull ICandle curPoint, float lastX, float curX, @NonNull Canvas canvas, @NonNull BaseKLineChartView view, int position) {
|
||||
if (isLine) {
|
||||
view.drawMainLine(canvas, mLinePaint, lastX, lastPoint.getClosePrice(), curX, curPoint.getClosePrice());
|
||||
view.drawMainMinuteLine(canvas, paint, lastX, lastPoint.getClosePrice(), curX, curPoint.getClosePrice());
|
||||
if (status == Status.MA) {
|
||||
//画ma60
|
||||
if (lastPoint.getMA60Price() != 0) {
|
||||
view.drawMainLine(canvas, ma10Paint, lastX, lastPoint.getMA60Price(), curX, curPoint.getMA60Price());
|
||||
}
|
||||
} else if (status == Status.BOLL) {
|
||||
//画boll
|
||||
if (lastPoint.getMb() != 0) {
|
||||
view.drawMainLine(canvas, ma10Paint, lastX, lastPoint.getMb(), curX, curPoint.getMb());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
drawCandle(view, canvas, curX, curPoint.getHighPrice(), curPoint.getLowPrice(), curPoint.getOpenPrice(), curPoint.getClosePrice());
|
||||
if (status == Status.MA) {
|
||||
//画ma5
|
||||
if (lastPoint.getMA5Price() != 0) {
|
||||
view.drawMainLine(canvas, ma5Paint, lastX, lastPoint.getMA5Price(), curX, curPoint.getMA5Price());
|
||||
}
|
||||
//画ma10
|
||||
if (lastPoint.getMA10Price() != 0) {
|
||||
view.drawMainLine(canvas, ma10Paint, lastX, lastPoint.getMA10Price(), curX, curPoint.getMA10Price());
|
||||
}
|
||||
//画ma30
|
||||
if (lastPoint.getMA30Price() != 0) {
|
||||
view.drawMainLine(canvas, ma30Paint, lastX, lastPoint.getMA30Price(), curX, curPoint.getMA30Price());
|
||||
}
|
||||
} else if (status == Status.BOLL) {
|
||||
//画boll
|
||||
if (lastPoint.getUp() != 0) {
|
||||
view.drawMainLine(canvas, ma5Paint, lastX, lastPoint.getUp(), curX, curPoint.getUp());
|
||||
}
|
||||
if (lastPoint.getMb() != 0) {
|
||||
view.drawMainLine(canvas, ma10Paint, lastX, lastPoint.getMb(), curX, curPoint.getMb());
|
||||
}
|
||||
if (lastPoint.getDn() != 0) {
|
||||
view.drawMainLine(canvas, ma30Paint, lastX, lastPoint.getDn(), curX, curPoint.getDn());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawText(@NonNull Canvas canvas, @NonNull BaseKLineChartView view, int position, float x, float y) {
|
||||
ICandle point = (IKLine) view.getItem(position);
|
||||
y = y - 5;
|
||||
if (isLine) {
|
||||
if (status == Status.MA) {
|
||||
if (point.getMA60Price() != 0) {
|
||||
String text = "MA60:" + view.formatValue(point.getMA60Price()) + " ";
|
||||
canvas.drawText(text, x, y, ma10Paint);
|
||||
}
|
||||
} else if (status == Status.BOLL) {
|
||||
if (point.getMb() != 0) {
|
||||
String text = "BOLL:" + view.formatValue(point.getMb()) + " ";
|
||||
canvas.drawText(text, x, y, ma10Paint);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (status == Status.MA) {
|
||||
String text;
|
||||
if (point.getMA5Price() != 0) {
|
||||
text = "MA5:" + view.formatValue(point.getMA5Price()) + " ";
|
||||
canvas.drawText(text, x, y, ma5Paint);
|
||||
x += ma5Paint.measureText(text);
|
||||
}
|
||||
if (point.getMA10Price() != 0) {
|
||||
text = "MA10:" + view.formatValue(point.getMA10Price()) + " ";
|
||||
canvas.drawText(text, x, y, ma10Paint);
|
||||
x += ma10Paint.measureText(text);
|
||||
}
|
||||
if (point.getMA20Price() != 0) {
|
||||
text = "MA30:" + view.formatValue(point.getMA30Price());
|
||||
canvas.drawText(text, x, y, ma30Paint);
|
||||
}
|
||||
} else if (status == Status.BOLL) {
|
||||
if (point.getMb() != 0) {
|
||||
String text = "BOLL:" + view.formatValue(point.getMb()) + " ";
|
||||
canvas.drawText(text, x, y, ma10Paint);
|
||||
x += ma5Paint.measureText(text);
|
||||
text = "UB:" + view.formatValue(point.getUp()) + " ";
|
||||
canvas.drawText(text, x, y, ma5Paint);
|
||||
x += ma10Paint.measureText(text);
|
||||
text = "LB:" + view.formatValue(point.getDn());
|
||||
canvas.drawText(text, x, y, ma30Paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (view.isLongPress()) {
|
||||
drawSelector(view, canvas);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMaxValue(ICandle point) {
|
||||
if (status == Status.BOLL) {
|
||||
if (Float.isNaN(point.getUp())) {
|
||||
if (point.getMb() == 0) {
|
||||
return point.getHighPrice();
|
||||
} else {
|
||||
return point.getMb();
|
||||
}
|
||||
} else if (point.getUp() == 0) {
|
||||
return point.getHighPrice();
|
||||
} else {
|
||||
return point.getUp();
|
||||
}
|
||||
} else {
|
||||
return Math.max(point.getHighPrice(), point.getMA30Price());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMinValue(ICandle point) {
|
||||
if (status == Status.BOLL) {
|
||||
if (point.getDn() == 0) {
|
||||
return point.getLowPrice();
|
||||
} else {
|
||||
return point.getDn();
|
||||
}
|
||||
} else {
|
||||
if (point.getMA30Price() == 0f) {
|
||||
return point.getLowPrice();
|
||||
} else {
|
||||
return Math.min(point.getMA30Price(), point.getLowPrice());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IValueFormatter getValueFormatter() {
|
||||
return new ValueFormatter();
|
||||
}
|
||||
|
||||
/**
|
||||
* 画Candle
|
||||
*
|
||||
* @param canvas
|
||||
* @param x x轴坐标
|
||||
* @param high 最高价
|
||||
* @param low 最低价
|
||||
* @param open 开盘价
|
||||
* @param close 收盘价
|
||||
*/
|
||||
private void drawCandle(BaseKLineChartView view, Canvas canvas, float x, float high, float low, float open, float close) {
|
||||
high = view.getMainY(high);
|
||||
low = view.getMainY(low);
|
||||
open = view.getMainY(open);
|
||||
close = view.getMainY(close);
|
||||
float r = mCandleWidth / 2;
|
||||
float lineR = mCandleLineWidth / 2;
|
||||
if (open > close) {
|
||||
//实心
|
||||
if (mCandleSolid) {
|
||||
canvas.drawRect(x - r, close, x + r, open, mRedPaint);
|
||||
canvas.drawRect(x - lineR, high, x + lineR, low, mRedPaint);
|
||||
} else {
|
||||
mRedPaint.setStrokeWidth(mCandleLineWidth);
|
||||
canvas.drawLine(x, high, x, close, mRedPaint);
|
||||
canvas.drawLine(x, open, x, low, mRedPaint);
|
||||
canvas.drawLine(x - r + lineR, open, x - r + lineR, close, mRedPaint);
|
||||
canvas.drawLine(x + r - lineR, open, x + r - lineR, close, mRedPaint);
|
||||
mRedPaint.setStrokeWidth(mCandleLineWidth * view.getScaleX());
|
||||
canvas.drawLine(x - r, open, x + r, open, mRedPaint);
|
||||
canvas.drawLine(x - r, close, x + r, close, mRedPaint);
|
||||
}
|
||||
|
||||
} else if (open < close) {
|
||||
canvas.drawRect(x - r, open, x + r, close, mGreenPaint);
|
||||
canvas.drawRect(x - lineR, high, x + lineR, low, mGreenPaint);
|
||||
} else {
|
||||
canvas.drawRect(x - r, open, x + r, close + 1, mRedPaint);
|
||||
canvas.drawRect(x - lineR, high, x + lineR, low, mRedPaint);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* draw选择器
|
||||
*
|
||||
* @param view
|
||||
* @param canvas
|
||||
*/
|
||||
private void drawSelector(BaseKLineChartView view, Canvas canvas) {
|
||||
Paint.FontMetrics metrics = mSelectorTextPaint.getFontMetrics();
|
||||
float textHeight = metrics.descent - metrics.ascent;
|
||||
|
||||
int index = view.getSelectedIndex();
|
||||
float padding = ViewUtil.Dp2Px(mContext, 5);
|
||||
float margin = ViewUtil.Dp2Px(mContext, 5);
|
||||
float width = 0;
|
||||
float left;
|
||||
float top = margin + view.getTopPadding();
|
||||
float height = padding * 8 + textHeight * 5;
|
||||
|
||||
ICandle point = (ICandle) view.getItem(index);
|
||||
List<String> strings = new ArrayList<>();
|
||||
strings.add(view.getAdapter().getDate(index));
|
||||
strings.add("高:" + point.getHighPrice());
|
||||
strings.add("低:" + point.getLowPrice());
|
||||
strings.add("开:" + point.getOpenPrice());
|
||||
strings.add("收:" + point.getClosePrice());
|
||||
|
||||
for (String s : strings) {
|
||||
width = Math.max(width, mSelectorTextPaint.measureText(s));
|
||||
}
|
||||
width += padding * 2;
|
||||
|
||||
float x = view.translateXtoX(view.getX(index));
|
||||
if (x > view.getChartWidth() / 2) {
|
||||
left = margin;
|
||||
} else {
|
||||
left = view.getChartWidth() - width - margin;
|
||||
}
|
||||
|
||||
RectF r = new RectF(left, top, left + width, top + height);
|
||||
canvas.drawRoundRect(r, padding, padding, mSelectorBackgroundPaint);
|
||||
float y = top + padding * 2 + (textHeight - metrics.bottom - metrics.top) / 2;
|
||||
|
||||
for (String s : strings) {
|
||||
canvas.drawText(s, left + padding, y, mSelectorTextPaint);
|
||||
y += textHeight + padding;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置蜡烛宽度
|
||||
*
|
||||
* @param candleWidth
|
||||
*/
|
||||
public void setCandleWidth(float candleWidth) {
|
||||
mCandleWidth = candleWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置蜡烛线宽度
|
||||
*
|
||||
* @param candleLineWidth
|
||||
*/
|
||||
public void setCandleLineWidth(float candleLineWidth) {
|
||||
mCandleLineWidth = candleLineWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置ma5颜色
|
||||
*
|
||||
* @param color
|
||||
*/
|
||||
public void setMa5Color(int color) {
|
||||
this.ma5Paint.setColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置ma10颜色
|
||||
*
|
||||
* @param color
|
||||
*/
|
||||
public void setMa10Color(int color) {
|
||||
this.ma10Paint.setColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置ma30颜色
|
||||
*
|
||||
* @param color
|
||||
*/
|
||||
public void setMa30Color(int color) {
|
||||
this.ma30Paint.setColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置选择器文字颜色
|
||||
*
|
||||
* @param color
|
||||
*/
|
||||
public void setSelectorTextColor(int color) {
|
||||
mSelectorTextPaint.setColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置选择器文字大小
|
||||
*
|
||||
* @param textSize
|
||||
*/
|
||||
public void setSelectorTextSize(float textSize) {
|
||||
mSelectorTextPaint.setTextSize(textSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置选择器背景
|
||||
*
|
||||
* @param color
|
||||
*/
|
||||
public void setSelectorBackgroundColor(int color) {
|
||||
mSelectorBackgroundPaint.setColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置曲线宽度
|
||||
*/
|
||||
public void setLineWidth(float width) {
|
||||
ma30Paint.setStrokeWidth(width);
|
||||
ma10Paint.setStrokeWidth(width);
|
||||
ma5Paint.setStrokeWidth(width);
|
||||
mLinePaint.setStrokeWidth(width);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置文字大小
|
||||
*/
|
||||
public void setTextSize(float textSize) {
|
||||
ma30Paint.setTextSize(textSize);
|
||||
ma10Paint.setTextSize(textSize);
|
||||
ma5Paint.setTextSize(textSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 蜡烛是否实心
|
||||
*/
|
||||
public void setCandleSolid(boolean candleSolid) {
|
||||
mCandleSolid = candleSolid;
|
||||
}
|
||||
|
||||
public void setLine(boolean line) {
|
||||
if (isLine != line) {
|
||||
isLine = line;
|
||||
if (isLine) {
|
||||
kChartView.setCandleWidth(kChartView.dp2px(7f));
|
||||
} else {
|
||||
kChartView.setCandleWidth(kChartView.dp2px(6f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isLine() {
|
||||
return isLine;
|
||||
}
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
package com.github.fujianlian.klinechart.draw;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.github.fujianlian.klinechart.BaseKLineChartView;
|
||||
import com.github.fujianlian.klinechart.base.IChartDraw;
|
||||
import com.github.fujianlian.klinechart.base.IValueFormatter;
|
||||
import com.github.fujianlian.klinechart.entity.IRSI;
|
||||
import com.github.fujianlian.klinechart.formatter.ValueFormatter;
|
||||
|
||||
/**
|
||||
* RSI实现类
|
||||
* Created by tifezh on 2016/6/19.
|
||||
*/
|
||||
public class RSIDraw implements IChartDraw<IRSI> {
|
||||
|
||||
private Paint mRSI1Paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint mRSI2Paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint mRSI3Paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
|
||||
public RSIDraw(BaseKLineChartView view) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawTranslated(@Nullable IRSI lastPoint, @NonNull IRSI curPoint, float lastX, float curX, @NonNull Canvas canvas, @NonNull BaseKLineChartView view, int position) {
|
||||
if (lastPoint.getRsi() != 0) {
|
||||
view.drawChildLine(canvas, mRSI1Paint, lastX, lastPoint.getRsi(), curX, curPoint.getRsi());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawText(@NonNull Canvas canvas, @NonNull BaseKLineChartView view, int position, float x, float y) {
|
||||
IRSI point = (IRSI) view.getItem(position);
|
||||
if (point.getRsi() != 0) {
|
||||
String text = "RSI(14) ";
|
||||
canvas.drawText(text, x, y, view.getTextPaint());
|
||||
x += view.getTextPaint().measureText(text);
|
||||
text = view.formatValue(point.getRsi());
|
||||
canvas.drawText(text, x, y, mRSI1Paint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMaxValue(IRSI point) {
|
||||
return point.getRsi();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMinValue(IRSI point) {
|
||||
return point.getRsi();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IValueFormatter getValueFormatter() {
|
||||
return new ValueFormatter();
|
||||
}
|
||||
|
||||
public void setRSI1Color(int color) {
|
||||
mRSI1Paint.setColor(color);
|
||||
}
|
||||
|
||||
public void setRSI2Color(int color) {
|
||||
mRSI2Paint.setColor(color);
|
||||
}
|
||||
|
||||
public void setRSI3Color(int color) {
|
||||
mRSI3Paint.setColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置曲线宽度
|
||||
*/
|
||||
public void setLineWidth(float width) {
|
||||
mRSI1Paint.setStrokeWidth(width);
|
||||
mRSI2Paint.setStrokeWidth(width);
|
||||
mRSI3Paint.setStrokeWidth(width);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置文字大小
|
||||
*/
|
||||
public void setTextSize(float textSize) {
|
||||
mRSI2Paint.setTextSize(textSize);
|
||||
mRSI3Paint.setTextSize(textSize);
|
||||
mRSI1Paint.setTextSize(textSize);
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package com.github.fujianlian.klinechart.draw;
|
||||
|
||||
/**
|
||||
* @author fujianlian Created on 2018/8/20 11:09
|
||||
* @descripe MainDraw当前子视图
|
||||
*/
|
||||
public enum Status {
|
||||
MA, BOLL, NONE
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
package com.github.fujianlian.klinechart.draw;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
|
||||
import com.github.fujianlian.klinechart.R;
|
||||
import com.github.fujianlian.klinechart.BaseKLineChartView;
|
||||
import com.github.fujianlian.klinechart.base.IChartDraw;
|
||||
import com.github.fujianlian.klinechart.base.IValueFormatter;
|
||||
import com.github.fujianlian.klinechart.entity.IVolume;
|
||||
import com.github.fujianlian.klinechart.formatter.BigValueFormatter;
|
||||
import com.github.fujianlian.klinechart.utils.ViewUtil;
|
||||
|
||||
/**
|
||||
* Created by hjm on 2017/11/14 17:49.
|
||||
*/
|
||||
public class VolumeDraw implements IChartDraw<IVolume> {
|
||||
|
||||
private Paint mRedPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint mGreenPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint ma5Paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint ma10Paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private int pillarWidth = 0;
|
||||
|
||||
public VolumeDraw(BaseKLineChartView view) {
|
||||
Context context = view.getContext();
|
||||
mRedPaint.setColor(ContextCompat.getColor(context, R.color.chart_red));
|
||||
mGreenPaint.setColor(ContextCompat.getColor(context, R.color.chart_green));
|
||||
pillarWidth = ViewUtil.Dp2Px(context, 4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawTranslated(
|
||||
@Nullable IVolume lastPoint, @NonNull IVolume curPoint, float lastX, float curX,
|
||||
@NonNull Canvas canvas, @NonNull BaseKLineChartView view, int position) {
|
||||
|
||||
drawHistogram(canvas, curPoint, lastPoint, curX, view, position);
|
||||
if (lastPoint.getMA5Volume() != 0f) {
|
||||
view.drawVolLine(canvas, ma5Paint, lastX, lastPoint.getMA5Volume(), curX, curPoint.getMA5Volume());
|
||||
}
|
||||
if (lastPoint.getMA10Volume() != 0f) {
|
||||
view.drawVolLine(canvas, ma10Paint, lastX, lastPoint.getMA10Volume(), curX, curPoint.getMA10Volume());
|
||||
}
|
||||
}
|
||||
|
||||
private void drawHistogram(
|
||||
Canvas canvas, IVolume curPoint, IVolume lastPoint, float curX,
|
||||
BaseKLineChartView view, int position) {
|
||||
|
||||
float r = pillarWidth / 2;
|
||||
float top = view.getVolY(curPoint.getVolume());
|
||||
int bottom = view.getVolRect().bottom;
|
||||
if (curPoint.getClosePrice() >= curPoint.getOpenPrice()) {//涨
|
||||
canvas.drawRect(curX - r, top, curX + r, bottom, mRedPaint);
|
||||
} else {
|
||||
canvas.drawRect(curX - r, top, curX + r, bottom, mGreenPaint);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawText(
|
||||
@NonNull Canvas canvas, @NonNull BaseKLineChartView view, int position, float x, float y) {
|
||||
IVolume point = (IVolume) view.getItem(position);
|
||||
String text = "VOL:" + getValueFormatter().format(point.getVolume()) + " ";
|
||||
canvas.drawText(text, x, y, view.getTextPaint());
|
||||
x += view.getTextPaint().measureText(text);
|
||||
text = "MA5:" + getValueFormatter().format(point.getMA5Volume()) + " ";
|
||||
canvas.drawText(text, x, y, ma5Paint);
|
||||
x += ma5Paint.measureText(text);
|
||||
text = "MA10:" + getValueFormatter().format(point.getMA10Volume());
|
||||
canvas.drawText(text, x, y, ma10Paint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMaxValue(IVolume point) {
|
||||
return Math.max(point.getVolume(), Math.max(point.getMA5Volume(), point.getMA10Volume()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMinValue(IVolume point) {
|
||||
return Math.min(point.getVolume(), Math.min(point.getMA5Volume(), point.getMA10Volume()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IValueFormatter getValueFormatter() {
|
||||
return new BigValueFormatter();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 MA5 线的颜色
|
||||
*
|
||||
* @param color
|
||||
*/
|
||||
public void setMa5Color(int color) {
|
||||
this.ma5Paint.setColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 MA10 线的颜色
|
||||
*
|
||||
* @param color
|
||||
*/
|
||||
public void setMa10Color(int color) {
|
||||
this.ma10Paint.setColor(color);
|
||||
}
|
||||
|
||||
public void setLineWidth(float width) {
|
||||
this.ma5Paint.setStrokeWidth(width);
|
||||
this.ma10Paint.setStrokeWidth(width);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置文字大小
|
||||
*
|
||||
* @param textSize
|
||||
*/
|
||||
public void setTextSize(float textSize) {
|
||||
this.ma5Paint.setTextSize(textSize);
|
||||
this.ma10Paint.setTextSize(textSize);
|
||||
}
|
||||
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
package com.github.fujianlian.klinechart.draw;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.github.fujianlian.klinechart.BaseKLineChartView;
|
||||
import com.github.fujianlian.klinechart.base.IChartDraw;
|
||||
import com.github.fujianlian.klinechart.base.IValueFormatter;
|
||||
import com.github.fujianlian.klinechart.entity.IWR;
|
||||
import com.github.fujianlian.klinechart.formatter.ValueFormatter;
|
||||
|
||||
/**
|
||||
* KDJ实现类
|
||||
* Created by tifezh on 2016/6/19.
|
||||
*/
|
||||
public class WRDraw implements IChartDraw<IWR> {
|
||||
|
||||
private Paint mRPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
|
||||
public WRDraw(BaseKLineChartView view) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawTranslated(@Nullable IWR lastPoint, @NonNull IWR curPoint, float lastX, float curX, @NonNull Canvas canvas, @NonNull BaseKLineChartView view, int position) {
|
||||
if (lastPoint.getR() != -10) {
|
||||
view.drawChildLine(canvas, mRPaint, lastX, lastPoint.getR(), curX, curPoint.getR());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawText(@NonNull Canvas canvas, @NonNull BaseKLineChartView view, int position, float x, float y) {
|
||||
IWR point = (IWR) view.getItem(position);
|
||||
if (point.getR() != -10) {
|
||||
String text = "WR(14):";
|
||||
canvas.drawText(text, x, y, view.getTextPaint());
|
||||
x += view.getTextPaint().measureText(text);
|
||||
text = view.formatValue(point.getR()) + " ";
|
||||
canvas.drawText(text, x, y, mRPaint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMaxValue(IWR point) {
|
||||
return point.getR();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMinValue(IWR point) {
|
||||
return point.getR();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IValueFormatter getValueFormatter() {
|
||||
return new ValueFormatter();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置%R颜色
|
||||
*/
|
||||
public void setRColor(int color) {
|
||||
mRPaint.setColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置曲线宽度
|
||||
*/
|
||||
public void setLineWidth(float width) {
|
||||
mRPaint.setStrokeWidth(width);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置文字大小
|
||||
*/
|
||||
public void setTextSize(float textSize) {
|
||||
mRPaint.setTextSize(textSize);
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package com.github.fujianlian.klinechart.entity;
|
||||
|
||||
/**
|
||||
* 蜡烛图实体接口
|
||||
* Created by tifezh on 2016/6/9.
|
||||
*/
|
||||
public interface ICandle {
|
||||
|
||||
/**
|
||||
* 开盘价
|
||||
*/
|
||||
float getOpenPrice();
|
||||
|
||||
/**
|
||||
* 最高价
|
||||
*/
|
||||
float getHighPrice();
|
||||
|
||||
/**
|
||||
* 最低价
|
||||
*/
|
||||
float getLowPrice();
|
||||
|
||||
/**
|
||||
* 收盘价
|
||||
*/
|
||||
float getClosePrice();
|
||||
|
||||
|
||||
// 以下为MA数据
|
||||
/**
|
||||
* 五(月,日,时,分,5分等)均价
|
||||
*/
|
||||
float getMA5Price();
|
||||
|
||||
/**
|
||||
* 十(月,日,时,分,5分等)均价
|
||||
*/
|
||||
float getMA10Price();
|
||||
|
||||
/**
|
||||
* 二十(月,日,时,分,5分等)均价
|
||||
*/
|
||||
float getMA20Price();
|
||||
|
||||
/**
|
||||
* 三十(月,日,时,分,5分等)均价
|
||||
*/
|
||||
float getMA30Price();
|
||||
|
||||
/**
|
||||
* 六十(月,日,时,分,5分等)均价
|
||||
*/
|
||||
float getMA60Price();
|
||||
|
||||
// 以下为BOLL数据
|
||||
/**
|
||||
* 上轨线
|
||||
*/
|
||||
float getUp();
|
||||
|
||||
/**
|
||||
* 中轨线
|
||||
*/
|
||||
float getMb();
|
||||
|
||||
/**
|
||||
* 下轨线
|
||||
*/
|
||||
float getDn();
|
||||
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.github.fujianlian.klinechart.entity;
|
||||
|
||||
/**
|
||||
* @author fujianlian Created on 2018/8/20 16:08
|
||||
* @descripe KDJ指标(随机指标)接口
|
||||
* 相关说明:https://baike.baidu.com/item/KDJ%E6%8C%87%E6%A0%87/6328421?fr=aladdin&fromid=3423560&fromtitle=kdj
|
||||
*/
|
||||
public interface IKDJ {
|
||||
|
||||
/**
|
||||
* K值
|
||||
*/
|
||||
float getK();
|
||||
|
||||
/**
|
||||
* D值
|
||||
*/
|
||||
float getD();
|
||||
|
||||
/**
|
||||
* J值
|
||||
*/
|
||||
float getJ();
|
||||
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package com.github.fujianlian.klinechart.entity;
|
||||
|
||||
/**
|
||||
* KDJ指标(随机指标)接口
|
||||
* Created by tifezh on 2016/6/9.
|
||||
*/
|
||||
public interface IKLine extends ICandle, IMACD, IKDJ, IRSI, IVolume, IWR {
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.github.fujianlian.klinechart.entity;
|
||||
|
||||
/**
|
||||
* MACD指标(指数平滑移动平均线)接口
|
||||
* @see <a href="https://baike.baidu.com/item/MACD指标"/>相关说明</a>
|
||||
* Created by tifezh on 2016/6/10.
|
||||
*/
|
||||
|
||||
public interface IMACD {
|
||||
|
||||
|
||||
/**
|
||||
* DEA值
|
||||
*/
|
||||
float getDea();
|
||||
|
||||
/**
|
||||
* DIF值
|
||||
*/
|
||||
float getDif();
|
||||
|
||||
/**
|
||||
* MACD值
|
||||
*/
|
||||
float getMacd();
|
||||
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.github.fujianlian.klinechart.entity;
|
||||
|
||||
/**
|
||||
* RSI指标接口
|
||||
* @see <a href="https://baike.baidu.com/item/RSI%E6%8C%87%E6%A0%87"/>相关说明</a>
|
||||
* Created by tifezh on 2016/6/10.
|
||||
*/
|
||||
|
||||
public interface IRSI {
|
||||
|
||||
/**
|
||||
* RSI值
|
||||
*/
|
||||
float getRsi();
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.github.fujianlian.klinechart.entity;
|
||||
|
||||
/**
|
||||
* 成交量接口
|
||||
* Created by hjm on 2017/11/14 17:46.
|
||||
*/
|
||||
|
||||
public interface IVolume {
|
||||
|
||||
/**
|
||||
* 开盘价
|
||||
*/
|
||||
float getOpenPrice();
|
||||
|
||||
/**
|
||||
* 收盘价
|
||||
*/
|
||||
float getClosePrice();
|
||||
|
||||
/**
|
||||
* 成交量
|
||||
*/
|
||||
float getVolume();
|
||||
|
||||
/**
|
||||
* 五(月,日,时,分,5分等)均量
|
||||
*/
|
||||
float getMA5Volume();
|
||||
|
||||
/**
|
||||
* 十(月,日,时,分,5分等)均量
|
||||
*/
|
||||
float getMA10Volume();
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.github.fujianlian.klinechart.entity;
|
||||
|
||||
/**
|
||||
* @author fujianlian Created on 2018/8/20 15:16
|
||||
* @descripe WR指标(随机指标)接口
|
||||
*/
|
||||
public interface IWR {
|
||||
|
||||
/**
|
||||
* %R值
|
||||
*/
|
||||
float getR();
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.github.fujianlian.klinechart.formatter;
|
||||
|
||||
import com.github.fujianlian.klinechart.base.IValueFormatter;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* 对较大数据进行格式化
|
||||
* Created by tifezh on 2017/12/13.
|
||||
*/
|
||||
|
||||
public class BigValueFormatter implements IValueFormatter{
|
||||
|
||||
//必须是排好序的
|
||||
private int[] values={10000,1000000,100000000};
|
||||
private String[] units={"万","百万","亿"};
|
||||
|
||||
@Override
|
||||
public String format(float value) {
|
||||
String unit="";
|
||||
int i=values.length-1;
|
||||
while (i>=0)
|
||||
{
|
||||
if(value>values[i]) {
|
||||
value /= values[i];
|
||||
unit = units[i];
|
||||
break;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
return String.format(Locale.getDefault(),"%.2f", value)+unit;
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.github.fujianlian.klinechart.formatter;
|
||||
|
||||
import com.github.fujianlian.klinechart.base.IDateTimeFormatter;
|
||||
import com.github.fujianlian.klinechart.utils.DateUtil;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 时间格式化器
|
||||
* Created by tifezh on 2016/6/21.
|
||||
*/
|
||||
|
||||
public class DateFormatter implements IDateTimeFormatter {
|
||||
@Override
|
||||
public String format(Date date) {
|
||||
if (date != null) {
|
||||
return DateUtil.DateFormat.format(date);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.github.fujianlian.klinechart.formatter;
|
||||
|
||||
import com.github.fujianlian.klinechart.base.IDateTimeFormatter;
|
||||
import com.github.fujianlian.klinechart.utils.DateUtil;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 时间格式化器
|
||||
* Created by tifezh on 2016/6/21.
|
||||
*/
|
||||
|
||||
public class TimeFormatter implements IDateTimeFormatter {
|
||||
@Override
|
||||
public String format(Date date) {
|
||||
if (date == null) {
|
||||
return "";
|
||||
}
|
||||
return DateUtil.shortTimeFormat.format(date);
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.github.fujianlian.klinechart.formatter;
|
||||
|
||||
import com.github.fujianlian.klinechart.base.IValueFormatter;
|
||||
|
||||
/**
|
||||
* Value格式化类
|
||||
* Created by tifezh on 2016/6/21.
|
||||
*/
|
||||
|
||||
public class ValueFormatter implements IValueFormatter {
|
||||
@Override
|
||||
public String format(float value) {
|
||||
return String.format("%.2f", value);
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.github.fujianlian.klinechart.utils;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
/**
|
||||
* 时间工具类
|
||||
* Created by tifezh on 2016/4/27.
|
||||
*/
|
||||
public class DateUtil {
|
||||
public static SimpleDateFormat longTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
|
||||
public static SimpleDateFormat shortTimeFormat = new SimpleDateFormat("HH:mm");
|
||||
public static SimpleDateFormat DateFormat = new SimpleDateFormat("yyyy/MM/dd");
|
||||
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.github.fujianlian.klinechart.utils;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* Created by tian on 2016/4/11.
|
||||
*/
|
||||
public class ViewUtil {
|
||||
static public int Dp2Px(Context context, float dp) {
|
||||
final float scale = context.getResources().getDisplayMetrics().density;
|
||||
return (int) (dp * scale + 0.5f);
|
||||
}
|
||||
|
||||
static public int Px2Dp(Context context, float px) {
|
||||
final float scale = context.getResources().getDisplayMetrics().density;
|
||||
return (int) (px / scale + 0.5f);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<declare-styleable name="KLineChartView">
|
||||
<!--公共的-->
|
||||
<attr name="kc_text_size" format="dimension"/>
|
||||
<attr name="kc_text_color" format="color"/>
|
||||
<attr name="kc_line_width" format="dimension"/>
|
||||
<attr name="kc_background_color" format="color"/>
|
||||
<attr name="kc_selected_line_color" format="color"/>
|
||||
<attr name="kc_selected_line_width" format="dimension"/>
|
||||
<attr name="kc_grid_line_width" format="dimension"/>
|
||||
<attr name="kc_grid_line_color" format="color"/>
|
||||
<attr name="kc_point_width" format="dimension"/>
|
||||
<!--macd-->
|
||||
<attr name="kc_macd_width" format="dimension"/>
|
||||
<attr name="kc_dif_color" format="color"/>
|
||||
<attr name="kc_dea_color" format="color"/>
|
||||
<attr name="kc_macd_color" format="color"/>
|
||||
<!--kdj-->
|
||||
<attr name="kc_k_color" format="color"/>
|
||||
<attr name="kc_d_color" format="color"/>
|
||||
<attr name="kc_j_color" format="color"/>
|
||||
<!--rsi-->
|
||||
<attr name="kc_rsi1_color" format="color"/>
|
||||
<attr name="kc_rsi2_color" format="color"/>
|
||||
<attr name="kc_ris3_color" format="color"/>
|
||||
<!--boll-->
|
||||
<attr name="kc_up_color" format="color"/>
|
||||
<attr name="kc_mb_color" format="color"/>
|
||||
<attr name="kc_dn_color" format="color"/>
|
||||
<!--main-->
|
||||
<attr name="kc_ma5_color" format="color"/>
|
||||
<attr name="kc_ma10_color" format="color"/>
|
||||
<attr name="kc_ma20_color" format="color"/>
|
||||
<attr name="kc_candle_width" format="dimension"/>
|
||||
<attr name="kc_candle_line_width" format="dimension"/>
|
||||
<attr name="kc_selector_background_color" format="color"/>
|
||||
<attr name="kc_selector_text_size" format="dimension"/>
|
||||
<attr name="kc_candle_solid" format="boolean"/>
|
||||
<!--tab-->
|
||||
<attr name="kc_tab_background_color" format="color"/>
|
||||
<attr name="kc_tab_text_color" format="color"/>
|
||||
<attr name="kc_tab_indicator_color" format="color"/>
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#3F51B5</color>
|
||||
<color name="colorPrimaryDark">#303F9F</color>
|
||||
<color name="colorAccent">#FF4081</color>
|
||||
|
||||
<color name="chart_red">#26BF66</color>
|
||||
<color name="chart_green">#FD6433</color>
|
||||
<color name="chart_line">#C9933E</color>
|
||||
<color name="chart_line_background">#1aC9933E</color>
|
||||
|
||||
<color name="chart_ma5">#DA8AE5</color>
|
||||
<color name="chart_ma10">#39B0E8</color>
|
||||
<color name="chart_ma30">#FFC76D</color>
|
||||
<color name="chart_white">#ffffff</color>
|
||||
|
||||
<color name="chart_background">#202326</color>
|
||||
<color name="chart_bac">#00FFFFFF</color>
|
||||
<color name="chart_point_bac">#202326</color>
|
||||
<color name="chart_grid_line">#1AFFFFFF</color>
|
||||
<color name="chart_text">#818596</color>
|
||||
<color name="chart_selector">#202326</color>
|
||||
<color name="chart_tab_background">#30343C</color>
|
||||
<color name="chart_tab_indicator">#FF6601</color>
|
||||
</resources>
|
||||
@@ -0,0 +1,13 @@
|
||||
<resources>
|
||||
<dimen name="chart_text_size">10sp</dimen>
|
||||
<dimen name="chart_selector_text_size">12sp</dimen>
|
||||
<dimen name="chart_candle_line_width">1dp</dimen>
|
||||
<dimen name="chart_candle_width">6dp</dimen>
|
||||
<dimen name="chart_line_width">1dp</dimen>
|
||||
<dimen name="chart_grid_line_width">0.8dp</dimen>
|
||||
<dimen name="chart_0.5dp">0.5dp</dimen>
|
||||
<dimen name="chart_point_width">7dp</dimen>
|
||||
<dimen name="chart_top_padding">15dp</dimen>
|
||||
<dimen name="chart_bottom_padding">15dp</dimen>
|
||||
<dimen name="child_top_padding">10dp</dimen>
|
||||
</resources>
|
||||
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">KLineChartLib</string>
|
||||
</resources>
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.github.fujianlian.klinechart;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user