欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android自定義view之仿支付寶芝麻信用儀表盤示例

 更新時(shí)間:2017年01月12日 09:19:10   作者:勇朝陳  
本篇文章主要介紹了Android自定義view之仿支付寶芝麻信用儀表盤,具有一定的參考價(jià)值,有興趣的可以了解一下。

自定義view練習(xí) 仿支付寶芝麻信用的儀表盤

對(duì)比圖:

首先是自定義一些屬性,可自己再添加,挺基礎(chǔ)的,上代碼

<?xml version="1.0" encoding="utf-8"?> 
<resources> 
  <declare-styleable name="RoundIndicatorView"> 
    <!--最大數(shù)值--> 
    <attr name="maxNum" format="integer"/> 
    <!--圓盤起始角度--> 
    <attr name="startAngle" format="integer"/> 
    <!--圓盤掃過的角度--> 
    <attr name="sweepAngle" format="integer"/> 
  </declare-styleable> 
</resources> 

接著在構(gòu)造方法里初始化自定義屬性和畫筆:

private void initAttr(AttributeSet attrs) { 
  TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.RoundIndicatorView); 
  maxNum = array.getInt(R.styleable.RoundIndicatorView_maxNum,500); 
  startAngle = array.getInt(R.styleable.RoundIndicatorView_startAngle,160); 
  sweepAngle = array.getInt(R.styleable.RoundIndicatorView_sweepAngle,220); 
  //內(nèi)外圓弧的寬度 
  sweepInWidth = dp2px(8);  
  sweepOutWidth = dp2px(3);  
  array.recycle(); 
} 
 
private void initPaint() { 
  paint = new Paint(Paint.ANTI_ALIAS_FLAG); 
  paint.setDither(true); 
  paint.setStyle(Paint.Style.STROKE); 
  paint.setColor(0xffffffff); 
  paint_2 = new Paint(Paint.ANTI_ALIAS_FLAG); 
  paint_3 = new Paint(Paint.ANTI_ALIAS_FLAG); 
  paint_4 = new Paint(Paint.ANTI_ALIAS_FLAG); 
} 

接下來重寫onMeasure,也是比較簡單,對(duì)于不是確定值的直接給定300*400的大?。?br />

@Override 
 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
 
  super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
 
  int wSize = MeasureSpec.getSize(widthMeasureSpec); 
 
  int wMode = MeasureSpec.getMode(widthMeasureSpec); 
 
  int hSize = MeasureSpec.getSize(heightMeasureSpec); 
 
  int hMode = MeasureSpec.getMode(heightMeasureSpec); 
 
 
 
  if (wMode == MeasureSpec.EXACTLY ){ 
 
    mWidth = wSize; 
 
  }else { 
 
    mWidth =dp2px(300); 
 
  } 
 
  if (hMode == MeasureSpec.EXACTLY ){ 
 
    mHeight= hSize; 
 
  }else { 
 
    mHeight =dp2px(400); 
 
  } 
 
  setMeasuredDimension(mWidth,mHeight); 
 
} 

核心部分onDraw來了,注意圓的半徑不要在構(gòu)造方法里就去設(shè)置,那時(shí)候是得不到view的寬高值的,所以我在onDraw方法里設(shè)置半徑,默認(rèn)就view寬度的1/4吧。把原點(diǎn)移到view的中心去:

@Override 
protected void onDraw(Canvas canvas) { 
  super.onDraw(canvas); 
  radius = getMeasuredWidth()/4; //不要在構(gòu)造方法里初始化,那時(shí)還沒測量寬高 
  canvas.save(); 
  canvas.translate(mWidth/2,(mWidth)/2); 
  drawRound(canvas); //畫內(nèi)外圓弧 
  drawScale(canvas);//畫刻度 
  drawIndicator(canvas); //畫當(dāng)前進(jìn)度值 
  drawCenterText(canvas);//畫中間的文字 
  canvas.restore(); 
} 

步驟清晰,按順序畫出儀表盤的四個(gè)部分,我們一個(gè)一個(gè)部分的看

drawRound():這個(gè)很簡單,內(nèi)外圓弧所需的屬性都已經(jīng)定義好了,畫筆是白色的,我們通過setAlpha()設(shè)置一下它的透明度,范圍是00~ff。

private void drawRound(Canvas canvas) { 
  canvas.save(); 
  //內(nèi)圓 
  paint.setAlpha(0x40); 
  paint.setStrokeWidth(sweepInWidth); 
  RectF rectf = new RectF(-radius,-radius,radius,radius); 
  canvas.drawArc(rectf,startAngle,sweepAngle,false,paint); 
  //外圓 
  paint.setStrokeWidth(sweepOutWidth); 
  int w = dp2px(10); 
  RectF rectf2 = new RectF(-radius-w , -radius-w , radius+w , radius+w); 
  canvas.drawArc(rectf2,startAngle,sweepAngle,false,paint); 
  canvas.restore(); 
} 

