Wie zeichne ich auf einen Ansichtsbereich, ohne Artefakte hoch zu skalieren, wenn der Ansichtsparent einen Skalierungsfaktor hat?

8

Wenn Sie in einer View Methode onDraw auf einen Canvas zeichnen, wissen Sie nichts über einen Skalierungsfaktor des übergeordneten Elements. Dies führt dazu, dass alle Ansichten und ihre Zeichnungen hoch / runter skaliert werden, wodurch man "pixelisierte" Zeichnungen erkunden kann.

Beispiel: Nehmen wir an, wir haben eine untergeordnete Ansicht mit einer benutzerdefinierten Zeichnung

%Vor%

Und wir fügen diese Ansicht einer übergeordneten Ansicht hinzu:

%Vor%

Die Leinwandzeichnung in der Unteransicht wird daher um Faktor 10 hochskaliert. Dies liegt daran, dass onDraw() eine Leinwand zum Zeichnen bereitstellt, die diesen Skalierungsfaktor nicht widerspiegelt. Das heißt, die Leinwand behält immer die gleichen Dimensionen, unabhängig von ihrem endgültigen Ziel. Daher haben Kinderansichten keine Möglichkeit, Zeichnungen mit höherer Auflösung zu erstellen, wenn ihre Eltern hochskaliert werden. Dies führt offensichtlich zu Skalierungsartefakten.

Sie können dasselbe Verhalten beobachten, wenn Sie die übergeordnete Ansicht einer Schaltfläche skalieren:

Gibt es eine Chance, alle Elterntransformationen zu berücksichtigen, wenn Sie auf untergeordnete Ansichten zeichnen? Oder ist dies eine allgemeine Einschränkung beim Zeichnen auf Leinwände in einer Ansichtshierarchie, in der die Ansichtselemente einen Skalierungsfaktor ungleich 1 haben können.

In meinem Anwendungsfall ist es keine Option, die Skalierungsänderung an alle untergeordneten Elemente weiterzuleiten, anstatt sie auf das übergeordnete Element anzuwenden. Dies ist aufgrund der Tatsache, dass einige dieser Kinder Animationen haben, die den Skalierungsfaktor ändern. Daher würden diese Animationen jede Maßstabsänderung außer Kraft setzen.

    
Lars Blumberg 19.05.2014, 14:05
quelle

1 Antwort

2

Dieses Problem bezieht sich auf das Kompositionsmuster. Android View Framework (das ist kein offizieller Name, aber Sie haben die Idee) folgt auch diesem Muster - ViewGroup (Basisklasse für alle Layouts) ist im Wesentlichen ein View . Wenn sich Ihr Layout also selbst zeichnet, werden nur die Inhalte aller untergeordneten Ansichten berücksichtigt. Klingt einfach.

Da API Level 11 View Transformationsmatrix kann über setScaleX , setTranslationX , etc. Methoden geändert werden (gut, in der Tat war es möglich, vor API Level 11, aber es war ein bisschen schwierig). Diese Transformation wird dann verwendet, um Zeichnungen von diesem bestimmten View zu transformieren. Wenn Sie also die Umwandlung auf ViewGroup anwenden, wirken Sie sich nur auf ViewGroup drawing aus, was wiederum darin besteht, die untergeordneten Elemente zu zeichnen.

Darüber hinaus betreffen diese Transformationen nur das Zeichnen und Versenden von Bewegungsereignissen. Wenn Sie also setScale* anwenden, ändern Sie nur die visuelle Repräsentation von View , während die logischen Koordinaten und die Größe von View gleich bleiben ( getLeft , getTop , getRight , getBottom , getWidth , getHeight ).

Jetzt näher zu Ihrer Frage. Kurz gesagt - Sie machen es falsch. Eine ausführlichere Erklärung folgt aus meinen früheren Aussagen. Wenn Sie die Umwandlung von View beeinflussen, ändern Sie nicht seine logische Position und Größe. Daher erkennt child View während des Zeichnens nichts Ungewöhnliches - es zeichnet, als ob überhaupt keine Skalierung vorhanden wäre.

Was dann zu tun? Ich würde drei verschiedene Lösungen vorschlagen.

  • Meine Lieblingslösung, die ich ziemlich oft benutze. Setze deine View aus dem Layout, das skaliert wird, und füge es hinzu. Dann müssen Sie diese View manuell skalieren, wobei Daten dahinter berücksichtigt werden.
  • Überschreiben Sie die Methode setScale des Layouts, die so skaliert wird, dass sie an untergeordnete Elemente weitergegeben wird. Sie können eine Schnittstelle erstellen und überprüfen, ob einer der Kinder sie implementiert.
  • Umgekehrt. In Ihrem View durchlaufen Sie alle übergeordneten Elemente, bis Sie den Stamm finden und die Skalierung entsprechend berechnen. Dies sollte nicht zu viel Arbeit sein, wenn Ihre Hierarchie nicht zu tief ist.
Dmitry Zaytsev 21.05.2014, 16:25
quelle