随机图形

前言 

最近写了2个自定义图形,随机矩形和漂浮的圆环,代码参考https://github.com/isqing/BubbleChart

随机矩形
漂浮的圆环

随机矩形

随机矩形最关键的是算随机的坐标,我计算的矩形左上角的x,y坐标,根据x,y坐标和矩形的宽高度绘制一个一个的小矩形

其实我计算的时候是有规律可循的,是一行一行的计算的,根据屏幕的宽度计算最大列数,根据个数计算最大行数,每行最少随机生成一个点的坐标,如果到最大行数还没到总个数,再次循环随机点,下面是计算的方法

public staticList getPoints(intw,inth,intmRectX,intmRectY,intmSpaceH,intamount){

List pointList=newArrayList<>();

intmaxRows =(int)Math.ceil(h/(mRectY+mSpaceH));//最大行数

intmaxCol =Math.min(5,w/mRectX);//最大列数

intmSum=0;//累计每次生成的个数

Map numberMap=newHashMap<>();

while(mSum

for(inti =0; i < maxRows; i++) {

intmPreRandom=0;//上次循环生成的值

if(numberMap.containsKey(i)){

mPreRandom=numberMap.get(i);

}

intmRandom =0;//随机生成一个的个数

if(maxCol>mPreRandom){

mRandom =newRandom().nextInt(maxCol-mPreRandom +1-1)+1;//生成1到maxCol,随机生成的每行的个数

}else{

mRandom=0;//当前行的个数超过最大个是

}

//当生成的随机数和之前的和大于图形总个数时

if(mSum + mRandom >= amount) {

mRandom = amount - mSum;

mSum = amount;

numberMap.put(i,mRandom+mPreRandom);

break;

}else{

mSum += mRandom;

numberMap.put(i,mRandom+mPreRandom);

}

}

}

for(inti=0;i

intcol=numberMap.get(i);//第i行的个数

intoverW=w;//计算剩余的宽度

floataverageW = w / col;//第一次取平均值

floatstartX=0;

floatendX=0;

floatmRandomX=0;

if(j==0){

startX=0;

endX=averageW- mRectX;

}else{

averageW=overW/(col-j);//计算剩余的平均宽度

startX = mRandomX+mRectX;

endX = mRandomX+mRectX + averageW - mRectX-10;//10为间隔

//                    Log.i("startX",startX+"==="+endX);

}

//计算y的范围

floatstartY=i*(mRectY+mSpaceH);

floatendY=(i+1)*(mRectY+mSpaceH)-mRectY;

mRandomX=startX + ((endX - startX) *newRandom().nextFloat());//x坐标

floatmRandomY =startY + ((endY - startY) *newRandom().nextFloat());//Y坐标

//                Log.i("mRandomX",mRandomX+"==="+mRectX+"==="+overW);

overW=(int)(w-(mRandomX+mRectX));

//                Log.i("overW",""+overW);

Point point=newPoint(mRandomX,mRandomY);

pointList.add(point);

}

}

returnpointList;

}

绘制随机图形

在onMeasure里面

intwidthP = DensityUtil.getScreenWidth(getContext());

intheightP = DensityUtil.getScreenHeight(getContext());

intheightZ1=((int)Math.ceil(hashOvalList.size()/4))*(mRectY+mSpaceH);

intheightZ2= (int)Math.ceil(hashOvalList.size()/(widthP/mRectX))*(mRectY+mSpaceH);

heightZ= Math.max(heightZ1,heightZ2)+mSpaceH;

if(heightZ<=0||heightZ

heightZ=heightP;

//            isHalfScreen=true;

}

setMeasuredDimension(widthP,heightZ);

chartPait=newPaint();

textPaint=newPaint();

//透明度动画

initAnimatorRed();

initAnimatorGreen();


drawRect主要是根据生成的坐标绘制矩形

