如何防止PhotoView绘制超出带顶部圆角的父LinearLayout边界?
解决PhotoView超出LinearLayout顶部圆角边界的问题
我之前处理过类似的布局裁剪问题,核心原因其实很清晰:你给LinearLayout设置了outlineProvider="background"来复用背景的圆角作为裁剪轮廓,但Android默认不会自动用这个轮廓去裁剪子View——clipChildren和clipPadding只能处理布局边界的裁剪,管不到自定义outline的情况。
下面给你几个按优先级排序的靠谱解决方案:
方案一:给LinearLayout添加clipToOutline="true"
这是最直接的修复方式,只需要在你的LinearLayout标签里补上这个属性,就能让它根据背景的圆角轮廓裁剪所有子View:
<LinearLayout android:outlineProvider="background" android:clipToOutline="true" <!-- 新增这个关键属性 --> android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/sheet_bg" android:orientation="vertical"> <include android:id="@+id/preview_layout_frame" layout="@layout/preview_snaped_helfie" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" /> <android.support.v7.widget.RecyclerView android:id="@+id/helfie_list" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:padding="20dp" /> </LinearLayout>
注意:
clipToOutline只对支持outline的View生效,LinearLayout完全符合要求,而且你的背景是shape圆角,系统能正确识别这个轮廓。
方案二:给PhotoView单独套一层带裁剪的FrameLayout
如果方案一因为include布局的层级嵌套问题没生效,可以给PhotoView单独加一个父容器,专门负责裁剪逻辑:
- 修改你的
preview_snaped_helfie布局,把PhotoView放在FrameLayout里:
<FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:outlineProvider="background" android:clipToOutline="true" android:background="@drawable/sheet_top_corners"> <!-- 只保留顶部圆角的shape --> <com.github.chrisbanes.photoview.PhotoView android:id="@+id/helfie_preview" android:layout_width="match_parent" android:layout_height="match_parent" android:adjustViewBounds="true" android:scaleType="center" /> </FrameLayout>
- 对应的
sheet_top_cornersshape和你原来的sheet_bg一致,只保留顶部圆角:
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="@color/dark" /> <corners android:topLeftRadius="35dp" android:topRightRadius="35dp" /> </shape>
这样PhotoView的缩放区域会被FrameLayout的圆角完全约束,不受外层LinearLayout的布局属性影响。
方案三:自定义裁剪容器(终极兜底方案)
如果上面的系统自带方案都因为设备兼容性问题失效,你可以写一个简单的自定义ViewGroup,手动控制画布裁剪:
public class RoundedTopContainer extends FrameLayout { private Path mClipPath; private float mTopRadius; public RoundedTopContainer(Context context) { super(context); init(context, null); } public RoundedTopContainer(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } private void init(Context context, AttributeSet attrs) { // 可以通过自定义属性传入圆角半径,这里默认35dp TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.RoundedTopContainer); mTopRadius = ta.getDimension(R.styleable.RoundedTopContainer_topRadius, dp2px(35)); ta.recycle(); mClipPath = new Path(); setWillNotDraw(false); // 开启自定义绘制 } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); // 绘制顶部圆角的裁剪路径 mClipPath.reset(); mClipPath.addRoundRect(new RectF(0, 0, w, h), new float[]{mTopRadius, mTopRadius, mTopRadius, mTopRadius, 0, 0, 0, 0}, Path.Direction.CW); } @Override protected void dispatchDraw(Canvas canvas) { int saveCount = canvas.save(); canvas.clipPath(mClipPath); super.dispatchDraw(canvas); canvas.restoreToCount(saveCount); } private float dp2px(float dp) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics()); } }
然后在布局里用这个容器包裹PhotoView,就能确保任何设备上都能正确裁剪顶部圆角。
内容的提问来源于stack exchange,提问作者Belvi Nosakhare




