模仿QQ運(yùn)動(dòng)item的界面

首先按照老規(guī)矩妖滔,無(wú)圖無(wú)真相嘛谨设,先看看先:

效果圖.gif

是不是很像呢苛萎,那具體是實(shí)現(xiàn)是怎樣的呢诊县,即使概括的來(lái)說(shuō)就是
1.計(jì)算各個(gè)變量的值(記得是會(huì)隨整個(gè)View的大小變化而變化)讲弄。
2其次利用好canvas.translate()這個(gè)方法,計(jì)算好大小移動(dòng)canvas的原點(diǎn)依痊。
3最后就是調(diào)用api提供的各種方法畫(huà)圖就是了避除。這么說(shuō)是不是太過(guò)于簡(jiǎn)略了呢,好胸嘁,現(xiàn)在就來(lái)

看看那具體的吧瓶摆。首先看看xml有什么參數(shù)吧

 <com.example.jack.besselcurve.BesselCurveView 
    android:id="@+id/besselCurveView" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:background="#ffffff" 
    android:layout_centerHorizontal="true" 
    app:besselColor="@color/besselColor" 
    app:besselColorText="@color/besselColorText" 
    app:friendAverageStep="6752" 
    app:averageStep="2603" 
    app:champion="Jack" 
    app:allStep="8765" 
    app:time="17:26" 
    app:ranking="15">
 </com.example.jack.besselcurve.BesselCurveView>

各參數(shù)對(duì)應(yīng)的解釋如下:

//時(shí)間 
private String time; 
//所有步數(shù) 
private int allStop; 
//還有平均步數(shù) 
private int friendAverageStep; 
//平均步數(shù) 
private int averageStep; 
//排名 
private String ranking; 
//頭像 
private Bitmap champion_icon; 
//冠軍名字 
private String champion;

接著代碼段初始化所有參數(shù):

TypedArray mTypedArray=context.getTheme().obtainStyledAttributes(attrs,R.styleable.BesselCurveView,defStyleAttr,0); 
int numCount=mTypedArray.getIndexCount(); 
for(int i=0;i<numCount;i++){ 
int attr=mTypedArray.getIndex(i); 
switch(attr){ 
     case R.styleable.BesselCurveView_allStep: 
     allStop=mTypedArray.getInt(attr,0); 
     break; 
case R.styleable.BesselCurveView_averageStep: 
     averageStep=mTypedArray.getInt(attr,0); 
     break; 
case R.styleable.BesselCurveView_friendAverageStep: 
     friendAverageStep = mTypedArray.getInt(attr,0); 
     break; 
case R.styleable.BesselCurveView_time: 
     time=mTypedArray.getString(attr); 
     break; 
case R.styleable.BesselCurveView_ranking: 
     ranking=mTypedArray.getString(attr); 
     break;
case R.styleable.BesselCurveView_champion: 
     champion=mTypedArray.getString(attr); 
     break; 
case R.styleable.BesselCurveView_besselColor: 
     mBesselCurveColor=mTypedArray.getColor(attr,Color.BLUE); 
     break; 
case R.styleable.BesselCurveView_besselColorText:
    besselColorText=mTypedArray.getColor(attr,Color.GRAY); break; 
  }
}

這些都是每個(gè)自定義都有的相當(dāng)于模板,來(lái)初始化參數(shù)性宏,都看的明白吧群井。接下來(lái)也很簡(jiǎn)單,就是初始化畫(huà)筆等變量毫胜,以便于后面看畫(huà)圖更簡(jiǎn)單:

