自定义控件篇:
自定义折线图

前言:自定义控件永远都是客户端开发的一个必须攻破的难题
首先得了解需要实现的样式,确定有没有可继承的控件类,若没有就直接继承View。
View也有自己的生命周期,先了解下我们常用的几个自定义View方法:
构造方法 - onMeasure - onLayout - onDraw - onTouchEvent - onAnimationStart
在构造方法里进行画图工具和数据的初始化
srceenWidth = Tool.getWidth(context);
srceenHeight = Tool.getHeight(context);
paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true); //去锯齿
paint.setStrokeWidth(2);
paint.setTextSize(context.getResources().getDimensionPixelSize(R.dimen.font_super_smallest));
paint.setColor(context.getResources().getColor(R.color._7C7F99));
String text = "08-06";
Rect rect = new Rect();
paint.getTextBounds(text,0,text.length(), rect);
textheight = rect.height();
textWidth = rect.width();
int srceenHeightpf = srceenHeight/100;
YPoint = Tool.dpToPx(10);
YLength = srceenHeightpf*PriceShjListKinView.Ypinf -YPoint;//K线高度缩小给上下留白
YPoint = YPoint -(YPoint/2);//上下各一半
YScale = YLength/YScalenum;//Y轴均分
在onMeasure方法里对View的高度和宽度做屏幕适配
setMeasuredDimension(srceenWidth, Tool.getHeight(context)/3);
在onLayout中可以获取到View中的子View进行高宽的动态变更
在onDraw中进行绘图:重点
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.setBackgroundColor(getResources().getColor(R.color.trade_tab));
//添加X轴刻度和文字
drawYklin(canvas);
//添加X轴刻度和文字
drawXklin(canvas);
/*早盘价折线*/
painm = new Paint();
painm.setStyle(Paint.Style.FILL);
painm.setAntiAlias(true); //去锯齿
painm.setStrokeWidth(2);
painm.setTextSize(context.getResources().getDimensionPixelSize(R.dimen.font_super_smallest));
painm.setColor(context.getResources().getColor(R.color._DE9724));
if(coordinatecoyp==null){
coordinatecoyp = new ArrayList<>();
}else {
coordinatecoyp.clear();
}
int YMax = YLength - (YScalenum-1) * YScale;
float KinMax = YLength - (YLength-YScale) * Tool.getSHJcalPrice(upPrice,downPrice,upPrice-downPrice);
float C = KinMax - YMax;
if(Mpricelist!=null){
for(int i=0; i<Mpricelist.size(); i++){
if(i!=Mpricelist.size()-1){
float y = YLength - (YLength-YScale+C) * Tool.getSHJcalPrice(Mpricelist.get(i).getYlin(),downPrice,upPrice-downPrice);
float y1 = YLength - (YLength-YScale+C) * Tool.getSHJcalPrice(Mpricelist.get(i+1).getYlin(),downPrice,upPrice-downPrice);
canvas.drawLine( i * XScale + textWidth/2 + addXwidth,y- YScale/2- textheight/2,
(i+1) * XScale+ textWidth/2 + addXwidth,y1- YScale/2- textheight/2, painm);
}
for(SHjKinBean sHjKinBean: coordinate){
if(sHjKinBean.getXlin().equals(Mpricelist.get(i).getXlin())&&sHjKinBean.getCoordinateX()==COORDINATEM){
SHjKinBean sHjKinBean1 = new SHjKinBean();
sHjKinBean1.setCoordinateY(YLength - (YLength-XScale) * Tool.getSHJcalPrice(Mpricelist.get(i).getYlin(),downPrice,upPrice-downPrice));
sHjKinBean1.setCoordinateX( i * XScale+ textWidth/2 + addXwidth);
sHjKinBean1.setXlin(Mpricelist.get(i).getXlin());
coordinatecoyp.add(sHjKinBean1);
}
}
}
}
/*午盘价折线*/
paina = new Paint();
paina.setStyle(Paint.Style.FILL);
paina.setAntiAlias(true); //去锯齿
paina.setStrokeWidth(2);
paina.setTextSize(context.getResources().getDimensionPixelSize(R.dimen.font_super_smallest));
paina.setColor(context.getResources().getColor(R.color._10A8F6));
if(Apricelist!=null){
for(int i=0; i<Apricelist.size(); i++){
if(i!=Apricelist.size()-1){
float y = YLength - (YLength-YScale+C) * Tool.getSHJcalPrice(Apricelist.get(i).getYlin(),downPrice,upPrice-downPrice);
float y1 = YLength - (YLength-YScale+C) * Tool.getSHJcalPrice(Apricelist.get(i+1).getYlin(),downPrice,upPrice-downPrice);
canvas.drawLine( i * XScale + textWidth/2 + addXwidth,y- YScale/2- textheight/2,
(i+1) * XScale + textWidth/2 + addXwidth,y1- YScale/2- textheight/2, paina);
}
for(SHjKinBean sHjKinBean: coordinate){
if(sHjKinBean.getXlin().equals(Apricelist.get(i).getXlin())&&sHjKinBean.getCoordinateX()==COORDINATEA){
SHjKinBean sHjKinBean1 = new SHjKinBean();
sHjKinBean1.setCoordinateY(YLength - (YLength-XScale) * Tool.getSHJcalPrice(Apricelist.get(i).getYlin(),downPrice,upPrice-downPrice));
sHjKinBean1.setCoordinateX( i * XScale+ textWidth/2 + addXwidth);
sHjKinBean1.setXlin(Apricelist.get(i).getXlin());
coordinatecoyp.add(sHjKinBean1);
}
}
}
}
//画点击弹出的详情
if (needPop&&coordinatecoyp.size()>0){
drawPopView(popX,popY,canvas);
}
}
如果数据变更,我们提供一个供数据返回后页面调用的方法进行View的数据变化
public void PirceSetShjKinData(List<SHJBean> shjlist){
this.shjlist = shjlist;
UpteInvaldata();
invalidate();
}
public void UpteInvaldata(){
upPrice = 0;
downPrice = 0;
boolean isfrist= true;
Mpricelist = new ArrayList<>();
Apricelist = new ArrayList<>();
coordinate = new ArrayList<>();//保存同一天价格高的xy轴坐标做
String coordinatedata = "";
for(SHJBean shjBeans:shjlist){
try {
float coordinatepriceM = -9999 , coordinatepriceA = -9999 ;
float coordinateis = COORDINATEM;//默认早盘
String price = shjBeans.getMprice()!=null?shjBeans.getMprice():shjBeans.getAprice();
if(isfrist){//最低值需要拿第一个值
downPrice = Tool.getSHJDouble2(Double.valueOf(price));
isfrist = false;
}
coordinatedata = shjBeans.getData();
Mpricelist.add(new SHjKinBean(Tool.getSHJDouble2(Double.valueOf(shjBeans.getMprice())),shjBeans.getData()));
Apricelist.add(new SHjKinBean(Tool.getSHJDouble2(Double.valueOf(shjBeans.getAprice())),shjBeans.getData()));
upPrice = upPrice>Tool.getSHJDouble2(Double.valueOf(price))?
upPrice:Tool.getSHJDouble2(Double.valueOf(price));//取出最高值
downPrice = downPrice < Tool.getSHJDouble2(Double.valueOf(price))?
downPrice:Tool.getSHJDouble2(Double.valueOf(price));//取出最低值
if(shjBeans.getMprice()!=null){
coordinatepriceM = Tool.getSHJDouble2(Double.valueOf(price));
}else {
coordinatepriceA = Tool.getSHJDouble2(Double.valueOf(price));
}
/*拿出同一天最高价格是午盘还是早盘*/
coordinateis = coordinatepriceM>coordinatepriceA?COORDINATEM:COORDINATEA;
SHjKinBean KinBean = new SHjKinBean();
KinBean.setCoordinateX(coordinateis);
KinBean.setXlin(coordinatedata);
coordinate.add(KinBean);
}catch (Exception e){
e.printStackTrace();
}
}
XLength = srceenWidth-Tool.dpToPx(45);
XScale = (XLength-(int) textWidth/2)/shjlist.size();
if(shjlist.size()<5){
addXwidth = XScale/2;
}else {
addXwidth = 0;
}
YLabel = new String[YScalenum];
float Ypricepf = Tool.getSHJcalPrice(upPrice,downPrice,YScalenum-1);//均分-1
for(int i=0;i<YScalenum;i++){
float Ypriceft = Tool.getSHJDouble2(Ypricepf*i)+downPrice;
DecimalFormat decimalFormat = new DecimalFormat("0.00");
YLabel[i] = decimalFormat.format(Ypriceft);
}
XLabel = new String[shjlist.size()];
for(int i=0;i<XLabel.length;i++){
XLabel[i] = shjlist.get(i).getData();
}
}
更新绘制需要调用invalidate();如果没有在UI线程里进行,则需要postInvalidate();
定义一个变量通知布局点击显示区域
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(MOVENUM==0){
downX = event.getX();
}
MOVENUM++;
break;
case MotionEvent.ACTION_MOVE:
if(needPop){
isMOVE = true;
popX = event.getX();
popY = event.getY();
invalidate();
}
break;
case MotionEvent.ACTION_UP:
if(!needPop&&!isMOVE){
needPop = !needPop;
}else {
float X = downX>event.getX()?downX-event.getX():event.getX()-downX;
if(X<=Tool.dpToPx(15)&&MOVENUM>1){
MOVENUM=0;
needPop = !needPop;
isMOVE = false;
}
}
popX = event.getX();
popY = event.getY();
invalidate();
downX = event.getX();
break;
}
return true;
}
同样,点击后需要通知View调用invalidate进行布局更新
点击后的手指区域处理代码:
float coorx;//最小的点击差比
int popWith = 0;
private void drawPopView(float x,float y,Canvas canvas){
int position=0;//最小的x轴
popWith = Tool.dpToPx(15);
for(int i=0;i<coordinatecoyp.size();i++){
if(i==0){
coorx = coordinatecoyp.get(i).getCoordinateX()>x?coordinatecoyp.get(i).getCoordinateX()-x:x-coordinatecoyp.get(i).getCoordinateX();
}
float coorxcopy = coordinatecoyp.get(i).getCoordinateX()>x?coordinatecoyp.get(i).getCoordinateX()-x:x-coordinatecoyp.get(i).getCoordinateX();
if(coorx>coorxcopy){
position = i;
coorx = coorxcopy;
}
}
x = coordinatecoyp.get(position).getCoordinateX();
Paint paintzb = new Paint();//竖线
paintzb.setStyle(Paint.Style.FILL);
paintzb.setAntiAlias(true); //去锯齿
paintzb.setStrokeWidth(1);
paintzb.setTextSize(context.getResources().getDimensionPixelSize(R.dimen.font_super_smallest));
paintzb.setColor(context.getResources().getColor(R.color.text_usually));
float newx;
if(x>XLength){
newx = XLength;
}else {
newx = x;
}
canvas.drawLine(newx, YLength - YScale/2- textheight/2, newx, YLength - Ypoplin * YScale- YScale/2- textheight/2, paintzb);
// y = coordinatecoyp.get(position).getCoordinateY();
Paint painapop = new Paint();
painapop.setStyle(Paint.Style.STROKE);
painapop.setAntiAlias(true); //去锯齿
painapop.setStrokeWidth(2);
painapop.setColor(context.getResources().getColor(R.color.text_usually));
Path path= new Path();
if(y-popWith*4 <10+ YPoint){
/*超出上边框*/
y = (10+YPoint) - (y-popWith*4) +y;
}else if(y>YLength-YScale/2- textheight/2){
/*超出下边框*/
float yend = y - YLength + textheight/2 + YScale/2;
y = y - yend;
}
String text = "交易日 :0101交易时间";
float width = paint.measureText(text);//文本的宽度
if(x+width>XLength){
/*超出右边框*/
path.moveTo(x-popWith,y-popWith*4);
path.lineTo(x-popWith,y);
path.lineTo(x-width,y);
path.lineTo(x-width,y-popWith*4);
path.lineTo(x-popWith,y-popWith*4);
}else {
path.moveTo(x+popWith,y-popWith*4);
path.lineTo(x+popWith,y);
path.lineTo(x+width,y);
path.lineTo(x+width,y-popWith*4);
path.lineTo(x+popWith,y-popWith*4);
}
canvas.drawPath(path, painapop);
painapop.setStyle(Paint.Style.FILL);
painapop.setColor(context.getResources().getColor(R.color.trade_tab));
canvas.drawPath(path, painapop);
String data="- -",pricem="- -",pricea="- -";
for(int i=0;i<Mpricelist.size();i++){
if(Mpricelist.get(i).getXlin().equals(coordinatecoyp.get(position).getXlin())){
data = Mpricelist.get(i).getXlin();
pricem = ""+Mpricelist.get(i).getYlin();
}
}
for(int i=0;i<Apricelist.size();i++){
if(Apricelist.get(i).getXlin().equals(coordinatecoyp.get(position).getXlin())){
data = Apricelist.get(i).getXlin();
pricea = ""+Apricelist.get(i).getYlin();
}
}
int popHeight = (popWith*4)/8;
if(x+width>XLength){
/*超出右边框*/
canvas.drawText("交易日:"+TimeDateUtil.changeDateFormat("yyyyMMdd", "MM-dd",data),x-width+Tool.dpToPx(10),y-popWith*4+popHeight*2+Tool.dpToPx(5),paint);
canvas.drawText("早盘价:"+ Utils.pricesFormatFloat(pricem),x-width+Tool.dpToPx(10),y-popWith*4+popHeight*4+Tool.dpToPx(5),painm);
canvas.drawText("午盘价:"+Utils.pricesFormatFloat(pricea),x-width+Tool.dpToPx(10),y-popWith*4+popHeight*6+Tool.dpToPx(5),paina);
}else {
canvas.drawText("交易日:"+TimeDateUtil.changeDateFormat("yyyyMMdd", "MM-dd",data),x+popWith+Tool.dpToPx(10),y-popWith*4+popHeight*2+Tool.dpToPx(5),paint);
canvas.drawText("早盘价:"+Utils.pricesFormatFloat(pricem),x+popWith+Tool.dpToPx(10),y-popWith*4+popHeight*4+Tool.dpToPx(5),painm);
canvas.drawText("午盘价:"+Utils.pricesFormatFloat(pricea),x+popWith+Tool.dpToPx(10),y-popWith*4+popHeight*6+Tool.dpToPx(5),paina);
}
}
整篇代码在下面贴出来
package com.sh.android.EGold.activity.price;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import com.sh.android.EGold.activity.R;
import com.sh.android.EGold.activity.main.SHJBean;
import com.sh.android.EGold.lib.kline.Tool;
import com.sh.android.EGold.util.TimeDateUtil;
import com.sh.android.EGold.util.Utils;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
/**
* Created by wzheng on 2017/8/30.
*/
public class ShjKinView extends View{
private int srceenWidth;
private int srceenHeight;
private Context context;
private int YPoint = 0;//上下边距26 上下边留白写定价值与日期
private int XScale = 0; // X刻度长度
private int YScale = 0; // Y刻度长度
private int XLength = 0;//X的总长度
private int YLength = 0;//Y的总长度
private int YScalenum = 7;
private String[] YLabel , XLabel;
private List<SHJBean> shjlist;
private List<SHjKinBean> Mpricelist ;
private List<SHjKinBean> Apricelist ;
private float downPrice,upPrice;
private List<SHjKinBean> coordinate;
private List<SHjKinBean> coordinatecoyp;
//这样写的好处是coordinate的顺序不用控制,只需要对应xy轴里的coordinateX存储是否早>午判断存储y轴,用Xlin保存时间
//因为早午盘x轴一样,先使用SHjKinBean
private float COORDINATEM = -1 ,COORDINATEA = -2;
private boolean needPop = false;
private float popX,popY;//弹框
private boolean isMOVE = false;
private int MOVENUM = 0;
private RecyclerView listView;
private Paint painm , paina , paint;//红,蓝色,灰色
private float textheight;
private float textWidth;
private float addXwidth = 0;
private int Ypoplin = 0;
public ShjKinView(Context context) {
this(context, null);
}
public ShjKinView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context=context;
init();
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(srceenWidth, Tool.getHeight(context)/3);
}
private void init(){
srceenWidth = Tool.getWidth(context);
srceenHeight = Tool.getHeight(context);
// initTypeText();
paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true); //去锯齿
paint.setStrokeWidth(2);
paint.setTextSize(context.getResources().getDimensionPixelSize(R.dimen.font_super_smallest));
paint.setColor(context.getResources().getColor(R.color._7C7F99));
String text = "08-06";
Rect rect = new Rect();
paint.getTextBounds(text,0,text.length(), rect);
textheight = rect.height();
textWidth = rect.width();
int srceenHeightpf = srceenHeight/100;
YPoint = Tool.dpToPx(10);
YLength = srceenHeightpf*PriceShjListKinView.Ypinf -YPoint;//K线高度缩小给上下留白
YPoint = YPoint -(YPoint/2);//上下各一半
YScale = YLength/YScalenum;//Y轴均分
}
public void PirceSetShjKinData(List<SHJBean> shjlist){
this.shjlist = shjlist;
UpteInvaldata();
invalidate();
postInvalidate();
}
public void UpteInvaldata(){
upPrice = 0;
downPrice = 0;
boolean isfrist= true;
Mpricelist = new ArrayList<>();
Apricelist = new ArrayList<>();
coordinate = new ArrayList<>();//保存同一天价格高的xy轴坐标做
String coordinatedata = "";
for(SHJBean shjBeans:shjlist){
try {
float coordinatepriceM = -9999 , coordinatepriceA = -9999 ;
float coordinateis = COORDINATEM;//默认早盘
String price = shjBeans.getMprice()!=null?shjBeans.getMprice():shjBeans.getAprice();
if(isfrist){//最低值需要拿第一个值
downPrice = Tool.getSHJDouble2(Double.valueOf(price));
isfrist = false;
}
coordinatedata = shjBeans.getData();
Mpricelist.add(new SHjKinBean(Tool.getSHJDouble2(Double.valueOf(shjBeans.getMprice())),shjBeans.getData()));
Apricelist.add(new SHjKinBean(Tool.getSHJDouble2(Double.valueOf(shjBeans.getAprice())),shjBeans.getData()));
upPrice = upPrice>Tool.getSHJDouble2(Double.valueOf(price))?
upPrice:Tool.getSHJDouble2(Double.valueOf(price));//取出最高值
downPrice = downPrice < Tool.getSHJDouble2(Double.valueOf(price))?
downPrice:Tool.getSHJDouble2(Double.valueOf(price));//取出最低值
if(shjBeans.getMprice()!=null){
coordinatepriceM = Tool.getSHJDouble2(Double.valueOf(price));
}else {
coordinatepriceA = Tool.getSHJDouble2(Double.valueOf(price));
}
/*拿出同一天最高价格是午盘还是早盘*/
coordinateis = coordinatepriceM>coordinatepriceA?COORDINATEM:COORDINATEA;
SHjKinBean KinBean = new SHjKinBean();
KinBean.setCoordinateX(coordinateis);
KinBean.setXlin(coordinatedata);
coordinate.add(KinBean);
}catch (Exception e){
e.printStackTrace();
}
}
XLength = srceenWidth-Tool.dpToPx(45);
XScale = (XLength-(int) textWidth/2)/shjlist.size();
if(shjlist.size()<5){
addXwidth = XScale/2;
}else {
addXwidth = 0;
}
YLabel = new String[YScalenum];
float Ypricepf = Tool.getSHJcalPrice(upPrice,downPrice,YScalenum-1);//均分-1
for(int i=0;i<YScalenum;i++){
float Ypriceft = Tool.getSHJDouble2(Ypricepf*i)+downPrice;
DecimalFormat decimalFormat = new DecimalFormat("0.00");
YLabel[i] = decimalFormat.format(Ypriceft);
}
XLabel = new String[shjlist.size()];
for(int i=0;i<XLabel.length;i++){
XLabel[i] = shjlist.get(i).getData();
}
}
float downX = 0;
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
listView.requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
listView.requestDisallowInterceptTouchEvent(false);
break;
}
return super.dispatchTouchEvent(event);
}
@Override
protected void onAnimationStart() {
super.onAnimationStart();
}
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(MOVENUM==0){
downX = event.getX();
}
MOVENUM++;
break;
case MotionEvent.ACTION_MOVE:
if(needPop){
isMOVE = true;
popX = event.getX();
popY = event.getY();
invalidate();
}
break;
case MotionEvent.ACTION_UP:
if(!needPop&&!isMOVE){
needPop = !needPop;
}else {
float X = downX>event.getX()?downX-event.getX():event.getX()-downX;
if(X<=Tool.dpToPx(15)&&MOVENUM>1){
MOVENUM=0;
needPop = !needPop;
isMOVE = false;
}
}
popX = event.getX();
popY = event.getY();
invalidate();
downX = event.getX();
break;
}
return true;
}
public void setlistview(RecyclerView listview){
listView = listview;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.setBackgroundColor(getResources().getColor(R.color.trade_tab));
//添加X轴刻度和文字
drawYklin(canvas);
//添加X轴刻度和文字
drawXklin(canvas);
/*早盘价折线*/
painm = new Paint();
painm.setStyle(Paint.Style.FILL);
painm.setAntiAlias(true); //去锯齿
painm.setStrokeWidth(2);
painm.setTextSize(context.getResources().getDimensionPixelSize(R.dimen.font_super_smallest));
painm.setColor(context.getResources().getColor(R.color._DE9724));
if(coordinatecoyp==null){
coordinatecoyp = new ArrayList<>();
}else {
coordinatecoyp.clear();
}
int YMax = YLength - (YScalenum-1) * YScale;
float KinMax = YLength - (YLength-YScale) * Tool.getSHJcalPrice(upPrice,downPrice,upPrice-downPrice);
float C = KinMax - YMax;
if(Mpricelist!=null){
for(int i=0; i<Mpricelist.size(); i++){
if(i!=Mpricelist.size()-1){
float y = YLength - (YLength-YScale+C) * Tool.getSHJcalPrice(Mpricelist.get(i).getYlin(),downPrice,upPrice-downPrice);
float y1 = YLength - (YLength-YScale+C) * Tool.getSHJcalPrice(Mpricelist.get(i+1).getYlin(),downPrice,upPrice-downPrice);
canvas.drawLine( i * XScale + textWidth/2 + addXwidth,y- YScale/2- textheight/2,
(i+1) * XScale+ textWidth/2 + addXwidth,y1- YScale/2- textheight/2, painm);
}
for(SHjKinBean sHjKinBean: coordinate){
if(sHjKinBean.getXlin().equals(Mpricelist.get(i).getXlin())&&sHjKinBean.getCoordinateX()==COORDINATEM){
SHjKinBean sHjKinBean1 = new SHjKinBean();
sHjKinBean1.setCoordinateY(YLength - (YLength-XScale) * Tool.getSHJcalPrice(Mpricelist.get(i).getYlin(),downPrice,upPrice-downPrice));
sHjKinBean1.setCoordinateX( i * XScale+ textWidth/2 + addXwidth);
sHjKinBean1.setXlin(Mpricelist.get(i).getXlin());
coordinatecoyp.add(sHjKinBean1);
}
}
}
}
/*午盘价折线*/
paina = new Paint();
paina.setStyle(Paint.Style.FILL);
paina.setAntiAlias(true); //去锯齿
paina.setStrokeWidth(2);
paina.setTextSize(context.getResources().getDimensionPixelSize(R.dimen.font_super_smallest));
paina.setColor(context.getResources().getColor(R.color._10A8F6));
if(Apricelist!=null){
for(int i=0; i<Apricelist.size(); i++){
if(i!=Apricelist.size()-1){
float y = YLength - (YLength-YScale+C) * Tool.getSHJcalPrice(Apricelist.get(i).getYlin(),downPrice,upPrice-downPrice);
float y1 = YLength - (YLength-YScale+C) * Tool.getSHJcalPrice(Apricelist.get(i+1).getYlin(),downPrice,upPrice-downPrice);
canvas.drawLine( i * XScale + textWidth/2 + addXwidth,y- YScale/2- textheight/2,
(i+1) * XScale + textWidth/2 + addXwidth,y1- YScale/2- textheight/2, paina);
}
for(SHjKinBean sHjKinBean: coordinate){
if(sHjKinBean.getXlin().equals(Apricelist.get(i).getXlin())&&sHjKinBean.getCoordinateX()==COORDINATEA){
SHjKinBean sHjKinBean1 = new SHjKinBean();
sHjKinBean1.setCoordinateY(YLength - (YLength-XScale) * Tool.getSHJcalPrice(Apricelist.get(i).getYlin(),downPrice,upPrice-downPrice));
sHjKinBean1.setCoordinateX( i * XScale+ textWidth/2 + addXwidth);
sHjKinBean1.setXlin(Apricelist.get(i).getXlin());
coordinatecoyp.add(sHjKinBean1);
}
}
}
}
//画点击弹出的详情
if (needPop&&coordinatecoyp.size()>0){
drawPopView(popX,popY,canvas);
}
}
float coorx;//最小的点击差比
int popWith = 0;
private void drawPopView(float x,float y,Canvas canvas){
int position=0;//最小的x轴
popWith = Tool.dpToPx(15);
for(int i=0;i<coordinatecoyp.size();i++){
if(i==0){
coorx = coordinatecoyp.get(i).getCoordinateX()>x?coordinatecoyp.get(i).getCoordinateX()-x:x-coordinatecoyp.get(i).getCoordinateX();
}
float coorxcopy = coordinatecoyp.get(i).getCoordinateX()>x?coordinatecoyp.get(i).getCoordinateX()-x:x-coordinatecoyp.get(i).getCoordinateX();
if(coorx>coorxcopy){
position = i;
coorx = coorxcopy;
}
}
x = coordinatecoyp.get(position).getCoordinateX();
Paint paintzb = new Paint();//竖线
paintzb.setStyle(Paint.Style.FILL);
paintzb.setAntiAlias(true); //去锯齿
paintzb.setStrokeWidth(1);
paintzb.setTextSize(context.getResources().getDimensionPixelSize(R.dimen.font_super_smallest));
paintzb.setColor(context.getResources().getColor(R.color.text_usually));
float newx;
if(x>XLength){
newx = XLength;
}else {
newx = x;
}
canvas.drawLine(newx, YLength - YScale/2- textheight/2, newx, YLength - Ypoplin * YScale- YScale/2- textheight/2, paintzb);
// y = coordinatecoyp.get(position).getCoordinateY();
Paint painapop = new Paint();
painapop.setStyle(Paint.Style.STROKE);
painapop.setAntiAlias(true); //去锯齿
painapop.setStrokeWidth(2);
painapop.setColor(context.getResources().getColor(R.color.text_usually));
Path path= new Path();
if(y-popWith*4 <10+ YPoint){
/*超出上边框*/
y = (10+YPoint) - (y-popWith*4) +y;
}else if(y>YLength-YScale/2- textheight/2){
/*超出下边框*/
float yend = y - YLength + textheight/2 + YScale/2;
y = y - yend;
}
String text = "交易日 :0101交易时间";
float width = paint.measureText(text);//文本的宽度
if(x+width>XLength){
/*超出右边框*/
path.moveTo(x-popWith,y-popWith*4);
path.lineTo(x-popWith,y);
path.lineTo(x-width,y);
path.lineTo(x-width,y-popWith*4);
path.lineTo(x-popWith,y-popWith*4);
}else {
path.moveTo(x+popWith,y-popWith*4);
path.lineTo(x+popWith,y);
path.lineTo(x+width,y);
path.lineTo(x+width,y-popWith*4);
path.lineTo(x+popWith,y-popWith*4);
}
canvas.drawPath(path, painapop);
painapop.setStyle(Paint.Style.FILL);
painapop.setColor(context.getResources().getColor(R.color.trade_tab));
canvas.drawPath(path, painapop);
String data="- -",pricem="- -",pricea="- -";
for(int i=0;i<Mpricelist.size();i++){
if(Mpricelist.get(i).getXlin().equals(coordinatecoyp.get(position).getXlin())){
data = Mpricelist.get(i).getXlin();
pricem = ""+Mpricelist.get(i).getYlin();
}
}
for(int i=0;i<Apricelist.size();i++){
if(Apricelist.get(i).getXlin().equals(coordinatecoyp.get(position).getXlin())){
data = Apricelist.get(i).getXlin();
pricea = ""+Apricelist.get(i).getYlin();
}
}
int popHeight = (popWith*4)/8;
if(x+width>XLength){
/*超出右边框*/
canvas.drawText("交易日:"+TimeDateUtil.changeDateFormat("yyyyMMdd", "MM-dd",data),x-width+Tool.dpToPx(10),y-popWith*4+popHeight*2+Tool.dpToPx(5),paint);
canvas.drawText("早盘价:"+ Utils.pricesFormatFloat(pricem),x-width+Tool.dpToPx(10),y-popWith*4+popHeight*4+Tool.dpToPx(5),painm);
canvas.drawText("午盘价:"+Utils.pricesFormatFloat(pricea),x-width+Tool.dpToPx(10),y-popWith*4+popHeight*6+Tool.dpToPx(5),paina);
}else {
canvas.drawText("交易日:"+TimeDateUtil.changeDateFormat("yyyyMMdd", "MM-dd",data),x+popWith+Tool.dpToPx(10),y-popWith*4+popHeight*2+Tool.dpToPx(5),paint);
canvas.drawText("早盘价:"+Utils.pricesFormatFloat(pricem),x+popWith+Tool.dpToPx(10),y-popWith*4+popHeight*4+Tool.dpToPx(5),painm);
canvas.drawText("午盘价:"+Utils.pricesFormatFloat(pricea),x+popWith+Tool.dpToPx(10),y-popWith*4+popHeight*6+Tool.dpToPx(5),paina);
}
}
/**
* X轴刻度 Y轴边线
* */
private void drawYklin(Canvas canvas){
if(XLabel==null){
return;
}
int left,right,centen;
if(XLabel.length%2==0){
centen = XLabel.length/2;
}
else{
centen = (XLabel.length-1)/2;
}
if(centen%2==0){
left = centen /2;
right =centen+centen /2;
}else {
left = (centen-1) /2;
right = centen+(centen-1)/2;
}
for(int i=0;i < XLabel.length;i++){
if(i==0||i==centen||i==left||i==right){
canvas.drawText(TimeDateUtil.changeDateFormat("yyyyMMdd", "MM-dd", XLabel[i]), i * XScale + addXwidth, YLength +Tool.dpToPx(10)- YScale/2, paint);//文字
}else {
Rect rect = new Rect();
paint.getTextBounds(TimeDateUtil.changeDateFormat("yyyyMMdd", "MM-dd", XLabel[i]), 0, TimeDateUtil.changeDateFormat("yyyyMMdd", "MM-dd", XLabel[i]).length(), rect);
if(i==XLabel.length-1){
canvas.drawText(TimeDateUtil.changeDateFormat("yyyyMMdd", "MM-dd", XLabel[i]), i * XScale + addXwidth, YLength +Tool.dpToPx(10)- YScale/2, paint);//文字
}
}
}
}
/**
* Y轴刻度 X轴边线
* */
private void drawXklin(Canvas canvas){
if(YLabel==null){
return;
}
paint.setStrokeWidth(1);
paint.setColor(context.getResources().getColor(R.color._7C7F99));
for(int i=0; i * YScale < YLength; i++) {
if(i >= YLength/YScale){
continue;
}
Ypoplin = i;
canvas.drawLine(0, YLength - i * YScale - YScale/2 - textheight/2, XLength, YLength - i * YScale- YScale/2- textheight/2, paint); //刻度
}
paint.setStrokeWidth(2);
}
class SHjKinBean{
public String Xlin;
public float Ylin;
public float coordinateX;
public float coordinateY;
SHjKinBean(){
}
SHjKinBean(float ylin,String xlin){
Ylin = ylin;
Xlin = xlin;
}
public float getCoordinateX() {
return coordinateX;
}
public void setCoordinateX(float coordinateX) {
this.coordinateX = coordinateX;
}
public float getCoordinateY() {
return coordinateY;
}
public void setCoordinateY(float coordinateY) {
this.coordinateY = coordinateY;
}
public String getXlin() {
return Xlin;
}
public void setXlin(String xlin) {
Xlin = xlin;
}
public float getYlin() {
return Ylin;
}
public void setYlin(float ylin) {
Ylin = ylin;
}
}
/*详细信息屏蔽*/
public void gonePop(){
if(needPop){
needPop = !needPop;
MOVENUM=0;
isMOVE = false;
invalidate();
}
}
}
自定义折线图控件
本文介绍如何在Android中自定义折线图控件,包括控件的生命周期、绘图方法、触摸事件处理及数据更新策略。通过实例演示了早盘价与午盘价的折线绘制,以及点击后显示详细信息的弹窗实现。
716

被折叠的 条评论
为什么被折叠?



