Ответ 1
Я нашел решение самостоятельно, даже если это не оптимально для выступлений.
Просто добавьте:
android:clipChildren="false"
в RelativeLayout (или любой другой макет, который у вас есть).
У этого есть 2 эффекта (может быть больше, это два, которые меня интересовали): - ViewGroup не обрезает рисунок своих детей (очевидно) - ViewGroup не проверяет пересечение с грязными регионами (недействительными) при рассмотрении того, какие дети перерисовывают
Я выкопал код представления о недействительности.
Процесс идет, больше или как, например:
- a Вид недействителен сам, область, которую он обычно рисует (прямоугольник), становится "грязной областью" для перерисовки
- В представлении отображается его родительский элемент (какая-то ViewGroup), он должен перерисовать себя
- родители делают то же самое с родительским корнем
- каждый родительский элемент в цикле иерархии для каждого дочернего элемента и проверьте, не пересекаются ли грязные области некоторых из них.
- если он также перерисовывает их
В шаге 4 задействуется обрезка: ViewGroup проверяет границы своего дочернего объекта, только если clipChildren имеет значение true: это означает, что если вы поместите его в 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 пиксель высоты/ширины.