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

Android自定義View實(shí)現(xiàn)多邊形統(tǒng)計(jì)圖示例代碼

 更新時(shí)間:2018年01月03日 10:04:26   作者:BigTotoro  
這篇文章主要給大家介紹了關(guān)于Android自定義View如何實(shí)現(xiàn)多邊形統(tǒng)計(jì)圖的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。

前言

  最近利用空閑時(shí)間學(xué)習(xí)了自定義View的一些知識(shí),為了鞏固,寫了一個(gè)小東西,順便分享出來(lái),下面話不多說(shuō)了,來(lái)一起看看詳細(xì)的介紹吧。

簡(jiǎn)介

  一個(gè)多邊形統(tǒng)計(jì)圖。邊數(shù),每個(gè)方向的值,每個(gè)點(diǎn)的文字等等都是可以設(shè)置的。

下面就來(lái)分析一下這個(gè)自定義View

這個(gè)view由以下幾個(gè)部分組成

  • M層N邊形
  • 中心到各頂點(diǎn)的連線
  • 填充區(qū)域
  • 文字
 @Override
 protected void onDraw(Canvas canvas) {
 if (!canDraw()) {
 return;
 }
 canvas.translate(width / 2, height / 2);
 computeMaxPoint();
 drawPolygon(canvas);
 drawLine(canvas);
 drawArea(canvas);
 drawText(canvas);
 }

我們一步一步來(lái)說(shuō)明

繪制多邊形

  繪制多邊形主要用到的是Path這個(gè)東西。具體的思路就是先計(jì)算好每個(gè)點(diǎn)的位置,同Path的lineTo方法連接起來(lái),然后繪制。

  我的做法是先算出最大的半徑(再之后還會(huì)用到,建議單獨(dú)存起來(lái)),然后根據(jù)所在層數(shù)來(lái)計(jì)算每一層的半徑,利用cos函數(shù)各sin函數(shù)計(jì)算出每一層各頂點(diǎn)的位置。

計(jì)算最大半徑并且保存頂點(diǎn)

 @Override
 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
 width = w;
 height = h;
 maxRadius = (float) ((width / 2) * 0.8);
 postInvalidate();
 }
 /*
 計(jì)算最大半徑,之后的位置都是基于最大半徑的比例
 */
 public void computeMaxPoint() {
 maxPointXList = new ArrayList<>();
 maxPointYList = new ArrayList<>();
 for (int i = 0; i < eageCount; i++) {
 float currentAngle = i * angle - 90;
 float currentX = (float) (maxRadius * Math.cos((currentAngle / 180) * Math.PI));
 float currentY = (float) (maxRadius * Math.sin((currentAngle / 180) * Math.PI));
 maxPointXList.add(currentX);
 maxPointYList.add(currentY);
 }
 }

  注意:cos和sin都是按照弧度制計(jì)算的,要換算。

  這里解釋一下為currentAngle什么要減去90度

  按照android的坐標(biāo)系,如果不減去90度直接乘上cos的話,第一個(gè)頂點(diǎn)會(huì)默認(rèn)在中心的右側(cè),而一般的認(rèn)知是第一個(gè)點(diǎn)在正上方,所以減去90度

按照比例和層數(shù)邊數(shù)繪制多邊形

 /*
 繪制多邊形和每一層
 */
 private void drawPolygon(Canvas canvas) {
 Path path = new Path();
 for (int i = 0; i < loopCount; i++) {
 path.reset();
 //依據(jù)最大半徑和角度來(lái)判斷每一層點(diǎn)的位置
 float rate = computeRate(i + 1, loopCount);
 for (int j = 0; j < eageCount; j++) {
 float currentX = maxPointXList.get(j) * rate;
 float currentY = maxPointYList.get(j) * rate;
 if (j == 0) {
  path.moveTo(currentX, currentY);
 } else {
  path.lineTo(currentX, currentY);
 }
 }
 path.close();
 canvas.drawPath(path, eagePaint);
 }
 }

  代碼還是很容易的吧,要是看不懂的話自己動(dòng)手算算就知道了,很容易計(jì)算各個(gè)點(diǎn)的位置。

繪制連線

  由于之前保存了頂點(diǎn)的坐標(biāo),這個(gè)就很容易了

 /*
 畫出從中心向各頂點(diǎn)的連線
 */
 private void drawLine(Canvas canvas) {
 Path path = new Path();
 for (int i = 0; i < eageCount; i++) {
  path.reset();
  path.lineTo(maxPointXList.get(i), maxPointYList.get(i));
  canvas.drawPath(path, eagePaint);
 }
 }