public void initValue(){ 
animSet=new AnimatorSet(); 
//外圓的畫(huà)筆 
mCirclePaint=new Paint(Paint.ANTI_ALIAS_FLAG);
mCirclePaint.setStyle(Paint.Style.STROKE); 
mCirclePaint.setStrokeWidth(radius/10); 
mCirclePaint.setStrokeJoin(Paint.Join.ROUND);
mCirclePaint.setStrokeCap(Paint.Cap.ROUND); 
mCirclePaint.setAntiAlias(true); 
//中間的文字的畫(huà)筆 
mCenterTextPaint=new Paint(); 
mCenterTextPaint.setColor(mBesselCurveColor); 
mCenterTextPaint.setTextSize(radius/5); 
mCenterTextPaint.setAntiAlias(true); 
//除中間之外的文字的畫(huà)筆 
mTextPaint=new Paint(); 
mTextPaint.setAntiAlias(true); 
//最低下的矩形 
mBottomRectPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
mBottomRectPaint.setColor(mBesselCurveColor); 
mBottomRectPaint.setAntiAlias(true); 
//虛線的畫(huà)筆 
mDottedLinePaint = new Paint(); 
mDottedLinePaint.setAntiAlias(true); 
mDottedLinePaint.setStyle(Paint.Style.STROKE); 
mDottedLinePaint.setStrokeWidth(2); mDottedLinePaint.setColor(mBesselCurveColor); mDottedLinePaint.setPathEffect(new DashPathEffect(new float[]{5,5},1)); //畫(huà)波浪線畫(huà)筆 WavylinesPaint=new Paint(); WavylinesPaint = new Paint(Paint.ANTI_ALIAS_FLAG); WavylinesPaint.setColor(wavyColor); WavylinesPaint.setStyle(Paint.Style.FILL_AND_STROKE); //虛線的畫(huà)線 mDottedLinePath=new Path(); 
//畫(huà)波浪線畫(huà)線 
WavyLinePath=new Path(); 
//底下更多的畫(huà)線 
morePath=new Path(); 
mWaveCount = (int) Math.round(widthView / mWaveLength + 1.5);
marginBottomText=radius/4; 
}

好了书斜,最重要的初始化都差不多了,現(xiàn)在就來(lái)畫(huà)圖(畫(huà)畫(huà))吧先貼出所有畫(huà)的代碼然后再逐一講解吧:

