彩票走势图

彩票走势图

前几天在做一个彩票的项目的时候遇到了彩票的走势图这个功能,网上查了没有,就自己写了个,现在和大家分享下,以方便后来做彩票走势图的同学们。

先分析下,走势图肯定是很大的一块,所以需要横向和纵向都能够通过手势来滑动,所以大家很快就能想到一个纵向的ScrollView嵌套一个横向的HorizontalScrollView就能够实现,这个是最外面的一层。如若想在对应的数字下面画球,大家肯定就想到了需要知道每个球的(x,y),走势图的期数一定的情况下,就可以设定走势图的高度,走势图的高度了定了,Y轴需要被分为多少份也定了,他和期数是一样的,x轴的需要分的份数是一定的,比如双色球的红球就分为33份,篮球就分为16份,所以每个球的x,y坐标就能被计算出来。

我给大家将走势图的代码贴出来,同时我做了个demo,喜欢省事的盆友们直接下载就好了。

这个是走势图的代码

<!-- lang: java -->
public class TrendView extends View  implements Observer{

public static int[][] TestRowRed = new int[][]{
	{6,14,18,22,28,29},
	{7,3,17,20,24,33},
	{3,19,11,24,27,30},

	{7,14,12,26,28,30},
	{1,2,7,20,22,29},
	{1,5,17,18,21,23},

	{2,4,7,22,23,29},
	{3,4,5,7,21,30},
	{6,14,18,22,28,21},

	{3,4,7,26,28,29}
};

public static int[] TestRowBlue = new int[]{3,12,11,24,27,33,5,23,2,31};

static final int kCopies_X = 33;//x 轴分多少份
static final int kCopies_Y = 10;//y 轴分多少份

float mDelt_X ;//x 轴每个坐标间的跨度,单位像素,根据实际view大小计算
float mDelt_Y ;//y 轴每个坐标间的跨度,单位像素,根据实际view大小计算

int countYLine = 10;//y轴的数量

//顶部的空白,用于填数字,单位dip
static final float kTopPadding_Y = 24.0f;
float mPadding_top;

private Matrix mMatrix = new Matrix();
public PaintFlagsDrawFilter mPaintFlagsDrawFilter;// 毛边过滤
/**
 * 画笔:线
 */
private Paint mLinePaint = new Paint();
static final float kFontSize = 13;
float mFontSize;
/**
 * 画笔:圆
 */
private Paint mCirclePaint = new Paint();
/**
 * view的宽高
 */
private int mWidth;
private int mHeight;

Context mContext;

/**
 * 画笔:球
 */
private Paint mBallPaint = new Paint();
private Drawable mCricleDrawable;
private Bitmap mCricleBmp;

boolean isNeedLink = false;//是否需要在ball之间连线
int lineColor;//连线的颜色
//
Handler handler = new Handler(){
	public void handleMessage(android.os.Message msg) {
	};
};
//用于自动刷新
Runnable freshRunnable = new Runnable() {
	@Override
	public void run() {
		// TODO Auto-generated method stub
		invalidate();
		handler.postDelayed(this, 500);
	}
};
/**
 * 一些初始化方法
 */
public void init(Context context,AttributeSet attrs){
	this.mContext = context;

	TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TrendView);
	int resId = a.getResourceId(R.styleable.TrendView_ballImage, R.drawable.ball_red);
	isNeedLink = a.getBoolean(R.styleable.TrendView_isNeedLinkEveryBall, false);
	lineColor = a.getColor(R.styleable.TrendView_lineColor, Color.RED);
	a.recycle();

