在前面一篇博文《Android高仿京東淘寶自動無限循環輪播控件的實現思路和過程》中已經基本介紹了實現輪播廣告的基本思路和過程,但是仔細觀察淘寶的輪播廣告欄,發現在輪播廣告欄的底部有個小小的弧形,為了實現更好的效果,在后期中在自己定義的無限輪播控件中添加了底部弧形的實現,在實現的過程中也遇到了一些問題,比較麻煩的就是繪制時弧形出現了鋸齒的問題。
實現弧形的主要代碼以及實現效果(帶有鋸齒的情況)
首先要感謝開源 感謝開源框架 https://github.com/florent37/ArcLayout ,弧形的實現效果是根據該框架而來,使用 path 來繪制弧形,首先就是要創建好 path 了。
1. 新建 path
1 private Path createClipPath() { 2 final Path path = new Path(); 3 path.moveTo(0, 0); 4 path.lineTo(0, height); 5 path.quadTo(width / 2, height - 2 * arcHeight, width, height); 6 path.lineTo(width, 0); 7 path.close(); 8 9 return path; 10 }
2.測量計算
繪制弧形是根據輪播控件的寬度和高度而來的,所以需要先測量出輪播控件的寬度和高度,並且當子 View 的位置和尺寸變化時,需要重新測量繪制。
1 @Override 2 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 3 super.onLayout(changed, left, top, right, bottom); 4 if (changed) { 5 calculateLayout(); 6 } 7 } 8 9 /** 10 *calculate layout 11 */ 12 private void calculateLayout() { 13 height = getMeasuredHeight(); 14 width = getMeasuredWidth(); 15 if (width > 0 && height > 0) { 16 17 clipPath = createClipPath(); 18 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && arcShape != ArcShape.inSide) { 19 setOutlineProvider(new ViewOutlineProvider() { 20 @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 21 @Override 22 public void getOutline(View view, Outline outline) { 23 outline.setConvexPath(clipPath); 24 } 25 }); 26 } 27 } 28 }
3、繪制弧形
繪制圖形時,有一個控件是很重要的,那就是 Canvas 畫布,也是最后一步,在畫布上面繪制。
1 @Override 2 protected void dispatchDraw(Canvas canvas) { 3 canvas.save(); 4 5 canvas.clipPath(clipPath); 6 super.dispatchDraw(canvas); 7 8 canvas.restore(); 9 }
4、效果圖
運行代碼,可以看到效果,效果圖如下。
問題
底部的弧形雖然已經繪制成功了,但是從效果圖中可以明顯看出弧形帶有鋸齒,效果並不好,再看下現在淘寶的效果,有點困擾了。
解決辦法
在網上查找了資料,也沒有發現什么好的辦法,最后在 Github 上面找到了答案 https://github.com/florent37/ArcLayout/issues/8。
解決方法並不難,但是需要引入另外一個繪圖工具 —— Paint,通過 Paint 來消除鋸齒,因為 Paint 本身就有自帶的消除鋸齒的方法 paint.setAntiAlias(true),當然還需要設置下 Xfermode,不過和目前網上提供的方法有所不同了,看下面的代碼,修改在畫布 Canvas 中的繪制方法。
1 @Override 2 protected void dispatchDraw(Canvas canvas) { 3 Paint paint = new Paint(); 4 paint.setAntiAlias(true); 5 paint.setColor(Color.WHITE); 6 int saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG); 7 super.dispatchDraw(canvas); 8 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY)); 9 canvas.drawPath(clipPath, paint); 10 canvas.restoreToCount(saveCount); 11 paint.setXfermode(null); 12 }
最終效果圖
修改代碼后運行,獲得最終效果,已經明顯消除了鋸齒,效果優美多了,弧形變得光滑了。
自定義的高仿京東淘寶控件已經修改完成了,代碼已經開源在 Github 上面,https://github.com/LT5505/SliderLayout