for(inti =0; i

HashOval hashOval=hashOvalList.get(i);

Point point =pointList.get(i);

//画圆角矩形

floatleft =  point.getX();

floatrigth = point.getX() +mRectX;

floattop = point.getY();

floatbottom = point.getY() +mRectY;

if(isHalfScreen) {

top = point.getY()+marginTop;

bottom = point.getY() +mRectY+marginTop;

}

mRect=newRectF(left+pading, top+pading, rigth-pading, bottom-pading);

chartPait.setStyle(Paint.Style.FILL);//充满

chartPait.setColor(hashOval.getChartColor());

chartPait.setAntiAlias(true);// 设置画笔的锯齿效果

intred = (hashOval.getChartColor() &0xff0000) >>16;

intgreen = (hashOval.getChartColor() &0x00ff00) >>8;

intblue = (hashOval.getChartColor() &0x0000ff);

if(hashOval.getIsAlpha()==0) {

chartPait.setARGB(animatedAplaGreen, red, green, blue);

}else{

chartPait.setARGB(animatedAplaRed, red, green, blue);

}

canvas.drawRoundRect(mRect,20,20,chartPait);//第二个参数是x半径,第三个参数是y半径

//写字

Rect bounds =newRect();

textPaint.setStyle(Paint.Style.FILL);//充满

textPaint.setColor(hashOval.getTextColor());

textPaint.setTextSize(DensityUtil.dip2px(getContext(),hashOval.getTextSize()));

textPaint.setAntiAlias(true);// 设置画笔的锯齿效果

textPaint.getTextBounds(hashOval.getText(),0, hashOval.getText().length(), bounds);

inttextW = bounds.width();

inttextH = bounds.height();

//            Log.i("textw",textW+","+mRectX);

//            Log.i("textH",textH+","+mRectY);

floattLeft=left+(mRectX-textW)/2;

floattTop=top+(mRectY-textH);

String text=hashOval.getText();

if(text.length()>4){

text=text.substring(0,4);

textPaint.getTextBounds(text,0, text.length(), bounds);

textW = bounds.width();

textH = bounds.height();

tLeft=left+(mRectX-textW)/2;

tTop=top+(mRectY-textH);

}

inttextRed = (Color.WHITE&0xff0000) >>16;

inttextGreen = (Color.WHITE&0x00ff00) >>8;

inttextBlue = (Color.WHITE&0x0000ff);

if(hashOval.getIsAlpha()==0) {

textPaint.setARGB(animatedAplaGreen, textRed, textGreen, textBlue);

}else{

textPaint.setARGB(animatedAplaRed, textRed, textGreen, textBlue);

}

canvas.drawText(text,tLeft,tTop,textPaint);

}


点击事件

重写onTouchEvent事件中的MotionEvent.ACTION_DOWN调用setClick(event.getX(),event.getY());根据点击的坐标,判断点击的在哪个小矩形里

private voidsetClick(floatx,floaty){

for(inti =0; i

HashOval hashOval =hashOvalList.get(i);

Point point =pointList.get(i);

//矩形

floatleft =  point.getX();

floatrigth = point.getX() +mRectX;

floattop = point.getY();

floatbottom = point.getY() +mRectY;

if(isHalfScreen){

top = point.getY()+marginTop;

bottom = point.getY() +mRectY+marginTop;

}

if(x>left&xtop&y

//                Toast.makeText(getContext(),hashOval.getText(),Toast.LENGTH_SHORT).show();

onClickChartItem.setOnClickChartItem(hashOval);

}

}

}


漂浮的圆环

这里有参考其他人的方法,在屏幕上随机生成圆环,然后向角度的方向移动,偏移圆心,根据圆心画圆环,计算圆环是否碰到边界,可配置圆环的分配,加了一些绘制动画

定义一个类Ball