	this.mPaintFlagsDrawFilter = new PaintFlagsDrawFilter(0,
			Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
	this.mCricleDrawable = getResources().getDrawable(
			R.drawable.ball_red);
	this.mCirclePaint.setTextSize(25);
	this.mCirclePaint.setTextScaleX(1.5f);
	this.mLinePaint.setStrokeWidth(2);
	this.mCricleBmp  = BitmapFactory.decodeResource(getResources(), resId);
	this.handler.postDelayed(freshRunnable, 500);
}
public TrendView(Context context, AttributeSet attrs, int defStyle) {
	super(context, attrs, defStyle);
	// TODO Auto-generated constructor stub
	init(context,attrs);
}

public TrendView(Context context, AttributeSet attrs) {
	super(context, attrs);
	// TODO Auto-generated constructor stub
	init(context,attrs);
}

@Override
public void update(Observable observable, Object data) {
	// TODO Auto-generated method stub
	Log.i("observer", "observable >"+observable);
}

@Override
protected void onDraw(Canvas canvas) {
	super.onDraw(canvas);
	canvas.setDrawFilter(mPaintFlagsDrawFilter);
	canvas.drawColor(Color.WHITE);
	drawTopNum(canvas);
	drawXLine(canvas);
	//		drawYLine(canvas);
	drawRightVerticalLine(canvas);
	drawBallLinkLine(canvas);
	drawBall(canvas);

}
/**
 * 画顶部的数字和开始横线
 * @param cns
 */
void drawTopNum(Canvas cns) {
	if (mPadding_top <=0) {
		return;
	}
	mLinePaint.setStrokeWidth(1);
	mLinePaint.setColor(Color.GRAY);
	mLinePaint.setTextSize(mFontSize);
	cns.drawLine(0,  mPadding_top, this.mWidth, mPadding_top, mLinePaint);
	mLinePaint.setColor(Color.RED);
	for (int i = 0;i < kCopies_X;i ++) {
		//写字符时,加点偏移
		if (i >= 9) {
			cns.drawText(String.valueOf(i+1), this.mDelt_X* i + (int)(this.mDelt_X * 0.1f) ,0 + mPadding_top * 0.7f , mLinePaint);
		}else {
			cns.drawText(String.valueOf(i+1), this.mDelt_X* i + (int)(this.mDelt_X * 0.4f) ,0 + mPadding_top * 0.7f, mLinePaint);
		}
	}
}

/**
 * 画y轴,--->
 * @param canvas
 */
void drawXLine(Canvas cns) {
	mLinePaint.setStrokeWidth(1);
	mLinePaint.setColor(Color.GRAY);
	for (int i = 0;i < kCopies_Y;i ++) {
		cns.drawLine(0, this.mDelt_Y* (i + 1) + mPadding_top, this.mWidth, this.mDelt_Y* (i + 1) + mPadding_top, mLinePaint);
	}	
}

/**
 * 画最右边的横线
 * @param canvas
 */
void drawRightVerticalLine(Canvas cns) {
	mLinePaint.setStrokeWidth(4);
	mLinePaint.setColor(Color.GRAY);
	cns.drawLine(mWidth ,0 + mPadding_top , mWidth,this.mHeight,  mLinePaint);
}

/**
 * 画X轴,    ^|
 * @param canvas
 */
void drawYLine(Canvas cns) {
	mLinePaint.setStrokeWidth(1);
	mLinePaint.setColor(Color.GREEN);
	for (int i = 0;i < kCopies_X;i ++) {
		cns.drawLine(this.mDelt_X* (i + 1),0 + mPadding_top , this.mDelt_X* (i + 1),this.mHeight,  mLinePaint);
	}	
}
void drawBallLinkLine(Canvas cns) {
	cns.setDrawFilter(mPaintFlagsDrawFilter);
	mLinePaint.setStrokeWidth(2);
	mLinePaint.setColor(lineColor);
	if (isNeedLink) {
		float[] lastXy = this.translateRowIndex2XY(0, TestRowBlue[0] - 1);
		for (int i = 1 ;i < TestRowBlue.length;i ++) {
			int value = TestRowBlue[i];
			float[] xy = this.translateRowIndex2XY(i, value - 1);
			cns.drawLine(lastXy[0]+ mDelt_X * 0.5f,lastXy[1]+ mDelt_Y * 0.5f , xy[0]+ mDelt_X * 0.5f,xy[1]+ mDelt_Y * 0.5f ,  mLinePaint);

			lastXy[0] = xy[0];
			lastXy[1] = xy[1];
		}
	} 
}

void drawBall(Canvas cns) {
	mLinePaint.setColor(Color.WHITE);
	mLinePaint.setTextSize(mFontSize - 4);//比顶部字体小点
	Rect src = new Rect();
	Rect dst = new Rect();
	if (isNeedLink) {
		for (int i = 0 ;i < TestRowBlue.length;i ++) {
			int value = TestRowBlue[i];
			float[] xy = this.translateRowIndex2XY(i, value - 1);
			src.left = 0;
			src.top = 0;
			src.bottom = (int) mCricleBmp.getHeight();
			src.right = (int)mCricleBmp.getWidth();

			dst.left = (int) (xy[0] + this.mDelt_X * 0.15f);
			dst.top = (int)(xy[1]+ this.mDelt_Y * 0.15f);
			dst.bottom = (int) (dst.top + mDelt_Y * 0.8f);
			dst.right = (int) (dst.left + mDelt_X * 0.8f);

			//在对应的位置画球球
			cns.drawBitmap(mCricleBmp, src, dst, this.mBallPaint);
			if (value >= 9) {
				cns.drawText(String.valueOf(value), dst.left  + (int)(this.mDelt_X * 0.1f) ,dst.top+ this.mDelt_Y * 0.5f , mLinePaint);
			}else {
				cns.drawText(String.valueOf(value ), dst.left  + (int)(this.mDelt_X * 0.2f) ,dst.top+ this.mDelt_Y * 0.5f , mLinePaint);
			}
		}
	} else {
		//just for test
		//row1
		for (int i = 0;i < TestRowRed.length; i ++) {
			int[] testRow = TestRowRed[i];
			for (int j = 0;j < testRow.length; j ++) {
				int xIndex = testRow[j] ;
				float[] xy = this.translateRowIndex2XY(i, xIndex - 1);

				src.left = 0;
				src.top = 0;
				src.bottom = (int) mCricleBmp.getHeight();
				src.right = (int)mCricleBmp.getWidth();

				//缩小球
				dst.left = (int) (xy[0] + this.mDelt_X * 0.15f);
				dst.top = (int)(xy[1]+ this.mDelt_Y * 0.15f);
				dst.bottom = (int) (dst.top + mDelt_Y * 0.8f);
				dst.right = (int) (dst.left + mDelt_X * 0.8f);

				//在对应的位置画球球
				cns.drawBitmap(mCricleBmp, src, dst, this.mBallPaint);
				if (xIndex >= 9) {
					cns.drawText(String.valueOf(xIndex), dst.left  + (int)(this.mDelt_X * 0.1f) ,dst.top+ this.mDelt_Y * 0.5f , mLinePaint);
				}else {
					cns.drawText(String.valueOf(xIndex ), dst.left  + (int)(this.mDelt_X * 0.2f) ,dst.top+ this.mDelt_Y * 0.5f , mLinePaint);
				}
			}
		}
	}

}
/**
 * 根据位置行和列,转成对应的x,y坐标,不做校正,即都返回左上角坐标 
 * @param rowIndex  所在行,从0开始
 * @param xIndex    所在列,从0开始
 * @return [x0,y0]
 */
float[] translateRowIndex2XY (int rowIndex,int xIndex) {
	float[] xy = new float[2];
	xy[0] = this.mDelt_X* xIndex ;
	xy[1] = this.mPadding_top + this.mDelt_Y * rowIndex;
	return xy;
}
/**
 * 根据view的宽高,初始化部分尺寸
 * @param w
 * @param h
 */
void setViewSize(int w,int h) {
	this.mWidth = w;
	this.mHeight = h;
	this.mDelt_X = 1.0f*this.mWidth  /kCopies_X;
	this.mPadding_top = (float) DimensionPixelUtil.dip2px(mContext, kTopPadding_Y);
	//减去顶部的预留空白后,再均分
	this.mDelt_Y = 1.0f*(this.mHeight  - mPadding_top)/kCopies_Y;

	this.mFontSize =   DimensionPixelUtil.sp2px(mContext, kFontSize);
	invalidate();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
	System.out.println("onMeasure---widthMeasureSpec::"+widthMeasureSpec +"  heightMeasureSpec::"+heightMeasureSpec);
	int measuredHeight = measureHeight(heightMeasureSpec);

	int measuredWidth = measureWidth(widthMeasureSpec);
	System.out.println("onMeasure---measuredWidth::"+measuredWidth +"  measuredHeight::"+measuredHeight);

	setMeasuredDimension(measuredWidth,measuredHeight);
	this.setViewSize(getMeasuredWidth(),getMeasuredHeight());

}

//如果是AT_MOST,specSize 代表的是最大可获得的空间; 
//如果是EXACTLY,specSize 代表的是精确的尺寸; 
//如果是UNSPECIFIED,对于控件尺寸来说,没有任何参考意义。

private int measureHeight(int measureSpec) {
	int specMode = MeasureSpec.getMode(measureSpec);
	int specSize = MeasureSpec.getSize(measureSpec);
	System.out.println("measureHeight----specMode::"+specMode +"  specSize::"+specSize);
	// Default size if no limits are specified.
	int result = 100;
	if (specMode == MeasureSpec.AT_MOST) {

		// Calculate the ideal size of your
		// control within this maximum size.
		// If your control fills the available
		// space return the outer bound.

		result = specSize;
	} else if (specMode == MeasureSpec.EXACTLY) {

		// If your control can fit within these bounds return that value.
		result = specSize;
	}
	return result;
}

private int measureWidth(int measureSpec) {
	int specMode = MeasureSpec.getMode(measureSpec);
	int specSize = MeasureSpec.getSize(measureSpec);
	System.out.println("measureWidth----specMode::"+specMode +"  specSize::"+specSize);
	// Default size if no limits are specified.
	int result = 500;
	if (specMode == MeasureSpec.AT_MOST) {
		// Calculate the ideal size of your control
		// within this maximum size.
		// If your control fills the available space
		// return the outer bound.
		result = specSize;
	}

	else if (specMode == MeasureSpec.EXACTLY) {
		// If your control can fit within these bounds return that value.

		result = specSize;
	}

	return result;
}

}

