При рисовании вне рамки клипа просмотра с Android: как я могу предотвратить недоразвитие представлений от рисования поверх моего пользовательского представления?

Я написал пользовательский вид Android, который нужно рисовать вне его границ.

Это то, что у меня есть:

Введите описание изображения здесь

Это то, что происходит, когда я нажимаю кнопку, скажем, правой кнопкой:

Введите описание изображения здесь

Как я могу предотвратить просмотр ниже, чтобы нарисовать поверх моего «дескриптора»?

Следующий связанный псевдокод из моего проекта.

Мой пользовательский вид 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> 

Вы можете представить фрагмент как представление, содержащее две кнопки внизу, в LinearLayout.

Вместо внешнего RelativeLayout я действительно использую представление из библиотеки: SlidingUpPanelLayout ( https://github.com/umano/AndroidSlidingUpPanel ). Но я тестировал поведение с этим RelativeLayout: то же самое, что означает, что библиотека не связана.

Я говорю это просто, чтобы вы знали, что я не могу просто разместить там FrameLayout и избежать рисования вне границ отсечения .

Я подозреваю, что это связано с тем, что когда я касаюсь кнопки, она перерисовывается сама, но мой другой вид (который находится где-то еще в иерархии) не получает повторного рисования (это оптимизация, и я сомневаюсь, что это может быть отключен).

Я хотел бы иметь возможность аннулировать мой пользовательский просмотр всякий раз, когда любое другое «близкое» (или любое) представление get становится недействительным, поэтому мне нужен какой-то прослушиватель при недействительности вида, но я не знаю никого.

Может кто-нибудь помочь?

Solutions Collecting From Web of "При рисовании вне рамки клипа просмотра с Android: как я могу предотвратить недоразвитие представлений от рисования поверх моего пользовательского представления?"

Я нашел решение самостоятельно, даже если это не оптимально для выступлений.

Просто добавь:

 android:clipChildren="false" 

К RelativeLayout (или любой другой макет, который у вас есть).

Это имеет 2 эффекта (может быть, это больше меня интересует): – ViewGroup не обрезает рисунок своих детей (очевидно) – ViewGroup не проверяет пересечение с грязными регионами (недействительными) при рассмотрении Которые дети перерисовывают

Я выкопал код представления о недействительности.

Процесс идет, больше или нравится, вот так:

  1. A Вид недействителен сам, регион, который он обычно рисует (прямоугольник), становится «грязной областью», которую нужно перерисовать
  2. Представление указывает его родительский элемент (например, ViewGroup), он должен перерисовать себя
  3. Родители делают то же самое с родителем с корнем
  4. Каждый родитель в петле иерархии для каждого ребенка и проверьте, пересекает ли грязная область некоторые из них
  5. Если он это также перерисовывает

На шаге 4 задействовано обрезание: ViewGroup проверяет границы своего дочернего объекта, только если clipChildren является истинным: это означает, что если вы поместите его в false, он всегда перерисовывает все его дочерние элементы, когда какой-либо из них будет признан недействительным .

Итак, моя иерархия View была такой:

 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) 

В моем случае «дескриптор» извлекает из привязки, поверх того, что обычно вытягивается каким-то элементом поддерева фрагмента.

Когда какое-либо представление внутри фрагмента недействительно, оно пропускает свою «грязную область» вверх в дереве просмотра, и каждая группа просмотра проверяет, есть ли в этом регионе другие дети, которые будут перерисовываться.

ViewGroup B будет зажимать то, что я рисую вне границ клипа, если я не устанавливаю на нем clipBounds = "false" .

Если что-то получится недействительным в поддереве фрагмента, ViewGroup A увидит, что грязная область ViewGroup B не пересекает область поддерева фрагмента и пропустит перерисовку ViewGroup B.

Но если я также скажу ViewGroup A о том, чтобы не создавать дочерние ролики, он все равно предоставит ViewGroup B команду invalidate, которая затем вызовет перерисовку моего дескриптора.

Поэтому решение состоит в том, чтобы установить

 android:clipChildren="false" 

На любой ViewGroup в иерархии над представлением, которая вытягивает из своих границ, на которых контент может упасть «под» областью вне привязки, которую вы рисуете.

Очевидным побочным эффектом этого является то, что всякий раз, когда я аннулирую любой вид внутри ViewGroup A, вызов invalidate будет перенаправлен с недопустимой областью ко всему просмотру в нем.

Однако любое представление, которое не пересекает грязную область, находящуюся внутри ViewGroup с clipChildren = "true" (по умолчанию), будет пропущено.

Поэтому, чтобы избежать проблем с производительностью при выполнении этого, убедитесь, что в ваших группах просмотра с clipChildren = "true" не так много «стандартных» прямых детей. И с «стандартным» я имею в виду, что они не выходят за пределы их взглядов.

Так, например, если в моем примере ViewGroup B содержит много просмотров, рассмотрим возможность обертывания всех тех, что есть в ViewGroup, с помощью clipChildren = "true" и оставить эту группу представлений и одно представление, которое выводит вне его региона в качестве прямых дочерних элементов ViewGroup B. То же самое происходит Для ViewGroup A.

Этот простой факт гарантирует, что ни один другой вид не получит перерисовку, если они не находятся в недействительной грязной области, минимизирующей необходимые перерисовывания.

Я все еще открыт, чтобы услышать больше внимания, если у кого-то есть;)

Поэтому я подожду немного, прежде чем отметить это как принятый ответ.

EDIT: Многие устройства выполняют что-то другое при обработке clipChildren = "false". Я обнаружил, что мне пришлось установить clipChildren = «false» во всех родительских представлениях моего пользовательского виджета, который может содержать элементы в их иерархии, которые должны нарисовать «вне привязанной области» виджета, или вы можете увидеть свой собственный рисунок Показывая ON TOP другого представления, которое должно было его покрыть. Например, в моем макете у меня был навигационный ящик, который должен был покрывать мою «ручку». Если я не установил clipChildren = "false" в макете NavigationDrawer, я иногда вижу, что мой дескриптор появляется перед открытым ящиком.

EDIT2: у моего пользовательского виджета была высота 0 и выведена «сверху». Работала отлично на устройствах Nexus, но у многих других была определенная «оптимизация», которая полностью пропускает чертежи, имеющие ширину 0 или 0. Поэтому имейте это в виду, если вы хотите написать компонент, который извлекается из его привязки: вы должны назначить его как минимум 1 пиксель высоты / ширины.