繪制覆蓋區(qū)域

  這個(gè)原理其實(shí)和繪制多邊形是一樣的,就是對(duì)頂點(diǎn)坐標(biāo)乘的比例發(fā)生了變化。每個(gè)方向的數(shù)值是由用戶傳遞進(jìn)來(lái)的。

 /*
 繪制個(gè)方向值覆蓋的區(qū)域
 */
 private void drawArea(Canvas canvas) {
 Path path = new Path();
 //原理就是用path根據(jù)各方向值創(chuàng)建一個(gè)封閉的區(qū)域,然后填充
 for (int i = 0; i < eageCount; i++) {
  float rate = pointValue.get(i);
  float currentX = maxPointXList.get(i) * rate;
  float currentY = maxPointYList.get(i) * rate;
  if (i == 0) {
  path.moveTo(currentX, currentY);
  } else {
  path.lineTo(currentX, currentY);
  }
 }
 path.close();
 canvas.drawPath(path, areaPaint);
 }

繪制文字

  說(shuō)實(shí)話,前面的沒(méi)有什么難點(diǎn),但是唯獨(dú)繪制文字有許多麻煩事。主要是文字是默認(rèn)自左向右的,最上面和最先面的文字倒是沒(méi)啥,左側(cè)和右側(cè)的文字就會(huì)出現(xiàn)問(wèn)題了,文字會(huì)繪制到多邊形上,看起來(lái)特別難受。這里我的解決辦法就是前面圖中看到的,讓字跟著多邊形的頂點(diǎn)位置一起旋轉(zhuǎn)。

 /*
 繪制文字
 */
 private void drawText(Canvas canvas) {
 if (pointName == null) {
  return;
 }
 //繪制文字的難點(diǎn)在于無(wú)法最好的適配屏幕的位置,會(huì)發(fā)生難以控制的偏倚
 for (int i = 0; i < pointName.size(); i++) {
  //解決辦法就是讓文字在不同的角度也發(fā)生旋轉(zhuǎn),并且在x軸上減去一定的數(shù)值來(lái)保證正確的位置
  float currentAngle = i * angle;
  //180度需要也別的處理,讓它正著顯示,不然就是倒著的
  if (currentAngle == 180) {
  float currentX = maxPointXList.get(i) * 1.1f;
  float currentY = maxPointYList.get(i) * 1.1f;
  canvas.drawText(pointName.get(i), currentX - (textPaint.getTextSize() / 4)
   * (pointName.get(i).length()), currentY, textPaint);
  } else {
  canvas.save();
  float currentX = maxPointXList.get(0) * 1.1f;
  float currentY = maxPointYList.get(0) * 1.1f;
  //旋轉(zhuǎn)畫布,達(dá)到旋轉(zhuǎn)文字的效果
  canvas.rotate(currentAngle);
  canvas.drawText(pointName.get(i), currentX - (textPaint.getTextSize() / 4)
   * (pointName.get(i).length()), currentY, textPaint);
  canvas.restore();
  }
 }
 }

到這里,整個(gè)組件就繪制完成了

額外的屬性

如果單純只是想畫出這個(gè)組件來(lái),其實(shí)沒(méi)啥難度。我們可以在加一些別的東西讓他更加實(shí)用。

動(dòng)畫效果

  利用屬性動(dòng)畫的知識(shí),我們可以做到讓中間的填充區(qū)域慢慢的擴(kuò)散出來(lái)。原理也簡(jiǎn)單,就是把0到1用屬性計(jì)算展開,當(dāng)做一個(gè)演化的比例,讓各個(gè)方向的值乘上這個(gè)數(shù)值,繪制一個(gè)比原先覆蓋區(qū)域小的區(qū)域就可以了。

 /*
 用屬性動(dòng)畫繪制組件
 */
 public void draw() {
 if (canDraw()) {
  final Float[] trueValues = pointValue.toArray(new Float[pointValue.size()]);
  ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
  valueAnimator.setDuration(1000);
  valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  @Override
  public void onAnimationUpdate(ValueAnimator animation) {
   float rate = animation.getAnimatedFraction();
   for (int i = 0; i < pointValue.size(); i++) {
   pointValue.set(i, trueValues[i] * rate);
   }
   invalidate();
  }
  });
  valueAnimator.start();
 }
 }

定義xml屬性

  我們正常使用系統(tǒng)組件的時(shí)候都會(huì)寫一大堆的xml來(lái)控制我們組件的屬性,自定義View也可以嘗試這些

  首先在value下創(chuàng)建atts文件

  然后指定你想要的屬性名稱和類型


  再然后就是讓atts和我們的view聯(lián)系上。這個(gè)也簡(jiǎn)單,仔細(xì)觀察View的構(gòu)造方法中的參數(shù),有這么一個(gè)玩意 AttributeSet attrs

public PolygonView(Context context, @Nullable AttributeSet attrs) {
 super(context, attrs);
 init(context, attrs);
 }
 public PolygonView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr);
 init(context, attrs);
 }

  它就是聯(lián)系xml和view的紐帶

xmlns:app="http://schemas.android.com/apk/res-auto"
<com.totoro.xkf.polygonview.PolygonView
 android:id="@+id/pv_polygon_view"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 app:areaColor="@android:color/holo_blue_light"
 app:eageColor="@android:color/black"
 app:eageCount="6"
 app:loopCount="4"
 app:textColor="@android:color/black" />