protected void onDraw(Canvas canvas) { 
super.onDraw(canvas); 
canvas.save(); 
canvas.translate(widthView/2,(heightView*((float)2/3))/2); 
//畫(huà)內(nèi)圓圈 
   mCirclePaint.setColor(besselColorText); 
   RectF mCircleRectF=new RectF(-radius,-radius,radius,radius); 
   canvas.drawArc(mCircleRectF,120,300,false,mCirclePaint); 
//畫(huà)外圓圈 
   mCirclePaint.setColor(mBesselCurveColor); 
   canvas.drawArc(mCircleRectF,120,mCircleNum,false,mCirclePaint); 
//畫(huà)中間的文字
   Rect mCenterRect=new Rect(); String tempAllStop=mCenterNum+""; 
   mCenterTextPaint.getTextBounds(tempAllStop,0,tempAllStop.length(),mCenterRect);
   int halfWidthText=(mCenterRect.right-mCenterRect.left)/2; 
   int halfHeightText=(mCenterRect.bottom-mCenterRect.top)/2; 
   canvas.drawText(tempAllStop,-halfWidthText,halfHeightText,mCenterTextPaint); 
//畫(huà)上邊的文字 
  mTextPaint.setColor(besselColorText); mTextPaint.setTextSize(radius/6); 
  String tempFriendAverageStep=stringTemplate(R.string.besselTime,time); 
  Rect mTopRect=new Rect();     mTextPaint.getTextBounds(tempFriendAverageStep,0,tempFriendAverageStep.length(),mTopRect); 
  int halfTopWidthText=(mTopRect.right-mTopRect.left)/2;    
  canvas.drawText(tempFriendAverageStep,-halfTopWidthText,-(halfHeightText+marginText),mTextPaint); 
//畫(huà)下邊的文字 String     
  tempAverageStep=stringTemplate(R.string.friendAverageStep,friendAverageStep+"");   
  Rect mBottomRect=new Rect(); 
 mTextPaint.getTextBounds(tempAverageStep,0,tempAverageStep.length(),mBottomRect);
  int halfBottomWidthText=(mBottomRect.right-mBottomRect.left)/2; 
  int mBottomHeightText=(mBottomRect.bottom-mBottomRect.top);
  canvas.drawText(tempAverageStep,-  halfBottomWidthText,mBottomHeightText+halfHeightText+marginText,mTextPaint); 
//畫(huà)排名 Rect mNumRect=new Rect(); 
  mCenterTextPaint.getTextBounds(ranking,0,ranking.length(),mNumRect); 
  int halfNum=(mNumRect.right-mNumRect.left)/2; 
  mCenterTextPaint.setTextSize(40); canvas.drawText(ranking,-  halfNum,radius,mCenterTextPaint); 
  String rankingLeft=getContext().getResources().getString(R.string.ranking_left); 
  mTextPaint.getTextBounds(rankingLeft,0,rankingLeft.length(),mNumRect);
  canvas.drawText(rankingLeft,-halfNum-(mNumRect.right-  mNumRect.left)/2-20,radius,mTextPaint);   
canvas.drawText(getContext().getResources().getString(R.string.ranking_right),halfNum+10,radius,mTextPaint); 
canvas.restore(); 
//畫(huà)最近七天和平均運(yùn)動(dòng) 
  mTextPaint.setTextSize(radius/9); canvas.save(); canvas.translate(0,heightView*((float)2/3));   
canvas.drawText(getContext().getResources().getString(R.string.nextSevenDay),marginLi neChart,0,mTextPaint); 
  Rect mPercentRect=new Rect(); 
  String mPercentText=stringTemplate(R.string.averageStep,averageStep+""); 
  mTextPaint.getTextBounds(mPercentText,0,mPercentText.length(),mPercentRect);
  canvas.drawText(mPercentText,widthView-marginLineChart-(mPercentRect.right-  mPercentRect.left),0,mTextPaint); 
//畫(huà)虛線 
  mDottedLinePath.moveTo(marginLineChart,marginBottomText); 
  mDottedLinePath.lineTo(widthView-marginLineChart,marginBottomText); 
  canvas.drawPath(mDottedLinePath,mDottedLinePaint); 
//畫(huà)7天數(shù)據(jù)柱狀圖 mTextPaint.setTextSize(radius/9);
   int lineWidth=(widthView-marginLineChart*2)/8; 
  mCalendar.setTime(new Date()); 
  RectF mRecf=null; 
  if(mListStep.size()>0){ 
  for(int i=mListStep.size();i>=1;i--){ 
  if(mListStep.get(i-1)!=0){ 
  int startX=marginLineChart+lineWidth*i-radius/23; 
  int endX=marginLineChart+lineWidth*i+radius/23; 
  if(mListStep.get(i-1)>mStandardStop){ 
//達(dá)標(biāo) mTextPaint.setColor(mBesselCurveColor); 
  int exceed=mListStep.get(i-1)-mStandardStop; 
  float standard=(float)
  (mCircleRectHeight*Double.valueOf(exceed/Double.valueOf(mStandardStop))); 
  mRecf=new RectF(startX,marginBottomText-(standard>mCircleRectHeight?mCircleRectHeight:standard) ,endX,marginBottomText+mCircleRectHeight);
  canvas.drawRoundRect(mRecf,50,50,mTextPaint); 
}else{ 
//不達(dá)標(biāo)
  mTextPaint.setColor(besselColorText); 
  float noStandard=(float)(mCircleRectHeight*Double.valueOf(mListStep.get(i-1)/Double.valueOf(mStandardStop))); 
  mRecf=new RectF(startX,marginBottomText,endX,marginBottomText+(   noStandard>mCircleRectHeight?mCircleRectHeight:noStandard)); 
  canvas.drawRoundRect(mRecf,50,50,mTextPaint);
 }
 } 
//畫(huà)底下的日期 
  mTextPaint.setColor(besselColorText); 
mCalendar.set(Calendar.DAY_OF_MONTH,mCalendar.get(Calendar.DAY_OF_MONTH)-1); 
  Rect rect =new Rect();
  String number=stringTemplate(R.string.day,mCalendar.get(Calendar.DAY_OF_MONTH)+"");
   mTextPaint.getTextBounds(number,0,number.length(),rect); 
   canvas.drawText(number,(marginLineChart+lineWidth*i)-(rect.right-rect.left)/2,marginBottomText+70,mTextPaint); 
} 
} 
  canvas.restore();
 //畫(huà)波浪圖形 
  canvas.save(); 
  float mWavyHeight=heightView*((float)4/5)+50; 
  canvas.translate(0,mWavyHeight); 
  WavyLinePath.reset(); 
  WavyLinePath.moveTo(-mWaveLength+ mOffset,0); 
  int wHeight=radius/5; 
  for(int i=0;i<mWaveCount;i++){ 
    WavyLinePath.quadTo((-mWaveLength*3/4)+(i*mWaveLength)+mOffset,wHeight,(-mWaveLength/2)+(i*mWaveLength)+mOffset,0); 
    WavyLinePath.quadTo((-mWaveLength/4)+(i * mWaveLength)+mOffset,- wHeight,i*mWaveLength+mOffset,0); 
} 
  WavyLinePath.lineTo(widthView,heightView-mWavyHeight); 
  WavyLinePath.lineTo(0,heightView-mWavyHeight);
  WavyLinePath.close();
  canvas.drawPath(WavyLinePath,WavylinesPaint); 
  canvas.restore(); 
//畫(huà)最低的信息 
  float removeHeight=mWavyHeight+(radius/5); 
  canvas.translate(0,removeHeight); 
  float rectHeight=heightView-removeHeight; 
//畫(huà)底下的矩形 
  RectF rect = new RectF(0,0,widthView,rectHeight); 
  canvas.drawRect(rect,mBottomRectPaint); 
//畫(huà)頭像 
  int bitmap_icon_x=radius/5;
  float centerHeight=rectHeight/2; 
  Bitmap bitmap_icon=getRoundCornerImage(champion_icon,50,radius/5,radius/5); 
  canvas.drawBitmap(bitmap_icon,bitmap_icon_x,centerHeight-  bitmap_icon.getHeight()/2,null);
  mTextPaint.setColor(Color.WHITE); mTextPaint.setTextSize(radius/8);
 //畫(huà)冠軍文字 
  int champion_x=radius/2; Rect mNameRect=new Rect(); 
  String championMame=stringTemplate(R.string.champion,champion); 
  mTextPaint.getTextBounds(championMame,0,championMame.length(),mNameRect); 
  canvas.drawText(championMame,champion_x,(rectHeight+(mNameRect.bottom-mNameRect.top))/2,mTextPaint); 
//畫(huà)查看 
  String look=getContext().getResources().getString(R.string.check); 
  mTextPaint.getTextBounds(look,0,look.length(),mNameRect); 
  canvas.drawText(look,widthView-(radius*(float)2/3),(rectHeight+(mNameRect.bottom-mNameRect.top))/2,mTextPaint);
 //畫(huà)更多圖像 
  float morePoint=(radius*(float)2/3)/2; 
  canvas.drawLine(widthView-morePoint,centerHeight-(mNameRect.bottom-  mNameRect.top)/2, widthView-morePoint+15,centerHeight,mTextPaint);
  canvas.drawLine(widthView-morePoint+15,centerHeight,widthView-morePoint,    centerHeight+(mNameRect.bottom-mNameRect.top)/2,mTextPaint);
 }

