Andorid自定义View实现K线图 代码示例
时间: 2023-11-28 16:48:56 浏览: 92
以下是一个简单的自定义View实现K线图的代码示例:
```
public class KLineView extends View {
private List<KLineData> mData; // K线数据
private int mWidth, mHeight; // 控件宽度、高度
private int mTopPadding; // 顶部留白
private int mBottomPadding; // 底部留白
private Paint mLinePaint; // K线画笔
private Paint mTextPaint; // 文本画笔
private float mMaxPrice, mMinPrice; // 最高价、最低价
private float mPriceScale; // 价格缩放比例
private float mVolumeScale; // 成交量缩放比例
private int mCandleWidth; // K线宽度
private int mCandleSpace; // K线间隔
public KLineView(Context context) {
this(context, null);
}
public KLineView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public KLineView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 初始化画笔
mLinePaint = new Paint();
mLinePaint.setStrokeWidth(2f);
mLinePaint.setAntiAlias(true);
mLinePaint.setStyle(Paint.Style.STROKE);
mTextPaint = new Paint();
mTextPaint.setTextSize(24f);
mTextPaint.setAntiAlias(true);
mTextPaint.setColor(Color.BLACK);
// 初始化K线宽度、间隔
mCandleWidth = dp2px(8);
mCandleSpace = dp2px(4);
// 初始化留白
mTopPadding = dp2px(20);
mBottomPadding = dp2px(20);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 获取控件宽度、高度
mWidth = MeasureSpec.getSize(widthMeasureSpec);
mHeight = MeasureSpec.getSize(heightMeasureSpec);
// 计算价格、成交量缩放比例
mPriceScale = (mHeight - mTopPadding - mBottomPadding) / (mMaxPrice - mMinPrice);
mVolumeScale = (mHeight - mTopPadding - mBottomPadding) / getMaxVolume();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 绘制K线图
drawCandles(canvas);
// 绘制边框
drawBorder(canvas);
// 绘制Y轴标签
drawYLabels(canvas);
}
/**
* 绘制K线图
*/
private void drawCandles(Canvas canvas) {
if (mData == null || mData.size() == 0) {
return;
}
mLinePaint.setColor(Color.RED);
mLinePaint.setStyle(Paint.Style.FILL);
float startX = mCandleWidth / 2 + mCandleSpace; // 第一个K线起始X坐标
float startY = 0f; // K线起始Y坐标
float endX, endY; // K线结束X坐标、Y坐标
for (int i = 0; i < mData.size(); i++) {
KLineData data = mData.get(i);
// 计算K线顶部、底部Y坐标
float highY = mTopPadding + (mMaxPrice - data.getHigh()) * mPriceScale;
float lowY = mTopPadding + (mMaxPrice - data.getLow()) * mPriceScale;
// 计算K线开盘、收盘Y坐标
float openY = mTopPadding + (mMaxPrice - data.getOpen()) * mPriceScale;
float closeY = mTopPadding + (mMaxPrice - data.getClose()) * mPriceScale;
// 绘制K线实体
if (data.getOpen() < data.getClose()) {
mLinePaint.setColor(Color.RED);
} else {
mLinePaint.setColor(Color.GREEN);
}
canvas.drawRect(startX - mCandleWidth / 2, closeY, startX + mCandleWidth / 2, openY, mLinePaint);
// 绘制K线上下影线
mLinePaint.setColor(Color.BLACK);
canvas.drawLine(startX, highY, startX, openY, mLinePaint);
canvas.drawLine(startX, lowY, startX, closeY, mLinePaint);
// 更新起始X坐标
startX += mCandleWidth + mCandleSpace;
}
}
/**
* 绘制边框
*/
private void drawBorder(Canvas canvas) {
mLinePaint.setColor(Color.BLACK);
mLinePaint.setStyle(Paint.Style.STROKE);
canvas.drawRect(0, 0, mWidth, mHeight, mLinePaint);
}
/**
* 绘制Y轴标签
*/
private void drawYLabels(Canvas canvas) {
float labelHeight = mTextPaint.descent() - mTextPaint.ascent();
// 绘制价格标签
float priceLabelY = mTopPadding - mTextPaint.ascent();
for (float price = mMinPrice; price <= mMaxPrice; price += (mMaxPrice - mMinPrice) / 5) {
float priceY = mTopPadding + (mMaxPrice - price) * mPriceScale;
canvas.drawText(String.format(Locale.getDefault(), "%.2f", price), 0, priceY + labelHeight / 2, mTextPaint);
canvas.drawLine(mCandleWidth / 2, priceY, mWidth, priceY, mLinePaint);
}
// 绘制成交量标签
float volumeLabelY = mHeight - mBottomPadding - mTextPaint.descent();
float maxVolume = getMaxVolume();
for (int i = 0; i < 5; i++) {
float volumeY = volumeLabelY - i * labelHeight * maxVolume / 5;
canvas.drawText(String.format(Locale.getDefault(), "%.0f", maxVolume * i / 5), 0, volumeY - labelHeight / 2, mTextPaint);
}
}
/**
* 设置K线数据
*/
public void setData(List<KLineData> data) {
mData = data;
calculateMaxAndMinPrice();
requestLayout();
invalidate();
}
/**
* 计算最高价、最低价
*/
private void calculateMaxAndMinPrice() {
if (mData == null || mData.size() == 0) {
return;
}
mMaxPrice = mData.get(0).getHigh();
mMinPrice = mData.get(0).getLow();
for (int i = 1; i < mData.size(); i++) {
KLineData data = mData.get(i);
mMaxPrice = Math.max(mMaxPrice, data.getHigh());
mMinPrice = Math.min(mMinPrice, data.getLow());
}
}
/**
* 获取最大成交量
*/
private float getMaxVolume() {
float maxVolume = 0f;
if (mData != null && mData.size() > 0) {
for (KLineData data : mData) {
maxVolume = Math.max(maxVolume, data.getVolume());
}
}
return maxVolume;
}
/**
* dp转px
*/
private int dp2px(int dp) {
return (int) (dp * getContext().getResources().getDisplayMetrics().density + 0.5f);
}
}
```
其中,KLineData表示K线数据,包括开盘价、收盘价、最高价、最低价、成交量等属性。可以根据实际需求进行修改。
阅读全文