Android中动画ImageView被椭圆遮罩层遮挡,如何调整显示层级?
解决ImageView被椭圆遮罩层遮挡的问题
嘿,我来帮你搞定这个遮挡问题!你遇到的情况其实是因为两个关键点:一是你的OverlayView使用了PorterDuff.Mode.CLEAR的混合模式且开启了软件图层,导致普通的elevation或z-index设置失效;二是视图的绘制顺序——默认情况下,布局中后添加的视图会被绘制在前面,所以如果你的遮罩层在ImageView之后添加,就会挡住它。
下面是具体的解决方案:
1. 调整布局层级(最直接有效)
在你的布局文件中,把OverlayView放在ImageView所在的LinearLayout前面。因为RelativeLayout的绘制顺序是按照视图在布局中声明的顺序来的,后面的视图会覆盖前面的。修改后的布局如下:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/relativeLayoutRoot" android:layout_width="fill_parent" android:layout_height="fill_parent"> <!-- 相机视图放在最底层 --> <net.ossrs.yasea.SrsCameraView android:id="@+id/glsurfaceview_camera" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignParentBottom="true" android:layout_alignParentEnd="true" android:layout_alignParentLeft="true" android:layout_alignParentRight="true" android:layout_alignParentStart="true" android:layout_alignParentTop="true" /> <!-- 遮罩层放在中间层 --> <com.yourpackage.OverlayView android:id="@+id/overlayView" android:layout_width="match_parent" android:layout_height="match_parent" /> <!-- ImageView放在最上层 --> <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:clipChildren="false" android:clipToPadding="false" android:gravity="center_vertical" android:orientation="vertical"> <ImageView android:id="@+id/faceView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/id_face"/> </LinearLayout> </RelativeLayout>
记得把com.yourpackage.OverlayView替换成你实际的包名+类名,然后在代码中初始化遮罩层:
OverlayView overlayView = findViewById(R.id.overlayView); overlayView.init(Color.WHITE, horizontalMarginValue, verticalMarginValue); // 传入你的边框颜色和边距参数
2. 如果是动态添加视图
如果遮罩层是通过代码动态添加到布局中的,那么要确保先添加遮罩层,再添加ImageView,或者在添加完成后调用bringChildToFront()把ImageView前置:
RelativeLayout root = findViewById(R.id.relativeLayoutRoot); // 先添加遮罩层 root.addView(overlayView); // 再添加ImageView的容器(或者ImageView本身) root.addView(linearLayoutWithImageView); // 或者如果已经添加了所有视图,手动把ImageView前置 root.bringChildToFront(findViewById(R.id.faceView));
3. 改用属性动画(可选,更可靠)
你现在用的TranslateAnimation是旧的补间动画,它只是改变视图的绘制位置,不会修改视图的实际布局参数。改用属性动画ObjectAnimator不仅动画效果更稳定,也能避免一些层级相关的潜在问题:
private void moveViewToScreenCenter(View view) { final RelativeLayout root = findViewById(R.id.relativeLayoutRoot); DisplayMetrics dm = new DisplayMetrics(); this.getWindowManager().getDefaultDisplay().getMetrics(dm); int statusBarOffset = dm.heightPixels - root.getMeasuredHeight(); int xDest = dm.widthPixels / 2 - view.getMeasuredWidth() / 2; int yDest = dm.heightPixels / 2 - view.getMeasuredHeight() / 2 - statusBarOffset; faceView.setVisibility(View.VISIBLE); Toast.makeText(this, "Please place your face within the oval.", Toast.LENGTH_LONG).show(); // 使用属性动画实现平移动画 ObjectAnimator animX = ObjectAnimator.ofFloat(view, "translationX", xDest - view.getLeft()); ObjectAnimator animY = ObjectAnimator.ofFloat(view, "translationY", yDest - view.getTop()); AnimatorSet animSet = new AnimatorSet(); animSet.playTogether(animX, animY); animSet.setDuration(1000); animSet.start(); }
为什么之前的方法没用?
elevation依赖硬件加速,但你的OverlayView设置了setLayerType(LAYER_TYPE_SOFTWARE, null),所以这个属性完全不起作用。z-index在RelativeLayout中其实是由视图的添加顺序决定的,不是单独的属性,所以直接设置没用。- 如果你之前尝试的
bringToFront()没生效,可能是因为遮罩层的软件图层特性导致绘制顺序不受这个方法影响,调整布局顺序是更稳妥的方式。
内容的提问来源于stack exchange,提问作者Alix Depauw
相关产品推荐
相关产品推荐

