This commit is contained in:
coco
2026-07-03 15:56:07 +08:00
commit caef23209c
5767 changed files with 1004268 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
/build
+32
View File
@@ -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
View File
@@ -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
@@ -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" />
@@ -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);
}
}
@@ -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 {
// EMA12 = 前一日EMA12 X 11/13 + 今日收盘价 X 2/13
ema12 = ema12 * 11f / 13f + closePrice * 2f / 13f;
// EMA26 = 前一日EMA26 X 25/27 + 今日收盘价 X 2/27
ema26 = ema26 * 25f / 27f + closePrice * 2f / 27f;
}
// DIF = EMA12 - EMA26
// 今日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;
}
}
}
}
@@ -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();
}
}
@@ -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);
}
}
}
@@ -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;
}
@@ -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;
}
}
@@ -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();
}
@@ -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();
}
@@ -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);
}
@@ -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);
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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;
}
}
@@ -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);
}
}
@@ -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
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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();
}
@@ -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();
}
@@ -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 {
}
@@ -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();
}
@@ -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();
}
@@ -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();
}
@@ -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();
}
@@ -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;
}
}
@@ -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 "";
}
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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");
}
@@ -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>
@@ -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);
}
}