代碼是不是有點(diǎn)多呢,沒(méi)辦法畫(huà)的東西本身就有點(diǎn)多了。好了剛開(kāi)始我說(shuō)要移動(dòng)canvas的原點(diǎn)是不是,你看剛開(kāi)始就移動(dòng)了吧:

  super.onDraw(canvas);
  canvas.save();
  canvas.translate(widthView/2,(heightView*((float)2/3))/2);

1惑淳、移動(dòng)原點(diǎn)到整個(gè)圓弧的中心,其中widthView是整個(gè)view的寬样屠,heightView是整個(gè)view的高,如下圖:


center.PNG

就在上圖的藍(lán)色點(diǎn)就是現(xiàn)在的原點(diǎn)。
然后在這原點(diǎn)里畫(huà)圓弧唄缺脉,代碼如下

 //畫(huà)內(nèi)圓圈 
mCirclePaint.setColor(besselColorText); 
RectF mCircleRectF=new RectF(-radius,-radius,radius,radius); 
canvas.drawArc(mCircleRectF,120,300,false,mCirclePaint);
 //畫(huà)外圓圈 
mCirclePaint.setColor(mBesselCurveColor); 
canvas.drawArc(mCircleRectF,120,mCircleNum,false,mCirclePaint);

mCircleNum是為了實(shí)現(xiàn)動(dòng)畫(huà)效果的瞧哟,這后面會(huì)講,這樣圓弧就畫(huà)完了枪向。效果也是如上圖。
2.在中心點(diǎn)再畫(huà)今天的走的總路程咧党,代碼如下:

 //畫(huà)中間的文字 