classBall {

intradius;// 半径

floatcx;// 圆心

floatcy;// 圆心

floatvx;// X轴速度

floatvy;// Y轴速度

Paintpaint;

// 移动

voidmove() {

//向角度的方向移动,偏移圆心

cx+=vx;

cy+=vy;

}

intleft() {

return(int) (cx-radius);

}

intright() {

return(int) (cx+radius);

}

intbottom() {

return(int) (cy+radius);

}

inttop() {

return(int) (cy-radius);

}

onMeasure初始化一些数据

mWidth=resolveSize(mWidth, widthMeasureSpec);

mHeight=resolveSize(mHeight, heightMeasureSpec);

setMeasuredDimension(mWidth,mHeight);

maxRadius=mWidth/12;

minRadius=maxRadius/2;

// 初始化圆的半径和圆心

for(inti=0; i

mBalls[i].radius=mRandom.nextInt(maxRadius+1-minRadius) +minRadius;

//            mBalls[i].mass = (int) (Math.PI * mBalls[i].radius * mBalls[i].radius);

// 初始化圆心的位置, x最小为 radius, 最大为mwidth- radius

mBalls[i].cx=mRandom.nextInt(mWidth-mBalls[i].radius) +mBalls[i].radius;

mBalls[i].cy=mRandom.nextInt(mHeight-mBalls[i].radius) +mBalls[i].radius;

}

cyclePaint=newPaint();

center= getWidth() /2;

mRadius= (int) (center-mStrokeWidth/2);

oval=newRectF(center-mRadius,center-mRadius,center+mRadius,center+mRadius);

centerTextPaint=newPaint();

centerTextRect=newRect();

centerTextPaint.getTextBounds(centerText,0,centerText.length(),centerTextRect);

dataPaint=newPaint();

initRingAnimator();

initCenterAnimator();

initDataAnimator();


drawRing画环,根据数据所占比例计算绘制的角度

floatstartPercent =0;

floatsweepPercent =0;

for(inti =0; i

floatbfb =dataList.get(i).getRingData() / sumData(dataList);

//            Log.i(TAG, dataList.get(i) + ", " + sumData(dataList) + "," + dataList.get(i).getRingData() / sumData(dataList));

sweepPercent = bfb *360;

//            Log.i(TAG, "sweepPercent: " + sweepPercent);

//第一段

cyclePaint.setAntiAlias(true);

cyclePaint.setStyle(Paint.Style.STROKE);

cyclePaint.setStrokeWidth(mStrokeWidth);

cyclePaint.setColor(dataList.get(i).getRingColor());

if(Math.min(sweepPercent -1,animatedRingValue- startPercent) >=0) {

canvas.drawArc(oval, startPercent, Math.min(sweepPercent -1,animatedRingValue- startPercent),false,cyclePaint);

//                drawText(canvas,sweepPercent/2+startPercent,dataList.get(i)+"",sweepPercent);

}

startPercent += sweepPercent;

}

drawDataText绘制环上的字,根据不同象限计算

dataPaint.setAntiAlias(true);

dataPaint.setStyle(Paint.Style.FILL);

dataPaint.setTextSize(dataTextSize);

dataPaint.setStrokeWidth(1);

//        dataPaint.setAlpha(animatedDataValue);

//        dataPaint.setColor(dataTextColor);

intred = (getDataTextColor() &0xff0000) >>16;

intgreen = (getDataTextColor() &0x00ff00) >>8;

intblue = (getDataTextColor() &0x0000ff);

dataPaint.setARGB(animatedDataValue, red, green, blue);

floatdataPre =0;

floatdataCurr =0;

for(inti =0; i

if(i ==0) {

dataPre =0;

}else{

dataPre += (dataList.get(i -1).getRingData() / sumData(dataList)) *360;

}

//            Log.i(TAG, "dataPre: " + dataPre);

dataCurr = (dataList.get(i).getRingData() / sumData(dataList)) *360+ dataPre;

//            Log.i(TAG, "dataCurr: " + dataCurr);

//一四象限

if(((dataPre + (dataCurr - dataPre) /2)>=0&&(dataPre + (dataCurr - dataPre) /2)<90)||((dataPre + (dataCurr - dataPre) /2)>=270&&(dataPre + (dataCurr - dataPre) /2)<360)){

PointF point2 = MathHelper.getInstance().calcArcEndPointXY(

ball.cx, ball.cy, ball.radius, dataPre + (dataCurr - dataPre) /2);

//标识2

DrawHelper.getInstance().drawRotateText(String.valueOf(dataList.get(i).getRingText()), point2.x, point2.y,0,

canvas,dataPaint);

}else{

//二三象限

PointF point2 = MathHelper.getInstance().calcArcEndPointXY(

ball.cx, ball.cy, ball.radius, dataPre + (dataCurr - dataPre) /2);

//标识2

DrawHelper.getInstance().drawRotateText(String.valueOf(dataList.get(i).getRingText()), point2.x, point2.y,0,

canvas,dataPaint);

}

}


在onDraw里面利用for循环绘制,判断环边界

// 先画出所有圆

for(inti =0; i

Ball ball =mBalls[i];

//            canvas.drawCircle(ball.cx, ball.cy, ball.radius, ball.paint);

center=(int) ball.cx;

oval=newRectF(ball.cx- ball.radius,ball.cy- ball.radius, ball.cx+ ball.radius, ball.cy+ ball.radius);

drawRing(canvas);

drawCenterText(canvas,ball);

drawDataText(canvas,ball);

}

// 球碰撞边界

for(inti =0; i

Ball ball =mBalls[i];

collisionDetectingAndChangeSpeed(ball);// 碰撞边界的计算

ball.move();// 移动

}

longstopTime = System.currentTimeMillis();

longrunTime = stopTime - startTime;

// 16毫秒执行一次

postInvalidateDelayed(Math.abs(runTime -16));

判断小球边界

public voidcollisionDetectingAndChangeSpeed(Ball ball) {

intleft = getLeft();

inttop = getTop();

intright = getRight();

intbottom = getBottom();

floatspeedX = ball.vx;

floatspeedY = ball.vy;

// 碰撞左右,X的速度取反。 speed的判断是防止重复检测碰撞,然后黏在墙上了=。=

if(ball.left() <= left && speedX <0) {

ball.vx= -ball.vx;

}else if(ball.top() <= top && speedY <0) {

ball.vy= -ball.vy;

}else if(ball.right() >= right && speedX >0) {

ball.vx= -ball.vx;

}else if(ball.bottom() >= bottom && speedY >0) {

ball.vy= -ball.vy;

}

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容

  • The Inner Game of Tennis W Timothy Gallwey Jonathan Cape ...
    网事_79a3阅读 11,989评论 3 20
  • 文/简小白sky 曾经有一首叫《挑妈妈》的诗走红网络,令无数人潸然泪下。 你问我出生前在做什么/我答,我在天上挑妈...
    简小白sky阅读 438评论 4 12
  • 感恩天地滋养万物 感恩祖先慈悲智慧 感恩国家培养护佑 感恩父母养育之恩 感恩老师辛勤教导 感恩同仁关心帮助 感恩农...
    快乐小屋刘丽华阅读 258评论 0 0
  • C++的代码的组织,依赖的管理规定几乎为零。学习golang的时候,一上来就是看语法,看代码,在代码组织和依赖管理...
    linjinhe阅读 537评论 0 0