乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      自定義 View

       quasiceo 2016-08-03

      定義 View——Canvas 與 ValueAnimator – Idtk

      時(shí)間 2016-05-27 13:40:39 Idtk

      涉及知識(shí)

      繪制過(guò)程

      類別 API 描述
      布局 onMeasure 測(cè)量View與Child View的大小

      onLayout 確定Child View的位置

      onSizeChanged 確定View的大小
      繪制 onDraw 實(shí)際繪制View的內(nèi)容
      事件處理 onTouchEvent 處理屏幕觸摸事件
      重繪 invalidate 調(diào)用onDraw方法,重繪View中變化的部分

      (如果對(duì)繪制過(guò)程與構(gòu)造函數(shù)還不了解的,請(qǐng)查看我之前文章 自定義View——Android坐標(biāo)系與View繪制流程 )

      Canvas涉及方法

      類別 API 描述
      繪制圖形 drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc 依次為繪制點(diǎn)、直線、矩形、圓角矩形、橢圓、圓、扇形
      繪制文本 drawText, drawPosText, drawTextOnPath 依次為繪制文字、指定每個(gè)字符位置繪制文字、根據(jù)路徑繪制文字
      畫布變換 translate, scale, rotate, skew 依次為平移、縮放、旋轉(zhuǎn)、傾斜(錯(cuò)切)
      畫布裁剪 clipPath, clipRect, clipRegion 依次為按路徑、按矩形、按區(qū)域?qū)Ξ嫴歼M(jìn)行裁剪
      畫布狀態(tài) save,restore 保存當(dāng)前畫布狀態(tài),恢復(fù)之前保存的畫布

      Paint涉及方法

      類別 API 描述
      顏色 setColor,setARGB,setAlpha 依次為設(shè)置畫筆顏色、透明度
      類型 setStyle 填充(FILL),描邊(STROKE),填充加描邊(FILL_AND_STROKE)
      抗鋸齒 setAntiAlias 畫筆是否抗鋸齒
      字體大小 setTextSize 設(shè)置字體大小
      字體測(cè)量 getFontMetrics(),getFontMetricsInt() 返回字體的測(cè)量,返回值一次為float、int
      文字寬度 measureText 返回文字的寬度
      文字對(duì)齊方式 setTextAlign 左對(duì)齊(LEFT),居中對(duì)齊(CENTER),右對(duì)齊(RIGHT)
      寬度 setStrokeWidth 設(shè)置畫筆寬度
      筆鋒 setStrokeCap 默認(rèn)(BUTT),半圓形(ROUND),方形(SQUARE)

      (PS: 因API較多,只列出了涉及的方法,想了解更多,請(qǐng)查看官方文檔)

      (注意: 以下的代碼中未指定函數(shù)名的都是在onDraw函數(shù)中進(jìn)行使用,同時(shí)為了演示方便,在onDraw中使用了一些new方法,請(qǐng)?jiān)趯?shí)際使用中不要這樣做,因?yàn)閛nDraw函數(shù)是經(jīng)常需要重新運(yùn)行的)

      一、Canvas

      1、創(chuàng)建畫筆

      創(chuàng)建畫筆并初始化

      //創(chuàng)建畫筆
      private Paint mPaint = new Paint();
      
      private void initPaint(){
          //初始化畫筆
          mPaint.setStyle(Paint.Style.FILL);//設(shè)置畫筆類型
          mPaint.setAntiAlias(true);//抗鋸齒
      }
      

      2、繪制坐標(biāo)軸

      使用onSizeChanged方法,獲取根據(jù)父布局等因素確認(rèn)的View寬高

      //寬高
      private int mWidth;
      private int mHeight;
      
      @Override
      protected void onSizeChanged(int w, int h, int oldw, int oldh) {
          super.onSizeChanged(w, h, oldw, oldh);
          mWidth = w;
          mHeight = h;
      }
      

      把原點(diǎn)從左上角移動(dòng)到畫布中心

      @Override
      protected void onDraw(Canvas canvas) {
          super.onDraw(canvas);
          canvas.translate(mWidth/2,mHeight/2);// 將畫布坐標(biāo)原點(diǎn)移動(dòng)到中心位置
      }
      

      繪制坐標(biāo)原點(diǎn)

      //繪制坐標(biāo)原點(diǎn)
      mPaint.setColor(Color.BLACK);//設(shè)置畫筆顏色
      mPaint.setStrokeWidth(10);//為了看得清楚,設(shè)置了較大的畫筆寬度
      canvas.drawPoint(0,0,mPaint);
      

      繪制坐標(biāo)系的4個(gè)端點(diǎn),一次繪制多個(gè)點(diǎn)

      //繪制坐標(biāo)軸4個(gè)斷點(diǎn)
      canvas.drawPoints(new float[]{
          mWidth/2*0.8f,0
          ,0,mHeight/2*0.8f
          ,-mWidth/2*0.8f,0
          ,0,-mHeight/2*0.8f},mPaint);
      

      繪制坐標(biāo)軸

      mPaint.setStrokeWidth(1);//恢復(fù)畫筆默認(rèn)寬度
      //繪制X軸
      canvas.drawLine(-mWidth/2*0.8f,0,mWidth/2*0.8f,0,mPaint);
      //繪制Y軸
      canvas.drawLine(0,mHeight/2*0.8f,0,mHeight/2*0.8f,mPaint);
      

      繪制坐標(biāo)軸箭頭,一次繪制多條線

      mPaint.setStrokeWidth(3);
      //繪制X軸箭頭
      canvas.drawLines(new float[]{
          mWidth/2*0.8f,0,mWidth/2*0.8f*0.95f,-mWidth/2*0.8f*0.05f,            mWidth/2*0.8f,0,mWidth/2*0.8f*0.95f,mWidth/2*0.8f*0.05f
      },mPaint);
      //繪制Y軸箭頭
      canvas.drawLines(new float[]{
            0,mHeight/2*0.8f,mWidth/2*0.8f*0.05f,mHeight/2*0.8f-mWidth/2*0.8f*0.05f,
            0,mHeight/2*0.8f,-mWidth/2*0.8f*0.05f,mHeight/2*0.8f-mWidth/2*0.8f*0.05f,
      },mPaint);
      

      為什么Y軸的箭頭是向下的呢?這是因?yàn)樵鴺?biāo)系原點(diǎn)在左上角,向下為Y軸正方向,有疑問(wèn)的可以查看我之前的文章 自定義View——Android坐標(biāo)系與View繪制流程

      如果覺(jué)得不舒服,一定要箭頭向上的話,可以在繪制Y軸箭頭之前翻轉(zhuǎn)坐標(biāo)系

      canvas.scale(1,-1);//翻轉(zhuǎn)Y軸
      

      3、畫布變換

      繪制矩形

      //繪制矩形
      mPaint.setStyle(Paint.Style.STROKE);//設(shè)置畫筆類型
      canvas.drawRect(-mWidth/8,-mHeight/8,mWidth/8,mHeight/8,mPaint);
      

      平移,同時(shí)使用 new Rect 方法設(shè)置矩形

      canvas.translate(200,200);
      mPaint.setColor(Color.BLUE);
      canvas.drawRect(new RectF(-mWidth/8,-mHeight/8,mWidth/8,mHeight/8),mPaint);
      

      縮放

      canvas.scale(0.5f,0.5f);
      mPaint.setColor(Color.BLUE);
      canvas.drawRect(new RectF(-mWidth/8,-mHeight/8,mWidth/8,mHeight/8),mPaint);
      

      旋轉(zhuǎn)

      canvas.rotate(90);
      mPaint.setColor(Color.BLUE);
      canvas.drawRect(new RectF(-mWidth/8,-mHeight/8,mWidth/8,mHeight/8),mPaint);
      

      錯(cuò)切

      canvas.skew(1,0.5f);
      mPaint.setColor(Color.BLUE);
      canvas.drawRect(new RectF(-mWidth/8,-mHeight/8,mWidth/8,mHeight/8),mPaint);
      

      4、畫布的保存和恢復(fù)

      save():用于保存canvas的狀態(tài),之后可以調(diào)用canvas的平移、旋轉(zhuǎn)、縮放、錯(cuò)切、裁剪等操作。restore():在save之后調(diào)用,用于恢復(fù)之前保存的畫布狀態(tài),從而在之后的操作中忽略save與restore之間的畫布變化。

      float point = Math.min(mWidth,mHeight)*0.06f/2;
      float r = point*(float) Math.sqrt(2);
      mPaint.setStyle(Paint.Style.STROKE);
      mPaint.setColor(Color.BLACK);
      canvas.save();
      canvas.rotate(90);
      canvas.drawCircle(200,0,r,mPaint);//圓心(200,0)
      canvas.restore();
      mPaint.setColor(Color.BLUE);
      canvas.drawCircle(200,0,r,mPaint);//圓心(200,0)
      

      保存畫布,旋轉(zhuǎn)90°,繪制一個(gè)圓,之后恢復(fù)畫布,使用相同參數(shù)再繪制一個(gè)圓??梢钥吹皆诨謴?fù)畫布前后,相同參數(shù)繪制的圓,分別顯示在了坐標(biāo)系的不同位置。

      二、豆瓣加載動(dòng)畫

      繪制2個(gè)點(diǎn)和一個(gè)半圓弧

      mPaint.setStyle(Paint.Style.STROKE);//設(shè)置畫筆樣式為描邊,如果已經(jīng)設(shè)置,可以忽略
      mPaint.setColor(Color.GREEN);
      mPaint.setStrokeWidth(10);
      float point = Math.min(mWidth,mHeight)*0.2f/2;
      float r = point*(float) Math.sqrt(2);
      RectF rectF = new RectF(-r,-r,r,r);
      canvas.drawArc(rectF,0,180,false,mPaint);
      canvas.drawPoints(new float[]{
              point,-point
              ,-point,-point
      },mPaint);
      

      但是豆瓣表情在旋轉(zhuǎn)的過(guò)程中,是一個(gè)鏈接著兩個(gè)點(diǎn)的270°的圓弧

      mPaint.setColor(Color.GREEN);
      mPaint.setStrokeWidth(10);
      float point = Math.min(mWidth,mHeight)*0.2f/2;
      float r = point*(float) Math.sqrt(2);
      RectF rectF = new RectF(-r,-r,r,r);
      canvas.drawArc(rectF,-180,270,false,mPaint);
      

      這里使用ValueAnimator類,來(lái)進(jìn)行演示(實(shí)際上應(yīng)該是根據(jù)touch以及網(wǎng)絡(luò)情況來(lái)進(jìn)行加載的變化)

      簡(jiǎn)單說(shuō)下ValueAnimator類:

      API 簡(jiǎn)介
      ofFloat(float… values) 構(gòu)建ValueAnimator,設(shè)置動(dòng)畫的浮點(diǎn)值,需要設(shè)置2個(gè)以上的值
      setDuration(long duration) 設(shè)置動(dòng)畫時(shí)長(zhǎng),默認(rèn)的持續(xù)時(shí)間為300毫秒。
      setInterpolator(TimeInterpolator value) 設(shè)置動(dòng)畫的線性非線性運(yùn)動(dòng),默認(rèn)AccelerateDecelerateInterpolator
      addUpdateListener(ValueAnimator.AnimatorUpdateListener listener) 監(jiān)聽(tīng)動(dòng)畫屬性每一幀的變化

      分解步驟,計(jì)算一下總共需要的角度:

      1、一個(gè)笑臉,x軸下方的圓弧旋轉(zhuǎn)135°,覆蓋2個(gè)點(diǎn),此過(guò)程中圓弧增加45°

      2、畫布旋轉(zhuǎn)135°,此過(guò)程中圓弧增加45°

      3、畫布旋轉(zhuǎn)360°,此過(guò)程中圓弧減少360/5度

      4、畫布旋轉(zhuǎn)90°,此過(guò)程中圓弧減少90/5度

      5、畫布旋轉(zhuǎn)135°,釋放覆蓋的2個(gè)點(diǎn)

      動(dòng)畫部分:

      private ValueAnimator animator;
      private float animatedValue;
      private long animatorDuration = 5000;
      private TimeInterpolator timeInterpolator = new DecelerateInterpolator();
      
      private void initAnimator(long duration){
          if (animator !=null &&animator.isRunning()){
              animator.cancel();
              animator.start();
          }else {
              animator=ValueAnimator.ofFloat(0,855).setDuration(duration);
              animator.setInterpolator(timeInterpolator);
              animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                  @Override
                  public void onAnimationUpdate(ValueAnimator animation) {
                      animatedValue = (float) animation.getAnimatedValue();
                      invalidate();
                  }
              });
              animator.start();
          }
      }
      

      表情部分:在繪制前最好使用sava()方法保存當(dāng)前的畫布狀態(tài),在結(jié)束后使用restore()恢復(fù)之前保存的狀態(tài)。為了是表情看上去更自然,所以減少10°的初始角度

      private void doubanAnimator2(Canvas canvas, Paint mPaint){
          mPaint.setStyle(Paint.Style.STROKE);//描邊
          mPaint.setStrokeCap(Paint.Cap.ROUND);//圓角筆觸
          mPaint.setColor(Color.rgb(97, 195, 109));
          mPaint.setStrokeWidth(15);
          float point = Math.min(mViewWidth,mViewWidth)*0.06f/2;
          float r = point*(float) Math.sqrt(2);
          RectF rectF = new RectF(-r,-r,r,r);
          canvas.save();
      
          // rotate
          if (animatedValue>=135){
              canvas.rotate(animatedValue-135);
          }
      
          // draw mouth
          float startAngle=0, sweepAngle=0;
          if (animatedValue<135){
              startAngle = animatedValue +5;
              sweepAngle = 170+animatedValue/3;
          }else if (animatedValue<270){
              startAngle = 135+5;
              sweepAngle = 170+animatedValue/3;
          }else if (animatedValue<630){
              startAngle = 135+5;
              sweepAngle = 260-(animatedValue-270)/5;
          }else if (animatedValue<720){
              startAngle = 135-(animatedValue-630)/2+5;
              sweepAngle = 260-(animatedValue-270)/5;
          }else{
              startAngle = 135-(animatedValue-630)/2-(animatedValue-720)/6+5;
              sweepAngle = 170;
          }
          canvas.drawArc(rectF,startAngle,sweepAngle,false,mPaint);
      
          // draw eye
          canvas.drawPoints(new float[]{
              -point,-point
              ,point,-point
          },mPaint);
      
          canvas.restore();
      }
      

      在調(diào)試完成之后就可以刪除,坐標(biāo)系部分的代碼了

      三、小結(jié)

      本文介紹了canvas的變化,文中的不同部分穿插說(shuō)明了canvas繪制各種圖形的方法,以及結(jié)合ValueAnimator制作的豆瓣加載動(dòng)畫。之后的一篇文章會(huì)主要分析字符串的長(zhǎng)度和寬度,根據(jù)這些來(lái)參數(shù)調(diào)整字符串的位置,以達(dá)到居中等效果,再后一篇文章內(nèi)容應(yīng)該就會(huì)編寫 PieChart 了。如果在閱讀過(guò)程中,有任何疑問(wèn)與問(wèn)題,歡迎與我聯(lián)系。

      GitHub: https://github.com/Idtk

      博客:http://www.

      郵箱: Idtkma@gmail.com

      分享

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多