Rect mCenterRect=new Rect(); 
String tempAllStop=mCenterNum+""; 
mCenterTextPaint.getTextBounds(tempAllStop,0,tempAllStop.length(),mCenterRect);
int halfWidthText=(mCenterRect.right-mCenterRect.left)/2; 
int halfHeightText=(mCenterRect.bottom-mCenterRect.top)/2; 
canvas.drawText(tempAllStop,-halfWidthText,halfHeightText,mCenterTextPaint);

基本的實(shí)現(xiàn)思路是用Rect在這個(gè)類(lèi)計(jì)算出你要畫(huà)文字的大小秘蛔,然后在原點(diǎn)畫(huà),不過(guò),記得這里的x,y點(diǎn)是在原點(diǎn)的左下深员,具體詳解看這里寫(xiě)鏈接內(nèi)容
接這就是畫(huà)時(shí)間和好友平均步數(shù)负蠕,其實(shí)實(shí)現(xiàn)原理也是一樣的,只不過(guò)在上面的高度是

canvas.drawText(tempFriendAverageStep,-halfTopWidthText,-(halfHeightText+marginText),mTextPaint);

是中心總步數(shù)高度的一半再加間隔倦畅,而下面的是:

canvas.drawText(tempAverageStep,-halfBottomWidthText,mBottomHeightText+halfHeightText+marginText,mTextPaint);

是下面文字總的高度再加上中心總步數(shù)高度的一半再加間隔≌谔牵現(xiàn)在效果如下圖:

img1.PNG

接著就是畫(huà)排名,首先還是套路:

Rect mNumRect=new Rect(); 
mCenterTextPaint.getTextBounds(ranking,0,ranking.length(),mNumRect); 
int halfNum=(mNumRect.right-mNumRect.left)/2; 
mCenterTextPaint.setTextSize(40); 
canvas.drawText(ranking,-halfNum,radius,mCenterTextPaint);

計(jì)算出排名文字的大小叠赐,然后在中心原點(diǎn)x軸為排名文字的一半欲账,y軸問(wèn)為半徑畫(huà)出排名,效果圖如下:

img2.PNG

接著就在排名的兩端畫(huà)文字就行了芭概,帶代碼如下:

String rankingLeft=getContext().getResources().getString(R.string.ranking_left); 
mTextPaint.getTextBounds(rankingLeft,0,rankingLeft.length(),mNumRect); 
canvas.drawText(rankingLeft,-halfNum-(mNumRect.right-mNumRect.left)/2-20,radius,mTextPaint); 
canvas.drawText(getContext().getResources().getString(R.string.ranking_right),halfNum+10,radius,mTextPaint); 

思路還是一樣赛不,就不說(shuō)了。此時(shí)效果

img3.PNG

畫(huà)底下柱狀圖是罢洲,首先用canvas.restore();恢復(fù)原點(diǎn)到(0,0)的狀態(tài)踢故,再用canvas.translate(0,heightView*((float)2/3));把原點(diǎn)移動(dòng)到圓弧的下面,接著又可以繼續(xù)畫(huà),實(shí)現(xiàn)思路和前面一樣:

