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