public void init(Context context, AttributeSet attrs) {
 TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.Polygon);
 initPaint();
 setTextColor(typedArray.getColor(R.styleable.Polygon_textColor, Color.BLACK));
 setLoopCount(typedArray.getInteger(R.styleable.Polygon_loopCount, 0));
 setEageCount(typedArray.getInteger(R.styleable.Polygon_eageCount, 0));
 setAreaColor(typedArray.getColor(R.styleable.Polygon_areaColor, Color.BLUE));
 setEageColor(typedArray.getColor(R.styleable.Polygon_eageColor, Color.GRAY));
 typedArray.recycle();
 }

這個(gè)東西不能忘了

快速使用

  感謝你看到這里,如果你想使用這個(gè)組件但是不想自己寫的話歡迎訪問(wèn)

項(xiàng)目Github里面有講如何添加依賴,導(dǎo)入組件

如果能幫到你的話,不勝榮幸?。?!

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • Flutter自定義實(shí)現(xiàn)神奇動(dòng)效的卡片切換視圖的示例代碼

    Flutter自定義實(shí)現(xiàn)神奇動(dòng)效的卡片切換視圖的示例代碼

    這篇文章主要介紹了Flutter自定義實(shí)現(xiàn)神奇動(dòng)效的卡片切換視圖的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-04-04
  • Android手機(jī)顯示多彩霓虹燈效果

    Android手機(jī)顯示多彩霓虹燈效果

    這篇文章主要為大家詳細(xì)介紹了Android手機(jī)顯示多彩霓虹燈效果的小實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • Android SharedPreferences數(shù)據(jù)存儲(chǔ)詳解

    Android SharedPreferences數(shù)據(jù)存儲(chǔ)詳解

    SharedPreferences是安卓平臺(tái)上一個(gè)輕量級(jí)的存儲(chǔ)類,用來(lái)保存應(yīng)用的一些常用配置,比如Activity狀態(tài),Activity暫停時(shí),將此activity的狀態(tài)保存到SharedPereferences中;當(dāng)Activity重載,系統(tǒng)回調(diào)方法onSaveInstanceState時(shí),再?gòu)腟haredPreferences中將值取出
    2022-11-11
  • android編程實(shí)現(xiàn)電話錄音的方法

    android編程實(shí)現(xiàn)電話錄音的方法

    這篇文章主要介紹了android編程實(shí)現(xiàn)電話錄音的方法,涉及Android監(jiān)聽電話通話及音頻采集的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-10-10
  • Android編程之代碼創(chuàng)建布局實(shí)例分析

    Android編程之代碼創(chuàng)建布局實(shí)例分析

    這篇文章主要介紹了Android編程之代碼創(chuàng)建布局的方法,結(jié)合實(shí)例形式分析了Android通過(guò)代碼創(chuàng)建布局的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-11-11
  • Android逆向入門之常見Davlik字節(jié)碼解析

    Android逆向入門之常見Davlik字節(jié)碼解析

    Dalvik是Google公司自己設(shè)計(jì)用于Android平臺(tái)的虛擬機(jī)。Dalvik虛擬機(jī)是Google等廠商合作開發(fā)的Android移動(dòng)設(shè)備平臺(tái)的核心組成部分之一,本篇文章我們來(lái)詳細(xì)解釋常見Davlik字節(jié)碼
    2021-11-11
  • Android Studio中引入Lambda表達(dá)式的方法

    Android Studio中引入Lambda表達(dá)式的方法

    這篇文章主要給大家介紹了在Android Studio中引入Lambda表達(dá)式的方法,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2017-03-03
  • Android使用線程獲取網(wǎng)絡(luò)圖片的方法

    Android使用線程獲取網(wǎng)絡(luò)圖片的方法

    這篇文章主要為大家詳細(xì)介紹了Android使用線程獲取網(wǎng)絡(luò)圖片的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-06-06
  • Android中ViewPager實(shí)現(xiàn)滑動(dòng)條及與Fragment結(jié)合的實(shí)例教程

    Android中ViewPager實(shí)現(xiàn)滑動(dòng)條及與Fragment結(jié)合的實(shí)例教程

    ViewPager類主要被用來(lái)實(shí)現(xiàn)可滑動(dòng)的視圖功能,這里我們就來(lái)共同學(xué)習(xí)Android中ViewPager實(shí)現(xiàn)滑動(dòng)條及與Fragment結(jié)合的實(shí)例教程,需要的朋友可以參考下
    2016-06-06
  • Android巧用DecorView實(shí)現(xiàn)對(duì)話框功能

    Android巧用DecorView實(shí)現(xiàn)對(duì)話框功能

    本篇文章主要介紹了Android巧用DecorView實(shí)現(xiàn)對(duì)話框功能,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-04-04

最新評(píng)論