//畫(huà)最近七天和平均運(yùn)動(dòng) 
mTextPaint.setTextSize(radius/9); 
canvas.save(); canvas.translate(0,heightView*((float)2/3)); 
canvas.drawText(getContext().getResources().getString(R.string.nextSevenDay),marginLineChart,0,mTextPaint); 
Rect mPercentRect=new Rect();
 String mPercentText=stringTemplate(R.string.averageStep,averageStep+""); 
mTextPaint.getTextBounds(mPercentText,0,mPercentText.length(),mPercentRect); 
canvas.drawText(mPercentText,widthView-marginLineChart-(mPercentRect.right-mPercentRect.left),0,mTextPaint); 
//畫(huà)虛線
 mDottedLinePath.moveTo(marginLineChart,marginBottomText); 
mDottedLinePath.lineTo(widthView-marginLineChart,marginBottomText); 
canvas.drawPath(mDottedLinePath,mDottedLinePaint);

此時(shí)效果如下:

img4.PNG

接下來(lái)畫(huà)柱狀圖惹苗,首先int lineWidth=(widthView-marginLineChart*2)/8;計(jì)算出每個(gè)點(diǎn)之間的間隔

img5.PNG
if(mListStep.size()>0){ 
  for(int i=mListStep.size();i>=1;i--){ 
    if(mListStep.get(i-1)!=0){ 
    //計(jì)算出起始點(diǎn)X和終點(diǎn)X的值 
     int startX=marginLineChart+lineWidth*i-radius/23; 
     int endX=marginLineChart+lineWidth*i+radius/23; 
    if(mListStep.get(i-1)>mStandardStop){ 
   //達(dá)標(biāo) mTextPaint.setColor(mBesselCurveColor); 
   //超出的部分  
     int exceed=mListStep.get(i-1)-mStandardStop;
  //算出柱體大小 float standard=(float)   (mCircleRectHeight*Double.valueOf(exceed/Double.valueOf(mStandardStop))); 
    mRecf=new RectF(startX,marginBottomText-(standard>mCircleRectHeight?mCircleRectHeight:standard) ,endX,marginBottomText+mCircleRectHeight); 
   canvas.drawRoundRect(mRecf,50,50,mTextPaint); 
}else{ 
  //不達(dá)標(biāo) 
   mTextPaint.setColor(besselColorText); 
 //算出不達(dá)標(biāo)柱體的大小 
  float noStandard=(float)(mCircleRectHeight*Double.valueOf(mListStep.get(i-1)/Double.valueOf(mStandardStop))); 
   mRecf=new RectF(startX,marginBottomText,endX,marginBottomText+(   noStandard>mCircleRectHeight?mCircleRectHeight:noStandard)); 
   canvas.drawRoundRect(mRecf,50,50,mTextPaint); 
}
} 
 //畫(huà)底下的日期 
   mTextPaint.setColor(besselColorText); 
mCalendar.set(Calendar.DAY_OF_MONTH,mCalendar.get(Calendar.DAY_OF_MONTH)-1); 
   Rect rect =new Rect(); 
   String number=stringTemplate(R.string.day,mCalendar.get(Calendar.DAY_OF_MONTH)+"");
   mTextPaint.getTextBounds(number,0,number.length(),rect); 
   canvas.drawText(number,(marginLineChart+lineWidth*i)-(rect.right-rect.left)/2,marginBottomText+70,mTextPaint); 
} 
}