第一部分完成,如圖

drawScale():如果你看過幾篇自定義view文章,應(yīng)該都知道了靠旋轉(zhuǎn)畫布來畫刻度和文字的套路了,調(diào)用canvas.rotate就可以旋轉(zhuǎn)畫布,負(fù)數(shù)代表順時(shí)針,這里我們打算把起始位置旋轉(zhuǎn)到原點(diǎn)正上方,即270度的地方,這樣畫刻度和文字的坐標(biāo)就很好計(jì)算了,每畫完一次讓畫布逆時(shí)針轉(zhuǎn)一個(gè)刻度間隔,一直循環(huán)到畫完。我們觀察一下原圖,粗的刻度線一共有6條,數(shù)字的刻度是再粗刻度線下面的,每兩個(gè)粗刻度線之間有5條細(xì)刻度線,并且中間那條細(xì)刻度線下方有對(duì)應(yīng)文字。我們把掃過的角度除以30,就是每個(gè)刻度的間隔了,然后通過判斷就可以畫對(duì)應(yīng)刻度和文字了。

關(guān)于獲取文字的寬高,有兩種方法,一種是paint.measureText(text)測量文字寬度,返回值類型是float,但是得不到高度。另一種是Rect rect = new Rect();paint.getTextBounds(text,0,text.length(),rect); 將文字的屬性放入rect里,不過是int值,我們畫的文字夠小的了,所以最好用第一種,除非需要高度值。

另外,我發(fā)現(xiàn)繪制文字時(shí),坐標(biāo)值代表的是文字的左下角,不同于一般的從左上角,所以canvas.drawText傳入的xy坐標(biāo)是text的左下角坐標(biāo)

private String[] text ={"較差","中等","良好","優(yōu)秀","極好"}; 
private void drawScale(Canvas canvas) { 
  canvas.save(); 
  float angle = (float)sweepAngle/30;//刻度間隔 
  canvas.rotate(-270+startAngle); //將起始刻度點(diǎn)旋轉(zhuǎn)到正上方(270) 
  for (int i = 0; i <= 30; i++) { 
    if(i%6 == 0){  //畫粗刻度和刻度值 
      paint.setStrokeWidth(dp2px(2)); 
      paint.setAlpha(0x70); 
      canvas.drawLine(0, -radius-sweepInWidth/2,0, -radius+sweepInWidth/2+dp2px(1), paint); 
      drawText(canvas,i*maxNum/30+"",paint); 
    }else {     //畫細(xì)刻度 
      paint.setStrokeWidth(dp2px(1)); 
      paint.setAlpha(0x50); 
      canvas.drawLine(0,-radius-sweepInWidth/2,0, -radius+sweepInWidth/2, paint); 
    } 
    if(i==3 || i==9 || i==15 || i==21 || i==27){ //畫刻度區(qū)間文字 
      paint.setStrokeWidth(dp2px(2)); 
      paint.setAlpha(0x50); 
      drawText(canvas,text[(i-3)/6], paint); 
    } 
    canvas.rotate(angle); //逆時(shí)針 
  } 
  canvas.restore(); 
} 
  private void drawText(Canvas canvas ,String text ,Paint paint) { 
    paint.setStyle(Paint.Style.FILL); 
    paint.setTextSize(sp2px(8)); 
    float width = paint.measureText(text); //相比getTextBounds來說,這個(gè)方法獲得的類型是float,更精確些 
//    Rect rect = new Rect(); 
//    paint.getTextBounds(text,0,text.length(),rect); 
    canvas.drawText(text,-width/2 , -radius + dp2px(15),paint); 
    paint.setStyle(Paint.Style.STROKE); 
  } 

第二部分完畢,看圖

drawIndicator:這一步是畫外圓弧上的進(jìn)度值,觀察原圖,發(fā)現(xiàn)有三個(gè)問題需要解決:表示進(jìn)度的弧度值和小圓點(diǎn)的坐標(biāo)怎么計(jì)算,進(jìn)度值的透明度漸變?cè)趺磳?shí)現(xiàn)?小圓點(diǎn)像光源一樣邊緣模糊的效果怎么實(shí)現(xiàn)?

對(duì)于坐標(biāo)計(jì)算,其實(shí)也較簡單,將當(dāng)前值比上最大值,得到一個(gè)比例就可以計(jì)算進(jìn)度條掃過的弧度,小圓點(diǎn)呢繪制與進(jìn)度條的尾端,角度已經(jīng)有了(起始角度+掃過的角度),用三角函數(shù)就可以算了。

