1. 程式人生 > >Android 自定義View小例項-實現繪製打折標籤

Android 自定義View小例項-實現繪製打折標籤

前言

許多商城APP都會有商品打折的需求,而為文字新增下劃線直接設定style就可以完成,我們在這裡說的如下圖,也就是我們demo實現的效果圖。

1. 選取自定義View的方法

我們都知道自定義View有多種方式,比如繼承自View、ViewGroup或者繼承自現有的View子類等,每種實現方式的不同我們所需要做的處理工作也不同,從圖中可以看出包含兩個TextView,所以我們這裡選取繼承特定的ViewGroup的方式來實現。這種方式我們不需要處理onMeasure和layout因此比較簡單。

2.實現過程

2.1 新建一個類

新建DiscountView類,繼承自LinearLayout,重寫三個構造方法,並在構造方法中做一些初始化操作

2.2 編寫佈局檔案

編寫一個佈局檔案,佈局中有兩個textView,垂直排放(程式碼略),在init方法中將佈局新增進來並初始化兩個textview

mRoot = LayoutInflater.from(getContext()).inflate(R.layout.view_layout, this);
price = mRoot.findViewById(R.id.small);
dataType = mRoot.findViewById(R.id.big);

在這裡我們可以看到效果圖有個淺藍色邊框,這個可以繪製,我這裡沒有繪製直接為佈局檔案新增的shape背景。

2.3. 獲取佈局檔案中內容的高度

根據View的基礎知識https://blog.csdn.net/huangliniqng/article/details/83933241我們可以通過下列方法計算出內容區域的長和寬:

int left = mRoot.getLeft();
int top = mRoot.getTop();
int right = mRoot.getRight();
int bottom = mRoot.getBottom();

int viewHeight = bottom - top;
int viewWidth = right - left;

viewHeight和viewwidth就是內容區域的長度和寬度 ,當然這是從原理的角度去做的,更簡單的直接通過

mRoot.getMeasuredWidth()和 mRoot.getMeasuredHeight()方法直接獲取內容區域的長和寬,注意的是這裡的內容區域是整個矩形。

將佈局新增進來之後,現在的樣子就是:

2.4. 繪製打折標籤

接下來的標籤就是繪製標籤,在這裡有兩個注意的問題:

(1) 繪製的方式有很多,可以繪製矩形後旋轉畫布或者直接用Path繪製,這裡我們採用使用Path繪製

(2) 既然要繪製東西,那麼就要重新onDraw方法,那麼繼承自Viewgroup的方式預設是不執行onDraw方法的所以記得要設定

setWillNotDraw(false);

2.5 初始化畫筆等資訊

我們繪製的打折標籤為紅色

paintDiscount = new Paint();
paintDiscount.setColor(Color.RED);
paintDiscount.setStyle(Paint.Style.FILL);

標籤的打折文字是白色

paintDisText.setAntiAlias(true);
paintDisText.setColor(Color.WHITE);
paintDisText.setStyle(Paint.Style.STROKE);

2.6 繪製標籤

我們通過比較兩張圖片可以明顯的看出,我們繪製的四個點分別在長的四分之一、長的二分之一、

寬的四分之一、寬的二分之一、所以我們直接用畫筆將四個點連線在一起就可以了,我們繪製是相對於mRoot

這個View,也就是mRoot的左上角的點的座標是(0,0),我們直接繪製:

path = new Path();
path.moveTo(0, viewHeight / 4);
path.lineTo(viewWidth / 4, 0);
path.lineTo(viewWidth / 2, 0);
path.lineTo(0, viewHeight / 2);
path.close();
canvas.drawPath(path, paintDiscount);

這個時候的效果如下:

ps:一般這種效果我們為了美觀,都是長>寬 並且接近一個正方形,當然我們可以任意設定寬高,但效果沒有這種好。

2.7 繪製文字

我們在這個path路徑上繪製文字:

paintDisText.setTextAlign(Paint.Align.LEFT);
canvas.drawTextOnPath(discountNumber, path, 0, 0, paintDisText);

效果如下(先把文字顏色設為亮色方便看效果):

睜大眼睛可以看到文字在路徑的上邊,設定文字大小:

paintDisText.setTextSize(35f);

同樣的也是在邊上,我們檢視原始碼看一下drawTextOnPath的使用以及上邊設定的兩個0的作用

我們可以看到我們之前設的兩個0就是相對於path的水平偏移量和豎直偏移量,我們只需要通過設定偏移量將文字偏移到中間就可以了

稍等~!肯定不可以隨便設個值,那樣在不同的手機上效果不一樣,設定有可能看不到效果

那麼這裡我們就要就算hOffset和vOffset的值,這裡中學學的三角函式就派上用場了!

如繪圖所示:

那麼為了將文字顯示在紅色四邊形的中央,我們的水平偏移量則是短邊紅線的二分之一、豎直偏移量是紅色四邊形高的二分之一。

給上述圖形新增輔助線後如圖:

這個時候就比較清晰了(繪圖能力太差~),角A、B、C三角角的角度是相等的

角C對應小三角形的兩邊分別為長的四分之一和寬的四分之一,是個直角三角形,所以直接 根據勾股定理求得最短紅邊的四分之一

float hOffset = (float) (Math.sqrt((Math.pow(viewHeight / 4.0f, 2) + Math.pow(viewWidth / 4.0f, 2))) / 2.0f) ;

SinB = SinA,SinA是已知的,SinB所在三角形的斜邊就是長的二分之一因為可以求出角B所在三角形的高度。

由等比三角形值path所在四邊形的高為角B所在三角形高度的一半,所以:

float vOffset = (float) (viewHeight * viewWidth * Math.sqrt((Math.pow(viewHeight, 2) + Math.pow(viewWidth, 2))) / ((Math.pow(viewHeight, 2) + Math.pow(viewWidth, 2))) / 6.0f);

這個時候我們在根據計算偏移量的效果進行微調就可以了,最終效果圖如下所示:

 

我們可以設定文字值和打折數目,意義是否繪製打折,如果不繪製則不會繪製path。

discountView.setDiscountNumber("8");
discountView.setTextBig("測試");
discountView.setTextSamll("sad4545");

原始碼位置:https://github.com/huanglinqing123/DiscountView

歡迎start和insuue