当使用Android绘制外部视图剪辑界限时:如何防止在我的自定义视图上绘制下划线视图?

我写了一个自定义的Android视图,需要绘制外部的剪辑边界。

这是我的:

在这里输入图像说明

这是当我点击一个button时会发生什么,说右键:

在这里输入图像说明

如何防止下面的视图在我的“句柄”之上绘制?

我的项目中的一些相关的伪代码如下。

我的自定义视图MyHandleView绘制像这样:

@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Path p = mPath; int handleWidth = mHandleWidth; int handleHeight = mHandleHeight; int left = (getWidth() >> 1) - handleWidth; canvas.save(); // allow drawing out of bounds vertically Rect clipBounds = canvas.getClipBounds(); clipBounds.inset(0, -handleHeight); canvas.clipRect(clipBounds, Region.Op.REPLACE); // translate up to draw the handle canvas.translate(left, -handleHeight); // draw my background shape canvas.drawPath(p, mPaint); canvas.restore(); } 

布局是这样的(我简化了一点):

 <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <!-- Main content of the SlidingUpPanel --> <fragment android:above=@+id/panel" class="com.neosperience.projects.percassi.android.home.HomeFragment" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="?android:attr/actionBarSize" tools:layout="@layout/fragment_home" /> <!-- The Sliding Panel --> <LinearLayout android:id="@id/panel" android:layout_width="match_parent" android:layout_height="@dimen/myFixedSize" android:alignParentBottom="true" android:orientation="vertical" android:clipChildren="false"> <MyHandleView xmlns:custom="http://schemas.android.com/apk/res-auto.com/apk/res/android" android:layout_width="match_parent" android:layout_height="0dp" custom:handleHeight="@dimen/card_panel_handle_height" custom:handleWidthRatio="@dimen/card_panel_handle_width_ratio" custom:handleBackgroundColor="#000"/> <TextView android:id="@+id/loyaltyCardPanelTitle" android:layout_width="match_parent" android:layout_height="@dimen/card_panel_height" android:background="#000" android:gravity="center" android:textStyle="bold" android:textSize="24sp" android:textColor="#fff" android:text="My TEXT"/> </LinearLayout> </RelativeLayout> 

您可以将该片段视为包含底部的两个button(在LinearLayout中)的视图。

代替外部的RelativeLayout我真的使用库中的一个视图:SlidingUpPanelLayout( https://github.com/umano/AndroidSlidingUpPanel )。 但是我用这个RelativeLayouttesting了这个行为:同样的事情,这意味着这个库是不相关的。

我只是为了让你知道, 我不能只放置一个FrameLayout,并避免在裁剪范围之外绘图

我怀疑这与事实有关,当我触摸button重绘自己,但我的其他视图(这是层次结构中的其他位置)不会被重新绘制(这是一个优化,我怀疑它可以禁用)。

我希望能够使任何其他“近”(或任何)视图无效,我的自定义视图无效,因此我需要某种监听器视图无效,但我不知道任何。

有人可以帮忙吗?

Solutions Collecting From Web of "当使用Android绘制外部视图剪辑界限时:如何防止在我的自定义视图上绘制下划线视图?"

我自己find了解决scheme,即使这不是最佳的表演。

只需添加:

 android:clipChildren="false" 

到RelativeLayout(或任何布局)。

这有2个效果(可能更多,这是我感兴趣的两个): – ViewGroup不剪辑他的孩子的绘画(显而易见) – ViewGroup不考虑与脏区域的交集(无效)在考虑哪些孩子重绘

我挖掘关于无效的视图代码。

这个过程如下所示:

  1. 一个视图本身是无效的,它通常绘制的区域(一个矩形)变成一个“脏区域”被重绘
  2. 视图告诉它的父(某种ViewGroup)它需要重绘自己
  3. 父母对根的父母也是这样做的
  4. 层次结构中的每个父级循环每个孩子,并检查脏区域是否与其中一些相交
  5. 如果这样做也重绘它们

在步骤4中涉及到了裁剪:只有在clipChildren为true的情况下,ViewGroup才会检查其子视图的边界:这意味着如果将其置于false,则在任何子视图失效时总是重绘所有子视图。

所以,我的视图层次是这样的:

 ViewGroup A | |----- fragment subtree (containing buttons, map, | whatever element that I don't want to draw | on top of my handle) | |----- ViewGroup B | |---- my handle (which draw outside its clip bounds) 

在我的情况下,“处理”将其绑定,通常由片段子树的某个元素引用。

当片段内的任何视图无效时,它将在视图树中向上传递其“脏区”,并且每个视图组将检查是否有其他孩子要在该区域中重绘。

如果我没有设置clipBounds =“false” ,ViewGroup B会剪辑我在剪辑边界之外绘制的内容。

如果在fragment子树中有任何东西被取消,ViewGroup A将会看到ViewGroup B的脏区域不与fragment子树区域相交,并且会跳过ViewGroup B的重绘。

但是,如果我也告诉ViewGroup A不剪辑儿童,它仍然会给ViewGroup B一个无效的命令,然后将导致我的句柄重绘。

所以解决scheme是确保设置

 android:clipChildren="false" 

在视图上方的层次结构中的任何ViewGroup中,绘制出内容可能落在“正在绘制的出界区域之下”的边界。

这样做的明显副作用是,无论何时我使ViewGroup A中的任何视图无效,无效呼叫都将被转发到无效区域,并将其转到所有视图中。

然而,任何视图都不会与位于ViewGroup内的,使用clipChildren =“true”(默认值)的脏区域相交的视图被跳过。

所以为了避免性能问题,请确保您的视图组与clipChildren =“true”没有太多的“标准”直接的孩子。 而“标准”我的意思是说,他们并没有超越他们的视野范围。

所以例如,如果在我的例子中ViewGroup B包含很多视图,考虑用clipChildren =“true”来包装ViewGroup中的所有视图,并且只留下这个视图组和一个在其区域之外绘制的ViewGroup B的子视图。同样的用于ViewGroup A.

这个简单的事实将确保没有其他视图将得到重绘,如果他们不在无效的脏区域最小化重绘需要。

如果有人有一个,我仍然愿意听取更多的意见;)

所以我会稍微等一下,然后将其标记为已接受的答案。

编辑:许多设备在处理clipChildren =“false”时做了一些不同的事情。 我发现我必须在我的自定义小部件的所有父视图上设置clipChildren =“false”,它可能包含层次结构中应该绘制小部件的“出界区域”的元素,或者您可能会看到您的自定义绘图显示应该覆盖它的另一种观点的ON TOP。 例如在我的布局中,我有一个导航抽屉,应该是我的“手柄”。 如果我没有在NavigationDrawer布局上设置clipChildren =“false”,我有时会看到我的手柄在打开的抽屉前popup。

编辑2:我的自定义小部件有0高度,并绘制本身的“顶部”。 在Nexus设备上工作良好,但其他许多设备都有一些“优化”,完全忽略了具有0高度或0宽度的视图的绘制。 因此,如果要编写一个可以绘制它的组件,就必须注意这一点:必须至less为其指定1个像素的高度/宽度。