这个是xml文件的代码

<!-- lang: java -->
<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:trendview="http://schemas.android.com/apk/res/com.example.caipiaotrendchart" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#F4F2EE" android:orientation="vertical" >

<ScrollView
    android:id="@+id/scrollview_fucai"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <HorizontalScrollView
        android:id="@+id/synchor_double_red"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/white"
        android:scrollbars="none" >

        <LinearLayout
            android:id="@+id/linear_setheight"
            android:layout_width="wrap_content"
            android:layout_height="314dip"
            android:orientation="horizontal" >

            <!-- 走势图 -->

            <RelativeLayout
                android:id="@+id/re_red_trend"
                android:layout_width="893dip"
                android:layout_height="fill_parent"
                 >

                <View
                    android:id="@+id/v1"
                    android:layout_width="1dip"
                    android:layout_height="fill_parent"
                    android:layout_marginTop="24dip"
                    android:background="@android:color/darker_gray" />

                <com.example.caipiaotrendchart.TrendView
                    android:id="@+id/trendview_double_a"
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    android:layout_alignParentTop="true"
                    android:layout_toRightOf="@id/v1"
                    
                    android:paddingBottom="5dip"
                    android:paddingTop="5dip"
                    trendview:ballImage="@drawable/ball_red"
                    trendview:lineColor="#ffff0000" />

                <View
                    android:layout_width="fill_parent"
                    android:layout_height="1dip"
                    android:layout_below="@id/trendview_double_a"
                    android:background="@android:color/darker_gray" />
                <!-- 装图的 -->

            </RelativeLayout>

            <RelativeLayout
                android:id="@+id/re_blue"
                android:layout_width="893dip"
                android:layout_height="fill_parent" >

                <com.example.caipiaotrendchart.TrendView
                    android:id="@+id/trendview_double_b"
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    android:layout_alignParentTop="true"
                    android:paddingBottom="5dip"
                    android:paddingTop="5dip"
                    trendview:ballImage="@drawable/ball_blue"
                    trendview:isNeedLinkEveryBall="true"
                    trendview:lineColor="#1699F5" />
                <!-- 装图的 -->

                <View
                    android:layout_width="fill_parent"
                    android:layout_height="1dip"
                    android:layout_below="@id/trendview_double_b"
                    android:background="@android:color/darker_gray" />
            </RelativeLayout>
        </LinearLayout>
    </HorizontalScrollView>