對(duì)于顏色漸變,可以用paint的shader渲染,它有5個(gè)子類

  • BitmapShader位圖
  • LinearGradient線性漸變
  • RadialGradient光束漸變
  • SweepGradient梯度漸變
  • ComposeShader混合漸變

 我們使用梯度漸變來實(shí)現(xiàn),傳入坐標(biāo)和一個(gè)顏色數(shù)組就可以實(shí)現(xiàn)對(duì)顏色的梯度漸變,這里我們對(duì)顏色的修改當(dāng)然只是修改它的透明度,我們知道32位的顏色值前8位就是表示透明度的。

對(duì)于小圓點(diǎn)有光源一樣的邊緣模糊效果,我用的是paint的setMaskFilter,其中有一個(gè)子類BlurMaskFilter可以實(shí)現(xiàn)邊緣模糊效果~( 不知道有沒有什么別的方法實(shí)現(xiàn)這種效果)   具體看代碼

private int[] indicatorColor = {0xffffffff,0x00ffffff,0x99ffffff,0xffffffff}; 

這里顏色數(shù)組這樣取值的原因在文章最后說明

private void drawIndicator(Canvas canvas) { 
  canvas.save(); 
  paint_2.setStyle(Paint.Style.STROKE); 
  int sweep; 
  if(currentNum<=maxNum){ 
    sweep = (int)((float)currentNum/(float)maxNum*sweepAngle); 
  }else { 
    sweep = sweepAngle; 
  } 
  paint_2.setStrokeWidth(sweepOutWidth); 
  Shader shader =new SweepGradient(0,0,indicatorColor,null); 
  paint_2.setShader(shader); 
  int w = dp2px(10); 
  RectF rectf = new RectF(-radius-w , -radius-w , radius+w , radius+w); 
  canvas.drawArc(rectf,startAngle,sweep,false,paint_2); 
  float x = (float) ((radius+dp2px(10))*Math.cos(Math.toRadians(startAngle+sweep))); 
  float y = (float) ((radius+dp2px(10))*Math.sin(Math.toRadians(startAngle+sweep))); 
  paint_3.setStyle(Paint.Style.FILL); 
  paint_3.setColor(0xffffffff); 
  paint_3.setMaskFilter(new BlurMaskFilter(dp2px(3), BlurMaskFilter.Blur.SOLID)); //需關(guān)閉硬件加速 
  canvas.drawCircle(x,y,dp2px(3),paint_3); 
  canvas.restore(); 
} 

記得關(guān)閉硬件加速,就是加一句<activity Android:hardwareAccelerated="false" >

第三部完畢,看圖

drawCenterText:這步簡單,注意剛才說的繪制文字時(shí)從左下角開始的和兩種測量文字寬度的區(qū)別就好。

private void drawCenterText(Canvas canvas) { 
  canvas.save(); 
  paint_4.setStyle(Paint.Style.FILL); 
  paint_4.setTextSize(radius/2); 
  paint_4.setColor(0xffffffff); 
  canvas.drawText(currentNum+"",-paint_4.measureText(currentNum+"")/2,0,paint_4); 
  paint_4.setTextSize(radius/4); 
  String content = "信用"; 
  if(currentNum < maxNum*1/5){ 
    content += text[0]; 
  }else if(currentNum >= maxNum*1/5 && currentNum < maxNum*2/5){ 
    content += text[1]; 
  }else if(currentNum >= maxNum*2/5 && currentNum < maxNum*3/5){ 
    content += text[2]; 
  }else if(currentNum >= maxNum*3/5 && currentNum < maxNum*4/5){ 
    content += text[3]; 
  }else if(currentNum >= maxNum*4/5){ 
    content += text[4]; 
  } 
  Rect r = new Rect(); 
  paint_4.getTextBounds(content,0,content.length(),r); 
  canvas.drawText(content,-r.width()/2,r.height()+20,paint_4); 
  canvas.restore(); 
} 

到這里繪制部分差不多完成了。接下來要實(shí)現(xiàn)的是當(dāng)改變值時(shí)的動(dòng)畫效果,同時(shí)改變背景顏色。

setCurrentNumAnim就是供用戶調(diào)用的。我們可以通過屬性動(dòng)畫來改變當(dāng)前值,注意要給當(dāng)前值(currentNum)加上setter和getter,因?yàn)閷傩詣?dòng)畫內(nèi)部需要調(diào)用它們。