mStandardStop是達(dá)標(biāo)的數(shù)據(jù)殿较,當(dāng)數(shù)據(jù)小于mStandardStop就是不達(dá)標(biāo),所以柱狀圖就要畫(huà)在虛線的下面桩蓉,mCircleRectHeight是柱狀圖一半的高
float standard=(float)(mCircleRectHeight*Double.valueOf(exceed/Double.valueOf(mStandardStop)));這句代碼是計(jì)算出下面圓柱體的具體大小淋纲,noStandard>mCircleRectHeight?mCircleRectHeight:noStandard當(dāng),但柱狀圖大于mCircleRectHeight時(shí)就用mCircleRectHeight不然就根據(jù)計(jì)算的數(shù)值來(lái)触机。當(dāng)數(shù)據(jù)大于mStandardStop時(shí)帚戳,
int exceed=mListStep.get(i-1)-mStandardStop;float standard=(float)(mCircleRectHeight*Double.valueOf(exceed/Double.valueOf(mStandardStop)));exceed是計(jì)算出超出的部分,再拿超出的部分算出具體的大小儡首,剩下的和小于的一樣片任,當(dāng)standard大于最大的mCircleRectHeight是就用mCircleRectHeight否則就用standard。底下日期是用Calendar得到前7天的日期再循環(huán)的畫(huà)上去蔬胯,思路和上面一樣不再贅述对供。此時(shí)效果如下:

img6.PNG

接下來(lái)是畫(huà)波浪,畫(huà)波浪是用了貝塞爾曲線的方法畫(huà)的氛濒,如果不懂貝塞爾曲線請(qǐng)參考這里寫(xiě)鏈接內(nèi)容产场,這也是我學(xué)貝塞爾曲線參考的內(nèi)容。首先我們又把canvas恢復(fù)到原點(diǎn)canvas.restore();再用float mWavyHeight=heightView*((float)4/5)+50; canvas.translate(0,mWavyHeight);移動(dòng)這個(gè)位置舞竿,是為了適配京景。

WavyLinePath.reset(); 
WavyLinePath.moveTo(-mWaveLength+ mOffset,0); 
int wHeight=radius/5; for(int i=0;i<mWaveCount;i++){ 
WavyLinePath.quadTo((-mWaveLength*3/4)+(i*mWaveLength)+mOffset,wHeight,(-mWaveLength/2)+(i*mWaveLength)+mOffset,0); 
WavyLinePath.quadTo((-mWaveLength/4)+(i * mWaveLength)+mOffset,-wHeight,i*mWaveLength+mOffset,0); 
} 
WavyLinePath.lineTo(widthView,heightView-mWavyHeight); 
WavyLinePath.lineTo(0,heightView-mWavyHeight); 
WavyLinePath.close(); 
canvas.drawPath(WavyLinePath,WavylinesPaint);

WavyLinePath.quadTo就是貝塞爾曲線調(diào)的方法,for循環(huán)幾次使之形成波浪圖形骗奖,記得一樣要WavyLinePath.lineTo().不讓會(huì)出現(xiàn)底下有些地方會(huì)畫(huà)不到确徙。原理是向上定一個(gè)控制點(diǎn)有向下定一個(gè)控制點(diǎn)使之形成一個(gè)sin函數(shù)圖形醒串。具體請(qǐng)學(xué)貝塞爾曲線。此時(shí)效果圖:

img7.PNG

最后就是畫(huà)底下的矩形和頭像和文字了鄙皇。最值得講的是頭像我一開(kāi)始的設(shè)想的傳Url的芜赌,不過(guò)這樣子又要做網(wǎng)絡(luò)方面的代碼工作,這樣子會(huì)破懷類(lèi)的功能單一性原則伴逸,所以最后我實(shí)在外部傳一個(gè)位圖缠沈,在位圖進(jìn)行處理使其圓角。剩下的只是畫(huà)文字而已错蝴,上面已經(jīng)講夠多了洲愤,就不在講了。
對(duì)了漱竖,最后還有一個(gè)剛開(kāi)始的動(dòng)畫(huà)效果禽篱。

public void startAnimator(){ 
     ValueAnimator mCircleAminator=ValueAnimator.ofFloat(0f,300f); 
     mCircleAminator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { 
     mCircleNum=(float)animation.getAnimatedValue(); postInvalidate();
 } 
}); 
   ValueAnimator mCenterText=ValueAnimator.ofInt(0,allStop); 