</ScrollView>

</RelativeLayout>

这个是那个工具类的代码

<!-- lang: java -->
public class DimensionPixelUtil {
public final static int PX = TypedValue.COMPLEX_UNIT_PX;
public final static int DIP = TypedValue.COMPLEX_UNIT_DIP;
public final static int SP = TypedValue.COMPLEX_UNIT_SP;

/**
 * 
 * @param unit
 *            单位 </br>0 px</br>1 dip</br>2 sp
 * @param value
 *            size 大小
 * @param context
 * @return
 */
public static float getDimensionPixelSize(int unit, float value,
		Context context) {
	DisplayMetrics metrics = new DisplayMetrics();
	WindowManager wm = (WindowManager) context
			.getSystemService(Context.WINDOW_SERVICE);
	wm.getDefaultDisplay().getMetrics(metrics);
	switch (unit) {
	case PX:
		return value;
	case DIP:
	case SP:
		return TypedValue.applyDimension(unit, value, metrics);
	default:
		throw new IllegalArgumentException("unknow unix");
	}
}

/**
 * 根据手机的屏幕属性从 dip 的单位 转成为 px(像素)
 * 
 * @param context
 * @param value
 * @return
 */
public static float dip2px(Context context, float value) {
	DisplayMetrics metrics = context.getResources().getDisplayMetrics();
	return value * metrics.density;
}

/**
 * 根据手机的屏幕属性从 px(像素) 的单位 转成为 dip
 * 
 * @param context
 * @param value
 * @return
 */
public static float px2dip(Context context, float value) {
	DisplayMetrics metrics = context.getResources().getDisplayMetrics();
	return value / metrics.density;
}

}

这个是mainactivity代码

<!-- lang: java -->
public class MainActivity extends Activity {

TrendView trendViewRedBall;
TrendView trendViewBlueBall;
@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.activity_main);
	trendViewRedBall = (TrendView) findViewById(R.id.trendview_double_a);
	trendViewBlueBall = (TrendView) findViewById(R.id.trendview_double_b);
}

}

走势图的高度和宽度是可以动态设定的,有兴趣的同学可以自己添加下,另外y轴分多少份也可以动态设定,大家只需要将 成员变量(static final int kCopies_Y = 10;//y 轴分多少份 ) 这个行代码的static final去掉,然后 设置kCopies_Y的get set方法,在mainactivity中set就可以了。

从这里下载代码 http://www.oschina.net/code/snippet_724007_34027 这个是效果图 在此输入图片描述

在此输入图片描述 有什么问题欢迎大家指教

转载于:https://my.oschina.net/xubohui/blog/207581

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值