對(duì)于動(dòng)畫的時(shí)間,簡單寫個(gè)計(jì)算公式就好,然后監(jiān)聽動(dòng)畫過程,在里面實(shí)現(xiàn)背景顏色的改變。怎么才能像支付寶芝麻信用那樣紅橙黃綠藍(lán)的漸變呢?我按自己思路實(shí)現(xiàn)了一個(gè)可以三種顏色之間漸變的效果。

大家學(xué)習(xí)屬性動(dòng)畫時(shí)應(yīng)該了解過插值器估值器的作用,我就是用ArgbEvaluator估值器實(shí)現(xiàn)顏色漸變的,調(diào)用它的evaluate方法,傳入一個(gè)0~1的比例,傳入開始和結(jié)束的顏色,就可以根據(jù)當(dāng)前比例得到介于這兩個(gè)顏色之間的顏色值。

這里我實(shí)現(xiàn)了紅到橙再到藍(lán)的漸變,假設(shè)最大值是500,那么當(dāng)前值x從0~250的過程中是從紅到橙,x/(500/2)就可以得到一個(gè)0~1的變化比例,當(dāng)前值從250~500的過程是橙到藍(lán),也需要一個(gè)0~1的變化過程的比例,計(jì)算方法就是(x-250)/(250)  其中250就是(500/2)得來的。按照這樣的思路當(dāng)然可以實(shí)現(xiàn)更多顏色之間的漸變,就是想辦法在各區(qū)間里算出一個(gè)0~1的比例值就行。注意數(shù)據(jù)類型轉(zhuǎn)換,上代碼!

public int getCurrentNum() { 
  return currentNum; 
} 
 
public void setCurrentNum(int currentNum) { 
  this.currentNum = currentNum; 
  invalidate(); 
} 
public void setCurrentNumAnim(int num) { 
  float duration = (float)Math.abs(num-currentNum)/maxNum *1500+500; //根據(jù)進(jìn)度差計(jì)算動(dòng)畫時(shí)間 
  ObjectAnimator anim = ObjectAnimator.ofInt(this,"currentNum",num); 
  anim.setDuration((long) Math.min(duration,2000)); 
  anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 
    @Override 
    public void onAnimationUpdate(ValueAnimator animation) { 
      int value = (int) animation.getAnimatedValue(); 
      int color = calculateColor(value); 
      setBackgroundColor(color); 
    } 
  }); 
  anim.start(); 
} 
private int calculateColor(int value){ 
  ArgbEvaluator evealuator = new ArgbEvaluator(); 
  float fraction = 0; 
  int color = 0; 
  if(value <= maxNum/2){ 
    fraction = (float)value/(maxNum/2); 
    color = (int) evealuator.evaluate(fraction,0xFFFF6347,0xFFFF8C00); //由紅到橙 
  }else { 
    fraction = ( (float)value-maxNum/2 ) / (maxNum/2); 
    color = (int) evealuator.evaluate(fraction,0xFFFF8C00,0xFF00CED1); //由橙到藍(lán) 
  } 
  return color; 
} 

鏘鏘鏘~ 完畢外部調(diào)用setCurrentNumAnim就可以動(dòng)畫的改變數(shù)值啦

好了,還有最后一個(gè)問題,就是前面提到的

為什么透明度漸變的顏色數(shù)組是這樣的

private int[] indicatorColor = {0xffffffff,0x00ffffff,0x99ffffff,0xffffffff}; 

大概就是從不透明-->透明-->半透明-->不透明的變化

問:第一個(gè)不是多余的么?為什么要一開始不透明?

答:我也有點(diǎn)納悶,因?yàn)閟weepGradient顏色漸變是從x正軸開始的,如果我顏色數(shù)組是這樣的,即從透明-->半透明-->不透明:

private int[] indicatorColor = {0x00ffffff,0x99ffffff,0xffffffff}; 

那么畫個(gè)圓是長這樣的

而我們的儀表盤這里是從160度開始,掃220度,也就是如果這樣有一部分角度(0~20度)會(huì)變透明,不是我們想要的效果。。。所以我用了這樣:

private int[] indicatorColor = {0xffffffff,0x00ffffff,0x99ffffff,0xffffffff}; 

這樣的數(shù)組。。畫出來是這樣的

這樣至少保證0~20度看起來也是很白的,整個(gè)進(jìn)度條就實(shí)現(xiàn)了像從透明到不透明的效果。

其實(shí)也不是很優(yōu)雅。。因?yàn)槠鹗冀嵌群蛼哌^的角度是可以自定義更改的。。所以小伙伴們有什么更好的方法么?

源碼地址:http://xiazai.jb51.net/201701/yuanma/diy_roundindicator_jb51.rar

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論