diff --git a/README.md b/README.md index a466e53..f0611f6 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # ClipPathLayout -[ ![Download](https://api.bintray.com/packages/dqh147258/ClipPathLayout/ClipPathLayout/images/download.svg?version=1.0.3) ](https://bintray.com/dqh147258/ClipPathLayout/ClipPathLayout/1.0.3/link) +[ ![Download](https://api.bintray.com/packages/dqh147258/ClipPathLayout/ClipPathLayout/images/download.svg?version=1.0.4) ](https://bintray.com/dqh147258/ClipPathLayout/ClipPathLayout/1.0.4/link) [![Platform](https://img.shields.io/badge/platform-android-blue.svg)]() [![License](https://img.shields.io/hexpm/l/plug.svg)](https://www.apache.org/licenses/LICENSE-2.0) @@ -130,6 +130,7 @@ mImageView = mLayout.findViewById(R.id.image); new PathInfo.Builder(new CirclePathGenerator(), mImageView) .setApplyFlag(mApplyFlag) .setClipType(mClipType) + .setAntiAlias(false) .create() .apply(); ``` @@ -214,6 +215,11 @@ Path的裁剪模式,有如下两种 ![](https://github.com/dqh147258/ClipPathLayout/blob/master/image/select_clip_mode.gif) +#### AntiAlias + +抗锯齿,true表示开启,false关闭,默认关闭. + +请慎用此功能,此功能会关闭硬件加速并且会新建图层,在View绘制期间还有一个图片生成过程,所以此功能开启会严重降低绘制性能,并且如果频繁刷新界面会导致内存抖动.所以这个功能只建议在静态而且不常刷新的情况下使用. ### 自定义ClipPathLayout diff --git a/app/src/main/java/com/yxf/clippathlayout/sample/CirclePathFragment.java b/app/src/main/java/com/yxf/clippathlayout/sample/CirclePathFragment.java index 8a53b3b..ef7f8e5 100644 --- a/app/src/main/java/com/yxf/clippathlayout/sample/CirclePathFragment.java +++ b/app/src/main/java/com/yxf/clippathlayout/sample/CirclePathFragment.java @@ -84,6 +84,7 @@ public void onClick(View v) { new PathInfo.Builder(new OvalPathGenerator(), mClipTypeSwitchView) .setApplyFlag(PathInfo.APPLY_FLAG_DRAW_AND_TOUCH) .setClipType(PathInfo.CLIP_TYPE_IN) + .setAntiAlias(true) .create() .apply(mLayout); diff --git a/app/src/main/java/com/yxf/clippathlayout/sample/YinYangFishFragment.java b/app/src/main/java/com/yxf/clippathlayout/sample/YinYangFishFragment.java index e3eade2..7b87b58 100644 --- a/app/src/main/java/com/yxf/clippathlayout/sample/YinYangFishFragment.java +++ b/app/src/main/java/com/yxf/clippathlayout/sample/YinYangFishFragment.java @@ -39,6 +39,7 @@ public void onClick(View v) { }); new PathInfo.Builder(new YinYangFishPathGenerator(270), mYinFishView) + .setAntiAlias(true) .create() .apply(); diff --git a/build.gradle b/build.gradle index a284e61..1a90f55 100644 --- a/build.gradle +++ b/build.gradle @@ -28,5 +28,5 @@ task clean(type: Delete) { } ext { - CLIP_PATH_LAYOUT_VERSION = '1.0.3' + CLIP_PATH_LAYOUT_VERSION = '1.0.4' } \ No newline at end of file diff --git a/clippathlayout/src/main/java/com/yxf/clippathlayout/ClipPathLayoutDelegate.java b/clippathlayout/src/main/java/com/yxf/clippathlayout/ClipPathLayoutDelegate.java index 09e18d7..4e39fa0 100644 --- a/clippathlayout/src/main/java/com/yxf/clippathlayout/ClipPathLayoutDelegate.java +++ b/clippathlayout/src/main/java/com/yxf/clippathlayout/ClipPathLayoutDelegate.java @@ -1,9 +1,17 @@ package com.yxf.clippathlayout; +import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.DrawFilter; import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.PaintFlagsDrawFilter; import android.graphics.Path; import android.graphics.PointF; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.os.Build; import android.util.Log; import android.view.View; import android.view.ViewGroup; @@ -32,6 +40,19 @@ public class ClipPathLayoutDelegate implements ClipPathLayout { private ViewGetKey mTempViewGetKey; + private Paint mPathPaint; + private Paint mBitmapPaint; + + private PorterDuffXfermode mDstInMode; + private PorterDuffXfermode mDstOutMode; + + private DrawFilter mOriginalDrawFilter; + private Integer mOriginalLayerType; + + private int mCanvasSavedCount; + + private DrawFilter mAntiAliasDrawFilter; + private boolean mHasLayoutRequest = false; private boolean mInBeforeDrawChild = false; @@ -150,32 +171,92 @@ public void beforeDrawChild(Canvas canvas, View child, long drawingTime) { } mInBeforeDrawChild = true; executePendingTask(); - canvas.save(); - canvas.translate(child.getLeft(), child.getTop()); if (mHasLayoutRequest) { mHasLayoutRequest = false; notifyAllPathChangedInternal(false); } + ViewGetKey key = getTempViewGetKey(child.hashCode(), child); PathInfo info = mPathInfoMap.get(key); + if (info != null && info.isAntiAlias()) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + mCanvasSavedCount = canvas.saveLayer(child.getLeft(), child.getTop(), child.getRight(), child.getBottom(), null); + } else { + mCanvasSavedCount = canvas.saveLayer(child.getLeft(), child.getTop(), child.getRight(), child.getBottom(), null, Canvas.ALL_SAVE_FLAG); + } + } else { + mCanvasSavedCount = canvas.save(); + } if (info != null) { - if ((info.getApplyFlag() & PathInfo.APPLY_FLAG_DRAW_ONLY) != 0) { - Path path = info.getPath(); - if (path != null) { - Utils.clipPath(canvas, path, info.getClipType()); - } else { - Log.d(TAG, "beforeDrawChild: path is null , hash code : " + info.hashCode()); + if (!info.isAntiAlias()) { + if ((info.getApplyFlag() & PathInfo.APPLY_FLAG_DRAW_ONLY) != 0) { + Path path = info.getPath(); + if (path != null) { + canvas.translate(child.getLeft(), child.getTop()); + Utils.clipPath(canvas, path, info.getClipType()); + canvas.translate(-child.getLeft(), -child.getTop()); + } else { + Log.d(TAG, "beforeDrawChild: path is null , hash code : " + info.hashCode()); + } + } + } else { + mOriginalDrawFilter = canvas.getDrawFilter(); + mOriginalLayerType = mParent.getLayerType(); + mParent.setLayerType(View.LAYER_TYPE_SOFTWARE, null); + if (mAntiAliasDrawFilter == null) { + mAntiAliasDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); } + canvas.setDrawFilter(mAntiAliasDrawFilter); } } resetTempViewGetKey(); - canvas.translate(-child.getLeft(), -child.getTop()); mInBeforeDrawChild = false; } @Override public void afterDrawChild(Canvas canvas, View child, long drawingTime) { - canvas.restore(); + ViewGetKey key = getTempViewGetKey(child.hashCode(), child); + PathInfo info = mPathInfoMap.get(key); + if (info != null && info.isAntiAlias()) { + if ((info.getApplyFlag() & PathInfo.APPLY_FLAG_DRAW_ONLY) != 0) { + Path path = info.getPath(); + if (path != null) { + Bitmap bitmap = Bitmap.createBitmap(child.getWidth(), child.getHeight(), Bitmap.Config.ARGB_8888); + Canvas c = new Canvas(bitmap); + if (mPathPaint == null) { + mPathPaint = new Paint(); + mPathPaint.setAntiAlias(true); + } + if (mBitmapPaint == null) { + mBitmapPaint = new Paint(); + mPathPaint.setAntiAlias(true); + } + c.drawPath(path, mPathPaint); + if (info.getClipType() == PathInfo.CLIP_TYPE_IN) { + if (mDstInMode == null) { + mDstInMode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN); + } + mBitmapPaint.setXfermode(mDstInMode); + } else { + if (mDstOutMode == null) { + mDstOutMode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT); + } + mBitmapPaint.setXfermode(mDstOutMode); + } + canvas.drawBitmap(bitmap, child.getLeft(), child.getTop(), mBitmapPaint); + //if use drawPath may cause some strange problems + /*canvas.translate(child.getLeft(), child.getTop()); + canvas.drawPath(path, mBitmapPaint); + canvas.translate(-child.getLeft(),-child.getTop());*/ + } else { + Log.d(TAG, "beforeDrawChild: path is null , hash code : " + info.hashCode()); + } + } + mParent.setLayerType(mOriginalLayerType, null); + canvas.setDrawFilter(mOriginalDrawFilter); + } + resetTempViewGetKey(); + canvas.restoreToCount(mCanvasSavedCount); } @Override diff --git a/clippathlayout/src/main/java/com/yxf/clippathlayout/PathInfo.java b/clippathlayout/src/main/java/com/yxf/clippathlayout/PathInfo.java index 832c608..6f6d626 100644 --- a/clippathlayout/src/main/java/com/yxf/clippathlayout/PathInfo.java +++ b/clippathlayout/src/main/java/com/yxf/clippathlayout/PathInfo.java @@ -32,6 +32,8 @@ public class PathInfo { private Path mPath; private PathRegion mPathRegion; + private boolean mAntiAlias; + private PathInfo(PathGenerator generator, View view) { mPathGenerator = generator; mViewReference = new WeakReference(view); @@ -130,15 +132,20 @@ void setPathRegion(PathRegion pathRegion) { mPathRegion = pathRegion; } + public boolean isAntiAlias() { + return mAntiAlias; + } + public static class Builder { private PathGenerator mPathGenerator; private View mView; private int mApplyFlag = APPLY_FLAG_DRAW_AND_TOUCH; private int mClipType = CLIP_TYPE_IN; + private boolean mAntiAlias = false; /** * @param generator Path生成器 - * @param view 实现了ClipPathLayout接口的ViewGroup的子View + * @param view 实现了ClipPathLayout接口的ViewGroup的子View */ public Builder(PathGenerator generator, View view) { if (generator == null) { @@ -161,10 +168,16 @@ public Builder setClipType(int type) { return this; } + public Builder setAntiAlias(boolean antiAlias) { + mAntiAlias = antiAlias; + return this; + } + public PathInfo create() { PathInfo info = new PathInfo(mPathGenerator, mView); info.mApplyFlag = mApplyFlag; info.mClipType = mClipType; + info.mAntiAlias = mAntiAlias; return info; } }