mCenterText.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { 
mCenterNum=(int)animation.getAnimatedValue(); postInvalidate(); 
} }); 
ValueAnimator mWavyAnimator = ValueAnimator.ofInt(0, mWaveLength); 
mWavyAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { 
mOffset = (int) animation.getAnimatedValue(); postInvalidate(); 
} }); 
animSet.setDuration(2000); 
animSet.playTogether(mCircleAminator,mCenterText,mWavyAnimator); 
animSet.start(); 
}
 //字符串拼接 
public String stringTemplate(int template,String content){ 
return String.format(getContext().getResources().getString(template),content);
 }

其實(shí)也簡(jiǎn)單通過(guò)設(shè)置ValueAnimator讓它在規(guī)定的時(shí)間內(nèi)產(chǎn)生數(shù)值的變化,再調(diào)用postInvalidate().對(duì)View的界面進(jìn)行刷新即可實(shí)現(xiàn)動(dòng)畫(huà)效果馍惹。

最后給源碼好好研究吧源碼只有好好看源碼才能學(xué)到更多東西躺率。

如果對(duì)你有幫助就請(qǐng)給我給星星或喜歡吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末万矾,一起剝皮案震驚了整個(gè)濱河市悼吱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌良狈,老刑警劉巖后添,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異薪丁,居然都是意外死亡遇西,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)严嗜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)粱檀,“玉大人,你說(shuō)我怎么就攤上這事漫玄∏羊牵” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵睦优,是天一觀的道長(zhǎng)渗常。 經(jīng)常有香客問(wèn)我,道長(zhǎng)汗盘,這世上最難降的妖魔是什么皱碘? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮隐孽,結(jié)果婚禮上尸执,老公的妹妹穿的比我還像新娘家凯。我一直安慰自己,他們只是感情好如失,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著送粱,像睡著了一般褪贵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上抗俄,一...
    開(kāi)封第一講書(shū)人閱讀 49,764評(píng)論 1 290
  • 那天脆丁,我揣著相機(jī)與錄音,去河邊找鬼动雹。 笑死槽卫,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的胰蝠。 我是一名探鬼主播歼培,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼茸塞!你這毒婦竟也來(lái)了躲庄?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤钾虐,失蹤者是張志新(化名)和其女友劉穎噪窘,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體效扫,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡倔监,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了菌仁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片浩习。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖掘托,靈堂內(nèi)的尸體忽然破棺而出瘦锹,到底是詐尸還是另有隱情,我是刑警寧澤闪盔,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布弯院,位于F島的核電站,受9級(jí)特大地震影響泪掀,放射性物質(zhì)發(fā)生泄漏听绳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一异赫、第九天 我趴在偏房一處隱蔽的房頂上張望椅挣。 院中可真熱鬧头岔,春花似錦、人聲如沸鼠证。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)量九。三九已至适掰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間荠列,已是汗流浹背类浪。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留肌似,地道東北人费就。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像川队,于是被迫代替她去往敵國(guó)和親力细。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,744評(píng)論 25 707
  • 系列文章之 Android中自定義View(一)系列文章之 Android中自定義View(二)系列文章之 And...
    YoungerDev閱讀 4,385評(píng)論 3 11
  • 自定義控件教程: 1呼寸,http://blog.csdn.net/aigestudio/article/detail...
    CoderGC閱讀 1,652評(píng)論 1 11
  • 昨天公司組織培訓(xùn)艳汽,內(nèi)容是打造狼性團(tuán)隊(duì)。彪哥和端哥都是組長(zhǎng)对雪,他們關(guān)系很好河狐,端哥是我組長(zhǎng)。培訓(xùn)老師要大家做游戲瑟捣,用面...
    Mokiil閱讀 271評(píng)論 0 1
  • 這幾天休息的不是很好馋艺,究其原因我發(fā)現(xiàn)是自己對(duì)自己的表現(xiàn)不滿意。我在意師傅的批評(píng)迈套,也反感自己的幼稚和不走心捐祠。熬夜看完...
    嘆誰(shuí)逍遙閱讀 138評(píng)論 0 0